blob: 92573bce37ec3c2981634be5a4a0eaf89f572c3b [file] [log] [blame]
/*
* Copyright 2022 Rive
*/
#pragma once
#include "rive/math/raw_path.hpp"
#include "rive/renderer.hpp"
#include "rive/renderer/draw.hpp"
#include "rive_render_paint.hpp"
namespace rive
{
// RenderPath implementation for Rive's pixel local storage renderer.
class RiveRenderPath : public LITE_RTTI_OVERRIDE(RenderPath, RiveRenderPath)
{
public:
RiveRenderPath() = default;
RiveRenderPath(FillRule fillRule, RawPath& rawPath);
void rewind() override;
void fillRule(FillRule rule) override
{
if (m_fillRule == rule)
{
return;
}
m_fillRule = rule;
// Most cached draws can be used interchangeably with any fill rule, but
// if there is a triangulator, it needs to be invalidated when the fill
// rule changes.
if (m_cachedElements[CACHE_FILLED].draw != nullptr &&
m_cachedElements[CACHE_FILLED].draw->triangulator() != nullptr)
{
invalidateDrawCache(CACHE_FILLED);
}
}
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;
void addPath(CommandPath* p, const Mat2D& m) override
{
addRenderPath(p->renderPath(), m);
}
void addRenderPath(RenderPath* path, const Mat2D& matrix) override;
const RawPath& getRawPath() const { return m_rawPath; }
FillRule getFillRule() const { return m_fillRule; }
const AABB& getBounds() const;
// Approximates the area of the path by linearizing it with a coarse
// tolerance of 8px in artboard space.
constexpr static float kCoarseAreaTolerance = 8;
float getCoarseArea() const;
// Determine if the path's signed, post-transform area is positive.
bool isClockwiseDominant(const Mat2D& viewMatrix) const;
uint64_t getRawPathMutationID() const;
// Feathering does not always look like a blur when there is strong
// curvature. This method returns a copy of the path with flatter curves
// that will more accurately depict a gaussian blur when drawn with the
// given feather.
//
// TODO: Move this work to the GPU.
rcp<RiveRenderPath> makeSoftenedCopyForFeathering(float feather,
float matrixMaxScale);
#ifdef DEBUG
// Allows ref holders to guarantee the rawPath doesn't mutate during a
// specific time.
void lockRawPathMutations() const { ++m_rawPathMutationLockCount; }
void unlockRawPathMutations() const
{
assert(m_rawPathMutationLockCount > 0);
--m_rawPathMutationLockCount;
}
#endif
private:
FillRule m_fillRule = FillRule::nonZero;
RawPath m_rawPath;
mutable AABB m_bounds;
mutable float m_coarseArea;
mutable uint64_t m_rawPathMutationID;
enum Dirt
{
kPathBoundsDirt = 1 << 0,
kRawPathMutationIDDirt = 1 << 1,
kPathCoarseAreaDirt = 1 << 2,
kAllDirt = ~0,
};
mutable uint32_t m_dirt = kAllDirt;
RIVE_DEBUG_CODE(mutable int m_rawPathMutationLockCount = 0;)
public:
void invalidateDrawCache() const
{
invalidateDrawCache(CACHE_STROKED);
invalidateDrawCache(CACHE_FILLED);
}
void invalidateDrawCache(int index) const
{
m_cachedElements[index].draw = nullptr;
}
void setDrawCache(gpu::RiveRenderPathDraw* drawCache,
const Mat2D& mat,
rive::RiveRenderPaint* riveRenderPaint) const;
gpu::DrawUniquePtr getDrawCache(const Mat2D& matrix,
const RiveRenderPaint* paint,
FillRule fillRule,
TrivialBlockAllocator* allocator,
const gpu::RenderContext::FrameDescriptor&,
gpu::InterlockMode interlockMode) const;
private:
enum
{
CACHE_STROKED,
CACHE_FILLED,
NUM_CACHES,
};
struct CacheElements
{
gpu::RiveRenderPathDraw* draw = nullptr;
float xx;
float xy;
float yx;
float yy;
};
mutable CacheElements m_cachedElements[NUM_CACHES];
mutable float m_cachedThickness;
mutable StrokeJoin m_cachedJoin;
mutable StrokeCap m_cachedCap;
mutable float m_cachedFeather;
};
} // namespace rive