blob: 36d2ea2d8dc4939e9205e5e82abd6def0998fee7 [file]
#ifdef RIVE_WASM_MODULE
// In-module implementations of the abstract render interfaces the bindings
// call through: geometry stays in module memory as RawPath and syncs to the
// host lazily; every native contact is a u32 handle crossing a rive_*_v1
// import. Compiled only into the script module (never the runtime).
#include "rive/factory.hpp"
#include "rive/math/raw_path.hpp"
#include "rive/renderer.hpp"
#include "rive/wasm/module_render.hpp"
#include "rive/wasm/rive_bindings_v1.h"
#include <stdio.h>
using namespace rive;
namespace
{
class ModuleRenderPath : public RenderPath
{
public:
ModuleRenderPath() = default;
ModuleRenderPath(RawPath& rawPath, FillRule rule) :
m_rawPath(rawPath), m_fillRule(rule)
{}
~ModuleRenderPath() override
{
if (m_handle != 0)
{
rive_path_release(m_handle);
}
}
void rewind() override
{
m_rawPath.rewind();
m_dirty = true;
}
void fillRule(FillRule value) override
{
m_fillRule = value;
m_dirty = true;
}
void addPath(CommandPath* path, const Mat2D& transform) override
{
addRenderPath(path->renderPath(), transform);
}
void addRenderPath(const RenderPath* path, const Mat2D& transform) override
{
auto modulePath = static_cast<const ModuleRenderPath*>(path);
m_rawPath.addPath(modulePath->m_rawPath, &transform);
m_dirty = true;
}
void moveTo(float x, float y) override
{
m_rawPath.moveTo(x, y);
m_dirty = true;
}
void lineTo(float x, float y) override
{
m_rawPath.lineTo(x, y);
m_dirty = true;
}
void cubicTo(float ox, float oy, float ix, float iy, float x, float y)
override
{
m_rawPath.cubicTo(ox, oy, ix, iy, x, y);
m_dirty = true;
}
void close() override
{
m_rawPath.close();
m_dirty = true;
}
void addRawPath(const RawPath& path) override
{
m_rawPath.addPath(path, nullptr);
m_dirty = true;
}
// Pushes geometry to the host when it changed since the last draw.
uint32_t sync()
{
if (m_handle == 0)
{
m_handle = rive_path_new();
m_dirty = true;
}
if (m_dirty)
{
rive_path_update(m_handle,
(const uint8_t*)m_rawPath.verbs().data(),
(uint32_t)m_rawPath.verbs().size(),
(const float*)m_rawPath.points().data(),
(uint32_t)m_rawPath.points().size() * 2,
(uint32_t)m_fillRule);
m_dirty = false;
}
return m_handle;
}
private:
RawPath m_rawPath;
FillRule m_fillRule = FillRule::nonZero;
uint32_t m_handle = 0;
bool m_dirty = false;
};
class ModuleRenderPaint : public RenderPaint
{
public:
ModuleRenderPaint() : m_handle(rive_paint_new()) {}
~ModuleRenderPaint() override { rive_paint_release(m_handle); }
void style(RenderPaintStyle value) override
{
rive_paint_style(m_handle, (uint32_t)value);
}
void color(ColorInt value) override { rive_paint_color(m_handle, value); }
void thickness(float value) override
{
rive_paint_thickness(m_handle, value);
}
void join(StrokeJoin value) override
{
rive_paint_join(m_handle, (uint32_t)value);
}
void cap(StrokeCap value) override
{
rive_paint_cap(m_handle, (uint32_t)value);
}
void feather(float value) override { rive_paint_feather(m_handle, value); }
void blendMode(BlendMode value) override
{
rive_paint_blend_mode(m_handle, (uint32_t)value);
}
void shader(rcp<RenderShader> value) override;
void invalidateStroke() override {}
uint32_t handle() const { return m_handle; }
private:
rcp<RenderShader> m_shader;
uint32_t m_handle;
};
class ModuleRenderShader : public RenderShader
{
public:
ModuleRenderShader(uint32_t handle) : m_handle(handle) {}
~ModuleRenderShader() override { rive_shader_release(m_handle); }
uint32_t handle() const { return m_handle; }
private:
uint32_t m_handle;
};
// Out of line so ModuleRenderShader's handle accessor is visible.
void ModuleRenderPaint::shader(rcp<RenderShader> value)
{
// Pinned so the host handle outlives the assignment.
m_shader = value;
rive_paint_shader(
m_handle,
value != nullptr
? static_cast<ModuleRenderShader*>(value.get())->handle()
: 0);
}
// Contents live in module memory and push to the host on unmap.
class ModuleRenderBuffer : public RenderBuffer
{
public:
ModuleRenderBuffer(RenderBufferType type,
RenderBufferFlags flags,
size_t sizeInBytes) :
RenderBuffer(type, flags, sizeInBytes),
m_handle(rive_buffer_new((uint32_t)type,
(uint32_t)flags,
(uint32_t)sizeInBytes)),
m_store(new uint8_t[sizeInBytes])
{}
~ModuleRenderBuffer() override
{
rive_buffer_release(m_handle);
delete[] m_store;
}
uint32_t handle() const { return m_handle; }
protected:
void* onMap() override { return m_store; }
void onUnmap() override
{
rive_buffer_update(m_handle, m_store, (uint32_t)sizeInBytes());
}
private:
uint32_t m_handle;
uint8_t* m_store;
};
class ModuleRenderImage : public RenderImage
{
public:
ModuleRenderImage(uint32_t handle) : m_handle(handle)
{
m_Width = (int)rive_image_width(handle);
m_Height = (int)rive_image_height(handle);
}
~ModuleRenderImage() override { rive_image_release(m_handle); }
uint32_t handle() const { return m_handle; }
private:
uint32_t m_handle;
};
class ModuleFactory : public Factory
{
public:
#if defined(RIVE_CANVAS) && defined(RIVE_ORE)
ore::Context* ore() override { return wasmModuleOreContext(); }
#endif
rcp<RenderBuffer> makeRenderBuffer(RenderBufferType type,
RenderBufferFlags flags,
size_t sizeInBytes) override
{
return make_rcp<ModuleRenderBuffer>(type, flags, sizeInBytes);
}
rcp<RenderShader> makeLinearGradient(float sx,
float sy,
float ex,
float ey,
const ColorInt colors[],
const float stops[],
size_t count) override
{
return make_rcp<ModuleRenderShader>(
rive_shader_linear(sx, sy, ex, ey, colors, stops, (uint32_t)count));
}
rcp<RenderShader> makeRadialGradient(float cx,
float cy,
float radius,
const ColorInt colors[],
const float stops[],
size_t count) override
{
return make_rcp<ModuleRenderShader>(
rive_shader_radial(cx, cy, radius, colors, stops, (uint32_t)count));
}
rcp<RenderPath> makeRenderPath(RawPath& rawPath, FillRule rule) override
{
return make_rcp<ModuleRenderPath>(rawPath, rule);
}
rcp<RenderPath> makeEmptyRenderPath() override
{
return make_rcp<ModuleRenderPath>();
}
rcp<RenderPaint> makeRenderPaint() override
{
return make_rcp<ModuleRenderPaint>();
}
rcp<RenderImage> decodeImage(Span<const uint8_t>) override
{
return nullptr;
}
};
class ModuleRenderer : public Renderer
{
public:
ModuleRenderer(uint32_t handle) : m_handle(handle) {}
void save() override { rive_renderer_save(m_handle); }
void restore() override { rive_renderer_restore(m_handle); }
void transform(const Mat2D& transform) override
{
rive_renderer_transform(m_handle,
transform.xx(),
transform.xy(),
transform.yx(),
transform.yy(),
transform.tx(),
transform.ty());
}
void drawPath(RenderPath* path, RenderPaint* paint) override
{
rive_renderer_draw_path(
m_handle,
static_cast<ModuleRenderPath*>(path)->sync(),
static_cast<ModuleRenderPaint*>(paint)->handle());
}
void clipPath(RenderPath* path) override
{
rive_renderer_clip_path(m_handle,
static_cast<ModuleRenderPath*>(path)->sync());
}
void drawImage(const RenderImage* image,
ImageSampler sampler,
BlendMode blend,
float opacity) override
{
rive_renderer_draw_image(
m_handle,
static_cast<const ModuleRenderImage*>(image)->handle(),
sampler.asKey(),
(uint32_t)blend,
opacity);
}
void drawImageMesh(const RenderImage* image,
ImageSampler sampler,
rcp<RenderBuffer> vertices,
rcp<RenderBuffer> uvCoords,
rcp<RenderBuffer> indices,
uint32_t vertexCount,
uint32_t indexCount,
BlendMode blend,
float opacity) override
{
rive_renderer_draw_image_mesh(
m_handle,
static_cast<const ModuleRenderImage*>(image)->handle(),
sampler.asKey(),
static_cast<ModuleRenderBuffer*>(vertices.get())->handle(),
static_cast<ModuleRenderBuffer*>(uvCoords.get())->handle(),
static_cast<ModuleRenderBuffer*>(indices.get())->handle(),
(uint32_t)blend,
opacity);
}
void modulateOpacity(float) override {}
uint32_t handle() const { return m_handle; }
private:
uint32_t m_handle;
};
} // namespace
namespace rive
{
uint32_t wasmModuleImageHandle(RenderImage* image)
{
return image != nullptr ? static_cast<ModuleRenderImage*>(image)->handle()
: 0;
}
Factory* wasmModuleFactory()
{
static ModuleFactory factory;
return &factory;
}
std::unique_ptr<Renderer> makeWasmModuleRenderer(uint32_t handle)
{
return std::make_unique<ModuleRenderer>(handle);
}
uint32_t wasmModuleRendererHandle(Renderer* renderer)
{
return renderer != nullptr
? static_cast<ModuleRenderer*>(renderer)->handle()
: 0;
}
rcp<RenderImage> makeWasmModuleRenderImage(uint32_t handle)
{
return make_rcp<ModuleRenderImage>(handle);
}
} // namespace rive
#endif