blob: daa694a8fa9981dca7af96b5eb38924834777e2d [file] [log] [blame]
#ifndef _RIVE_METRICS_PATH_HPP_
#define _RIVE_METRICS_PATH_HPP_
#include "rive/command_path.hpp"
#include "rive/math/vec2d.hpp"
#include <cassert>
#include <vector>
namespace rive {
struct CubicSegment {
float t;
float length;
CubicSegment(float tValue, float lengthValue) : t(tValue), length(lengthValue) {}
};
struct PathPart {
static const unsigned char line = 0;
/// Type is 0 when this is a line segment, it's 1 or greater when it's a
/// cubic. When it's a cubic it also represents the index in
/// CubicSegments-1.
unsigned char type;
/// Offset is the offset in original path points (which get transformed
/// when they're added to another path).
unsigned char offset;
// Only used by the cubic to count the number of cubic segments used by
// this part.
unsigned char numSegments;
PathPart(unsigned char t, unsigned char l) : type(t), offset(l), numSegments(0) {}
};
class MetricsPath : public CommandPath {
private:
std::vector<Vec2D> m_Points;
std::vector<Vec2D> m_TransformedPoints;
std::vector<CubicSegment> m_CubicSegments;
std::vector<PathPart> m_Parts;
std::vector<float> m_Lengths;
std::vector<MetricsPath*> m_Paths;
float m_ComputedLength = 0.0f;
Mat2D m_ComputedLengthTransform;
public:
const std::vector<MetricsPath*>& paths() const { return m_Paths; }
void addPath(CommandPath* path, const Mat2D& transform) override;
void reset() override;
void moveTo(float x, float y) override;
void lineTo(float x, float y) override;
void cubicTo(float ox, float oy, float ix, float iy, float x, float y) override;
void close() override;
float length() const { return m_ComputedLength; }
/// Add commands to the result RenderPath that will draw the segment
/// from startLength to endLength of this MetricsPath. Requires
/// computeLength be called prior to trimming.
void trim(float startLength, float endLength, bool moveTo, RenderPath* result);
private:
float computeLength(const Mat2D& transform);
/// Extract a single segment from startT to endT as render commands
/// added to result.
void extractSubPart(int index, float startT, float endT, bool moveTo, RenderPath* result);
};
class OnlyMetricsPath : public MetricsPath {
public:
void fillRule(FillRule value) override {}
RenderPath* renderPath() override {
// Should never be used for actual rendering.
assert(false);
return nullptr;
}
};
class RenderMetricsPath : public MetricsPath {
private:
std::unique_ptr<RenderPath> m_RenderPath;
public:
RenderMetricsPath(std::unique_ptr<RenderPath>);
RenderPath* renderPath() override { return m_RenderPath.get(); }
void addPath(CommandPath* path, const Mat2D& transform) override;
void fillRule(FillRule value) override;
void reset() override;
void moveTo(float x, float y) override;
void lineTo(float x, float y) override;
void cubicTo(float ox, float oy, float ix, float iy, float x, float y) override;
void close() override;
};
} // namespace rive
#endif