d0eb3f3bfbb4d628194f433d87ce13be4a8c3554
[platform/core/uifw/rive-tizen.git] / src / renderer / src / thorvg_renderer.cpp
1 #include "thorvg_renderer.hpp"
2 #include "math/vec2d.hpp"
3 #include "shapes/paint/color.hpp"
4
5 using namespace rive;
6
7 TvgRenderPath::TvgRenderPath()
8 {
9    this->m_Shape = tvg::Shape::gen().release();
10 }
11
12 TvgRenderPath::~TvgRenderPath()
13 {
14    if (!active) delete(m_Shape);
15 }
16
17 void TvgRenderPath::fillRule(FillRule value)
18 {
19    switch (value)
20    {
21       case FillRule::evenOdd:
22          m_Shape->fill(tvg::FillRule::EvenOdd);
23          break;
24       case FillRule::nonZero:
25          m_Shape->fill(tvg::FillRule::Winding);
26          break;
27    }
28 }
29
30 Point applyTransform(const Vec2D &vec, const Mat2D &mat)
31 {
32    Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1};
33    m.e11 = mat[0];
34    m.e12 = mat[2];
35    m.e13 = mat[4];
36    m.e21 = mat[1];
37    m.e22 = mat[3];
38    m.e23 = mat[5];
39
40    return {vec[0] * m.e11 + vec[1] * m.e12 + m.e13, vec[0] * m.e21 + vec[1] * m.e22 + m.e23};
41 }
42
43 void TvgRenderPath::reset()
44 {
45    m_Shape->reset();
46    m_PathType.clear();
47    m_PathPoints.clear();
48 }
49
50 void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform)
51 {
52    auto m_PathType = static_cast<TvgRenderPath*>(path)->m_PathType;
53    auto m_PathPoints = static_cast<TvgRenderPath*>(path)->m_PathPoints;
54    int index = 0;
55
56    /* OPTIMIZE ME: Should avoid data copy in loop... */
57
58    for (size_t i = 0; i < m_PathType.size(); i++)
59    {
60       /* OPTIMIZE ME: apply transform only when it's not identity */
61       switch(m_PathType[i])
62       {
63          case PathCommand::MoveTo:
64          {
65             auto pt = applyTransform(m_PathPoints[index], transform);
66             m_Shape->moveTo(pt.x, pt.y);
67             index += 1;
68             break;
69          }
70          case PathCommand::LineTo:
71          {
72             auto pt = applyTransform(m_PathPoints[index], transform);
73             m_Shape->lineTo(pt.x, pt.y);
74             index += 1;
75             break;
76          }
77          case PathCommand::CubicTo:
78          {
79             auto pt1 = applyTransform(m_PathPoints[index], transform);
80             auto pt2 = applyTransform(m_PathPoints[index + 1], transform);
81             auto pt3 = applyTransform(m_PathPoints[index + 2], transform);
82             m_Shape->cubicTo(pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y);
83             index += 3;
84             break;
85          }
86          case PathCommand::Close:
87          {
88             m_Shape->close();
89             index += 1;
90             break;
91          }
92       }
93    }
94 }
95
96 void TvgRenderPath::moveTo(float x, float y)
97 {
98    m_PathType.push_back(PathCommand::MoveTo);
99    m_PathPoints.push_back({x, y});
100 }
101
102 void TvgRenderPath::lineTo(float x, float y)
103 {
104    m_PathType.push_back(PathCommand::LineTo);
105    m_PathPoints.push_back({x, y});
106 }
107
108 void TvgRenderPath::cubicTo(float ox, float oy, float ix, float iy, float x, float y)
109 {
110    m_PathType.push_back(PathCommand::CubicTo);
111    m_PathPoints.push_back({ox, oy});
112    m_PathPoints.push_back({ix, iy});
113    m_PathPoints.push_back({x, y});
114 }
115
116 void TvgRenderPath::close()
117 {
118    m_PathType.push_back(PathCommand::Close);
119 }
120
121 TvgRenderPaint::TvgRenderPaint()
122 {
123
124 }
125
126 void TvgRenderPaint::style(RenderPaintStyle style)
127 {
128    m_Paint.style = style;
129 }
130
131 void TvgRenderPaint::color(unsigned int value)
132 {
133    m_Paint.color[0] = value >> 16 & 255;
134    m_Paint.color[1] = value >> 8 & 255;
135    m_Paint.color[2] = value >> 0 & 255;
136    m_Paint.color[3] = value >> 24 & 255;
137 }
138
139 void TvgRenderPaint::thickness(float value)
140 {
141    m_Paint.thickness = value;
142 }
143
144 void TvgRenderPaint::join(StrokeJoin value)
145 {
146    switch (value)
147    {
148       case rive::StrokeJoin::round:
149          m_Paint.join = tvg::StrokeJoin::Round;
150          break;
151       case rive::StrokeJoin::bevel:
152          m_Paint.join = tvg::StrokeJoin::Bevel;
153          break;
154       case rive::StrokeJoin::miter:
155          m_Paint.join = tvg::StrokeJoin::Miter;
156          break;
157    }
158 }
159
160 void TvgRenderPaint::cap(StrokeCap value)
161 {
162    switch (value)
163    {
164       case rive::StrokeCap::butt:
165          m_Paint.cap = tvg::StrokeCap::Butt;
166          break;
167       case rive::StrokeCap::round:
168          m_Paint.cap = tvg::StrokeCap::Round;
169          break;
170       case rive::StrokeCap::square:
171          m_Paint.cap = tvg::StrokeCap::Square;
172          break;
173    }
174 }
175
176 void TvgRenderPaint::linearGradient(float sx, float sy, float ex, float ey)
177 {
178    m_GradientBuilder = new TvgLinearGradientBuilder(sx, sy, ex, ey);
179 }
180
181 void TvgRenderPaint::radialGradient(float sx, float sy, float ex, float ey)
182 {
183    m_GradientBuilder = new TvgRadialGradientBuilder(sx, sy, ex, ey);
184 }
185
186 void TvgRenderPaint::addStop(unsigned int color, float stop)
187 {
188    m_GradientBuilder->stops.emplace_back(GradientStop(color, stop));
189 }
190
191 void TvgRenderPaint::completeGradient()
192 {
193    m_GradientBuilder->make(&m_Paint);
194    delete m_GradientBuilder;
195 }
196
197 void TvgRenderPaint::blendMode(BlendMode value)
198 {
199
200 }
201
202 void TvgRadialGradientBuilder::make(TvgPaint* paint)
203 {
204    paint->isGradient = true;
205    int numStops = stops.size();
206
207    paint->gradientFill = tvg::RadialGradient::gen().release();
208         float radius = Vec2D::distance(Vec2D(sx, sy), Vec2D(ex, ey));
209    static_cast<RadialGradient*>(paint->gradientFill)->radial(sx, sy, radius);
210
211    tvg::Fill::ColorStop colorStops[numStops];
212    for (int i = 0; i < numStops; i++)
213    {
214       unsigned int value = stops[i].color;
215       uint8_t r = value >> 16 & 255;
216       uint8_t g = value >> 8 & 255;
217       uint8_t b = value >> 0 & 255;
218       uint8_t a = value >> 24 & 255;
219
220       colorStops[i] = {stops[i].stop, r, g, b, a};
221    }
222
223    static_cast<RadialGradient*>(paint->gradientFill)->colorStops(colorStops, numStops);
224 }
225
226 void TvgLinearGradientBuilder::make(TvgPaint* paint)
227 {
228    paint->isGradient = true;
229    int numStops = stops.size();
230
231    paint->gradientFill = tvg::LinearGradient::gen().release();
232    static_cast<LinearGradient*>(paint->gradientFill)->linear(sx, sy, ex, ey);
233
234    tvg::Fill::ColorStop colorStops[numStops];
235    for (int i = 0; i < numStops; i++)
236    {
237       unsigned int value = stops[i].color;
238       uint8_t r = value >> 16 & 255;
239       uint8_t g = value >> 8 & 255;
240       uint8_t b = value >> 0 & 255;
241       uint8_t a = value >> 24 & 255;
242
243       colorStops[i] = {stops[i].stop, r, g, b, a};
244    }
245
246    static_cast<LinearGradient*>(paint->gradientFill)->colorStops(colorStops, numStops);
247 }
248
249 void TvgRenderer::save()
250 {
251    m_SaveTransform = m_Transform;
252 }
253
254 void TvgRenderer::restore()
255 {
256    m_Transform = m_SaveTransform;
257 }
258
259 void TvgRenderer::transform(const Mat2D& transform)
260 {
261    m_Transform = m_Transform * transform;
262 }
263
264 void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint)
265 {
266    auto renderPath = static_cast<TvgRenderPath*>(path);
267    auto shape = static_cast<TvgRenderPath*>(path)->shape();
268    auto tvgPaint = static_cast<TvgRenderPaint*>(paint)->paint();
269
270    /* OPTIMIZE ME: Stroke / Fill Paints required to draw separately.
271       thorvg doesn't need to handle both, we can avoid one of them rendering... */
272
273    if (tvgPaint->style == RenderPaintStyle::fill)
274    {
275       if (tvgPaint->isGradient == false)
276          shape->fill(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]);
277       else
278       {
279          if (tvgPaint->gradientApplied == false)
280          {
281             shape->fill(unique_ptr<tvg::Fill>(tvgPaint->gradientFill));
282             tvgPaint->gradientApplied = true;
283          }
284       }
285    }
286    else if (tvgPaint->style == RenderPaintStyle::stroke)
287    {
288       shape->stroke(tvgPaint->cap);
289       shape->stroke(tvgPaint->join);
290       shape->stroke(tvgPaint->thickness);
291
292       if (tvgPaint->isGradient == false)
293          shape->stroke(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]);
294       else
295       {
296         if (tvgPaint->gradientApplied == false)
297         {
298           shape->stroke(unique_ptr<tvg::Fill>(tvgPaint->gradientFill));
299           tvgPaint->gradientApplied = true;
300         }
301       }
302    }
303
304    shape->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1});
305
306    if (renderPath->onCanvas())
307    {
308       m_Canvas->update(shape);
309    }
310    else
311    {
312       m_Canvas->push(unique_ptr<Shape>(shape));
313       renderPath->onCanvas(true);
314    }
315 }
316
317 void TvgRenderer::clipPath(RenderPath* path)
318 {
319
320 }
321
322 namespace rive
323 {
324    RenderPath* makeRenderPath() { return new TvgRenderPath();}
325    RenderPaint* makeRenderPaint() { return new TvgRenderPaint();}
326 }