blob: 2f4dac2cd4e29d31c55f53be784c61af2a643fbc [file] [log] [blame]
/*
* 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(RawPath& path)
{
return ViewerContent::RiveFactory()->makeRenderPath(path, FillRule::nonZero);
}
static void stroke_path(Renderer* renderer, 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(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]);
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 rivestd::make_unique<TrimPathContent>();
}