diff --git a/esvg/Circle.cpp b/esvg/Circle.cpp index b9d8d2f..31a7eba 100644 --- a/esvg/Circle.cpp +++ b/esvg/Circle.cpp @@ -102,14 +102,15 @@ 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 colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort); + std::shared_ptr colorFill = esvg::render::createColor(m_paint.fill, mtx); std::shared_ptr colorStroke; if (m_paint.strokeWidth > 0.0f) { - colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort); + colorStroke = esvg::render::createColor(m_paint.stroke, mtx); } // Check if we need to display background if (colorFill != nullptr) { listSegmentFill.createSegmentList(listPoints); + colorFill->setViewPort(listSegmentFill.getViewPort()); listSegmentFill.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpFill.generate(_myRenderer.getSize(), @@ -123,6 +124,7 @@ void esvg::Circle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t m_paint.lineCap, m_paint.lineJoin, m_paint.miterLimit); + colorStroke->setViewPort(listSegmentStroke.getViewPort()); listSegmentStroke.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), diff --git a/esvg/Ellipse.cpp b/esvg/Ellipse.cpp index e3ce54c..9e65ee9 100644 --- a/esvg/Ellipse.cpp +++ b/esvg/Ellipse.cpp @@ -107,14 +107,15 @@ 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 colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort); + std::shared_ptr colorFill = esvg::render::createColor(m_paint.fill, mtx); std::shared_ptr colorStroke; if (m_paint.strokeWidth > 0.0f) { - colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort); + colorStroke = esvg::render::createColor(m_paint.stroke, mtx); } // Check if we need to display background if (colorFill != nullptr) { listSegmentFill.createSegmentList(listPoints); + colorFill->setViewPort(listSegmentFill.getViewPort()); listSegmentFill.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpFill.generate(_myRenderer.getSize(), @@ -128,6 +129,7 @@ void esvg::Ellipse::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t m_paint.lineCap, m_paint.lineJoin, m_paint.miterLimit); + colorStroke->setViewPort(listSegmentStroke.getViewPort()); listSegmentStroke.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), diff --git a/esvg/Line.cpp b/esvg/Line.cpp index 1b68dbf..8c96f73 100644 --- a/esvg/Line.cpp +++ b/esvg/Line.cpp @@ -81,10 +81,10 @@ 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 colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort); + std::shared_ptr colorFill = esvg::render::createColor(m_paint.fill, mtx); std::shared_ptr colorStroke; if (m_paint.strokeWidth > 0.0f) { - colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort); + colorStroke = esvg::render::createColor(m_paint.stroke, mtx); } // Check if we need to display background // No background ... @@ -95,6 +95,7 @@ void esvg::Line::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l m_paint.lineCap, m_paint.lineJoin, m_paint.miterLimit); + colorStroke->setViewPort(listSegmentStroke.getViewPort()); listSegmentStroke.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), diff --git a/esvg/Path.cpp b/esvg/Path.cpp index 044c511..fe98356 100644 --- a/esvg/Path.cpp +++ b/esvg/Path.cpp @@ -271,14 +271,15 @@ 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 colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort); + std::shared_ptr colorFill = esvg::render::createColor(m_paint.fill, mtx); std::shared_ptr colorStroke; if (m_paint.strokeWidth > 0.0f) { - colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort); + colorStroke = esvg::render::createColor(m_paint.stroke, mtx); } // Check if we need to display background if (colorFill != nullptr) { listSegmentFill.createSegmentList(listPoints); + colorFill->setViewPort(listSegmentFill.getViewPort()); 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); @@ -290,6 +291,7 @@ void esvg::Path::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l m_paint.lineCap, m_paint.lineJoin, m_paint.miterLimit); + colorStroke->setViewPort(listSegmentStroke.getViewPort()); listSegmentStroke.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), listSegmentStroke); diff --git a/esvg/Polygon.cpp b/esvg/Polygon.cpp index 0b2eaa8..97137c7 100644 --- a/esvg/Polygon.cpp +++ b/esvg/Polygon.cpp @@ -88,14 +88,15 @@ 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 colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort); + std::shared_ptr colorFill = esvg::render::createColor(m_paint.fill, mtx); std::shared_ptr colorStroke; if (m_paint.strokeWidth > 0.0f) { - colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort); + colorStroke = esvg::render::createColor(m_paint.stroke, mtx); } // Check if we need to display background if (colorFill != nullptr) { listSegmentFill.createSegmentList(listPoints); + colorFill->setViewPort(listSegmentFill.getViewPort()); listSegmentFill.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpFill.generate(_myRenderer.getSize(), @@ -109,6 +110,7 @@ void esvg::Polygon::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t m_paint.lineCap, m_paint.lineJoin, m_paint.miterLimit); + colorStroke->setViewPort(listSegmentStroke.getViewPort()); listSegmentStroke.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), diff --git a/esvg/Polyline.cpp b/esvg/Polyline.cpp index 9729256..b1ff9ab 100644 --- a/esvg/Polyline.cpp +++ b/esvg/Polyline.cpp @@ -85,14 +85,15 @@ 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 colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort); + std::shared_ptr colorFill = esvg::render::createColor(m_paint.fill, mtx); std::shared_ptr colorStroke; if (m_paint.strokeWidth > 0.0f) { - colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort); + colorStroke = esvg::render::createColor(m_paint.stroke, mtx); } // Check if we need to display background if (colorFill != nullptr) { listSegmentFill.createSegmentList(listPoints); + colorFill->setViewPort(listSegmentFill.getViewPort()); listSegmentFill.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpFill.generate(_myRenderer.getSize(), @@ -106,6 +107,7 @@ void esvg::Polyline::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_ m_paint.lineCap, m_paint.lineJoin, m_paint.miterLimit); + colorStroke->setViewPort(listSegmentStroke.getViewPort()); listSegmentStroke.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), diff --git a/esvg/Rectangle.cpp b/esvg/Rectangle.cpp index 627acc2..87ea8e1 100644 --- a/esvg/Rectangle.cpp +++ b/esvg/Rectangle.cpp @@ -103,14 +103,15 @@ 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 colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort); + std::shared_ptr colorFill = esvg::render::createColor(m_paint.fill, mtx); std::shared_ptr colorStroke; if (m_paint.strokeWidth > 0.0f) { - colorStroke = esvg::render::createColor(m_paint.stroke, mtx, m_paint.viewPort); + colorStroke = esvg::render::createColor(m_paint.stroke, mtx); } // Check if we need to display background if (colorFill != nullptr) { listSegmentFill.createSegmentList(listPoints); + colorFill->setViewPort(listSegmentFill.getViewPort()); listSegmentFill.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpFill.generate(_myRenderer.getSize(), @@ -124,6 +125,7 @@ void esvg::Rectangle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32 m_paint.lineCap, m_paint.lineJoin, m_paint.miterLimit); + colorStroke->setViewPort(listSegmentStroke.getViewPort()); listSegmentStroke.applyMatrix(mtx); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), diff --git a/esvg/render/DynamicColor.cpp b/esvg/render/DynamicColor.cpp index cea0766..ff44b04 100644 --- a/esvg/render/DynamicColor.cpp +++ b/esvg/render/DynamicColor.cpp @@ -11,16 +11,64 @@ #include #include -esvg::render::DynamicColorLinear::DynamicColorLinear(const std::string& _link, const mat2& _mtx, const vec2 _size) : +esvg::render::DynamicColorLinear::DynamicColorLinear(const std::string& _link, const mat2& _mtx) : m_colorName(_link), m_matrix(_mtx), - m_size(_size) { + m_viewPort(vec2(9999999999.0,9999999999.0),vec2(-9999999999.0,-9999999999.0)) { } +void esvg::render::DynamicColorLinear::setViewPort(const std::pair& _viewPort) { + m_viewPort = _viewPort; +} + +static vec2 getIntersect(const vec2& _point1, + const vec2& _vect1, + const vec2& _point2, + const vec2& _vect2) { + float diviseur = _vect1.x() * _vect2.y() - _vect1.y() * _vect2.x(); + if(diviseur != 0.0f) { + float mmm = ( _vect1.x() * _point1.y() + - _vect1.x() * _point2.y() + - _vect1.y() * _point1.x() + + _vect1.y() * _point2.x() + ) / diviseur; + return vec2(_point2 + _vect2 * mmm); + } + ESVG_ERROR("Get divider / 0.0f"); + return _point2; +} + +// TODO : This can optimize ... really slow ... etk::Color esvg::render::DynamicColorLinear::getColor(const ivec2& _pos) { - return etk::color::purple; + if (m_data.size() < 2) { + return etk::color::purple; + } + vec2 vectorBase = m_pos2 - m_pos1; + vec2 vectorOrtho(vectorBase.y(), -vectorBase.x()); + vec2 intersec = getIntersect(m_pos1, vectorBase, + vec2(_pos.x(), _pos.y()), vectorOrtho); + float baseSize = vectorBase.length(); + float baseDraw = (m_pos1 - intersec).length(); + float ratio = baseDraw / baseSize; + if (ratio <= m_data[0].first*0.01f) { + return m_data[0].second; + } + if (ratio >= m_data.back().first*0.01f) { + return m_data.back().second; + } + for (size_t iii=1; iii(m_data[iii-1].second.r() * (1.0-localRatio) + m_data[iii].second.r() * localRatio, + m_data[iii-1].second.g() * (1.0-localRatio) + m_data[iii].second.g() * localRatio, + m_data[iii-1].second.b() * (1.0-localRatio) + m_data[iii].second.b() * localRatio, + m_data[iii-1].second.a() * (1.0-localRatio) + m_data[iii].second.a() * localRatio); + } + } + return etk::color::green; } void esvg::render::DynamicColorLinear::generate(esvg::Document* _document) { @@ -40,23 +88,34 @@ void esvg::render::DynamicColorLinear::generate(esvg::Document* _document) { } ESVG_INFO("get for color linear:"); gradient->display(2); + ESVG_INFO(" viewport = {" << m_viewPort.first << "," << m_viewPort.second << "}"); + vec2 size = m_viewPort.second - m_viewPort.first; - esvg::Dimension pos1 = gradient->getPosition1(); - esvg::Dimension pos2 = gradient->getPosition2(); - std::vector>> data = gradient->getColors(); - // ROTATE and many things ... - + esvg::Dimension dimPos1 = gradient->getPosition1(); + m_pos1 = dimPos1.getPixel(size); + if (dimPos1.getType() == esvg::distance_pourcent) { + m_pos1 += m_viewPort.first; + } + esvg::Dimension dimPos2 = gradient->getPosition2(); + m_pos2 = dimPos2.getPixel(size); + if (dimPos2.getType() == esvg::distance_pourcent) { + m_pos2 += m_viewPort.first; + } + // Move the positions ... + m_pos1 = m_matrix * m_pos1; + m_pos2 = m_matrix * m_pos2; + m_data = gradient->getColors(); } -std::shared_ptr esvg::render::createColor(std::pair, std::string> _color, const mat2& _mtx, const vec2 _size) { +std::shared_ptr esvg::render::createColor(std::pair, std::string> _color, const mat2& _mtx) { // Check if need to create a color: if ( _color.first.a() == 0x00 && _color.second == "") { return nullptr; } if (_color.second != "") { - return std::make_shared(_color.second, _mtx, _size); + return std::make_shared(_color.second, _mtx); } return std::make_shared(_color.first); } diff --git a/esvg/render/DynamicColor.h b/esvg/render/DynamicColor.h index b4f2318..f7a20b0 100644 --- a/esvg/render/DynamicColor.h +++ b/esvg/render/DynamicColor.h @@ -26,6 +26,7 @@ namespace esvg { virtual ~DynamicColor() {}; virtual etk::Color getColor(const ivec2& _pos) = 0; virtual void generate(esvg::Document* _document) = 0; + virtual void setViewPort(const std::pair& _viewPort) = 0; }; class DynamicColorUni : public esvg::render::DynamicColor { public: @@ -41,19 +42,26 @@ namespace esvg { virtual void generate(esvg::Document* _document) { // nothing to do ... } + virtual void setViewPort(const std::pair& _viewPort) { + // nothing to do ... + }; }; class DynamicColorLinear : public esvg::render::DynamicColor { public: std::string m_colorName; mat2 m_matrix; - vec2 m_size; + std::pair m_viewPort; + vec2 m_pos1; + vec2 m_pos2; + std::vector>> m_data; public: - DynamicColorLinear(const std::string& _link, const mat2& _mtx, const vec2 _size); + DynamicColorLinear(const std::string& _link, const mat2& _mtx); virtual etk::Color getColor(const ivec2& _pos); virtual void generate(esvg::Document* _document); + virtual void setViewPort(const std::pair& _viewPort); }; - std::shared_ptr createColor(std::pair, std::string> _color, const mat2& _mtx, const vec2 _size); + std::shared_ptr createColor(std::pair, std::string> _color, const mat2& _mtx); } } diff --git a/esvg/render/PointList.cpp b/esvg/render/PointList.cpp index 2a2c7a6..4733a5c 100644 --- a/esvg/render/PointList.cpp +++ b/esvg/render/PointList.cpp @@ -26,6 +26,16 @@ void esvg::render::PointList::applyMatrix(const mat2& _transformationMatrix) { } } +std::pair esvg::render::PointList::getViewPort() { + std::pair out(vec2(9999999999.0,9999999999.0),vec2(-9999999999.0,-9999999999.0)); + for (auto &it : m_data) { + for (auto &it2 : it) { + out.first.setMin(it2.m_pos); + out.second.setMax(it2.m_pos); + } + } + return out; +} void esvg::render::PointList::display() { ESVG_VERBOSE(" Display list of points : size=" << m_data.size()); diff --git a/esvg/render/PointList.h b/esvg/render/PointList.h index e329c15..125d120 100644 --- a/esvg/render/PointList.h +++ b/esvg/render/PointList.h @@ -25,6 +25,7 @@ namespace esvg { void addList(std::vector& _list); void display(); void applyMatrix(const mat2& _transformationMatrix); + std::pair getViewPort(); }; } } diff --git a/esvg/render/SegmentList.cpp b/esvg/render/SegmentList.cpp index f086892..301a6d1 100644 --- a/esvg/render/SegmentList.cpp +++ b/esvg/render/SegmentList.cpp @@ -28,6 +28,16 @@ void esvg::render::SegmentList::addSegment(const esvg::render::Point& _pos0, con m_data.push_back(Segment(_pos0.m_pos, _pos1.m_pos)); } +std::pair esvg::render::SegmentList::getViewPort() { + std::pair out(vec2(9999999999.0,9999999999.0),vec2(-9999999999.0,-9999999999.0)); + for (auto &it : m_data) { + out.first.setMin(it.p0); + out.second.setMax(it.p0); + out.first.setMin(it.p1); + out.second.setMax(it.p1); + } + return out; +} void esvg::render::SegmentList::createSegmentList(const esvg::render::PointList& _listPoint) { for (auto &it : _listPoint.m_data) { // Build Segments diff --git a/esvg/render/SegmentList.h b/esvg/render/SegmentList.h index 67b2a1d..f86e272 100644 --- a/esvg/render/SegmentList.h +++ b/esvg/render/SegmentList.h @@ -43,6 +43,7 @@ namespace esvg { float _width, bool _isStart); public: + std::pair getViewPort(); void applyMatrix(const mat2& _transformationMatrix); }; } diff --git a/test/testGradientLinear.cpp b/test/testGradientLinear.cpp index ea35abe..d37c513 100644 --- a/test/testGradientLinear.cpp +++ b/test/testGradientLinear.cpp @@ -46,4 +46,40 @@ TEST(TestGradientLinear, vertical) { doc.parse(data); etk::FSNodeWriteAllData("TestGradientLinear_vertical.svg", data); doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_vertical.bmp", g_visualDebug); -} \ No newline at end of file +} + +TEST(TestGradientLinear, diag1) { + std::string data("\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + esvg::Document doc; + doc.parse(data); + etk::FSNodeWriteAllData("TestGradientLinear_diag1.svg", data); + doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_diag1.bmp", g_visualDebug); +} + +TEST(TestGradientLinear, diag2) { + std::string data("\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + esvg::Document doc; + doc.parse(data); + etk::FSNodeWriteAllData("TestGradientLinear_diag2.svg", data); + doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_diag2.bmp", g_visualDebug); +} + +