blob: 8aa2d6ffc35f2c31f4ad5b00b3fee08cdda6cf53 [file]
/*
* 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 drawImage(const RenderImage*,
ImageSampler,
BlendMode,
float opacity,
float additiveness) override;
void applyLayerMask(const RenderImage*,
ImageSampler,
LayerMaskMode) override;
void clipStroke(RenderPath*, const StrokeParams&) 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;
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,
float additiveness) override;
void drawImageMeshInstanced(const RenderImage*,
ImageSampler,
rcp<RenderBuffer> vertices_f32,
rcp<RenderBuffer> uvCoords_f32,
rcp<RenderBuffer> indices_u16,
uint32_t vertexCount,
uint32_t indexCount,
rcp<ImageMeshInstances>) override;
void modulateOpacity(float opacity) override;
void modulateColor(ColorInt color, bool replace = false) override;
bool currentTransform(Mat2D* out) const override
{
*out = m_renderStateStack.back().matrix;
return true;
}
bool currentModulatedOpacity(float* out) const override
{
*out = m_renderStateStack.back().modulatedOpacity;
return true;
}
// 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_renderStateStack.back().clipRectInverseMatrix != nullptr;
}
const AABB& getClipRect() const
{
return m_renderStateStack.back().clipRect;
}
const Mat2D& getClipRectMatrix() const
{
return m_renderStateStack.back().clipRectMatrix;
}
float currentModulatedOpacity() const
{
return m_renderStateStack.back().modulatedOpacity;
}
ColorInt currentModulatedColor() const
{
return m_renderStateStack.back().modulatedColor;
}
#endif
private:
enum class ForceClosed : bool
{
no,
yes,
};
void clipRectImpl(AABB, const RiveRenderPath* originalPath);
void clipPathImpl(const RiveRenderPath*,
std::optional<StrokeParams> = {},
float feather = 0.0f,
ForceClosed forceClosed = ForceClosed::no,
IAABB* boundsOut = nullptr);
// 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,
fullyClipped,
};
[[nodiscard]] ApplyClipResult applyClip(gpu::Draw*);
struct RenderState
{
Mat2D matrix;
size_t clipStackHeight = 0;
AABB clipRect;
Mat2D clipRectMatrix;
IAABB clipRectPixelBounds;
const gpu::ClipRectInverseMatrix* clipRectInverseMatrix = nullptr;
float modulatedOpacity = 1.0f;
ColorInt modulatedColor = 0xFFFFFFFF;
// The pixel bounds for all clipping (clip rects *and* clip paths),
// which defaults to a maximally-large rectangle
IAABB overallClipPixelBounds = IAABB::makeMaximal();
};
std::vector<RenderState> m_renderStateStack{1};
// A draw's color with this scope's modulation folded in.
ColorInt modulated(ColorInt color, float opacity) const;
struct ClipElement
{
ClipElement() = default;
ClipElement(const Mat2D&,
const RiveRenderPath*,
FillRule,
IAABB pixelBounds,
std::optional<StrokeParams>,
float feather,
bool forceClosed);
~ClipElement();
void reset(const Mat2D&,
const RiveRenderPath*,
FillRule,
IAABB pixelBounds,
std::optional<StrokeParams>,
float feather,
bool forceClosed);
bool isEquivalent(const Mat2D&,
const RiveRenderPath*,
std::optional<StrokeParams>,
float feather,
bool forceClosed) const;
Mat2D matrix;
uint64_t rawPathMutationID;
AABB pathBounds;
IAABB pixelBounds;
rcp<const RiveRenderPath> path;
FillRule fillRule; // Bc RiveRenderPath fillRule can mutate during the
// artboard draw process.
uint32_t clipID;
std::optional<StrokeParams> stroke;
float feather;
bool forceClosed;
};
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;
};
} // namespace rive