[DEV] add spread mode and better calculation
This commit is contained in:
parent
063ae69628
commit
c613a23825
@ -56,24 +56,22 @@ bool esvg::LinearGradient::parseXML(const std::shared_ptr<exml::Element>& _eleme
|
||||
contentX = _element->getAttribute("gradientUnits");
|
||||
if (contentX == "userSpaceOnUse") {
|
||||
m_unit = gradientUnits_userSpaceOnUse;
|
||||
} else if (contentX == "objectBoundingBox") {
|
||||
m_unit = gradientUnits_objectBoundingBox;
|
||||
} else {
|
||||
// by default we will use "objectBoundingBox"
|
||||
m_unit = gradientUnits_objectBoundingBox;
|
||||
if (contentX.size() != 0) {
|
||||
if ( contentX.size() != 0
|
||||
&& contentX != "objectBoundingBox") {
|
||||
ESVG_ERROR("Parsing error of 'gradientUnits' ==> not suported value: '" << contentX << "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
|
||||
}
|
||||
}
|
||||
contentX = _element->getAttribute("spreadMethod");
|
||||
if (contentX == "reflect") {
|
||||
m_spread = spreadMethod_reflect;
|
||||
} else if (contentX == "repeate") {
|
||||
m_spread = spreadMethod_repeate;
|
||||
} else if (contentX == "repeat") {
|
||||
m_spread = spreadMethod_repeat;
|
||||
} else {
|
||||
// by default we will use "none"
|
||||
m_spread = spreadMethod_pad;
|
||||
if (contentX.size() != 0) {
|
||||
if ( contentX.size() != 0
|
||||
&& contentX != "pad") {
|
||||
ESVG_ERROR("Parsing error of 'spreadMethod' ==> not suported value: '" << contentX << "' not in : {reflect/repeate/pad} use pad");
|
||||
}
|
||||
}
|
||||
|
@ -58,9 +58,27 @@ etk::Color<float,4> esvg::render::DynamicColorLinear::getColor(const ivec2& _pos
|
||||
vec2 vectorBaseDraw = intersec - m_pos1;
|
||||
float baseDraw = vectorBaseDraw.length();
|
||||
ratio = baseDraw / baseSize;
|
||||
//ratio -= float(int32_t(ratio));
|
||||
if (vectorBase.dot(vectorBaseDraw) < 0) {
|
||||
ratio *= -1.0;
|
||||
switch(m_spread) {
|
||||
case spreadMethod_pad:
|
||||
if (vectorBase.dot(vectorBaseDraw) < 0) {
|
||||
ratio *= -1.0;
|
||||
}
|
||||
break;
|
||||
case spreadMethod_reflect:
|
||||
ratio -= float((int32_t(ratio)>>1)<<1);
|
||||
if (ratio > 1.0f) {
|
||||
ratio = 2.0f-ratio;
|
||||
}
|
||||
break;
|
||||
case spreadMethod_repeat:
|
||||
if (vectorBase.dot(vectorBaseDraw) < 0) {
|
||||
ratio *= -1.0;
|
||||
}
|
||||
ratio -= float(int32_t(ratio));
|
||||
if (ratio <0.0f) {
|
||||
ratio = 1.0f-std::abs(ratio);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
|
||||
@ -72,25 +90,60 @@ etk::Color<float,4> esvg::render::DynamicColorLinear::getColor(const ivec2& _pos
|
||||
vec2 vectorBaseDrawY = intersecY - m_pos1;
|
||||
float baseDrawX = vectorBaseDrawX.length();
|
||||
float baseDrawY = vectorBaseDrawY.length();
|
||||
if (m_baseSize.x() != 0.0f) {
|
||||
float val = baseDrawX/m_baseSize.x();
|
||||
#if 1
|
||||
if (m_axeX.dot(vectorBaseDrawX) < 0) {
|
||||
val *= -1.0;
|
||||
baseDrawX *= -1.0f;
|
||||
}
|
||||
if (m_baseSize.y() == 0.0f) {
|
||||
val *= 0.5f;
|
||||
}
|
||||
ratio += val;
|
||||
}
|
||||
if (m_baseSize.y() != 0.0f) {
|
||||
float val = baseDrawY/m_baseSize.y();
|
||||
if (m_axeY.dot(vectorBaseDrawY) < 0) {
|
||||
val *= -1.0;
|
||||
baseDrawY *= -1.0f;
|
||||
}
|
||||
if (m_baseSize.x() == 0.0f) {
|
||||
val *= 0.5f;
|
||||
if (m_baseSize.x()+m_baseSize.y() != 0.0f) {
|
||||
if ( m_baseSize.x() != 0.0f
|
||||
&& m_baseSize.y() != 0.0f) {
|
||||
ratio = (baseDrawX*m_baseSize.y() + baseDrawY*m_baseSize.x())/(m_baseSize.x()*m_baseSize.y()*2.0f);
|
||||
} else if (m_baseSize.x() != 0.0f) {
|
||||
ratio = baseDrawX/m_baseSize.x();
|
||||
} else {
|
||||
ratio = baseDrawY/m_baseSize.y();
|
||||
}
|
||||
} else {
|
||||
ratio = 1.0f;
|
||||
}
|
||||
ratio += val;
|
||||
#else
|
||||
bool dotX = m_axeX.dot(vectorBaseDrawX) < 0;
|
||||
bool dotY = m_axeY.dot(vectorBaseDrawY) < 0;
|
||||
if (m_baseSize.x()+m_baseSize.y() != 0.0f) {
|
||||
if (dotX != dotY) {
|
||||
if (dotX == false) {
|
||||
ratio = (-baseDrawX*m_baseSize.y() + baseDrawY*m_baseSize.x())/(m_baseSize.x()*m_baseSize.y()*2.0f);
|
||||
} else {
|
||||
ratio = (baseDrawX*m_baseSize.y() - baseDrawY*m_baseSize.x())/(m_baseSize.x()*m_baseSize.y()*2.0f);
|
||||
}
|
||||
if (ratio < 0.0f) {
|
||||
ratio *= -1;
|
||||
}
|
||||
} else {
|
||||
ratio = (baseDrawX*m_baseSize.y() + baseDrawY*m_baseSize.x())/(m_baseSize.x()*m_baseSize.y()*2.0f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
switch(m_spread) {
|
||||
case spreadMethod_pad:
|
||||
// nothing to do ...
|
||||
break;
|
||||
case spreadMethod_reflect:
|
||||
ratio = std::abs(ratio);
|
||||
ratio -= float((int32_t(ratio)>>1)<<1);
|
||||
if (ratio > 1.0f) {
|
||||
ratio = 2.0f-ratio;
|
||||
}
|
||||
break;
|
||||
case spreadMethod_repeat:
|
||||
ratio -= float(int32_t(ratio));
|
||||
if (ratio <0.0f) {
|
||||
ratio = 1.0f-std::abs(ratio);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ratio <= m_data[0].first*0.01f) {
|
||||
@ -148,8 +201,19 @@ void esvg::render::DynamicColorLinear::generate(esvg::Document* _document) {
|
||||
m_pos1 = m_matrix * m_pos1;
|
||||
m_pos2 = m_matrix * m_pos2;
|
||||
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
|
||||
m_axeX = m_matrix.applyScaleRotation(vec2(1.0f, 0.0f));
|
||||
m_axeY = m_matrix.applyScaleRotation(vec2(0.0f, 1.0f));
|
||||
vec2 delta = m_pos2 - m_pos1;
|
||||
if (delta.x() < 0.0f) {
|
||||
m_axeX = vec2(-1.0f, 0.0f);
|
||||
} else {
|
||||
m_axeX = vec2(1.0f, 0.0f);
|
||||
}
|
||||
if (delta.y() < 0.0f) {
|
||||
m_axeY = vec2(0.0f, -1.0f);
|
||||
} else {
|
||||
m_axeY = vec2(0.0f, 1.0f);
|
||||
}
|
||||
m_axeX = m_matrix.applyScaleRotation(m_axeX);
|
||||
m_axeY = m_matrix.applyScaleRotation(m_axeY);
|
||||
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
|
||||
vec2 intersecX = getIntersect(m_pos1, m_axeX,
|
||||
m_pos2, m_axeY);
|
||||
|
@ -12,7 +12,7 @@
|
||||
static const char* values[] = {
|
||||
"pad",
|
||||
"reflect",
|
||||
"repeate"
|
||||
"repeat"
|
||||
};
|
||||
|
||||
std::ostream& esvg::operator <<(std::ostream& _os, enum esvg::spreadMethod _obj) {
|
||||
|
@ -15,7 +15,7 @@ namespace esvg {
|
||||
enum spreadMethod {
|
||||
spreadMethod_pad,
|
||||
spreadMethod_reflect,
|
||||
spreadMethod_repeate
|
||||
spreadMethod_repeat
|
||||
};
|
||||
/**
|
||||
* @brief Debug operator To display the curent element in a Human redeable information
|
||||
|
@ -224,3 +224,143 @@ TEST(TestGradientLinear, inkscape) {
|
||||
}
|
||||
|
||||
|
||||
TEST(TestGradientLinear, unitBox_spreadNone) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%'>\n"
|
||||
" <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
|
||||
" </linearGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientLinear_unitBox_spreadNone.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitBox_spreadNone.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestGradientLinear, unitBox_spreadPad) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='pad'>\n"
|
||||
" <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
|
||||
" </linearGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientLinear_unitBox_spreadPad.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitBox_spreadPad.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
|
||||
TEST(TestGradientLinear, unitBox_spreadReflect) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='reflect'>\n"
|
||||
" <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
|
||||
" </linearGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientLinear_unitBox_spreadReflect.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitBox_spreadReflect.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
|
||||
TEST(TestGradientLinear, unitBox_spreadRepeate) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='repeat'>\n"
|
||||
" <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
|
||||
" </linearGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientLinear_unitBox_spreadRepeate.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitBox_spreadRepeate.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestGradientLinear, unitUser_spreadNone) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' gradientUnits='userSpaceOnUse'>\n"
|
||||
" <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
|
||||
" </linearGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientLinear_unitUser_spreadNone.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitUser_spreadNone.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestGradientLinear, unitUser_spreadPad) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='pad' gradientUnits='userSpaceOnUse' >\n"
|
||||
" <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
|
||||
" </linearGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientLinear_unitUser_spreadPad.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitUser_spreadPad.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
|
||||
TEST(TestGradientLinear, unitUser_spreadReflect) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n"
|
||||
" <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
|
||||
" </linearGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientLinear_unitUser_spreadReflect.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitUser_spreadReflect.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
|
||||
TEST(TestGradientLinear, unitUser_spreadRepeate) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n"
|
||||
" <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
|
||||
" </linearGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientLinear_unitUser_spreadRepeate.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitUser_spreadRepeate.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user