diff --git a/.rive_head b/.rive_head index 5f2e06759..56f720e4d 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -2bd842b54b10e487731fcb51c728098d4956996a +5c312867e32d4a347e5483dca9798b1dd3dd30d1 diff --git a/include/rive/shapes/paint/dash_path.hpp b/include/rive/shapes/paint/dash_path.hpp new file mode 100644 index 000000000..a5d10545b --- /dev/null +++ b/include/rive/shapes/paint/dash_path.hpp @@ -0,0 +1,39 @@ +#ifndef _RIVE_DASH_PATH_HPP_ +#define _RIVE_DASH_PATH_HPP_ + +#include "rive/shapes/paint/stroke_effect.hpp" +#include "rive/renderer.hpp" +#include "rive/math/raw_path.hpp" +#include "rive/math/contour_measure.hpp" + +namespace rive +{ +class Dash +{ +public: + Dash(); + Dash(float value, bool percentage); + + float value() const; + bool percentage() const; + +private: + float m_value; + bool m_percentage; +}; + +class PathDasher +{ +protected: + void invalidateSourcePath(); + void invalidateDash(); + RenderPath* dash(const RawPath& source, Factory* factory, Dash offset, Span dashes); + +private: + RawPath m_rawPath; + RenderPath* m_renderPath = nullptr; + rcp m_dashedPath; + std::vector> m_contours; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/src/shapes/paint/dash_path.cpp b/src/shapes/paint/dash_path.cpp new file mode 100644 index 000000000..21b6b03ba --- /dev/null +++ b/src/shapes/paint/dash_path.cpp @@ -0,0 +1,70 @@ +#include "rive/shapes/paint/dash_path.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +Dash::Dash() : m_value(0.0f), m_percentage(false) {} +Dash::Dash(float value, bool percentage) : m_value(value), m_percentage(percentage) {} +float Dash::value() const { return m_value; } +bool Dash::percentage() const { return m_percentage; } + +void PathDasher::invalidateSourcePath() +{ + m_contours.clear(); + invalidateDash(); +} +void PathDasher::invalidateDash() { m_renderPath = nullptr; } + +RenderPath* PathDasher::dash(const RawPath& source, + Factory* factory, + Dash offset, + Span dashes) +{ + if (m_renderPath != nullptr) + { + // Previous result hasn't been invalidated, it's still good. + return m_renderPath; + } + + m_rawPath.rewind(); + if (m_contours.empty()) + { + ContourMeasureIter iter(&source); + while (auto meas = iter.next()) + { + m_contours.push_back(meas); + } + } + + int dashIndex = 0; + for (const rcp& contour : m_contours) + { + float distance = offset.percentage() ? offset.value() * contour->length() : offset.value(); + bool draw = true; + while (distance < contour->length()) + { + const Dash& dash = dashes[dashIndex]; + float dashLength = dash.percentage() ? dash.value() * contour->length() : dash.value(); + if (draw) + { + contour->getSegment(distance, distance + dashLength, &m_rawPath, true); + } + distance += dashLength; + draw = !draw; + } + } + + if (!m_dashedPath) + { + m_dashedPath = factory->makeEmptyRenderPath(); + } + else + { + m_dashedPath->rewind(); + } + + m_renderPath = m_dashedPath.get(); + m_rawPath.addTo(m_renderPath); + + return m_renderPath; +} \ No newline at end of file