From 1ef9c6be9be901bba5759ace6c5843c487c11e43 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Thu, 25 Jul 2024 19:48:33 +0200 Subject: [PATCH] common: move&fix trimming wrapping logic The logic of interpretation of trimming start and end values has been moved to the sw_engine, so the values provided by the user are not modified. No logical changes in the interpretation alg. For pairs of trim's start/end values where the distance between begin and end is >= 1, the entire stroke should be drawn, but instead, nothing or only part is drawn. Fixed. Stroke trim docs fixed. --- inc/thorvg.h | 2 +- src/bindings/capi/thorvg_capi.h | 2 +- src/renderer/sw_engine/tvgSwShape.cpp | 12 ++++++----- src/renderer/tvgRender.h | 29 ++++++++++++++++++++++++++- src/renderer/tvgShape.h | 17 ---------------- 5 files changed, 37 insertions(+), 25 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index f8f15bba..ee098590 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -990,7 +990,7 @@ public: /** * @brief Sets the trim of the stroke along the defined path segment, allowing control over which part of the stroke is visible. * - * The values of the arguments @p begin, @p end, and @p offset are in the range of 0.0 to 1.0, representing the beginning of the path and the end, respectively. + * If the values of the arguments @p begin and @p end exceed the 0-1 range, they are wrapped around in a manner similar to angle wrapping, effectively treating the range as circular. * * @param[in] begin Specifies the start of the segment to display along the path. * @param[in] end Specifies the end of the segment to display along the path. diff --git a/src/bindings/capi/thorvg_capi.h b/src/bindings/capi/thorvg_capi.h index 98acfc86..db46ad41 100644 --- a/src/bindings/capi/thorvg_capi.h +++ b/src/bindings/capi/thorvg_capi.h @@ -1485,7 +1485,7 @@ TVG_API Tvg_Result tvg_shape_get_stroke_miterlimit(const Tvg_Paint* paint, float /*! * \brief Sets the trim of the stroke along the defined path segment, allowing control over which part of the stroke is visible. * -* The values of the arguments @p begin, @p end, and @p offset are in the range of 0.0 to 1.0, representing the beginning of the path and the end, respectively. +* If the values of the arguments @p begin and @p end exceed the 0-1 range, they are wrapped around in a manner similar to angle wrapping, effectively treating the range as circular. * * \param[in] paint A Tvg_Paint pointer to the shape object. * \param[in] begin Specifies the start of the segment to display along the path. diff --git a/src/renderer/sw_engine/tvgSwShape.cpp b/src/renderer/sw_engine/tvgSwShape.cpp index dc8611f0..96c3bc28 100644 --- a/src/renderer/sw_engine/tvgSwShape.cpp +++ b/src/renderer/sw_engine/tvgSwShape.cpp @@ -245,10 +245,10 @@ static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const } -static void _trimPattern(SwDashStroke* dash, const RenderShape* rshape, float length) +static void _trimPattern(SwDashStroke* dash, const RenderShape* rshape, float length, float trimBegin, float trimEnd) { - auto begin = length * rshape->stroke->trim.begin; - auto end = length * rshape->stroke->trim.end; + auto begin = length * trimBegin; + auto end = length * trimEnd; //default if (end > begin) { @@ -341,6 +341,8 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans auto offset = 0.0f; dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset); auto simultaneous = rshape->stroke->trim.simultaneous; + float trimBegin = 0.0f, trimEnd = 1.0f; + if (trimmed) rshape->stroke->strokeTrim(trimBegin, trimEnd); if (dash.cnt == 0) { if (trimmed) dash.pattern = (float*)malloc(sizeof(float) * 4); @@ -372,7 +374,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans //must begin with moveTo if (cmds[0] == PathCommand::MoveTo) { - if (trimmed) _trimPattern(&dash, rshape, _outlineLength(rshape, 0, 0, simultaneous)); + if (trimmed) _trimPattern(&dash, rshape, _outlineLength(rshape, 0, 0, simultaneous), trimBegin, trimEnd); _dashMoveTo(dash, offIdx, offset, pts); cmds++; pts++; @@ -387,7 +389,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans case PathCommand::MoveTo: { if (trimmed) { if (simultaneous) { - _trimPattern(&dash, rshape, _outlineLength(rshape, pts - startPts, cmds - startCmds, true)); + _trimPattern(&dash, rshape, _outlineLength(rshape, pts - startPts, cmds - startCmds, true), trimBegin, trimEnd); _dashMoveTo(dash, offIdx, offset, pts); } else _dashMoveTo(dash, pts); } else _dashMoveTo(dash, offIdx, offset, pts); diff --git a/src/renderer/tvgRender.h b/src/renderer/tvgRender.h index 00cb1211..532bb088 100644 --- a/src/renderer/tvgRender.h +++ b/src/renderer/tvgRender.h @@ -23,6 +23,7 @@ #ifndef _TVG_RENDER_H_ #define _TVG_RENDER_H_ +#include #include "tvgCommon.h" #include "tvgArray.h" #include "tvgLock.h" @@ -155,6 +156,32 @@ struct RenderStroke trim = rhs.trim; } + bool strokeTrim(float& begin, float& end) const + { + begin = trim.begin; + end = trim.end; + + if (fabsf(end - begin) > 1.0f) { + begin = 0.0f; + end = 1.0f; + return false; + } + + auto loop = true; + + if (begin > 1.0f && end > 1.0f) loop = false; + if (begin < 0.0f && end < 0.0f) loop = false; + if (begin >= 0.0f && begin <= 1.0f && end >= 0.0f && end <= 1.0f) loop = false; + + if (begin > 1.0f) begin -= 1.0f; + if (begin < 0.0f) begin += 1.0f; + if (end > 1.0f) end -= 1.0f; + if (end < 0.0f) end += 1.0f; + + if ((loop && begin < end) || (!loop && begin > end)) std::swap(begin, end); + return true; + } + ~RenderStroke() { free(dashPattern); @@ -199,7 +226,7 @@ struct RenderShape { if (!stroke) return false; if (stroke->trim.begin == 0.0f && stroke->trim.end == 1.0f) return false; - if (stroke->trim.begin == 1.0f && stroke->trim.end == 0.0f) return false; + if (fabsf(stroke->trim.end - stroke->trim.begin) > 1.0f) return false; return true; } diff --git a/src/renderer/tvgShape.h b/src/renderer/tvgShape.h index ddfefad7..4f9ddf40 100644 --- a/src/renderer/tvgShape.h +++ b/src/renderer/tvgShape.h @@ -217,23 +217,6 @@ struct Shape::Impl if (mathEqual(rs.stroke->trim.begin, begin) && mathEqual(rs.stroke->trim.end, end) && rs.stroke->trim.simultaneous == simultaneous) return; - auto loop = true; - - if (begin > 1.0f && end > 1.0f) loop = false; - if (begin < 0.0f && end < 0.0f) loop = false; - if (begin >= 0.0f && begin <= 1.0f && end >= 0.0f && end <= 1.0f) loop = false; - - if (begin > 1.0f) begin -= 1.0f; - if (begin < 0.0f) begin += 1.0f; - if (end > 1.0f) end -= 1.0f; - if (end < 0.0f) end += 1.0f; - - if ((loop && begin < end) || (!loop && begin > end)) { - auto tmp = begin; - begin = end; - end = tmp; - } - rs.stroke->trim.begin = begin; rs.stroke->trim.end = end; rs.stroke->trim.simultaneous = simultaneous;