From cb8cadfbbafdd4208621f309333fbb80af2a9649 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 14 Jan 2025 23:59:33 +0100 Subject: [PATCH] wg_engine: apply common trimming logic The trim-related implementation has been removed and replaced with the one available in common. @Issue: https://github.com/thorvg/thorvg/issues/2854 --- src/renderer/wg_engine/tvgWgGeometry.h | 69 ++++++++-------- src/renderer/wg_engine/tvgWgRenderData.cpp | 92 +++++----------------- src/renderer/wg_engine/tvgWgRenderData.h | 2 +- 3 files changed, 55 insertions(+), 108 deletions(-) diff --git a/src/renderer/wg_engine/tvgWgGeometry.h b/src/renderer/wg_engine/tvgWgGeometry.h index 4c45f5e5..6de3bfc6 100755 --- a/src/renderer/wg_engine/tvgWgGeometry.h +++ b/src/renderer/wg_engine/tvgWgGeometry.h @@ -161,56 +161,51 @@ struct WgVertexBuffer append(bezier.at((float)i / nsegs)); } - // trim source buffer - void trim(const WgVertexBuffer& buff, float beg, float end) - { - // empty buffer guard - if (buff.vcount == 0) return; - // initialize - float len_beg = buff.total() * beg; - float len_end = buff.total() * end; - // find points - size_t index_beg = buff.getIndexByLength(len_beg); - size_t index_end = buff.getIndexByLength(len_end); - float len_total_beg = buff.vleng[index_beg]; - float len_total_end = buff.vleng[index_end]; - float len_seg_beg = buff.vdist[index_beg]; - float len_seg_end = buff.vdist[index_end]; - // append points - float t_beg = len_seg_beg > 0.0f ? 1.0f - (len_total_beg - len_beg) / len_seg_beg : 0.0f; - float t_end = len_seg_end > 0.0f ? 1.0f - (len_total_end - len_end) / len_seg_end : 0.0f; - //t_beg == 1 handled in appendRange - if (index_beg > 0 && t_beg != 1.0f) append(lerp(buff.vbuff[index_beg-1], buff.vbuff[index_beg], t_beg)); - appendRange(buff, index_beg, index_end); - //t_end == 0 handled in appendRange - if (index_end > 0 && t_end != 0.0f) append(lerp(buff.vbuff[index_end-1], buff.vbuff[index_end], t_end)); - } - - // decode path with callback for external prcesses - void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline) + void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline, bool trim = false) { // decode path reset(tscale); + + PathCommand *cmds, *trimmedCmds = nullptr; + Point *pts, *trimmedPts = nullptr; + uint32_t cmdCnt{}; + + if (trim) { + RenderPath trimmedPath; + if (!rshape.stroke->trim.trim(rshape.path, trimmedPath)) return; + + cmds = trimmedCmds = trimmedPath.cmds.data; + cmdCnt = trimmedPath.cmds.count; + pts = trimmedPts = trimmedPath.pts.data; + + trimmedPath.cmds.data = nullptr; + trimmedPath.pts.data = nullptr; + } else { + cmds = rshape.path.cmds.data; + cmdCnt = rshape.path.cmds.count; + pts = rshape.path.pts.data; + } + size_t pntIndex = 0; - ARRAY_FOREACH(p, rshape.path.cmds) { - auto cmd = *p; + for (uint32_t i = 0; i < cmdCnt; i++) { + auto& cmd = cmds[i]; if (cmd == PathCommand::MoveTo) { // after path decoding we need to update distances and total length if (update_dist) updateDistances(); if ((onPolyline) && (vcount > 0)) onPolyline(*this); reset(tscale); - append(rshape.path.pts[pntIndex]); + append(pts[pntIndex]); pntIndex++; } else if (cmd == PathCommand::LineTo) { - append(rshape.path.pts[pntIndex]); + append(pts[pntIndex]); pntIndex++; } else if (cmd == PathCommand::Close) { close(); // proceed path if close command is not the last command and next command is LineTo or CubicTo - if (((p + 1) < rshape.path.cmds.end()) && - ((*(p + 1) == PathCommand::LineTo) || - (*(p + 1) == PathCommand::CubicTo))) { + if (i + 1 < cmdCnt && + (cmds[i + 1] == PathCommand::LineTo || + cmds[i + 1] == PathCommand::CubicTo)) { // proceed current path if (update_dist) updateDistances(); if ((vcount > 0) && (onPolyline)) onPolyline(*this); @@ -221,10 +216,14 @@ struct WgVertexBuffer } } else if (cmd == PathCommand::CubicTo) { // append tesselated cubic spline with tscale param - appendCubic(vbuff[vcount - 1], rshape.path.pts[pntIndex + 0], rshape.path.pts[pntIndex + 1], rshape.path.pts[pntIndex + 2]); + appendCubic(vbuff[vcount - 1], pts[pntIndex + 0], pts[pntIndex + 1], pts[pntIndex + 2]); pntIndex += 3; } } + + free(trimmedCmds); + free(trimmedPts); + // after path decoding we need to update distances and total length if (update_dist) updateDistances(); if ((vcount > 0) && (onPolyline)) onPolyline(*this); diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index e8c7f696..0e6e5f1c 100755 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -385,62 +385,24 @@ void WgRenderDataShape::updateMeshes(WgContext& context, const RenderShape &rsha // path decoded vertex buffer WgVertexBuffer pbuff; pbuff.reset(scale); - // append shape without strokes - if (!rshape.stroke) { - pbuff.decodePath(rshape, false, [&](const WgVertexBuffer& path_buff) { + + if (rshape.strokeTrim()) { + WgVertexBuffer trimbuff; + trimbuff.reset(scale); + + pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) { appendShape(context, path_buff); }); - // append shape with strokes + trimbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) { + appendShape(context, path_buff); + proceedStrokes(context, rshape.stroke, path_buff); + }, true); } else { - float tbeg{}, tend{}; - if (!rshape.stroke->trim.get(tbeg, tend)) { tbeg = 0.0f; tend = 1.0f; } - bool loop = tbeg > tend; - if (tbeg == tend) { - pbuff.decodePath(rshape, false, [&](const WgVertexBuffer& path_buff) { - appendShape(context, path_buff); - }); - } else if (rshape.stroke->trim.simultaneous) { - pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) { - appendShape(context, path_buff); - if (loop) { - proceedStrokes(context, rshape.stroke, tbeg, 1.0f, path_buff); - proceedStrokes(context, rshape.stroke, 0.0f, tend, path_buff); - } else { - proceedStrokes(context, rshape.stroke, tbeg, tend, path_buff); - } - }); - } else { - float totalLen = 0.0f; - pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) { - appendShape(context, path_buff); - totalLen += path_buff.total(); - }); - float len_beg = totalLen * tbeg; // trim length begin - float len_end = totalLen * tend; // trim length end - float len_acc = 0.0; // accumulated length - // append strokes - pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) { - float len_path = path_buff.total(); // current path length - if (loop) { - if (len_acc + len_path >= len_beg) { - auto tbeg = len_acc <= len_beg ? (len_beg - len_acc) / len_path : 0.0f; - proceedStrokes(context, rshape.stroke, tbeg, 1.0f, path_buff); - } - if (len_acc < len_end) { - auto tend = len_acc + len_path >= len_end ? (len_end - len_acc) / len_path : 1.0f; - proceedStrokes(context, rshape.stroke, 0.0f, tend, path_buff); - } - } else { - if (len_acc + len_path >= len_beg && len_acc <= len_end) { - auto tbeg = len_acc <= len_beg ? (len_beg - len_acc) / len_path : 0.0f; - auto tend = len_acc + len_path >= len_end ? (len_end - len_acc) / len_path : 1.0f; - proceedStrokes(context, rshape.stroke, tbeg, tend, path_buff); - } - } - len_acc += len_path; - }); - } - } + pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) { + appendShape(context, path_buff); + if (rshape.stroke) proceedStrokes(context, rshape.stroke, path_buff); + }); + } // update shapes bbox (with empty path handling) if ((this->meshGroupShapesBBox.meshes.count > 0 ) || (this->meshGroupStrokesBBox.meshes.count > 0)) { @@ -450,29 +412,15 @@ void WgRenderDataShape::updateMeshes(WgContext& context, const RenderShape &rsha } -void WgRenderDataShape::proceedStrokes(WgContext& context, const RenderStroke* rstroke, float tbeg, float tend, const WgVertexBuffer& buff) +void WgRenderDataShape::proceedStrokes(WgContext& context, const RenderStroke* rstroke, const WgVertexBuffer& buff) { assert(rstroke); static WgVertexBufferInd strokesGenerator; strokesGenerator.reset(buff.tscale); - // trim -> dash -> stroke - if ((tbeg != 0.0f) || (tend != 1.0f)) { - if (tbeg == tend) return; - WgVertexBuffer trimed_buff; - trimed_buff.reset(buff.tscale); - trimed_buff.trim(buff, tbeg, tend); - trimed_buff.updateDistances(); - // trim ->dash -> stroke - if (rstroke->dashPattern) strokesGenerator.appendStrokesDashed(trimed_buff, rstroke); - // trim -> stroke - else strokesGenerator.appendStrokes(trimed_buff, rstroke); - } else - // dash -> stroke - if (rstroke->dashPattern) { - strokesGenerator.appendStrokesDashed(buff, rstroke); - // stroke - } else - strokesGenerator.appendStrokes(buff, rstroke); + + if (rstroke->dashPattern) strokesGenerator.appendStrokesDashed(buff, rstroke); + else strokesGenerator.appendStrokes(buff, rstroke); + appendStroke(context, strokesGenerator); } diff --git a/src/renderer/wg_engine/tvgWgRenderData.h b/src/renderer/wg_engine/tvgWgRenderData.h index cb0e8a02..eda5da67 100755 --- a/src/renderer/wg_engine/tvgWgRenderData.h +++ b/src/renderer/wg_engine/tvgWgRenderData.h @@ -130,7 +130,7 @@ struct WgRenderDataShape: public WgRenderDataPaint void updateBBox(Point pmin, Point pmax); void updateAABB(const Matrix& tr); void updateMeshes(WgContext& context, const RenderShape& rshape, const Matrix& tr); - void proceedStrokes(WgContext& context, const RenderStroke* rstroke, float tbeg, float tend, const WgVertexBuffer& buff); + void proceedStrokes(WgContext& context, const RenderStroke* rstroke, const WgVertexBuffer& buff); void releaseMeshes(WgContext& context); void release(WgContext& context) override; Type type() override { return Type::Shape; };