From 8b27efc99f0513efe6a163c0a38f5c0977001669 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Wed, 30 Oct 2024 12:02:23 +0000 Subject: [PATCH] wg_engine: fix cubic splines and circles tesselation quality Tesseletion factor now depends on scale matix of the shape --- src/renderer/wg_engine/tvgWgGeometry.h | 25 +++++++++++++--------- src/renderer/wg_engine/tvgWgRenderData.cpp | 7 +++++- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/renderer/wg_engine/tvgWgGeometry.h b/src/renderer/wg_engine/tvgWgGeometry.h index 39e5a4b0..48235818 100755 --- a/src/renderer/wg_engine/tvgWgGeometry.h +++ b/src/renderer/wg_engine/tvgWgGeometry.h @@ -39,15 +39,17 @@ struct WgVertexBuffer float vleng[WG_POINTS_COUNT]; // distance to the first point through all previous points size_t vcount{}; bool closed{}; + float tscale = 1.0f; // tesselation scale // callback for external process of polyline using onPolylineFn = std::function; // reset buffer - void reset() + void reset(float scale) { vcount = 0; closed = false; + tscale = scale; } // get the last point with optional index offset from the end @@ -134,8 +136,8 @@ struct WgVertexBuffer { // get approx circle length float clen = 2.0f * radius * MATH_PI; - size_t nsegs = std::max((uint32_t)(clen / 8), 16U); - // append circle + size_t nsegs = std::max((uint32_t)(clen * tscale / 8), 16U); + // append circle^ Point prev { std::sin(0.0f) * radius, std::cos(0.0f) * radius }; for (size_t i = 1; i <= nsegs; i++) { float t = (2.0f * MATH_PI * i) / nsegs; @@ -151,8 +153,8 @@ struct WgVertexBuffer void appendCubic(const Point& v0, const Point& v1, const Point& v2, const Point& v3) { // get approx cubic length - float clen = length(v0 - v1) + length(v1 - v2) + length(v2 - v3); - size_t nsegs = std::max((uint32_t)(clen / 8), 16U); + float clen = (length(v0 - v1) + length(v1 - v2) + length(v2 - v3)); + size_t nsegs = std::max((uint32_t)(clen * tscale / 16), 16U); // append cubic Bezier bezier{v0, v1, v2, v3}; for (size_t i = 1; i <= nsegs; i++) @@ -189,7 +191,7 @@ struct WgVertexBuffer void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline) { // decode path - reset(); + reset(tscale); size_t pntIndex = 0; for (uint32_t cmdIndex = 0; cmdIndex < rshape.path.cmds.count; cmdIndex++) { PathCommand cmd = rshape.path.cmds[cmdIndex]; @@ -198,7 +200,7 @@ struct WgVertexBuffer if (update_dist) updateDistances(); if ((onPolyline) && (vcount != 0)) onPolyline(*this); - reset(); + reset(tscale); append(rshape.path.pts[pntIndex]); pntIndex++; } else if (cmd == PathCommand::LineTo) { @@ -226,11 +228,13 @@ struct WgVertexBufferInd uint32_t ibuff[WG_POINTS_COUNT*16]; size_t vcount = 0; size_t icount = 0; + float tscale = 1.0f; // reset buffer - void reset() + void reset(float scale) { icount = vcount = 0; + tscale = scale; } // get min and max values of the buffer @@ -269,7 +273,7 @@ struct WgVertexBufferInd { // dashed buffer WgVertexBuffer dashed; - dashed.reset(); + dashed.reset(tscale); // ignore single points polyline if (buff.vcount < 2) return; const float* dashPattern = rstroke->dashPattern; @@ -294,7 +298,7 @@ struct WgVertexBufferInd if (index_dash % 2 != 0) { dashed.updateDistances(); appendStrokes(dashed, rstroke); - dashed.reset(); + dashed.reset(tscale); } } // update current subline length @@ -391,6 +395,7 @@ struct WgVertexBufferInd if ((rstroke->join == StrokeJoin::Round) || (rstroke->cap == StrokeCap::Round)) { // create mesh for circle WgVertexBuffer circle; + circle.reset(buff.tscale); circle.appendCircle(halfWidth); // append caps (round) if (rstroke->cap == StrokeCap::Round) { diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index f9c15d93..2eebf159 100755 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -381,8 +381,12 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha releaseMeshes(context); strokeFirst = rshape.stroke ? rshape.stroke->strokeFirst : false; + // get object scale + float scale = std::max(std::min(length(Point{tr.e11 + tr.e12,tr.e21 + tr.e22}), 8.0f), 1.0f); + // path decoded vertex buffer WgVertexBuffer pbuff; + pbuff.reset(scale); // append shape without strokes if (!rshape.stroke) { pbuff.decodePath(rshape, false, [&](const WgVertexBuffer& path_buff) { @@ -451,11 +455,12 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha void WgRenderDataShape::proceedStrokes(WgContext context, const RenderStroke* rstroke, float tbeg, float tend, const WgVertexBuffer& buff) { assert(rstroke); - gStrokesGenerator->reset(); + gStrokesGenerator->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