blob: 6318785350183dba6bf0d5c56a7aa8d7480a17c9 [file]
#ifndef _RIVE_ARTBOARD_PAINT_SOURCE_HPP_
#define _RIVE_ARTBOARD_PAINT_SOURCE_HPP_
#include "rive/advance_flags.hpp"
#include "rive/math/aabb.hpp"
#include "rive/math/mat2d.hpp"
#include "rive/refcnt.hpp"
#include "rive/shapes/paint/image_sampler.hpp"
#include <cstdint>
#include <memory>
namespace rive
{
class Artboard;
class ArtboardHost;
class ArtboardInstance;
class DataContext;
class Factory;
class LinearAnimationInstance;
class RenderPaint;
class Renderer;
class StateMachineInstance;
class ViewModelInstance;
#ifdef RIVE_CANVAS
namespace gpu
{
class RenderCanvas;
}
#endif
namespace cmd
{
class DeferredCanvasHost;
}
/// Where a path modulated by a paint image has to be drawn. [renderer] is the
/// renderer the draw started on, unless an immediate host interrupted it to
/// rasterize -- that renderer can no longer sample the canvas, so the host
/// hands back a clean one, which has to be given [transform] and [opacity] by
/// hand and inherits no clip (the same limitation a cached artboard has).
struct ModulatedDrawTarget
{
Renderer* renderer = nullptr;
Mat2D transform;
float opacity = 1.0f;
};
/// An artboard used as a paint's image: one instance of the source artboard,
/// the scene that plays it, and the offscreen raster it is drawn into. Owned by
/// a PaintImage at runtime and by the editor's native binding, so both advance
/// and rasterize it the same way.
class ArtboardPaintSource
{
public:
/// Instances [source] on [factory] and picks what plays it: the default
/// state machine, else the first state machine, else the first animation,
/// else nothing (the artboard draws static). Returns null when the source
/// cannot be instanced, including past the nesting depth that guards
/// against a reference cycle the importer could not see.
///
/// [host] (optional) becomes the instance's host, so a change inside it
/// reaches the artboard the paint is in (Artboard::changed walks hosts).
static std::unique_ptr<ArtboardPaintSource> make(
const Artboard* source,
Factory* factory,
ArtboardHost* host = nullptr);
~ArtboardPaintSource();
ArtboardPaintSource(const ArtboardPaintSource&) = delete;
ArtboardPaintSource& operator=(const ArtboardPaintSource&) = delete;
/// Advances the scene and the instance's own advancing components, by the
/// same rules NestedArtboard applies to what it hosts. Returns whether
/// anything wants to keep advancing.
bool advance(float elapsedSeconds, AdvanceFlags flags);
/// Whether the last advance left the instance needing an update pass.
bool needsUpdate() const;
void update();
/// The instance's own box: what gets rasterized, and the logical size the
/// paint's "original" size mode maps one artboard unit from.
AABB bounds() const;
ArtboardInstance* artboard() const { return m_artboard.get(); }
/// Binds the instance and its scene to [dataContext]: the context of the
/// artboard the paint is in, passed straight through the way a
/// NestedArtboard with no bind path passes its host's. The source's binds
/// resolve against it, so they find the host's view model, or any view
/// model reachable from it.
void dataContext(rcp<DataContext> dataContext);
void relinkDataContext(rcp<ViewModelInstance> viewModelInstance);
void clearDataContext();
void unbind();
void updateDataBinds();
/// Rasterizes the artboard (when it changed, or the raster no longer fits
/// how it is viewed) into an offscreen canvas from [host], and installs
/// that canvas as [paint]'s modulated image. [imageTransform] maps the
/// image's normalized 0..1 space into the space [renderer] is drawing the
/// path in, exactly as for an image asset.
///
/// Returns false, leaving [paint] untouched, when nothing could be
/// rasterized -- no host, or the host could not open a frame. The caller
/// clears any stale image, as it does for an undecoded asset.
///
/// [target] receives the renderer the path has to be drawn through.
bool applyTo(
Renderer* renderer,
cmd::DeferredCanvasHost* host,
RenderPaint* paint,
ImageSampler sampler,
const Mat2D& imageTransform,
ModulatedDrawTarget* target);
#ifdef TESTING
uint32_t rasterWidth() const;
uint32_t rasterHeight() const;
uint32_t rasterCount() const { return m_rasterCount; }
bool hasStateMachine() const { return m_stateMachine != nullptr; }
bool hasAnimation() const { return m_animation != nullptr; }
#endif
private:
explicit ArtboardPaintSource(std::unique_ptr<ArtboardInstance> artboard);
#ifdef RIVE_CANVAS
bool rasterize(cmd::DeferredCanvasHost* host);
#endif
// Declared first so it is destroyed last: the scene instances below hold
// pointers into it.
std::unique_ptr<ArtboardInstance> m_artboard;
std::unique_ptr<StateMachineInstance> m_stateMachine;
std::unique_ptr<LinearAnimationInstance> m_animation;
#ifdef RIVE_CANVAS
rcp<gpu::RenderCanvas> m_canvas;
uint32_t m_widthPx = 0;
uint32_t m_heightPx = 0;
// Consecutive draws that wanted a smaller raster; see decideRasterResize.
uint8_t m_shrinkStreak = 0;
bool m_dirty = true;
#endif
#ifdef TESTING
uint32_t m_rasterCount = 0;
#endif
};
} // namespace rive
#endif