[DEV] Render gradient really slowly

This commit is contained in:
Edouard DUPIN 2015-12-10 21:40:42 +01:00
parent 5f6c4bab85
commit 85a35ae71b
14 changed files with 166 additions and 28 deletions

View File

@ -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<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx);
std::shared_ptr<esvg::render::DynamicColor> 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(),

View File

@ -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<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx);
std::shared_ptr<esvg::render::DynamicColor> 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(),

View File

@ -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<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx);
std::shared_ptr<esvg::render::DynamicColor> 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(),

View File

@ -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<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx);
std::shared_ptr<esvg::render::DynamicColor> 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);

View File

@ -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<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx);
std::shared_ptr<esvg::render::DynamicColor> 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(),

View File

@ -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<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx);
std::shared_ptr<esvg::render::DynamicColor> 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(),

View File

@ -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<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx, m_paint.viewPort);
std::shared_ptr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(m_paint.fill, mtx);
std::shared_ptr<esvg::render::DynamicColor> 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(),

View File

@ -11,16 +11,64 @@
#include <esvg/LinearGradient.h>
#include <esvg/esvg.h>
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<vec2, vec2>& _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<float,4> 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.size(); ++iii) {
if (ratio <= m_data[iii].first*0.01f) {
float localRatio = ratio - m_data[iii-1].first*0.01f;
localRatio = localRatio / ((m_data[iii].first - m_data[iii-1].first) * 0.01f);
return etk::Color<float,4>(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<std::pair<float, etk::Color<float,4>>> 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::DynamicColor> esvg::render::createColor(std::pair<etk::Color<float,4>, std::string> _color, const mat2& _mtx, const vec2 _size) {
std::shared_ptr<esvg::render::DynamicColor> esvg::render::createColor(std::pair<etk::Color<float,4>, 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<esvg::render::DynamicColorLinear>(_color.second, _mtx, _size);
return std::make_shared<esvg::render::DynamicColorLinear>(_color.second, _mtx);
}
return std::make_shared<esvg::render::DynamicColorUni>(_color.first);
}

View File

@ -26,6 +26,7 @@ namespace esvg {
virtual ~DynamicColor() {};
virtual etk::Color<float,4> getColor(const ivec2& _pos) = 0;
virtual void generate(esvg::Document* _document) = 0;
virtual void setViewPort(const std::pair<vec2, vec2>& _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<vec2, vec2>& _viewPort) {
// nothing to do ...
};
};
class DynamicColorLinear : public esvg::render::DynamicColor {
public:
std::string m_colorName;
mat2 m_matrix;
vec2 m_size;
std::pair<vec2, vec2> m_viewPort;
vec2 m_pos1;
vec2 m_pos2;
std::vector<std::pair<float, etk::Color<float,4>>> 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<float,4> getColor(const ivec2& _pos);
virtual void generate(esvg::Document* _document);
virtual void setViewPort(const std::pair<vec2, vec2>& _viewPort);
};
std::shared_ptr<DynamicColor> createColor(std::pair<etk::Color<float,4>, std::string> _color, const mat2& _mtx, const vec2 _size);
std::shared_ptr<DynamicColor> createColor(std::pair<etk::Color<float,4>, std::string> _color, const mat2& _mtx);
}
}

View File

@ -26,6 +26,16 @@ void esvg::render::PointList::applyMatrix(const mat2& _transformationMatrix) {
}
}
std::pair<vec2, vec2> esvg::render::PointList::getViewPort() {
std::pair<vec2, vec2> 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());

View File

@ -25,6 +25,7 @@ namespace esvg {
void addList(std::vector<esvg::render::Point>& _list);
void display();
void applyMatrix(const mat2& _transformationMatrix);
std::pair<vec2, vec2> getViewPort();
};
}
}

View File

@ -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<vec2, vec2> esvg::render::SegmentList::getViewPort() {
std::pair<vec2, vec2> 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

View File

@ -43,6 +43,7 @@ namespace esvg {
float _width,
bool _isStart);
public:
std::pair<vec2, vec2> getViewPort();
void applyMatrix(const mat2& _transformationMatrix);
};
}

View File

@ -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);
}
}
TEST(TestGradientLinear, diag1) {
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='0%' y1='0%' x2='100%' y2='100%'>\n"
" <stop offset='0%' style='stop-color:rgb(255,255,0);stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:rgb(255,0,0);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_diag1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_diag1.bmp", g_visualDebug);
}
TEST(TestGradientLinear, diag2) {
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='0%' y1='100%' x2='100%' y2='0%'>\n"
" <stop offset='0%' style='stop-color:rgb(255,255,0);stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:rgb(255,0,0);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_diag2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_diag2.bmp", g_visualDebug);
}