[DEV] start think of the gradient rendering ==> very complicated ...

This commit is contained in:
Edouard DUPIN 2015-12-08 21:42:30 +01:00
parent effc33ef14
commit 7e67a54e32
22 changed files with 292 additions and 298 deletions

View File

@ -17,8 +17,8 @@ const float esvg::kappa90(0.5522847493f);
#define __class__ "PaintState"
esvg::PaintState::PaintState() :
fill(etk::color::black),
stroke(etk::color::none),
fill(std::pair<etk::Color<float,4>, std::string>(etk::color::black, "")),
stroke(std::pair<etk::Color<float,4>, std::string>(etk::color::none, "")),
strokeWidth(1.0f),
flagEvenOdd(false),
lineCap(esvg::cap_butt),
@ -30,8 +30,8 @@ esvg::PaintState::PaintState() :
}
void esvg::PaintState::clear() {
fill = etk::color::black;
stroke = etk::color::none;
fill = std::pair<etk::Color<float,4>, std::string>(etk::color::black, "");
stroke = std::pair<etk::Color<float,4>, std::string>(etk::color::none, "");
strokeWidth = 1.0;
viewPort.setValue(255,255);
flagEvenOdd = false;
@ -151,10 +151,9 @@ std::pair<float, enum esvg::distance> esvg::Base::parseLength2(const std::string
}
SVG_VERBOSE(" lenght : '" << n << "' => unit=" << unit);
// note : ";" is for the parsing of the style elements ...
if( unit.size() == 0
|| unit[0] == ';' ) {
if(unit.size() == 0) {
return std::make_pair(n, esvg::distance_pixel);
} else if (unit[0] == '%') { // xxx %
} else if (unit[0] == '%') { // xxx %
return std::make_pair(n, esvg::distance_pourcent);
} else if ( unit[0] == 'e'
&& unit[1] == 'm') { // xxx em
@ -212,43 +211,14 @@ float esvg::Base::parseLength(const std::string& _dataInput) {
return 0.0f;
}
// return the next char position ... (after ';' or NULL)
int32_t esvg::extractPartOfStyle(const std::string& _data, std::string& _outputType, std::string& _outputData, int32_t _pos) {
_outputType = "";
_outputData = "";
if (_pos == -1) {
return -2;
}
bool processFirst=true;
//SVG_DEBUG("parse : '" << _data.Extract(_pos) << "'");
for( int32_t iii=_pos; iii<_data.size(); iii++) {
//SVG_DEBUG(" ? '" << _data[iii] << "'");
if (_data[iii] == ';') {
// end of the element
return iii+1;
}
if (_data[iii] == ' ') {
// nothing to do ... we do not copy espaces ...
} else if (_data[iii] == ':') {
processFirst = false;
} else {
if (processFirst) {
_outputType += _data[iii];
} else {
_outputData += _data[iii];
}
}
}
SVG_VERBOSE(" extract : '" << _outputType << "':'" << _outputData << "'");
return -1;
}
void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _element) {
if (_element == nullptr) {
return;
}
/*
bool fillNone = false;
bool strokeNone = false;
*/
std::string content;
// ---------------- get unique ID ----------------
m_id = _element->getAttribute("id");
@ -256,9 +226,11 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
content = _element->getAttribute("stroke");
if (content.size()!=0) {
m_paint.stroke = parseColor(content);
if (m_paint.stroke.a() == 0) {
/*
if (m_paint.stroke.first.a() == 0) {
strokeNone = true;
}
*/
}
content = _element->getAttribute("stroke-width");
if (content.size()!=0) {
@ -268,7 +240,7 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
if (content.size()!=0) {
float opacity = parseLength(content);
opacity = std::avg(0.0f, opacity, 1.0f);
m_paint.stroke.setA(opacity);
m_paint.stroke.first.setA(opacity);
}
content = _element->getAttribute("stroke-dasharray");
@ -314,15 +286,17 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
content = _element->getAttribute("fill");
if (content.size()!=0) {
m_paint.fill = parseColor(content);
/*
if (m_paint.fill.a() == 0) {
fillNone = true;
}
*/
}
content = _element->getAttribute("fill-opacity");
if (content.size()!=0) {
float opacity = parseLength(content);
opacity = std::avg(0.0f, opacity, 1.0f);
m_paint.fill.setA(opacity);
m_paint.fill.first.setA(opacity);
}
content = _element->getAttribute("fill-rule");
if (content.size()!=0) {
@ -340,102 +314,20 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
m_paint.opacity = parseLength(content);
m_paint.opacity = std::avg(0.0f, m_paint.opacity, 1.0f);
}
// ---------------- STYLE ----------------
content = _element->getAttribute("style");
if (content.size()!=0) {
std::string outputType;
std::string outputValue;
for( int32_t sss=extractPartOfStyle(content, outputType, outputValue, 0);
-2 != sss;
sss=extractPartOfStyle(content, outputType, outputValue, sss) ) {
SVG_VERBOSE(" style parse : \"" << outputType << "\" with value : \"" << outputValue << "\"");
if (outputType == "fill") {
m_paint.fill = parseColor(outputValue);
SVG_VERBOSE(" input : \"" << outputValue << "\" == > " << m_paint.fill);
if (m_paint.fill.a() == 0) {
fillNone = true;
}
} else if (outputType == "stroke") {
m_paint.stroke = parseColor(outputValue);
SVG_VERBOSE(" input : \"" << outputValue << "\" == > " << m_paint.stroke);
if (m_paint.stroke.a() == 0) {
strokeNone = true;
}
} else if (outputType == "stroke-width" ) {
m_paint.strokeWidth = parseLength(outputValue);
SVG_VERBOSE(" input : \"" << outputValue << "\" == > " << m_paint.strokeWidth);
} else if (outputType == "opacity" ) {
m_paint.opacity = parseLength(content);
m_paint.opacity = std::avg(0.0f, m_paint.opacity, 1.0f);
SVG_VERBOSE(" input : \"" << outputValue << "\" == > " << m_paint.opacity);
} else if (outputType == "fill-opacity") {
float opacity = parseLength(outputValue);
opacity = std::avg(0.0f, opacity, 1.0f);
m_paint.fill.setA(opacity);
SVG_VERBOSE(" input : \"" << outputValue << "\" == > " << m_paint.fill);
} else if (outputType == "stroke-opacity") {
float opacity = parseLength(outputValue);
opacity = std::avg(0.0f, opacity, 1.0f);
m_paint.stroke.setA(opacity);
SVG_VERBOSE(" input : \"" << outputValue << "\" == > " << m_paint.stroke);
} else if (outputType == "fill-rule" ) {
if (outputValue == "nonzero" ) {
m_paint.flagEvenOdd = false;
} else if (outputValue == "evenodd") {
m_paint.flagEvenOdd = true;
} else {
SVG_ERROR("not know " << outputType << " value : \"" << outputValue << "\", not in [nonzero,evenodd]");
}
} else if (outputType == "stroke-linecap") {
if (outputValue == "butt") {
m_paint.lineCap = esvg::cap_butt;
} else if (outputValue == "round") {
m_paint.lineCap = esvg::cap_round;
} else if (outputValue == "square") {
m_paint.lineCap = esvg::cap_square;
} else {
m_paint.lineCap = esvg::cap_butt;
SVG_ERROR("not know " << outputType << " value : \"" << outputValue << "\", not in [butt,round,square]");
}
} else if (outputType == "stroke-linejoin") {
if (outputValue == "miter") {
m_paint.lineJoin = esvg::join_miter;
} else if (outputValue == "round") {
m_paint.lineJoin = esvg::join_round;
} else if (outputValue == "bevel") {
m_paint.lineJoin = esvg::join_bevel;
} else {
m_paint.lineJoin = esvg::join_miter;
SVG_ERROR("not know " << outputType << " value : \"" << outputValue << "\", not in [miter,round,bevel]");
}
} else if (outputType == "stroke-dasharray") {
if (outputValue == "none") {
// OK, Nothing to do ...
} else {
SVG_TODO(" 'stroke-dasharray' not implemented ...");
}
} else if (outputType == "stroke-miterlimit") {
float tmp = parseLength(outputValue);
m_paint.miterLimit = std::max(0.0f, tmp);
} else if (outputType == "marker-start") {
// TODO : ...
} else {
SVG_ERROR("not know painting element in style balise : \"" << outputType << "\" with value : \"" << outputValue << "\"");
}
}
}
// Note : No parsing of 'style' it is already converted in attribute before...
// check if somewere none is set to the filling:
/*
if (fillNone == true) {
m_paint.fill.setA(0.0f);
}
if (strokeNone == true) {
m_paint.stroke.setA(0.0f);
}
*/
}
etk::Color<uint8_t,4> esvg::Base::parseColor(const std::string& _inputData) {
etk::Color<uint8_t,4> localColor = etk::color::white;
std::pair<etk::Color<float,4>, std::string> esvg::Base::parseColor(const std::string& _inputData) {
std::pair<etk::Color<float,4>, std::string> localColor(etk::color::white, "");
if( _inputData.size() > 4
&& _inputData[0] == 'u'
@ -443,13 +335,14 @@ etk::Color<uint8_t,4> esvg::Base::parseColor(const std::string& _inputData) {
&& _inputData[2] == 'l'
&& _inputData[3] == '(') {
if (_inputData[4] == '#') {
// TODO : parse gradient ...
localColor = std::pair<etk::Color<float,4>, std::string>(etk::color::none, &(_inputData[5]));
} else {
SVG_ERROR(" pb in parsing the color : \"" << _inputData << "\" == > url(XXX) is not supported now ...");
}
SVG_ERROR(" pb in parsing the color : \"" << _inputData << "\" == > url(XXX) is not supported now ...");
} else {
localColor = etk::Color<uint8_t,4>(_inputData);
localColor = std::pair<etk::Color<float,4>, std::string>(_inputData, "");
}
SVG_VERBOSE("Parse color : \"" << _inputData << "\" == > " << localColor);
SVG_VERBOSE("Parse color : \"" << _inputData << "\" == > " << localColor.first << " " << localColor.second);
return localColor;
}

View File

@ -40,8 +40,8 @@ namespace esvg {
PaintState();
void clear();
public:
etk::Color<float,4> fill;
etk::Color<float,4> stroke;
std::pair<etk::Color<float,4>, std::string> fill;
std::pair<etk::Color<float,4>, std::string> stroke;
float strokeWidth;
bool flagEvenOdd; //!< Fill rules
enum esvg::cap lineCap;
@ -51,8 +51,6 @@ namespace esvg {
float opacity;
};
int32_t extractPartOfStyle(const std::string& _data, std::string& _outputType, std::string& _outputData, int32_t _pos);
class Base {
protected:
PaintState m_paint;
@ -95,9 +93,9 @@ namespace esvg {
/**
* @brief parse a color specification from the svg file
* @param[in] _inputData Data C String with the xml definition
* @return the parsed color
* @return The parsed color (color used and the link if needed)
*/
etk::Color<uint8_t,4> parseColor(const std::string& _inputData);
std::pair<etk::Color<float,4>, std::string> parseColor(const std::string& _inputData);
protected:
std::string m_id; //!< unique ID of the element.
public:

View File

@ -102,8 +102,13 @@ void esvg::Circle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorStroke;
if (m_paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort);
}
// Check if we need to display background
if (m_paint.fill.a() != 0x00) {
if (colorFill != nullptr) {
listSegmentFill.createSegmentList(listPoints);
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -112,8 +117,7 @@ void esvg::Circle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
listSegmentFill);
}
// check if we need to display stroke:
if ( m_paint.strokeWidth > 0
&& m_paint.stroke.a() != 0x00) {
if (colorStroke != nullptr) {
listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth,
m_paint.lineCap,
@ -127,9 +131,9 @@ void esvg::Circle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
}
// add on images:
_myRenderer.print(tmpFill,
m_paint.fill,
colorFill,
tmpStroke,
m_paint.stroke,
colorStroke,
m_paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);

View File

@ -75,8 +75,8 @@ void esvg::Dimension::set(std::string _config) {
SVG_VERBOSE(" config dimention : \"" << _config << "\" == > " << *this );
}
static enum distance parseType(std::string& _config) {
enum distance type = esvg::distance_pixel;
static enum esvg::distance parseType(std::string& _config) {
enum esvg::distance type = esvg::distance_pixel;
if (etk::end_with(_config, "%", false) == true) {
type = esvg::distance_pourcent;
_config.erase(_config.size()-1, 1);
@ -120,7 +120,7 @@ void esvg::Dimension::set(std::string _configX, std::string _configY) {
float valueY = etk::string_to_float(_configY);
// TODO : Check difference ...
set(vec2(valueX, valueY), typeX);
SVG_VERBOSE(" config dimention : \"" << _config << "\" == > " << *this );
SVG_VERBOSE(" config dimention : '" << _configX << "' '" << _configY << "' == > " << *this );
}

View File

@ -97,7 +97,7 @@ namespace esvg {
*/
void set(const vec2& _size, enum distance _type);
private:
public:
/**
* @brief set the current dimention in requested type
* @param[in] _config dimension configuration.

View File

@ -107,8 +107,13 @@ void esvg::Ellipse::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorStroke;
if (m_paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort);
}
// Check if we need to display background
if (m_paint.fill.a() != 0x00) {
if (colorFill != nullptr) {
listSegmentFill.createSegmentList(listPoints);
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -117,8 +122,7 @@ void esvg::Ellipse::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
listSegmentFill);
}
// check if we need to display stroke:
if ( m_paint.strokeWidth > 0
&& m_paint.stroke.a() != 0x00) {
if (colorStroke != nullptr) {
listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth,
m_paint.lineCap,
@ -132,9 +136,9 @@ void esvg::Ellipse::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
}
// add on images:
_myRenderer.print(tmpFill,
m_paint.fill,
colorFill,
tmpStroke,
m_paint.stroke,
colorStroke,
m_paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);

View File

@ -99,7 +99,9 @@ bool esvg::Group::parseXML(const std::shared_ptr<exml::Element>& _element, mat2&
}
void esvg::Group::display(int32_t _spacing) {
SVG_DEBUG(spacingDist(_spacing) << "Group (START) fill=" << m_paint.fill << " stroke=" << m_paint.stroke << " stroke-width=" << m_paint.strokeWidth );
SVG_DEBUG(spacingDist(_spacing) << "Group (START) fill=" << m_paint.fill.first << "/" << m_paint.fill.second
<< " stroke=" << m_paint.stroke.first << "/" << m_paint.stroke.second
<< " stroke-width=" << m_paint.strokeWidth );
for (size_t iii=0; iii<m_subElementList.size(); ++iii) {
if (m_subElementList[iii] != nullptr) {
m_subElementList[iii]->display(_spacing+1);

View File

@ -81,11 +81,15 @@ void esvg::Line::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorStroke;
if (m_paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort);
}
// Check if we need to display background
// No background ...
// check if we need to display stroke:
if ( m_paint.strokeWidth > 0
&& m_paint.stroke.a() != 0x00) {
if (colorStroke != nullptr) {
listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth,
m_paint.lineCap,
@ -99,9 +103,9 @@ void esvg::Line::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l
}
// add on images:
_myRenderer.print(tmpFill,
m_paint.fill,
colorFill,
tmpStroke,
m_paint.stroke,
colorStroke,
m_paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);

View File

@ -15,14 +15,15 @@
#define __class__ "LinearGradient"
esvg::LinearGradient::LinearGradient(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
m_pos1.setValue(0,0);
m_pos2.setValue(0,0);
m_pos1.set(vec2(0,0), esvg::distance_pixel);
m_pos2.set(vec2(0,0), esvg::distance_pixel);
}
esvg::LinearGradient::~LinearGradient() {
}
bool esvg::LinearGradient::parseXML(const std::shared_ptr<exml::Element>& _element, mat2& _parentTrans, vec2& _sizeMax) {
// line must have a minimum size...
//m_paint.strokeWidth = 1;
@ -39,22 +40,12 @@ bool esvg::LinearGradient::parseXML(const std::shared_ptr<exml::Element>& _eleme
// add the property of the parrent modifications ...
m_transformMatrix *= _parentTrans;
std::string content = _element->getAttribute("x1");
if (content.size()!=0) {
m_pos1.setX(parseLength(content));
}
content = _element->getAttribute("y1");
if (content.size()!=0) {
m_pos1.setY(parseLength(content));
}
content = _element->getAttribute("x2");
if (content.size()!=0) {
m_pos2.setX(parseLength(content));
}
content = _element->getAttribute("y2");
if (content.size()!=0) {
m_pos2.setY(parseLength(content));
}
std::string contentX = _element->getAttribute("x1");
std::string contentY = _element->getAttribute("y1");
m_pos1.set(contentX, contentY);
contentX = _element->getAttribute("x2");
contentY = _element->getAttribute("y2");
m_pos2.set(contentX, contentY);
// parse all sub node :
for(int32_t iii=0; iii<_element->size() ; iii++) {
@ -64,36 +55,29 @@ bool esvg::LinearGradient::parseXML(const std::shared_ptr<exml::Element>& _eleme
continue;
}
if (child->getValue() == "stop") {
float offset = 0;
float offset = 100;
etk::Color<float,4> stopColor = etk::color::none;
// ---------------- offset ----------------
content = child->getAttribute("offset");
std::string content = child->getAttribute("offset");
if (content.size()!=0) {
offset = parseLength(content);
offset = std::avg(0.0f, offset, 100.0f);
}
// ---------------- STYLE ----------------
content = _element->getAttribute("style");
if (content.size()!=0) {
std::string outputType;
std::string outputValue;
for( int32_t sss=extractPartOfStyle(content, outputType, outputValue, 0);
-2 != sss;
sss=extractPartOfStyle(content, outputType, outputValue, sss) ) {
SVG_VERBOSE(" style parse : \"" << outputType << "\" with value : \"" << outputValue << "\"");
if (outputType == "stop-color") {
stopColor = parseColor(outputValue);
SVG_VERBOSE(" input : \"" << outputValue << "\" == > " << stopColor);
} else if (outputType == "stop-opacity") {
float opacity = parseLength(outputValue);
opacity = std::avg(0.0f, opacity, 1.0f);
stopColor.setA(opacity);
SVG_VERBOSE(" input : \"" << outputValue << "\" == > " << stopColor);
} else {
SVG_ERROR("not know painting element in style balise : \"" << outputType << "\" with value : \"" << outputValue << "\"");
}
std::pair<float, enum esvg::distance> tmp = parseLength2(content);
if (tmp.second != esvg::distance_pourcent) {
SVG_ERROR("offset : " << content << " res=" << tmp.first << "," << tmp.second << " Not support other than pourcent %");
} else {
offset = tmp.first;
}
}
content = child->getAttribute("stop-color");
if (content.size()!=0) {
stopColor = parseColor(content).first;
SVG_VERBOSE(" color : \"" << content << "\" == > " << stopColor);
}
content = child->getAttribute("stop-opacity");
if (content.size()!=0) {
float opacity = parseLength(content);
opacity = std::avg(0.0f, opacity, 1.0f);
stopColor.setA(opacity);
SVG_VERBOSE(" opacity : \"" << content << "\" == > " << stopColor);
}
m_data.push_back(std::pair<float, etk::Color<float,4>>(offset, stopColor));
} else {
SVG_ERROR("(l " << child->getPos() << ") node not suported : \"" << child->getValue() << "\" must be [stop]");

View File

@ -14,8 +14,8 @@
namespace esvg {
class LinearGradient : public esvg::Base {
private:
vec2 m_pos1; //!< gradient position x1 y1
vec2 m_pos2; //!< gradient position x2 y2
esvg::Dimension m_pos1; //!< gradient position x1 y1
esvg::Dimension m_pos2; //!< gradient position x2 y2
std::vector<std::pair<float, etk::Color<float,4>>> m_data;
public:
LinearGradient(PaintState _parentPaintState);

View File

@ -271,16 +271,20 @@ void esvg::Path::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorStroke;
if (m_paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort);
}
// Check if we need to display background
if (m_paint.fill.a() != 0x00) {
if (colorFill != nullptr) {
listSegmentFill.createSegmentList(listPoints);
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), listSegmentFill);
}
// check if we need to display stroke:
if ( m_paint.strokeWidth > 0
&& m_paint.stroke.a() != 0x00) {
if (colorStroke != nullptr) {
listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth,
m_paint.lineCap,
@ -292,9 +296,9 @@ void esvg::Path::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l
}
// add on images:
_myRenderer.print(tmpFill,
m_paint.fill,
colorFill,
tmpStroke,
m_paint.stroke,
colorStroke,
m_paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);

View File

@ -88,8 +88,13 @@ void esvg::Polygon::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorStroke;
if (m_paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort);
}
// Check if we need to display background
if (m_paint.fill.a() != 0x00) {
if (colorFill != nullptr) {
listSegmentFill.createSegmentList(listPoints);
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -98,8 +103,7 @@ void esvg::Polygon::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
listSegmentFill);
}
// check if we need to display stroke:
if ( m_paint.strokeWidth > 0
&& m_paint.stroke.a() != 0x00) {
if (colorStroke != nullptr) {
listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth,
m_paint.lineCap,
@ -113,9 +117,9 @@ void esvg::Polygon::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
}
// add on images:
_myRenderer.print(tmpFill,
m_paint.fill,
colorFill,
tmpStroke,
m_paint.stroke,
colorStroke,
m_paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);

View File

@ -85,8 +85,13 @@ void esvg::Polyline::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorStroke;
if (m_paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort);
}
// Check if we need to display background
if (m_paint.fill.a() != 0x00) {
if (colorFill != nullptr) {
listSegmentFill.createSegmentList(listPoints);
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -95,8 +100,7 @@ void esvg::Polyline::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_
listSegmentFill);
}
// check if we need to display stroke:
if ( m_paint.strokeWidth > 0
&& m_paint.stroke.a() != 0x00) {
if (colorStroke != nullptr) {
listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth,
m_paint.lineCap,
@ -110,9 +114,9 @@ void esvg::Polyline::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_
}
// add on images:
_myRenderer.print(tmpFill,
m_paint.fill,
colorFill,
tmpStroke,
m_paint.stroke,
colorStroke,
m_paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);

View File

@ -59,7 +59,8 @@ void esvg::Rectangle::display(int32_t _spacing) {
}
void esvg::Rectangle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _level) {
SVG_VERBOSE(spacingDist(_level) << "DRAW esvg::Rectangle : fill=" << m_paint.fill << " stroke=" << m_paint.stroke);
SVG_VERBOSE(spacingDist(_level) << "DRAW esvg::Rectangle: fill=" << m_paint.fill.first << "/" << m_paint.fill.second
<< " stroke=" << m_paint.stroke.first << "/" << m_paint.stroke.second);
esvg::render::Path listElement;
listElement.clear();
if ( m_roundedCorner.x() == 0.0f
@ -102,8 +103,13 @@ void esvg::Rectangle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorStroke;
if (m_paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort);
}
// Check if we need to display background
if (m_paint.fill.a() != 0x00) {
if (colorFill != nullptr) {
listSegmentFill.createSegmentList(listPoints);
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -112,8 +118,7 @@ void esvg::Rectangle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32
listSegmentFill);
}
// check if we need to display stroke:
if ( m_paint.strokeWidth > 0
&& m_paint.stroke.a() != 0x00) {
if (colorStroke != nullptr) {
listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth,
m_paint.lineCap,
@ -127,9 +132,9 @@ void esvg::Rectangle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32
}
// add on images:
_myRenderer.print(tmpFill,
m_paint.fill,
colorFill,
tmpStroke,
m_paint.stroke,
colorStroke,
m_paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);

View File

@ -13,14 +13,15 @@
#undef __class__
#define __class__ "Renderer"
esvg::Renderer::Renderer(const ivec2& _size, bool _visualDebug) :
esvg::Renderer::Renderer(const ivec2& _size, esvg::Document* _document, bool _visualDebug) :
#ifdef DEBUG
m_visualDebug(_visualDebug),
m_factor(1),
#endif
m_interpolationRecurtionMax(10),
m_interpolationThreshold(0.25f),
m_nbSubScanLine(8) {
m_nbSubScanLine(8),
m_document(_document) {
#ifdef DEBUG
if (m_visualDebug == true) {
m_factor = 20;
@ -57,9 +58,9 @@ etk::Color<float,4> esvg::Renderer::mergeColor(etk::Color<float,4> _base, etk::C
}
void esvg::Renderer::print(const esvg::render::Weight& _weightFill,
const etk::Color<float,4>& _colorFill,
const std::shared_ptr<esvg::render::DynamicColor>& _colorFill,
const esvg::render::Weight& _weightStroke,
const etk::Color<float,4>& _colorStroke,
const std::shared_ptr<esvg::render::DynamicColor>& _colorStroke,
float _opacity) {
int32_t sizeX = m_size.x();
int32_t sizeY = m_size.y();
@ -67,68 +68,25 @@ void esvg::Renderer::print(const esvg::render::Weight& _weightFill,
sizeX *= m_factor;
sizeY *= m_factor;
#endif
if (_colorFill.a() == 0x00) {
if (_colorStroke.a() != 0x00) {
// only stroke
for (int32_t yyy=0; yyy<sizeY; ++yyy) {
for (int32_t xxx=0; xxx<sizeX; ++xxx) {
#if DEBUG
ivec2 pos(xxx/m_factor, yyy/m_factor);
#else
ivec2 pos(xxx, yyy);
#endif
float valueStroke = _weightStroke.get(pos);
if (valueStroke != 0.0f) {
// set a ratio of the merging value
etk::Color<float,4> tmpColor = _colorStroke * valueStroke;
tmpColor.setA(tmpColor.a() * _opacity);
// integrate the value at the previous color
m_buffer[sizeX*yyy + xxx] = mergeColor(m_buffer[sizeX*yyy + xxx], tmpColor);
}
}
}
}
} else {
if (_colorStroke.a() == 0x00) {
// only Fill
for (int32_t yyy=0; yyy<sizeY; ++yyy) {
for (int32_t xxx=0; xxx<sizeX; ++xxx) {
#if DEBUG
ivec2 pos(xxx/m_factor, yyy/m_factor);
#else
ivec2 pos(xxx, yyy);
#endif
float valueFill = _weightFill.get(pos);
if (valueFill != 0.0f) {
// set a ratio of the merging value
etk::Color<float,4> tmpColor = _colorFill * valueFill;
tmpColor.setA(tmpColor.a() * _opacity);
// integrate the value at the previous color
m_buffer[sizeX*yyy + xxx] = mergeColor(m_buffer[sizeX*yyy + xxx], tmpColor);
}
}
}
} else {
// all together
for (int32_t yyy=0; yyy<sizeY; ++yyy) {
for (int32_t xxx=0; xxx<sizeX; ++xxx) {
#if DEBUG
ivec2 pos(xxx/m_factor, yyy/m_factor);
#else
ivec2 pos(xxx, yyy);
#endif
float valueFill = _weightFill.get(pos);
float valueStroke = _weightStroke.get(pos);
// calculate merge of stroke and fill value:
etk::Color<float,4> intermediateColorFill = _colorFill;
intermediateColorFill.setA(intermediateColorFill.a()*valueFill);
etk::Color<float,4> intermediateColorStroke = _colorStroke;
intermediateColorStroke.setA(intermediateColorStroke.a()*valueStroke);
etk::Color<float,4> intermediateColor = mergeColor(intermediateColorFill, intermediateColorStroke);
intermediateColor.setA(intermediateColor.a() * _opacity);
m_buffer[sizeX*yyy + xxx] = mergeColor(m_buffer[sizeX*yyy + xxx], intermediateColor);
}
}
// all together
for (int32_t yyy=0; yyy<sizeY; ++yyy) {
for (int32_t xxx=0; xxx<sizeX; ++xxx) {
#if DEBUG
ivec2 pos(xxx/m_factor, yyy/m_factor);
#else
ivec2 pos(xxx, yyy);
#endif
float valueFill = _weightFill.get(pos);
float valueStroke = _weightStroke.get(pos);
// calculate merge of stroke and fill value:
etk::Color<float,4> intermediateColorFill = _colorFill->getColor(pos);
intermediateColorFill.setA(intermediateColorFill.a()*valueFill);
etk::Color<float,4> intermediateColorStroke = _colorStroke->getColor(pos);
intermediateColorStroke.setA(intermediateColorStroke.a()*valueStroke);
etk::Color<float,4> intermediateColor = mergeColor(intermediateColorFill, intermediateColorStroke);
intermediateColor.setA(intermediateColor.a() * _opacity);
m_buffer[sizeX*yyy + xxx] = mergeColor(m_buffer[sizeX*yyy + xxx], intermediateColor);
}
}
}

View File

@ -13,8 +13,10 @@
#include <etk/math/Vector2D.h>
#include <etk/Color.h>
#include <esvg/render/Weight.h>
#include <esvg/render/DynamicColor.h>
namespace esvg {
class Document;
class Renderer {
#ifdef DEBUG
private:
@ -22,7 +24,7 @@ namespace esvg {
int32_t m_factor;
#endif
public:
Renderer(const ivec2& _size, bool _visualDebug=false);
Renderer(const ivec2& _size, esvg::Document* _document, bool _visualDebug=false);
~Renderer();
protected:
ivec2 m_size;
@ -55,13 +57,19 @@ namespace esvg {
etk::Color<float,4> mergeColor(etk::Color<float,4> _base, etk::Color<float,4> _integration);
public:
void print(const esvg::render::Weight& _weightFill,
const etk::Color<float,4>& _colorFill,
const std::shared_ptr<esvg::render::DynamicColor>& _colorFill,
const esvg::render::Weight& _weightStroke,
const etk::Color<float,4>& _colorStroke,
const std::shared_ptr<esvg::render::DynamicColor>& _colorStroke,
float _opacity);
#ifdef DEBUG
void addDebugSegment(const esvg::render::SegmentList& _listSegment);
#endif
protected:
esvg::Document* m_document;
public:
esvg::Document* getMainDocument() {
return m_document;
}
};
};

View File

@ -74,7 +74,7 @@ void esvg::Document::generateAnImage(const ivec2& _size, const std::string& _fil
}
SVG_DEBUG("Generate size " << sizeRender);
std::shared_ptr<esvg::Renderer> renderedElement = std::make_shared<esvg::Renderer>(sizeRender, _visualDebug);
std::shared_ptr<esvg::Renderer> renderedElement = std::make_shared<esvg::Renderer>(sizeRender, this, _visualDebug);
// create the first element matrix modification ...
mat2 basicTrans;
basicTrans *= etk::mat2Scale(vec2(sizeRender.x()/m_size.x(), sizeRender.y()/m_size.y()));
@ -99,7 +99,7 @@ std::vector<etk::Color<float,4>> esvg::Document::renderImageFloatRGBA(ivec2& _si
_size.setY(m_size.y());
}
SVG_DEBUG("Generate size " << _size);
std::shared_ptr<esvg::Renderer> renderedElement = std::make_shared<esvg::Renderer>(_size);
std::shared_ptr<esvg::Renderer> renderedElement = std::make_shared<esvg::Renderer>(_size, this);
// create the first element matrix modification ...
mat2 basicTrans;
basicTrans *= etk::mat2Scale(vec2(_size.x()/m_size.x(), _size.y()/m_size.y()));
@ -170,6 +170,7 @@ bool esvg::Document::parse(const std::string& _data) {
m_loadOK = false;
return m_loadOK;
}
cleanStyleProperty(root);
m_loadOK = parseXMLData(root);
return m_loadOK;
}
@ -198,6 +199,7 @@ bool esvg::Document::load(const std::string& _file) {
m_loadOK = false;
return m_loadOK;
}
cleanStyleProperty(root);
m_loadOK = parseXMLData(root);
return m_loadOK;
}
@ -206,7 +208,36 @@ bool esvg::Document::store(const std::string& _file) {
return false;
}
bool esvg::Document::cleanStyleProperty(const std::shared_ptr<exml::Element>& _root) {
// for each nodes:
for(int32_t iii=0; iii< _root->size(); iii++) {
std::shared_ptr<exml::Element> child = _root->getElement(iii);
if (child == nullptr) {
continue;
}
// get attribute style:
if (child->existAttribute("style") == true) {
std::string content = child->getAttribute("style");
if (content.size() != 0) {
std::vector<std::string> listStyle = etk::split(content, ';');
for (auto &it : listStyle) {
std::vector<std::string> value = etk::split(it, ':');
if (value.size() != 2) {
SVG_ERROR("parsing style with a wrong patern : " << it << " missing ':'");
continue;
}
// TODO : Check if the attibute already exist ...
child->setAttribute(value[0], value[1]);
}
}
// remove attribute style:
child->removeAttribute("style");
}
// sub-parsing ...
cleanStyleProperty(child);
}
return true;
}
bool esvg::Document::parseXMLData(const std::shared_ptr<exml::Element>& _root, bool _isReference) {
// get the svg version :
@ -223,7 +254,7 @@ bool esvg::Document::parseXMLData(const std::shared_ptr<exml::Element>& _root, b
}
vec2 maxSize(0,0);
vec2 size(0,0);
// parse all sub node :
// parse all sub node:
for(int32_t iii=0; iii< _root->size(); iii++) {
std::shared_ptr<exml::Element> child = _root->getElement(iii);
if (child == nullptr) {

View File

@ -59,6 +59,10 @@ namespace esvg {
*/
bool store(const std::string& _file);
protected:
/**
* @brief change all style in a xml atribute
*/
virtual bool cleanStyleProperty(const std::shared_ptr<exml::Element>& _root);
virtual bool parseXMLData(const std::shared_ptr<exml::Element>& _root, bool _isReference = false);
public:
bool isLoadOk() {

View File

@ -0,0 +1,33 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#include <esvg/debug.h>
#include <esvg/render/DynamicColor.h>
esvg::render::DynamicColorLinear::DynamicColorLinear(const std::string& _link, const mat2& _mtx, const vec2 _objectSize, const vec2 _objectPos)
{
}
etk::Color<float,4> esvg::render::DynamicColorLinear::getColor(const ivec2& _pos) {
return etk::color::purple;
}
std::shared_ptr<esvg::render::DynamicColor> esvg::render::createColor(std::pair<etk::Color<float,4>, std::string> _color, const mat2& _mtx, const vec2 _size) {
// Check if need to create a color:
if ( _color.first.a() == 0x00
&& _color.second == "") {
return nullptr;
}
if (_color.second != "") {
return std::make_shared<esvg::render::DynamicColorLinear>(_color.second, _mtx, _size);
}
return std::make_shared<esvg::render::DynamicColorUni>(_color.first);
}

View File

@ -0,0 +1,52 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#ifndef __ESVG_RENDER_DYNAMIC_COLOR_H__
#define __ESVG_RENDER_DYNAMIC_COLOR_H__
#include <etk/types.h>
#include <etk/Color.h>
#include <etk/math/Vector2D.h>
#include <etk/math/Matrix2.h>
namespace esvg {
namespace render {
class DynamicColor {
public:
DynamicColor() {
// nothing to do ...
}
virtual ~DynamicColor() {};
virtual etk::Color<float,4> getColor(const ivec2& _pos) = 0;
};
class DynamicColorUni : public esvg::render::DynamicColor {
public:
etk::Color<float,4> m_color;
public:
DynamicColorUni(const etk::Color<float,4>& _color) :
m_color(_color) {
}
etk::Color<float,4> getColor(const ivec2& _pos) {
return m_color;
}
};
class DynamicColorLinear : public esvg::render::DynamicColor {
public:
etk::Color<float,4> m_color;
public:
DynamicColorLinear(const std::string& _link, const mat2& _mtx, const vec2 _objectSize, const vec2 _objectPos);
etk::Color<float,4> getColor(const ivec2& _pos);
};
std::shared_ptr<DynamicColor> createColor(std::pair<etk::Color<float,4>, std::string> _color, const mat2& _mtx, const vec2 _size);
}
}
#endif

View File

@ -62,6 +62,7 @@ def create(target, module_name):
'esvg/render/Segment.cpp',
'esvg/render/SegmentList.cpp',
'esvg/render/Weight.cpp',
'esvg/render/DynamicColor.cpp',
'esvg/LinearGradient.cpp',
'esvg/RadialGradient.cpp'
])
@ -102,6 +103,7 @@ def create(target, module_name):
'esvg/render/Segment.h',
'esvg/render/SegmentList.h',
'esvg/render/Weight.h',
'esvg/render/DynamicColor.h',
'esvg/LinearGradient.h',
'esvg/RadialGradient.h'
])

View File

@ -27,7 +27,7 @@ TEST(TestGradientLinear, horizontal) {
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientLinear_horizontal.svg", data);
//doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_horizontal.bmp", g_visualDebug);
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_horizontal.bmp", g_visualDebug);
}