DrawImage for Tess Renderer

drawImage (without a Rive provided mesh) wasn't implemented in Tess. For now this just builds a tiny vertex buffer when it uploads the image.

I'll rework this when I add batching to this renderer (the vertex buffer will only be generated on demand and placed into the batched vertex buffer for the whole frame/artboard depending on where we'll create the batching boundary)

Diffs=
c9f97f7c1 DrawImage for Tess Renderer
This commit is contained in:
luigi-rosso
2022-08-24 02:30:59 +00:00
parent f6790796e8
commit 118b04085a
5 changed files with 79 additions and 22 deletions

View File

@@ -1 +1 @@
e617e4448d1028f08ccaecf24d02cab2d019e40e
c9f97f7c18a92cd0d417b76b235f841b1e577cac

View File

@@ -102,7 +102,8 @@
"scoped_allocator": "cpp",
"span": "cpp",
"typeindex": "cpp",
"filesystem": "cpp"
"filesystem": "cpp",
"*.idl": "cpp"
},
"git.ignoreLimitWarning": true
}

View File

@@ -13,10 +13,15 @@ namespace rive {
class SokolRenderImage : public RenderImage {
private:
sg_image m_image;
sg_buffer m_vertexBuffer;
public:
SokolRenderImage(sg_image image);
// bytes is expected to be tightly packed RGBA*width*height.
SokolRenderImage(const uint8_t* bytes, uint32_t width, uint32_t height);
~SokolRenderImage() override;
sg_image image() const { return m_image; }
sg_buffer vertexBuffer() const { return m_vertexBuffer; }
};
class SokolTessRenderer : public TessRenderer {
@@ -41,6 +46,7 @@ private:
sg_pipeline m_incClipPipeline;
sg_pipeline m_decClipPipeline;
sg_buffer m_boundsIndices;
sg_buffer m_defaultUV;
std::vector<SubPath> m_ClipPaths;

View File

@@ -134,8 +134,6 @@ std::unique_ptr<RenderPath> SokolFactory::makeEmptyRenderPath() {
return std::make_unique<SokolRenderPath>();
}
SokolRenderImage::SokolRenderImage(sg_image image) : m_image(image) {}
class SokolBuffer : public RenderBuffer {
private:
sg_buffer m_Buffer;
@@ -468,9 +466,24 @@ SokolTessRenderer::SokolTessRenderer() {
.type = SG_BUFFERTYPE_INDEXBUFFER,
.data = SG_RANGE(indices),
});
// The UV buffer used by drawImage. Consider this the "default uv
// vertex buffer" used when a mesh isn't provided by Rive.
Vec2D defUV[] = {
Vec2D(0.0f, 0.0f),
Vec2D(1.0f, 0.0f),
Vec2D(1.0f, 1.0f),
Vec2D(0.0f, 1.0f),
};
m_defaultUV = sg_make_buffer((sg_buffer_desc){
.type = SG_BUFFERTYPE_VERTEXBUFFER,
.data = SG_RANGE(defUV),
});
}
SokolTessRenderer::~SokolTessRenderer() {
sg_destroy_buffer(m_defaultUV);
sg_destroy_buffer(m_boundsIndices);
sg_destroy_pipeline(m_meshPipeline);
sg_destroy_pipeline(m_incClipPipeline);
@@ -530,7 +543,26 @@ void SokolTessRenderer::orthographicProjection(float left,
// }
}
void SokolTessRenderer::drawImage(const RenderImage*, BlendMode, float opacity) {}
void SokolTessRenderer::drawImage(const RenderImage* image, BlendMode, float opacity) {
vs_params_t vs_params;
const Mat2D& world = transform();
vs_params.mvp = m_Projection * world;
auto sokolImage = static_cast<const SokolRenderImage*>(image);
setPipeline(m_meshPipeline);
sg_bindings bind = {
.vertex_buffers[0] = sokolImage->vertexBuffer(),
.vertex_buffers[1] = m_defaultUV,
.index_buffer = m_boundsIndices,
.fs_images[SLOT_tex] = sokolImage->image(),
};
sg_apply_bindings(&bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_vs_params, SG_RANGE_REF(vs_params));
sg_draw(0, 6, 1);
}
void SokolTessRenderer::drawImageMesh(const RenderImage* renderImage,
rcp<RenderBuffer> vertices_f32,
rcp<RenderBuffer> uvCoords_f32,
@@ -915,3 +947,31 @@ void SokolTessRenderer::drawPath(RenderPath* path, RenderPaint* paint) {
static_cast<SokolRenderPaint*>(paint)->draw(static_cast<SokolRenderPath*>(path));
}
SokolRenderImage::SokolRenderImage(const uint8_t* bytes, uint32_t width, uint32_t height) :
m_image(sg_make_image((sg_image_desc){
.width = (int)width,
.height = (int)height,
.data.subimage[0][0] = {bytes, width * height * 4},
.pixel_format = SG_PIXELFORMAT_RGBA8,
}))
{
float halfWidth = width / 2.0f;
float halfHeight = height / 2.0f;
Vec2D points[] = {
Vec2D(-halfWidth, -halfHeight),
Vec2D(halfWidth, -halfHeight),
Vec2D(halfWidth, halfHeight),
Vec2D(-halfWidth, halfHeight),
};
m_vertexBuffer = sg_make_buffer((sg_buffer_desc){
.type = SG_BUFFERTYPE_VERTEXBUFFER,
.data = SG_RANGE(points),
});
}
SokolRenderImage::~SokolRenderImage() {
sg_destroy_buffer(m_vertexBuffer);
sg_destroy_image(m_image);
}

View File

@@ -4,30 +4,20 @@
#include "rive/tess/sokol/sokol_tess_renderer.hpp"
#include "sokol_gfx.h"
sg_pixel_format SgPixelFormat(Bitmap* bitmap) {
switch (bitmap->pixelFormat()) {
case Bitmap::PixelFormat::R: return SG_PIXELFORMAT_R8;
case Bitmap::PixelFormat::RGBA: return SG_PIXELFORMAT_RGBA8;
default: return SG_PIXELFORMAT_NONE;
}
}
std::unique_ptr<rive::RenderImage>
ViewerSokolFactory::decodeImage(rive::Span<const uint8_t> bytes) {
auto bitmap = Bitmap::decode(bytes);
if (bitmap) {
// We have a bitmap, let's make an image.
// Sokol doesn't support an RGB pixel format, so we have to bump RGB to RGBA.
if (bitmap->pixelFormat() == Bitmap::PixelFormat::RGB) {
// For now our SokolRenderImage only works with RGBA.
if (bitmap->pixelFormat() != Bitmap::PixelFormat::RGBA) {
bitmap->pixelFormat(Bitmap::PixelFormat::RGBA);
}
return std::make_unique<rive::SokolRenderImage>(sg_make_image((sg_image_desc){
.width = (int)bitmap->width(),
.height = (int)bitmap->height(),
.data.subimage[0][0] = {bitmap->bytes(), bitmap->byteSize()},
.pixel_format = SgPixelFormat(bitmap.get()),
}));
return std::make_unique<rive::SokolRenderImage>(bitmap->bytes(),
bitmap->width(),
bitmap->height());
}
return nullptr;
}