| /* |
| * Copyright 2022 Rive |
| */ |
| |
| #include "viewer/viewer_content.hpp" |
| #include "rive/factory.hpp" |
| #include "rive/renderer.hpp" |
| #include "rive/math/contour_measure.hpp" |
| |
| using namespace rive; |
| |
| static Vec2D ave(Vec2D a, Vec2D b) { return (a + b) * 0.5f; } |
| |
| static RawPath make_quad_path(Span<const Vec2D> pts) { |
| const int N = pts.size(); |
| RawPath path; |
| if (N >= 2) { |
| path.move(pts[0]); |
| if (N == 2) { |
| path.line(pts[1]); |
| } else if (N == 3) { |
| path.quad(pts[1], pts[2]); |
| } else { |
| for (int i = 1; i < N - 2; ++i) { |
| path.quad(pts[i], ave(pts[i], pts[i + 1])); |
| } |
| path.quad(pts[N - 2], pts[N - 1]); |
| } |
| } |
| return path; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////// |
| |
| static std::unique_ptr<RenderPath> make_rpath(const RawPath& path) { |
| return ViewerContent::RiveFactory()->makeRenderPath( |
| path.points(), path.verbs(), FillRule::nonZero); |
| } |
| |
| static void stroke_path(Renderer* renderer, const RawPath& path, float size, ColorInt color) { |
| auto paint = ViewerContent::RiveFactory()->makeRenderPaint(); |
| paint->color(color); |
| paint->thickness(size); |
| paint->style(RenderPaintStyle::stroke); |
| renderer->drawPath(make_rpath(path).get(), paint.get()); |
| } |
| |
| static void fill_rect(Renderer* renderer, const AABB& r, RenderPaint* paint) { |
| RawPath rp; |
| rp.addRect(r); |
| renderer->drawPath(make_rpath(rp).get(), paint); |
| } |
| |
| static void fill_point(Renderer* renderer, Vec2D p, float r, RenderPaint* paint) { |
| fill_rect(renderer, {p.x - r, p.y - r, p.x + r, p.y + r}, paint); |
| } |
| |
| static RawPath trim(ContourMeasure* cm, float startT, float endT) { |
| // start and end are 0...1 |
| auto startD = startT * cm->length(); |
| auto endD = endT * cm->length(); |
| if (startD > endD) { |
| std::swap(startD, endD); |
| } |
| |
| RawPath path; |
| cm->getSegment(startD, endD, &path, true); |
| return path; |
| } |
| |
| class TrimPathContent : public ViewerContent { |
| std::vector<Vec2D> m_pathpts; |
| int m_trackingIndex = -1; |
| |
| float m_trimFrom = 0, m_trimTo = 1; |
| |
| public: |
| TrimPathContent() { |
| m_pathpts.push_back({20, 300}); |
| m_pathpts.push_back({220, 100}); |
| m_pathpts.push_back({420, 500}); |
| m_pathpts.push_back({620, 100}); |
| m_pathpts.push_back({820, 300}); |
| } |
| |
| void handleDraw(rive::Renderer* renderer, double) override { |
| auto path = make_quad_path(toSpan(m_pathpts)); |
| |
| RawPath cubicpath; |
| cubicpath.move(m_pathpts[0]); |
| cubicpath.cubic(m_pathpts[1], m_pathpts[2], m_pathpts[3]); |
| cubicpath.line(m_pathpts[4]); |
| |
| const RawPath* ps[] = {&path, &cubicpath}; |
| |
| renderer->save(); |
| for (auto p : ps) { |
| renderer->save(); |
| |
| auto cm = ContourMeasureIter(*p, false).next(); |
| auto p1 = trim(cm.get(), m_trimFrom, m_trimTo); |
| stroke_path(renderer, p1, 20, 0xFFFF0000); |
| |
| stroke_path(renderer, *p, 4, 0xFFFFFFFF); |
| |
| renderer->restore(); |
| renderer->translate(0, 500); |
| } |
| renderer->restore(); |
| |
| auto paint = ViewerContent::RiveFactory()->makeRenderPaint(); |
| paint->color(0xFF008800); |
| const float r = 6; |
| for (auto p : m_pathpts) { |
| fill_point(renderer, p, r, paint.get()); |
| } |
| } |
| |
| void handlePointerMove(float x, float y) override { |
| if (m_trackingIndex >= 0) { |
| m_pathpts[m_trackingIndex] = Vec2D{x, y}; |
| } |
| } |
| void handlePointerDown(float x, float y) override { |
| auto pt = Vec2D{x, y}; |
| auto close_to = [](Vec2D a, Vec2D b) { return Vec2D::distance(a, b) <= 10; }; |
| for (size_t i = 0; i < m_pathpts.size(); ++i) { |
| if (close_to(pt, m_pathpts[i])) { |
| m_trackingIndex = i; |
| break; |
| } |
| } |
| } |
| |
| void handlePointerUp(float x, float y) override { m_trackingIndex = -1; } |
| |
| void handleResize(int width, int height) override {} |
| |
| void handleImgui() override { |
| ImGui::Begin("trim", nullptr); |
| ImGui::SliderFloat("From", &m_trimFrom, 0, 1); |
| ImGui::SliderFloat("To", &m_trimTo, 0, 1); |
| ImGui::End(); |
| } |
| }; |
| |
| std::unique_ptr<ViewerContent> ViewerContent::TrimPath(const char[]) { |
| return std::make_unique<TrimPathContent>(); |
| } |