From f1e9ce04601eca14e887c0d32d893a7747cf296c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 14 Feb 2025 01:58:15 +0100 Subject: [PATCH] common: refactoring the dash pattern introdced the length to avoid duplicate among engines --- src/renderer/gl_engine/tvgGlTessellator.cpp | 31 ++++-------- src/renderer/gl_engine/tvgGlTessellator.h | 18 +++---- src/renderer/sw_engine/tvgSwRenderer.cpp | 2 +- src/renderer/sw_engine/tvgSwShape.cpp | 17 ++++--- src/renderer/tvgRender.h | 32 +++++++------ src/renderer/tvgShape.h | 42 +++++++--------- src/renderer/wg_engine/tvgWgGeometry.h | 53 ++++++++++----------- src/renderer/wg_engine/tvgWgRenderData.cpp | 4 +- 8 files changed, 90 insertions(+), 109 deletions(-) diff --git a/src/renderer/gl_engine/tvgGlTessellator.cpp b/src/renderer/gl_engine/tvgGlTessellator.cpp index 64a0e736..628feff4 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.cpp +++ b/src/renderer/gl_engine/tvgGlTessellator.cpp @@ -1507,12 +1507,9 @@ void Stroker::stroke(const RenderShape *rshape, const RenderPath& path) mStrokeWidth = strokeWidth / mMatrix.e11; } - const float *patterns = nullptr; - auto offset = 0.0f; - auto patternCnt = rshape->strokeDash(&patterns, &offset); - - if (patternCnt == 0) doStroke(path); - else doDashStroke(path, patterns, patternCnt, offset); + auto& dash = rshape->stroke->dash; + if (dash.count == 0) doStroke(path); + else doDashStroke(path, dash.pattern, dash.count, dash.offset, dash.length); } @@ -1572,14 +1569,14 @@ void Stroker::doStroke(const RenderPath& path) } -void Stroker::doDashStroke(const RenderPath& path, const float *patterns, uint32_t patternCnt, float offset) +void Stroker::doDashStroke(const RenderPath& path, const float *patterns, uint32_t patternCnt, float offset, float length) { RenderPath dpath; dpath.cmds.reserve(20 * path.cmds.count); dpath.pts.reserve(20 * path.pts.count); - DashStroke dash(&dpath.cmds, &dpath.pts, patterns, patternCnt, offset); + DashStroke dash(&dpath.cmds, &dpath.pts, patterns, patternCnt, offset, length); dash.doStroke(path); doStroke(dpath); } @@ -1915,18 +1912,13 @@ void Stroker::strokeRound(const Point& p, const Point& outDir) } -DashStroke::DashStroke(Array *cmds, Array *pts, const float *patterns, uint32_t patternCnt, float offset) +DashStroke::DashStroke(Array *cmds, Array *pts, const float *patterns, uint32_t patternCnt, float offset, float length) : mCmds(cmds), mPts(pts), mDashPattern(patterns), mDashCount(patternCnt), mDashOffset(offset), - mCurrLen(), - mCurrIdx(), - mCurOpGap(false), - mMove(true), - mPtStart(), - mPtCur() + mDashLength(length) { } @@ -1937,12 +1929,9 @@ void DashStroke::doStroke(const RenderPath& path) 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; + auto length = (mDashCount % 2) ? mDashLength * 2 : mDashLength; + offset = fmodf(offset, length); + if (offset < 0) offset += length; for (uint32_t i = 0; i < mDashCount * (mDashCount % 2 + 1); ++i, ++idx) { auto curPattern = mDashPattern[i % mDashCount]; diff --git a/src/renderer/gl_engine/tvgGlTessellator.h b/src/renderer/gl_engine/tvgGlTessellator.h index fafd8501..44fbab41 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.h +++ b/src/renderer/gl_engine/tvgGlTessellator.h @@ -85,7 +85,7 @@ public: private: void doStroke(const RenderPath& path); - void doDashStroke(const RenderPath& path, const float* patterns, uint32_t patternCnt, float offset); + void doDashStroke(const RenderPath& path, const float* patterns, uint32_t patternCnt, float offset, float length); float strokeRadius() const { @@ -119,8 +119,7 @@ private: class DashStroke { public: - DashStroke(Array* cmds, Array* pts, const float* patterns, uint32_t patternCnt, float offset); - ~DashStroke() = default; + DashStroke(Array* cmds, Array* pts, const float* patterns, uint32_t patternCnt, float offset, float length); void doStroke(const RenderPath& path); private: @@ -135,12 +134,13 @@ private: const float* mDashPattern; uint32_t mDashCount; float mDashOffset; - float mCurrLen; - int32_t mCurrIdx; - bool mCurOpGap; - bool mMove; - Point mPtStart; - Point mPtCur; + float mDashLength; + float mCurrLen = 0.0f; + int32_t mCurrIdx = 0; + bool mCurOpGap = false; + bool mMove = true; + Point mPtStart = {}; + Point mPtCur = {}; }; class BWTessellator diff --git a/src/renderer/sw_engine/tvgSwRenderer.cpp b/src/renderer/sw_engine/tvgSwRenderer.cpp index 0e915114..c5122ae0 100644 --- a/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -85,7 +85,7 @@ struct SwShapeTask : SwTask Additionally, the stroke style should not be dashed. */ bool antialiasing(float strokeWidth) { - return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst || rshape->trimpath() || rshape->stroke->color.a < 255; + return strokeWidth < 2.0f || rshape->stroke->dash.count > 0 || rshape->stroke->strokeFirst || rshape->trimpath() || rshape->stroke->color.a < 255; } float validStrokeWidth(bool clipper) diff --git a/src/renderer/sw_engine/tvgSwShape.cpp b/src/renderer/sw_engine/tvgSwShape.cpp index 3985890b..edc27779 100644 --- a/src/renderer/sw_engine/tvgSwShape.cpp +++ b/src/renderer/sw_engine/tvgSwShape.cpp @@ -244,7 +244,6 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans if (trimmed) { RenderPath trimmedPath; if (!rshape->stroke->trim.trim(rshape->path, trimmedPath)) return nullptr; - cmds = trimmedCmds = trimmedPath.cmds.data; cmdCnt = trimmedPath.cmds.count; pts = trimmedPts = trimmedPath.pts.data; @@ -263,19 +262,19 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans if (cmdCnt == 0 || ptsCnt == 0) return nullptr; SwDashStroke dash; - auto offset = 0.0f; - dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset); + dash.pattern = rshape->stroke->dash.pattern; + dash.cnt = rshape->stroke->dash.count; + auto offset = rshape->stroke->dash.offset; //offset - auto patternLength = 0.0f; uint32_t offIdx = 0; if (!tvg::zero(offset)) { - for (size_t i = 0; i < dash.cnt; ++i) patternLength += dash.pattern[i]; + auto length = rshape->stroke->dash.length; bool isOdd = dash.cnt % 2; - if (isOdd) patternLength *= 2; + if (isOdd) length *= 2; - offset = fmodf(offset, patternLength); - if (offset < 0) offset += patternLength; + offset = fmodf(offset, length); + if (offset < 0) offset += length; for (size_t i = 0; i < dash.cnt * (1 + (size_t)isOdd); ++i, ++offIdx) { auto curPattern = dash.pattern[i % dash.cnt]; @@ -510,7 +509,7 @@ bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix& auto ret = true; //Dash style with/without trimming - if (rshape->stroke->dashCnt > 0) { + if (rshape->stroke->dash.count > 0) { shapeOutline = _genDashOutline(rshape, transform, mpool, tid, rshape->trimpath()); if (!shapeOutline) return false; dashStroking = true; diff --git a/src/renderer/tvgRender.h b/src/renderer/tvgRender.h index b3b2628d..148dc0dd 100644 --- a/src/renderer/tvgRender.h +++ b/src/renderer/tvgRender.h @@ -127,9 +127,12 @@ struct RenderStroke float width = 0.0f; RenderColor color{}; Fill *fill = nullptr; - float* dashPattern = nullptr; - uint32_t dashCnt = 0; - float dashOffset = 0.0f; + struct { + float* pattern = nullptr; + uint32_t count = 0; + float offset = 0.0f; + float length = 0.0f; + } dash; float miterlimit = 4.0f; RenderTrimPath trim; StrokeCap cap = StrokeCap::Square; @@ -145,15 +148,16 @@ struct RenderStroke if (rhs.fill) fill = rhs.fill->duplicate(); else fill = nullptr; - tvg::free(dashPattern); - if (rhs.dashCnt > 0) { - dashPattern = tvg::malloc(sizeof(float) * rhs.dashCnt); - memcpy(dashPattern, rhs.dashPattern, sizeof(float) * rhs.dashCnt); + tvg::free(dash.pattern); + if (rhs.dash.count > 0) { + dash.pattern = tvg::malloc(sizeof(float) * rhs.dash.count); + memcpy(dash.pattern, rhs.dash.pattern, sizeof(float) * rhs.dash.count); } else { - dashPattern = nullptr; + dash.pattern = nullptr; } - dashCnt = rhs.dashCnt; - dashOffset = rhs.dashOffset; + dash.count = rhs.dash.count; + dash.offset = rhs.dash.offset; + dash.length = rhs.dash.length; miterlimit = rhs.miterlimit; cap = rhs.cap; join = rhs.join; @@ -163,7 +167,7 @@ struct RenderStroke ~RenderStroke() { - tvg::free(dashPattern); + tvg::free(dash.pattern); delete(fill); } }; @@ -223,9 +227,9 @@ struct RenderShape uint32_t strokeDash(const float** dashPattern, float* offset) const { if (!stroke) return 0; - if (dashPattern) *dashPattern = stroke->dashPattern; - if (offset) *offset = stroke->dashOffset; - return stroke->dashCnt; + if (dashPattern) *dashPattern = stroke->dash.pattern; + if (offset) *offset = stroke->dash.offset; + return stroke->dash.count; } StrokeCap strokeCap() const diff --git a/src/renderer/tvgShape.h b/src/renderer/tvgShape.h index 6eb2d621..c1061e67 100644 --- a/src/renderer/tvgShape.h +++ b/src/renderer/tvgShape.h @@ -282,34 +282,28 @@ struct Shape::Impl : Paint::Impl Result strokeDash(const float* pattern, uint32_t cnt, float offset) { - if ((cnt == 1) || (!pattern && cnt > 0) || (pattern && cnt == 0)) { - return Result::InvalidArguments; - } - - for (uint32_t i = 0; i < cnt; i++) { - if (pattern[i] < FLOAT_EPSILON) return Result::InvalidArguments; - } - + if ((cnt == 1) || (!pattern && cnt > 0) || (pattern && cnt == 0)) return Result::InvalidArguments; + if (!rs.stroke) rs.stroke = new RenderStroke; //Reset dash - if (!pattern && cnt == 0) { - tvg::free(rs.stroke->dashPattern); - rs.stroke->dashPattern = nullptr; - } else { - if (!rs.stroke) rs.stroke = new RenderStroke(); - if (rs.stroke->dashCnt != cnt) { - tvg::free(rs.stroke->dashPattern); - rs.stroke->dashPattern = nullptr; - } - if (!rs.stroke->dashPattern) { - rs.stroke->dashPattern = tvg::malloc(sizeof(float) * cnt); - if (!rs.stroke->dashPattern) return Result::FailedAllocation; - } + auto& dash = rs.stroke->dash; + if (dash.count != cnt) { + tvg::free(dash.pattern); + dash.pattern = nullptr; + } + if (cnt > 0) { + if (!dash.pattern) dash.pattern = tvg::malloc(sizeof(float) * cnt); + dash.length = 0.0f; for (uint32_t i = 0; i < cnt; ++i) { - rs.stroke->dashPattern[i] = pattern[i]; + if (pattern[i] < FLT_EPSILON) { + dash.count = 0; + return Result::InvalidArguments; + } + dash.pattern[i] = pattern[i]; + dash.length += dash.pattern[i]; } } - rs.stroke->dashCnt = cnt; - rs.stroke->dashOffset = offset; + rs.stroke->dash.count = cnt; + rs.stroke->dash.offset = offset; renderFlag |= RenderUpdateFlag::Stroke; return Result::Success; diff --git a/src/renderer/wg_engine/tvgWgGeometry.h b/src/renderer/wg_engine/tvgWgGeometry.h index d9df703b..906bf2dd 100755 --- a/src/renderer/wg_engine/tvgWgGeometry.h +++ b/src/renderer/wg_engine/tvgWgGeometry.h @@ -352,48 +352,43 @@ struct WgIndexedVertexBuffer vcount += 4; icount += 6; } - - // dash buffer by pattern + + void appendStrokesDashed(const WgVertexBuffer& buff, const RenderStroke* rstroke) { - // dashed buffer dashed->reset(scale); - // ignore single points polyline - if (buff.count < 2) return; - const float* dashPattern = rstroke->dashPattern; - size_t dashCnt = rstroke->dashCnt; - // starting state - uint32_t index_dash = 0; - float len_total = dashPattern[index_dash]; - // get dashes length - float dashes_lenth{}; - for (uint32_t i = 0; i < dashCnt * (dashCnt % 2 + 1); i++) { - dashes_lenth += dashPattern[i % dashCnt]; - } - if (dashes_lenth == 0) return; + auto& dash = rstroke->dash; + + if (buff.count < 2 || tvg::zero(dash.length)) return; + + uint32_t index = 0; + auto total = dash.pattern[index]; + auto length = (dash.count % 2) ? dash.length * 2 : dash.length; + // normalize dash offset - float dashOffset = rstroke->dashOffset; - while(dashOffset < 0) dashOffset += dashes_lenth; - while(dashOffset > dashes_lenth) dashOffset -= dashes_lenth; + auto dashOffset = dash.offset; + while(dashOffset < 0) dashOffset += length; + while(dashOffset > length) dashOffset -= length; auto gap = false; + // scip dashes by offset - while(len_total <= dashOffset) { - index_dash = (index_dash + 1) % dashCnt; - len_total += dashPattern[index_dash]; + while(total <= dashOffset) { + index = (index + 1) % dash.count; + total += dash.pattern[index]; gap = !gap; } - len_total -= dashOffset; + total -= dashOffset; + // iterate by polyline points for (uint32_t i = 0; i < buff.count - 1; i++) { - // append current polyline point if (!gap) dashed->append(buff.data[i]); // move inside polyline segment - while(len_total < buff.dist[i+1].interval) { + while(total < buff.dist[i+1].interval) { // get current point - dashed->append(tvg::lerp(buff.data[i], buff.data[i+1], len_total / buff.dist[i+1].interval)); + dashed->append(tvg::lerp(buff.data[i], buff.data[i+1], total / buff.dist[i+1].interval)); // update current state - index_dash = (index_dash + 1) % dashCnt; - len_total += dashPattern[index_dash]; + index = (index + 1) % dash.count; + total += dash.pattern[index]; // preceed stroke if dash if (!gap) { dashed->updateDistances(); @@ -403,7 +398,7 @@ struct WgIndexedVertexBuffer gap = !gap; } // update current subline length - len_total -= buff.dist[i+1].interval; + total -= buff.dist[i+1].interval; } // draw last subline if (!gap) { diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index a293be3e..c3c0c161 100755 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -394,8 +394,8 @@ void WgRenderDataShape::proceedStrokes(WgContext& context, const RenderStroke* r { assert(rstroke); auto strokesGenerator = pool->reqIndexedVertexBuffer(buff.scale); - if (rstroke->dashPattern) strokesGenerator->appendStrokesDashed(buff, rstroke); - else strokesGenerator->appendStrokes(buff, rstroke); + if (rstroke->dash.count == 0) strokesGenerator->appendStrokes(buff, rstroke); + else strokesGenerator->appendStrokesDashed(buff, rstroke); appendStroke(context, *strokesGenerator);