blob: fde264e1fa2da3a07c5df364ac6b0df4b0ba0dd9 [file] [log] [blame]
/*
* Copyright 2022 Rive
*/
#pragma once
#include "rive/math/raw_path.hpp"
#include "rive/renderer.hpp"
#include "rive/pls/pls.hpp"
#include "rive/pls/pls_draw.hpp"
#include "rive/pls/pls_render_context.hpp"
#include <vector>
namespace rive
{
class GrInnerFanTriangulator;
};
namespace rive::pls
{
class PLSPath;
class PLSPaint;
class PLSRenderContext;
// Renderer implementation for Rive's pixel local storage renderer.
class PLSRenderer : public Renderer
{
public:
PLSRenderer(PLSRenderContext*);
~PLSRenderer() override;
void save() override;
void restore() override;
void transform(const Mat2D& matrix) override;
void drawPath(RenderPath*, RenderPaint*) override;
void clipPath(RenderPath*) override;
void drawImage(const RenderImage*, BlendMode, float opacity) override;
void drawImageMesh(const RenderImage*,
rcp<RenderBuffer> vertices_f32,
rcp<RenderBuffer> uvCoords_f32,
rcp<RenderBuffer> indices_u16,
uint32_t vertexCount,
uint32_t indexCount,
BlendMode,
float opacity) override;
// Determines if a path is an axis-aligned rectangle that can be represented by rive::AABB.
static bool IsAABB(const RawPath&, AABB* result);
#ifdef TESTING
bool hasClipRect() const { return m_stack.back().clipRectInverseMatrix != nullptr; }
const AABB& getClipRect() const { return m_stack.back().clipRect; }
const Mat2D& getClipRectMatrix() const { return m_stack.back().clipRectMatrix; }
#endif
private:
void clipRectImpl(AABB, const PLSPath* originalPath);
void clipPathImpl(const PLSPath*);
// Clips and pushes the given draw to m_context. If the clipped draw is too complex to be
// supported by the GPU buffers, even after a logical flush, then nothing is drawn.
void clipAndPushDraw(PLSDrawUniquePtr);
// Pushes any necessary clip updates to m_internalDrawBatch and sets the PLSDraw's clipID and
// clipRectInverseMatrix, if any.
// Returns false if the operation failed, at which point the caller should issue a logical flush
// and try again.
[[nodiscard]] bool applyClip(PLSDraw*);
struct RenderState
{
Mat2D matrix;
size_t clipStackHeight = 0;
AABB clipRect;
Mat2D clipRectMatrix;
const pls::ClipRectInverseMatrix* clipRectInverseMatrix = nullptr;
bool clipIsEmpty = false;
};
std::vector<RenderState> m_stack{1};
struct ClipElement
{
ClipElement() = default;
ClipElement(const Mat2D&, const PLSPath*, FillRule);
~ClipElement();
void reset(const Mat2D&, const PLSPath*, FillRule);
bool isEquivalent(const Mat2D&, const PLSPath*) const;
Mat2D matrix;
uint64_t rawPathMutationID;
AABB pathBounds;
rcp<const PLSPath> path;
FillRule fillRule; // Bc PLSPath fillRule can mutate during the artboard draw process.
uint32_t clipID;
};
std::vector<ClipElement> m_clipStack;
PLSRenderContext* const m_context;
std::vector<PLSDrawUniquePtr> m_internalDrawBatch;
// Path of the rectangle [0, 0, 1, 1]. Used to draw images.
rcp<PLSPath> m_unitRectPath;
// Used to build coarse path interiors for the "interior triangulation" algorithm.
RawPath m_scratchPath;
};
} // namespace rive::pls