| /* | |
| * Copyright 2026 Rive | |
| */ | |
| #include "gm.hpp" | |
| #include "gmutils.hpp" | |
| #include "rive/math/math_types.hpp" | |
| #include "assets/nomoon.png.hpp" | |
| using namespace rivegm; | |
| using namespace rive; | |
| constexpr int QuadSize = 120; | |
| constexpr int Columns = 4; | |
| constexpr int Rows = 4; | |
| constexpr int Pad = 10; | |
| struct QuadMesh | |
| { | |
| rcp<RenderBuffer> pts; | |
| rcp<RenderBuffer> uvs; | |
| rcp<RenderBuffer> indices; | |
| uint32_t vertexCount = 4; | |
| uint32_t indexCount = 6; | |
| }; | |
| static rcp<RenderBuffer> makeVertexBuffer( | |
| Factory* factory, | |
| const Vec2D values[4]) | |
| { | |
| auto buffer = factory->makeRenderBuffer( | |
| RenderBufferType::vertex, | |
| RenderBufferFlags::mappedOnceAtInitialization, | |
| 4 * sizeof(Vec2D)); | |
| memcpy(buffer->map(), values, 4 * sizeof(Vec2D)); | |
| buffer->unmap(); | |
| return buffer; | |
| } | |
| static QuadMesh makeQuad(Factory* factory) | |
| { | |
| const Vec2D pts[4] = | |
| {{0, 0}, {QuadSize, 0}, {QuadSize, QuadSize}, {0, QuadSize}}; | |
| const Vec2D uvs[4] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; | |
| const uint16_t indices[6] = {0, 1, 2, 0, 2, 3}; | |
| QuadMesh mesh; | |
| mesh.pts = makeVertexBuffer(factory, pts); | |
| mesh.uvs = makeVertexBuffer(factory, uvs); | |
| mesh.indices = factory->makeRenderBuffer( | |
| RenderBufferType::index, | |
| RenderBufferFlags::mappedOnceAtInitialization, | |
| sizeof(indices)); | |
| memcpy(mesh.indices->map(), indices, sizeof(indices)); | |
| mesh.indices->unmap(); | |
| return mesh; | |
| } | |
| static Mat2D cellTransform(int column, int row) | |
| { | |
| return Mat2D::fromTranslate( | |
| Pad + column * (QuadSize + Pad), | |
| Pad + row * (QuadSize + Pad)); | |
| } | |
| // Use a gray background so we can see opacity and additiveness | |
| DEF_SIMPLE_GM_WITH_CLEAR_COLOR( | |
| mesh_instanced, | |
| 0xff808080, | |
| Columns*(QuadSize + Pad) + Pad, | |
| Rows*(QuadSize + Pad) + Pad, | |
| ren) | |
| { | |
| auto img = LoadImage(assets::nomoon_png()); | |
| if (img == nullptr) | |
| { | |
| return; | |
| } | |
| Factory* factory = TestingWindow::Get()->factory(); | |
| QuadMesh mesh = makeQuad(factory); | |
| auto instances = factory->makeImageMeshInstances(Columns * Rows); | |
| Span<ImageMeshInstanceData> data = instances->edit(); | |
| for (int column = 0; column < Columns; ++column) | |
| { | |
| const float t = column / float(Columns - 1); | |
| // Row 0: transform only | |
| Mat2D spin = Mat2D::fromTranslate(QuadSize * 0.5f, QuadSize * 0.5f) * | |
| Mat2D::fromRotation(t * math::PI * 0.5f) * | |
| Mat2D::fromTranslate(QuadSize * -0.5f, QuadSize * -0.5f); | |
| data[column].transform = cellTransform(column, 0) * spin; | |
| // Row 1: opacity ramp | |
| data[Columns + column].transform = cellTransform(column, 1); | |
| data[Columns + column].opacity = 1.0f - 0.25f * column; | |
| // Row 2: UV transform | |
| data[Columns * 2 + column].transform = cellTransform(column, 2); | |
| data[Columns * 2 + column].uvScale = {0.5f, 0.5f}; | |
| data[Columns * 2 + column].uvTranslate = { | |
| (column & 1) ? 0.5f : 0.0f, | |
| (column & 2) ? 0.5f : 0.0f}; | |
| // Row 3: additiveness ramp. | |
| data[Columns * 3 + column].transform = cellTransform(column, 3); | |
| data[Columns * 3 + column].additiveness = t; | |
| } | |
| instances->endEdit(); | |
| ren->drawImageMeshInstanced( | |
| img.get(), | |
| ImageSampler::LinearClamp(), | |
| mesh.pts, | |
| mesh.uvs, | |
| mesh.indices, | |
| mesh.vertexCount, | |
| mesh.indexCount, | |
| instances); | |
| } |