From 41b340bbdbe2dc09d6bc6671c49ec34d2a306833 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Thu, 13 Feb 2025 23:54:24 +0100 Subject: [PATCH] gl_engine: add offset support in dashed strokes Offset is correctly applied to dashed strokes, properly shifting the dash pattern. @Issue: https://github.com/thorvg/thorvg/issues/3217 @Issue: https://github.com/thorvg/thorvg/issues/3223 @Issue: https://github.com/thorvg/thorvg/issues/3191 --- src/renderer/gl_engine/tvgGlTessellator.cpp | 38 ++++++++++++++++----- src/renderer/gl_engine/tvgGlTessellator.h | 5 +-- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/renderer/gl_engine/tvgGlTessellator.cpp b/src/renderer/gl_engine/tvgGlTessellator.cpp index 24c7d7aa..73f8d2db 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.cpp +++ b/src/renderer/gl_engine/tvgGlTessellator.cpp @@ -1679,10 +1679,11 @@ void Stroker::stroke(const RenderShape *rshape) } const float *dash_pattern = nullptr; - auto dashCnt = rshape->strokeDash(&dash_pattern, nullptr); + auto dash_offset = 0.0f; + auto dashCnt = rshape->strokeDash(&dash_pattern, &dash_offset); if (dashCnt == 0) doStroke(cmds, cmdCnt, pts, ptsCnt); - else doDashStroke(cmds, cmdCnt, pts, ptsCnt, dashCnt, dash_pattern); + else doDashStroke(cmds, cmdCnt, pts, ptsCnt, dashCnt, dash_pattern, dash_offset); } @@ -1810,7 +1811,7 @@ void Stroker::doStroke(const PathCommand *cmds, uint32_t cmd_count, const Point } void Stroker::doDashStroke(const PathCommand *cmds, uint32_t cmd_count, const Point *pts, uint32_t pts_count, - uint32_t dash_count, const float *dash_pattern) + uint32_t dash_count, const float *dash_pattern, float dash_offset) { Array dash_cmds{}; Array dash_pts{}; @@ -1818,7 +1819,7 @@ void Stroker::doDashStroke(const PathCommand *cmds, uint32_t cmd_count, const Po dash_cmds.reserve(20 * cmd_count); dash_pts.reserve(20 * pts_count); - DashStroke dash(&dash_cmds, &dash_pts, dash_count, dash_pattern); + DashStroke dash(&dash_cmds, &dash_pts, dash_count, dash_pattern, dash_offset); dash.doStroke(cmds, cmd_count, pts, pts_count); @@ -2190,11 +2191,12 @@ void Stroker::strokeRound(const GlPoint& p, const GlPoint& outDir) } -DashStroke::DashStroke(Array *cmds, Array *pts, uint32_t dash_count, const float *dash_pattern) +DashStroke::DashStroke(Array *cmds, Array *pts, uint32_t dash_count, const float *dash_pattern, float dash_offset) : mCmds(cmds), mPts(pts), mDashCount(dash_count), mDashPattern(dash_pattern), + mDashOffset(dash_offset), mCurrLen(), mCurrIdx(), mCurOpGap(false), @@ -2206,6 +2208,26 @@ DashStroke::DashStroke(Array *cmds, Array *pts, uint32_t das void DashStroke::doStroke(const PathCommand *cmds, uint32_t cmd_count, const Point *pts, uint32_t pts_count) { + int32_t idx = 0; + auto offset = mDashOffset; + bool gap = false; + if (!tvg::zero(mDashOffset)) { + auto len = 0.0f; + for (uint32_t i = 0; i < mDashCount; ++i) len += mDashPattern[i]; + if (mDashCount % 2) len *= 2; + + offset = fmodf(offset, len); + if (offset < 0) offset += len; + + for (uint32_t i = 0; i < mDashCount * (mDashCount % 2 + 1); ++i, ++idx) { + auto curPattern = mDashPattern[i % mDashCount]; + if (offset < curPattern) break; + offset -= curPattern; + gap = !gap; + } + idx = idx % mDashCount; + } + for (uint32_t i = 0; i < cmd_count; i++) { switch (*cmds) { case PathCommand::Close: { @@ -2215,9 +2237,9 @@ void DashStroke::doStroke(const PathCommand *cmds, uint32_t cmd_count, const Poi case PathCommand::MoveTo: { // reset the dash state - mCurrIdx = 0; - mCurrLen = mDashPattern[0]; - mCurOpGap = false; + mCurrIdx = idx; + mCurrLen = mDashPattern[idx] - offset; + mCurOpGap = gap; mPtStart = mPtCur = *pts; pts++; break; diff --git a/src/renderer/gl_engine/tvgGlTessellator.h b/src/renderer/gl_engine/tvgGlTessellator.h index e71b4e08..00a15b2b 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.h +++ b/src/renderer/gl_engine/tvgGlTessellator.h @@ -118,7 +118,7 @@ private: void doTrimStroke(const PathCommand* cmds, uint32_t cmd_count, const Point* pts, uint32_t pts_count, bool simultaneous, float start, float end); void doStroke(const PathCommand* cmds, uint32_t cmd_count, const Point* pts, uint32_t pts_count); void doDashStroke(const PathCommand* cmds, uint32_t cmd_count, const Point* pts, uint32_t pts_count, - uint32_t dash_count, const float* dash_pattern); + uint32_t dash_count, const float* dash_pattern, float dash_offset); float strokeRadius() const { @@ -164,7 +164,7 @@ private: class DashStroke { public: - DashStroke(Array* cmds, Array* pts, uint32_t dash_count, const float* dash_pattern); + DashStroke(Array* cmds, Array* pts, uint32_t dash_count, const float* dash_pattern, float dash_offset); ~DashStroke() = default; @@ -183,6 +183,7 @@ private: Array* mPts; uint32_t mDashCount; const float* mDashPattern; + float mDashOffset; float mCurrLen; int32_t mCurrIdx; bool mCurOpGap;