blob: 1fb60049b8caa433256d47fd19af3a59537d398b [file] [log] [blame]
/*
* Copyright 2022 Rive
*/
#pragma once
#include "rive/math/raw_path.hpp"
#include "rive/renderer.hpp"
#include "rive/renderer/gpu.hpp"
#include "rive/renderer/draw.hpp"
#include "rive/renderer/render_context.hpp"
#include <vector>
namespace rive::gpu
{
class RenderContext;
} // namespace rive::gpu
namespace rive
{
class GrInnerFanTriangulator;
class RiveRenderPath;
class RiveRenderPaint;
// Renderer implementation for Rive's pixel local storage renderer.
class RiveRenderer : public Renderer
{
public:
RiveRenderer(gpu::RenderContext*);
~RiveRenderer() 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*,
ImageSampler,
BlendMode,
float opacity) override;
void drawImageMesh(const RenderImage*,
ImageSampler,
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 RiveRenderPath* originalPath);
void clipPathImpl(const RiveRenderPath*);
// 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(gpu::DrawUniquePtr);
// Pushes any necessary clip updates to m_internalDrawBatch and sets the
// Draw's clipID and clipRectInverseMatrix, if any. Returns failure if the
// operation failed, at which point the caller should issue a logical flush
// and try again.
enum class ApplyClipResult
{
success,
failure,
clipEmpty,
};
[[nodiscard]] ApplyClipResult applyClip(gpu::Draw*);
struct RenderState
{
Mat2D matrix;
size_t clipStackHeight = 0;
AABB clipRect;
Mat2D clipRectMatrix;
const gpu::ClipRectInverseMatrix* clipRectInverseMatrix = nullptr;
bool clipIsEmpty = false;
};
std::vector<RenderState> m_stack{1};
struct ClipElement
{
ClipElement() = default;
ClipElement(const Mat2D&, const RiveRenderPath*, FillRule);
~ClipElement();
void reset(const Mat2D&, const RiveRenderPath*, FillRule);
bool isEquivalent(const Mat2D&, const RiveRenderPath*) const;
Mat2D matrix;
uint64_t rawPathMutationID;
AABB pathBounds;
rcp<const RiveRenderPath> path;
FillRule fillRule; // Bc RiveRenderPath fillRule can mutate during the
// artboard draw process.
uint32_t clipID;
};
std::vector<ClipElement> m_clipStack;
gpu::RenderContext* const m_context;
std::vector<gpu::DrawUniquePtr> m_internalDrawBatch;
// Path of the rectangle [0, 0, 1, 1]. Used to draw images.
rcp<RiveRenderPath> m_unitRectPath;
// Used to build coarse path interiors for the "interior triangulation"
// algorithm.
RawPath m_scratchPath;
};
} // namespace rive