1 #include "tvg_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()
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 m_PathType = static_cast<TvgRenderPath*>(path)->m_PathType;
53 /* OPTIMIZE ME: Should avoid data copy here */
54 auto srcPathPoints = static_cast<TvgRenderPath*>(path)->m_PathPoints;
55 m_PathPoints.resize(srcPathPoints.size());
56 std::copy(srcPathPoints.begin(), srcPathPoints.end(), m_PathPoints.begin());
58 /* OPTIMIZE ME: Should avoid data copy in loop... */
61 for (size_t i = 0; i < m_PathType.size(); i++)
63 /* OPTIMIZE ME: apply transform only when it's not identity */
66 case PathCommand::MoveTo:
68 auto pt = applyTransform(m_PathPoints[index], transform);
69 m_PathPoints[index] = {pt.x, pt.y};
70 m_Shape->moveTo(pt.x, pt.y);
74 case PathCommand::LineTo:
76 auto pt = applyTransform(m_PathPoints[index], transform);
77 m_PathPoints[index] = {pt.x, pt.y};
78 m_Shape->lineTo(pt.x, pt.y);
82 case PathCommand::CubicTo:
84 auto pt1 = applyTransform(m_PathPoints[index], transform);
85 auto pt2 = applyTransform(m_PathPoints[index + 1], transform);
86 auto pt3 = applyTransform(m_PathPoints[index + 2], transform);
87 m_PathPoints[index] = {pt1.x, pt1.y};
88 m_PathPoints[index + 1] = {pt2.x, pt2.y};
89 m_PathPoints[index + 2] = {pt3.x, pt3.y};
90 m_Shape->cubicTo(pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y);
94 case PathCommand::Close:
104 void TvgRenderPath::moveTo(float x, float y)
106 m_PathType.push_back(PathCommand::MoveTo);
107 m_PathPoints.push_back({x, y});
108 m_Shape->moveTo(x, y);
111 void TvgRenderPath::lineTo(float x, float y)
113 m_PathType.push_back(PathCommand::LineTo);
114 m_PathPoints.push_back({x, y});
115 m_Shape->lineTo(x, y);
118 void TvgRenderPath::cubicTo(float ox, float oy, float ix, float iy, float x, float y)
120 m_PathType.push_back(PathCommand::CubicTo);
121 m_PathPoints.push_back({ox, oy});
122 m_PathPoints.push_back({ix, iy});
123 m_PathPoints.push_back({x, y});
124 m_Shape->cubicTo(ox, oy, ix, iy, x, y);
127 void TvgRenderPath::close()
129 m_PathType.push_back(PathCommand::Close);
133 TvgRenderPaint::TvgRenderPaint()
138 void TvgRenderPaint::style(RenderPaintStyle style)
140 m_Paint.style = style;
143 void TvgRenderPaint::color(unsigned int value)
145 m_Paint.color[0] = value >> 16 & 255;
146 m_Paint.color[1] = value >> 8 & 255;
147 m_Paint.color[2] = value >> 0 & 255;
148 m_Paint.color[3] = value >> 24 & 255;
151 void TvgRenderPaint::thickness(float value)
153 m_Paint.thickness = value;
156 void TvgRenderPaint::join(StrokeJoin value)
160 case rive::StrokeJoin::round:
161 m_Paint.join = tvg::StrokeJoin::Round;
163 case rive::StrokeJoin::bevel:
164 m_Paint.join = tvg::StrokeJoin::Bevel;
166 case rive::StrokeJoin::miter:
167 m_Paint.join = tvg::StrokeJoin::Miter;
172 void TvgRenderPaint::cap(StrokeCap value)
176 case rive::StrokeCap::butt:
177 m_Paint.cap = tvg::StrokeCap::Butt;
179 case rive::StrokeCap::round:
180 m_Paint.cap = tvg::StrokeCap::Round;
182 case rive::StrokeCap::square:
183 m_Paint.cap = tvg::StrokeCap::Square;
188 void TvgRenderPaint::linearGradient(float sx, float sy, float ex, float ey)
190 m_GradientBuilder = new TvgLinearGradientBuilder(sx, sy, ex, ey);
193 void TvgRenderPaint::radialGradient(float sx, float sy, float ex, float ey)
195 m_GradientBuilder = new TvgRadialGradientBuilder(sx, sy, ex, ey);
198 void TvgRenderPaint::addStop(unsigned int color, float stop)
200 m_GradientBuilder->stops.emplace_back(GradientStop(color, stop));
203 void TvgRenderPaint::completeGradient()
205 m_GradientBuilder->make(&m_Paint);
206 delete m_GradientBuilder;
209 void TvgRenderPaint::blendMode(BlendMode value)
214 void TvgRadialGradientBuilder::make(TvgPaint* paint)
216 paint->isGradient = true;
217 int numStops = stops.size();
219 paint->gradientFill = tvg::RadialGradient::gen().release();
220 float radius = Vec2D::distance(Vec2D(sx, sy), Vec2D(ex, ey));
221 static_cast<RadialGradient*>(paint->gradientFill)->radial(sx, sy, radius);
223 tvg::Fill::ColorStop colorStops[numStops];
224 for (int i = 0; i < numStops; i++)
226 unsigned int value = stops[i].color;
227 uint8_t r = value >> 16 & 255;
228 uint8_t g = value >> 8 & 255;
229 uint8_t b = value >> 0 & 255;
230 uint8_t a = value >> 24 & 255;
232 colorStops[i] = {stops[i].stop, r, g, b, a};
235 static_cast<RadialGradient*>(paint->gradientFill)->colorStops(colorStops, numStops);
238 void TvgLinearGradientBuilder::make(TvgPaint* paint)
240 paint->isGradient = true;
241 int numStops = stops.size();
243 paint->gradientFill = tvg::LinearGradient::gen().release();
244 static_cast<LinearGradient*>(paint->gradientFill)->linear(sx, sy, ex, ey);
246 tvg::Fill::ColorStop colorStops[numStops];
247 for (int i = 0; i < numStops; i++)
249 unsigned int value = stops[i].color;
250 uint8_t r = value >> 16 & 255;
251 uint8_t g = value >> 8 & 255;
252 uint8_t b = value >> 0 & 255;
253 uint8_t a = value >> 24 & 255;
255 colorStops[i] = {stops[i].stop, r, g, b, a};
258 static_cast<LinearGradient*>(paint->gradientFill)->colorStops(colorStops, numStops);
261 void TvgRenderer::save()
263 m_SaveTransform = m_Transform;
266 void TvgRenderer::restore()
268 m_Transform = m_SaveTransform;
271 void TvgRenderer::transform(const Mat2D& transform)
273 m_Transform = m_Transform * transform;
276 void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint)
278 auto shape = static_cast<TvgRenderPath*>(path)->shape();
279 auto tvgPaint = static_cast<TvgRenderPaint*>(paint)->paint();
281 /* OPTIMIZE ME: Stroke / Fill Paints required to draw separately.
282 thorvg doesn't need to handle both, we can avoid one of them rendering... */
284 if (tvgPaint->style == RenderPaintStyle::fill)
286 if (tvgPaint->isGradient == false)
287 shape->fill(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]);
290 if (tvgPaint->gradientApplied == false)
292 shape->fill(unique_ptr<tvg::Fill>(tvgPaint->gradientFill));
293 tvgPaint->gradientApplied = true;
297 else if (tvgPaint->style == RenderPaintStyle::stroke)
299 shape->stroke(tvgPaint->cap);
300 shape->stroke(tvgPaint->join);
301 shape->stroke(tvgPaint->thickness);
303 if (tvgPaint->isGradient == false)
304 shape->stroke(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]);
307 if (tvgPaint->gradientApplied == false)
309 shape->stroke(unique_ptr<tvg::Fill>(tvgPaint->gradientFill));
310 tvgPaint->gradientApplied = true;
317 m_ClipPath->fill(255, 255, 255, 255);
318 shape->composite(unique_ptr<Shape>(static_cast<Shape*>(m_ClipPath->duplicate())), tvg::CompositeMethod::ClipPath);
319 m_ClipPath = nullptr;
322 shape->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1});
323 m_Canvas->push(unique_ptr<Paint>(shape->duplicate()));
327 void TvgRenderer::clipPath(RenderPath* path)
329 //Note: ClipPath transform matrix is calculated by transfrom matrix in addRenderPath function
330 m_ClipPath = static_cast<TvgRenderPath*>(path)->shape();
331 m_ClipPath->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1});
336 RenderPath* makeRenderPath() { return new TvgRenderPath();}
337 RenderPaint* makeRenderPaint() { return new TvgRenderPaint();}