Fixing stroke contouring.
diff --git a/include/rive/contour_stroke.hpp b/include/rive/contour_stroke.hpp index 5bea445..59c77a7 100644 --- a/include/rive/contour_stroke.hpp +++ b/include/rive/contour_stroke.hpp
@@ -3,6 +3,7 @@ #include "rive/renderer.hpp" #include "rive/math/aabb.hpp" +#include "rive/math/mat2d.hpp" #include <vector> #include <cstdint> @@ -34,7 +35,8 @@ bool isClosed, StrokeJoin join, StrokeCap cap, - float strokeWidth); + float strokeWidth, + const Mat2D& transform); }; } // namespace rive #endif \ No newline at end of file
diff --git a/include/rive/shapes/paint/stroke.hpp b/include/rive/shapes/paint/stroke.hpp index 80c4fb5..38cb498 100644 --- a/include/rive/shapes/paint/stroke.hpp +++ b/include/rive/shapes/paint/stroke.hpp
@@ -17,6 +17,7 @@ void addStrokeEffect(StrokeEffect* effect); bool hasStrokeEffect() { return m_Effect != nullptr; } void invalidate(); + void invalidateRendering(); bool isVisible() const override; protected:
diff --git a/renderer/library/src/opengl/opengl_render_paint.cpp b/renderer/library/src/opengl/opengl_render_paint.cpp index 902d39c..de9e2de 100644 --- a/renderer/library/src/opengl/opengl_render_paint.cpp +++ b/renderer/library/src/opengl/opengl_render_paint.cpp
@@ -94,7 +94,6 @@ bool OpenGLRenderPaint::doesDraw() const { - return true; return m_Color[3] > 0.0f && (m_Gradient == nullptr || m_Gradient->m_IsVisible); } @@ -117,9 +116,13 @@ { if (m_StrokeDirty) { + static Mat2D identity; m_Stroke->reset(); - path->extrudeStroke( - m_Stroke, m_StrokeJoin, m_StrokeCap, m_StrokeThickness / 2.0f); + path->extrudeStroke(m_Stroke, + m_StrokeJoin, + m_StrokeCap, + m_StrokeThickness / 2.0f, + identity); m_StrokeDirty = false; }
diff --git a/renderer/library/src/opengl/opengl_render_path.cpp b/renderer/library/src/opengl/opengl_render_path.cpp index fa931ae..daf64cf 100644 --- a/renderer/library/src/opengl/opengl_render_path.cpp +++ b/renderer/library/src/opengl/opengl_render_path.cpp
@@ -17,6 +17,7 @@ for (auto& subPath : m_SubPaths) { Mat2D pathTransform; + // Mat2D::multiply(pathTransform, transform, subPath.transform()); Mat2D::multiply(pathTransform, transform, subPath.transform()); reinterpret_cast<OpenGLRenderPath*>(subPath.path()) ->stencil(renderer, pathTransform); @@ -194,12 +195,8 @@ { for (auto& subPath : m_SubPaths) { - const Mat2D& subPathTransform = subPath.transform(); - Mat2D pathTransform; - Mat2D::multiply(pathTransform, transform, subPathTransform); reinterpret_cast<OpenGLRenderPath*>(subPath.path()) - ->renderStroke( - stroke, renderer, pathTransform, subPathTransform); + ->renderStroke(stroke, renderer, transform, localTransform); } return; }
diff --git a/renderer/library/src/opengl/opengl_renderer.cpp b/renderer/library/src/opengl/opengl_renderer.cpp index 83a89ca..e7bfbda 100644 --- a/renderer/library/src/opengl/opengl_renderer.cpp +++ b/renderer/library/src/opengl/opengl_renderer.cpp
@@ -266,7 +266,8 @@ glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); - glPath->stencil(this, transform()); + auto xform = transform(); + glPath->stencil(this, xform); glColorMask(true, true, true, true); glStencilFunc(GL_NOTEQUAL, 0, m_IsClipping ? 0x7F : 0xFF);
diff --git a/renderer/viewer/assets/bone_deform.riv b/renderer/viewer/assets/bone_deform.riv new file mode 100644 index 0000000..9f6e275 --- /dev/null +++ b/renderer/viewer/assets/bone_deform.riv Binary files differ
diff --git a/renderer/viewer/assets/rotate_square.riv b/renderer/viewer/assets/rotate_square.riv new file mode 100644 index 0000000..eba670a --- /dev/null +++ b/renderer/viewer/assets/rotate_square.riv Binary files differ
diff --git a/renderer/viewer/assets/runner.riv b/renderer/viewer/assets/runner.riv new file mode 100644 index 0000000..b6a0feb --- /dev/null +++ b/renderer/viewer/assets/runner.riv Binary files differ
diff --git a/renderer/viewer/assets/runner_boy.riv b/renderer/viewer/assets/runner_boy.riv new file mode 100644 index 0000000..f4b3780 --- /dev/null +++ b/renderer/viewer/assets/runner_boy.riv Binary files differ
diff --git a/renderer/viewer/src/viewer.cpp b/renderer/viewer/src/viewer.cpp index 517d5a2..bcfcba6 100644 --- a/renderer/viewer/src/viewer.cpp +++ b/renderer/viewer/src/viewer.cpp
@@ -110,7 +110,10 @@ // std::string filename = "assets/juice.riv"; // std::string filename = "assets/clip.riv"; // std::string filename = "assets/clipped_circle_star_2.riv"; - std::string filename = "assets/marty.riv"; + // std::string filename = "assets/marty.riv"; + std::string filename = "assets/runner.riv"; + // std::string filename = "assets/rotate_square.riv"; + // std::string filename = "assets/bone_deform.riv"; // std::string filename = "assets/off_road_car.riv"; // std::string filename = "assets/simple_stroke.riv"; // std::string filename = "assets/leg_issues.riv"; @@ -143,7 +146,7 @@ rive::LinearAnimationInstance* animationInstance = nullptr; int animationIndex = 0; - auto animation = + rive::LinearAnimation* animation = // nullptr; animationIndex >= 0 && animationIndex < artboard->animationCount() ? artboard->animation(animationIndex) : nullptr; @@ -179,7 +182,7 @@ { if (animationInstance != nullptr) { - animationInstance->advance(elapsed); + animationInstance->advance(elapsed * 0.25f); animationInstance->apply(artboard); } artboard->advance(elapsed);
diff --git a/src/contour_render_path.cpp b/src/contour_render_path.cpp index d70b986..568c826 100644 --- a/src/contour_render_path.cpp +++ b/src/contour_render_path.cpp
@@ -69,14 +69,16 @@ void ContourRenderPath::extrudeStroke(ContourStroke* stroke, StrokeJoin join, StrokeCap cap, - float strokeWidth) + float strokeWidth, + const Mat2D& transform) { if (isContainer()) { for (auto& subPath : m_SubPaths) { static_cast<ContourRenderPath*>(subPath.path()) - ->extrudeStroke(stroke, join, cap, strokeWidth); + ->extrudeStroke( + stroke, join, cap, strokeWidth, subPath.transform()); } return; } @@ -86,6 +88,6 @@ computeContour(); } - stroke->extrude(this, m_IsClosed, join, cap, strokeWidth); + stroke->extrude(this, m_IsClosed, join, cap, strokeWidth, transform); } #endif \ No newline at end of file
diff --git a/src/contour_stroke.cpp b/src/contour_stroke.cpp index 54bc4d4..161699c 100644 --- a/src/contour_stroke.cpp +++ b/src/contour_stroke.cpp
@@ -26,14 +26,24 @@ bool isClosed, StrokeJoin join, StrokeCap cap, - float strokeWidth) + float strokeWidth, + const Mat2D& transform) { - const std::vector<Vec2D>& points = renderPath->contourVertices(); + // TODO: if transform is identity, no need to copy and transform + // contourPoints->points. + + const std::vector<Vec2D>& contourPoints = renderPath->contourVertices(); + std::vector<Vec2D> points(contourPoints); auto pointCount = points.size(); if (pointCount < 6) { return; } + for (int i = 4; i < pointCount; i++) + { + Vec2D& point = points[i]; + Vec2D::transform(point, point, transform); + } auto startOffset = m_TriangleStrip.size(); Vec2D lastPoint = points[4]; Vec2D lastDiff;
diff --git a/src/shapes/paint/stroke.cpp b/src/shapes/paint/stroke.cpp index 9a853a9..5cd1645 100644 --- a/src/shapes/paint/stroke.cpp +++ b/src/shapes/paint/stroke.cpp
@@ -67,6 +67,11 @@ { m_Effect->invalidateEffect(); } + invalidateRendering(); +} + +void Stroke::invalidateRendering() +{ assert(m_RenderPaint != nullptr); m_RenderPaint->invalidateStroke(); } \ No newline at end of file
diff --git a/src/shapes/paint/trim_path.cpp b/src/shapes/paint/trim_path.cpp index b62cd65..cc15a83 100644 --- a/src/shapes/paint/trim_path.cpp +++ b/src/shapes/paint/trim_path.cpp
@@ -112,7 +112,10 @@ void TrimPath::invalidateEffect() { m_RenderPath = nullptr; - parent()->as<Stroke>()->parent()->addDirt(ComponentDirt::Paint); + Stroke* stroke = parent()->as<Stroke>(); + stroke->parent()->addDirt(ComponentDirt::Paint); + // Drive this up so the rendering layer can invalidate too. + stroke->invalidateRendering(); } void TrimPath::startChanged() { invalidateEffect(); }
diff --git a/src/shapes/path.cpp b/src/shapes/path.cpp index e201c98..5a805ce 100644 --- a/src/shapes/path.cpp +++ b/src/shapes/path.cpp
@@ -278,6 +278,8 @@ if (m_Shape != nullptr) { m_Shape->pathChanged(); + // We invalidate stroke if the path points change. + m_Shape->invalidateStroke(); } } @@ -287,6 +289,11 @@ { m_Shape->pathChanged(); } + if (hasDirt(value, ComponentDirt::Transform) && m_Shape != nullptr) + { + // We invalidate stroke if a local path transform changes. + m_Shape->invalidateStroke(); + } } void Path::update(ComponentDirt value) @@ -298,13 +305,6 @@ { buildPath(*m_CommandPath, isPathClosed(), m_Vertices); } - // if (hasDirt(value, ComponentDirt::WorldTransform) && m_Shape != nullptr) - // { - // // Make sure the path composer has an opportunity to rebuild the path - // // (this is why the composer depends on the shape and all its paths, - // // ascertaning it updates after both) - // m_Shape->pathChanged(); - // } } #ifdef ENABLE_QUERY_FLAT_VERTICES
diff --git a/src/shapes/shape.cpp b/src/shapes/shape.cpp index 66ab67e..ff959e4 100644 --- a/src/shapes/shape.cpp +++ b/src/shapes/shape.cpp
@@ -29,11 +29,7 @@ } } -void Shape::pathChanged() -{ - m_PathComposer.addDirt(ComponentDirt::Path, true); - invalidateStroke(); -} +void Shape::pathChanged() { m_PathComposer.addDirt(ComponentDirt::Path, true); } void Shape::draw(Renderer* renderer) {