blob: 640a06888e8263ed6bb3da561af14ca4821bac1c [file]
#ifndef _RIVE_PATH_HPP_
#define _RIVE_PATH_HPP_
#include "rive/command_path.hpp"
#include "rive/generated/shapes/path_base.hpp"
#include "rive/math/mat2d.hpp"
#include "rive/math/raw_path.hpp"
#include "rive/shapes/shape_paint_container.hpp"
#include <vector>
namespace rive
{
class Shape;
class PathVertex;
class RenderPathDeformer;
#ifdef ENABLE_QUERY_FLAT_VERTICES
/// Optionally compiled in for tools that need to compute per frame world
/// transformed path vertices. These should not be used at runtime as it's
/// not optimized for performance (it does a lot of memory allocation).
/// A flattened path is composed of only linear
/// and cubic vertices. No corner vertices and it's entirely in world space.
/// This is helpful for getting a close to identical representation of the
/// vertices used to issue the high level path draw commands.
class FlattenedPath
{
private:
std::vector<PathVertex*> m_Vertices;
public:
~FlattenedPath();
const std::vector<PathVertex*>& vertices() const { return m_Vertices; }
void addVertex(PathVertex* vertex, const Mat2D& transform);
};
#endif
class Path : public PathBase
{
protected:
Shape* m_Shape = nullptr;
std::vector<PathVertex*> m_Vertices;
bool m_deferredPathDirt = false;
PathFlags m_pathFlags = PathFlags::none;
RawPath m_rawPath;
RenderPathDeformer* deformer() const;
void isHoleChanged() override;
public:
static float computeIdealControlPointDistance(const Vec2D& toPrev,
const Vec2D& toNext,
float radius);
static void addRoundedRect(RawPath& rawPath,
const AABB& bounds,
float topLeft,
float topRight,
float bottomRight,
float bottomLeft);
Shape* shape() const { return m_Shape; }
StatusCode onAddedClean(CoreContext* context) override;
void buildDependencies() override;
virtual const Mat2D& pathTransform() const;
bool collapse(bool value) override;
const RawPath& rawPath() const { return m_rawPath; }
// True while m_rawPath has yet to be rebuilt for pending changes: the Path
// dirt is still queued, or the build was deferred. Layout runs before
// Path::update in the update pass, so a measure can land here first and
// must build its own copy rather than read a stale/empty rawPath.
bool needsPathBuild() const
{
return hasDirt(ComponentDirt::Path) || m_deferredPathDirt;
}
// Bounds in this path's own space derived from its properties rather than
// its built geometry, for callers that run before update() has positioned
// vertices. A ParametricPath knows its box up front; anything vertex-driven
// returns false and must be measured from geometry.
virtual bool tryPropertyBounds(AABB& result) const { return false; }
void update(ComponentDirt value) override;
void addFlags(PathFlags flags);
bool isFlagged(PathFlags flags) const;
bool canDeferPathUpdate();
void addVertex(PathVertex* vertex);
void popVertex();
virtual void markPathDirty(bool sendToLayout = true);
virtual bool isPathClosed() const { return true; }
void onDirty(ComponentDirt dirt) override;
inline bool isHidden() const { return (pathFlags() & 0x1) == 0x1; }
#ifdef ENABLE_QUERY_FLAT_VERTICES
FlattenedPath* makeFlat(bool transformToParent);
#endif
#ifdef TESTING
std::vector<PathVertex*>& vertices() { return m_Vertices; }
#endif
void buildPath(RawPath&) const;
AABB localBounds() const override;
};
} // namespace rive
#endif