1 #include "thorvg_renderer.hpp"
2 #include "math/vec2d.hpp"
3 #include "shapes/paint/color.hpp"
7 TvgRenderPath::TvgRenderPath()
9 this->m_Shape = tvg::Shape::gen().release();
12 TvgRenderPath::~TvgRenderPath()
14 if (!active) delete(m_Shape);
17 void TvgRenderPath::fillRule(FillRule value)
21 case FillRule::evenOdd:
22 m_Shape->fill(tvg::FillRule::EvenOdd);
24 case FillRule::nonZero:
25 m_Shape->fill(tvg::FillRule::Winding);
30 Point applyTransform(const Vec2D &vec, const Mat2D &mat)
32 Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1};
40 return {vec[0] * m.e11 + vec[1] * m.e12 + m.e13, vec[0] * m.e21 + vec[1] * m.e22 + m.e23};
43 void TvgRenderPath::reset()
50 void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform)
52 auto m_PathType = static_cast<TvgRenderPath*>(path)->m_PathType;
53 auto m_PathPoints = static_cast<TvgRenderPath*>(path)->m_PathPoints;
56 /* OPTIMIZE ME: Should avoid data copy in loop... */
58 for (size_t i = 0; i < m_PathType.size(); i++)
60 /* OPTIMIZE ME: apply transform only when it's not identity */
63 case PathCommand::MoveTo:
65 auto pt = applyTransform(m_PathPoints[index], transform);
66 m_Shape->moveTo(pt.x, pt.y);
70 case PathCommand::LineTo:
72 auto pt = applyTransform(m_PathPoints[index], transform);
73 m_Shape->lineTo(pt.x, pt.y);
77 case PathCommand::CubicTo:
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);
86 case PathCommand::Close:
96 void TvgRenderPath::moveTo(float x, float y)
98 m_PathType.push_back(PathCommand::MoveTo);
99 m_PathPoints.push_back({x, y});
102 void TvgRenderPath::lineTo(float x, float y)
104 m_PathType.push_back(PathCommand::LineTo);
105 m_PathPoints.push_back({x, y});
108 void TvgRenderPath::cubicTo(float ox, float oy, float ix, float iy, float x, float y)
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});
116 void TvgRenderPath::close()
118 m_PathType.push_back(PathCommand::Close);
121 TvgRenderPaint::TvgRenderPaint()
126 void TvgRenderPaint::style(RenderPaintStyle style)
128 m_Paint.style = style;
131 void TvgRenderPaint::color(unsigned int value)
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;
139 void TvgRenderPaint::thickness(float value)
141 m_Paint.thickness = value;
144 void TvgRenderPaint::join(StrokeJoin value)
148 case rive::StrokeJoin::round:
149 m_Paint.join = tvg::StrokeJoin::Round;
151 case rive::StrokeJoin::bevel:
152 m_Paint.join = tvg::StrokeJoin::Bevel;
154 case rive::StrokeJoin::miter:
155 m_Paint.join = tvg::StrokeJoin::Miter;
160 void TvgRenderPaint::cap(StrokeCap value)
164 case rive::StrokeCap::butt:
165 m_Paint.cap = tvg::StrokeCap::Butt;
167 case rive::StrokeCap::round:
168 m_Paint.cap = tvg::StrokeCap::Round;
170 case rive::StrokeCap::square:
171 m_Paint.cap = tvg::StrokeCap::Square;
176 void TvgRenderPaint::linearGradient(float sx, float sy, float ex, float ey)
178 m_GradientBuilder = new TvgLinearGradientBuilder(sx, sy, ex, ey);
181 void TvgRenderPaint::radialGradient(float sx, float sy, float ex, float ey)
183 m_GradientBuilder = new TvgRadialGradientBuilder(sx, sy, ex, ey);
186 void TvgRenderPaint::addStop(unsigned int color, float stop)
188 m_GradientBuilder->stops.emplace_back(GradientStop(color, stop));
191 void TvgRenderPaint::completeGradient()
193 m_GradientBuilder->make(&m_Paint);
194 delete m_GradientBuilder;
197 void TvgRenderPaint::blendMode(BlendMode value)
202 void TvgRadialGradientBuilder::make(TvgPaint* paint)
204 paint->isGradient = true;
205 int numStops = stops.size();
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);
211 tvg::Fill::ColorStop colorStops[numStops];
212 for (int i = 0; i < numStops; i++)
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;
220 colorStops[i] = {stops[i].stop, r, g, b, a};
223 static_cast<RadialGradient*>(paint->gradientFill)->colorStops(colorStops, numStops);
226 void TvgLinearGradientBuilder::make(TvgPaint* paint)
228 paint->isGradient = true;
229 int numStops = stops.size();
231 paint->gradientFill = tvg::LinearGradient::gen().release();
232 static_cast<LinearGradient*>(paint->gradientFill)->linear(sx, sy, ex, ey);
234 tvg::Fill::ColorStop colorStops[numStops];
235 for (int i = 0; i < numStops; i++)
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;
243 colorStops[i] = {stops[i].stop, r, g, b, a};
246 static_cast<LinearGradient*>(paint->gradientFill)->colorStops(colorStops, numStops);
249 void TvgRenderer::save()
251 m_SaveTransform = m_Transform;
254 void TvgRenderer::restore()
256 m_Transform = m_SaveTransform;
259 void TvgRenderer::transform(const Mat2D& transform)
261 m_Transform = m_Transform * transform;
264 void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint)
266 auto renderPath = static_cast<TvgRenderPath*>(path);
267 auto shape = static_cast<TvgRenderPath*>(path)->shape();
268 auto tvgPaint = static_cast<TvgRenderPaint*>(paint)->paint();
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... */
273 if (tvgPaint->style == RenderPaintStyle::fill)
275 if (tvgPaint->isGradient == false)
276 shape->fill(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]);
279 if (tvgPaint->gradientApplied == false)
281 shape->fill(unique_ptr<tvg::Fill>(tvgPaint->gradientFill));
282 tvgPaint->gradientApplied = true;
286 else if (tvgPaint->style == RenderPaintStyle::stroke)
288 shape->stroke(tvgPaint->cap);
289 shape->stroke(tvgPaint->join);
290 shape->stroke(tvgPaint->thickness);
292 if (tvgPaint->isGradient == false)
293 shape->stroke(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]);
296 if (tvgPaint->gradientApplied == false)
298 shape->stroke(unique_ptr<tvg::Fill>(tvgPaint->gradientFill));
299 tvgPaint->gradientApplied = true;
304 shape->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1});
306 if (renderPath->onCanvas())
308 m_Canvas->update(shape);
312 m_Canvas->push(unique_ptr<Shape>(shape));
313 renderPath->onCanvas(true);
317 void TvgRenderer::clipPath(RenderPath* path)
324 RenderPath* makeRenderPath() { return new TvgRenderPath();}
325 RenderPaint* makeRenderPaint() { return new TvgRenderPaint();}