blob: c66fe1dfbcb9bb8778e717fd3d507ea5dfbce7dd [file] [log] [blame]
#include "rive/shapes/mesh.hpp"
#include "rive/shapes/image.hpp"
#include "rive/shapes/vertex.hpp"
#include "rive/shapes/mesh_vertex.hpp"
#include "rive/bones/skin.hpp"
#include "rive/artboard.hpp"
#include "rive/factory.hpp"
#include "rive/span.hpp"
#include "rive/assets/image_asset.hpp"
#include <limits>
using namespace rive;
/// Called whenever a vertex moves (x/y change).
void Mesh::markDrawableDirty()
{
if (skin() != nullptr)
{
skin()->addDirt(ComponentDirt::Skin);
}
addDirt(ComponentDirt::Vertices);
}
void Mesh::addVertex(MeshVertex* vertex) { m_Vertices.push_back(vertex); }
StatusCode Mesh::onAddedDirty(CoreContext* context)
{
StatusCode result = Super::onAddedDirty(context);
if (result != StatusCode::Ok)
{
return result;
}
if (!parent()->is<Image>())
{
return StatusCode::MissingObject;
}
// All good, tell the image it has a mesh.
parent()->as<Image>()->setMesh(this);
return StatusCode::Ok;
}
StatusCode Mesh::onAddedClean(CoreContext* context)
{
// Make sure Core found indices in the file for this Mesh.
if (m_IndexBuffer == nullptr)
{
return StatusCode::InvalidObject;
}
// Check the indices are all in range. We should consider having a better
// error reporting system to the implementor.
for (auto index : *m_IndexBuffer)
{
if (index >= m_Vertices.size())
{
return StatusCode::InvalidObject;
}
}
return Super::onAddedClean(context);
}
void Mesh::decodeTriangleIndexBytes(Span<const uint8_t> value)
{
// decode the triangle index bytes
rcp<IndexBuffer> buffer = rcp<IndexBuffer>(new IndexBuffer());
BinaryReader reader(value);
while (!reader.reachedEnd())
{
buffer->push_back(reader.readVarUintAs<uint16_t>());
}
m_IndexBuffer = buffer;
}
void Mesh::copyTriangleIndexBytes(const MeshBase& object)
{
m_IndexBuffer = object.as<Mesh>()->m_IndexBuffer;
}
/// Called whenever a bone moves that is connected to the skin.
void Mesh::markSkinDirty() { addDirt(ComponentDirt::Vertices); }
Core* Mesh::clone() const
{
auto factory = artboard()->factory();
auto clone = static_cast<Mesh*>(MeshBase::clone());
clone->m_VertexRenderBufferDirty = true;
clone->m_VertexRenderBuffer = factory->makeRenderBuffer(RenderBufferType::vertex,
RenderBufferFlags::none,
m_Vertices.size() * sizeof(Vec2D));
clone->m_UVRenderBuffer = m_UVRenderBuffer;
clone->m_IndexRenderBuffer = m_IndexRenderBuffer;
return clone;
}
void Mesh::initializeSharedBuffers(RenderImage* renderImage)
{
Mat2D uvTransform = renderImage != nullptr ? renderImage->uvTransform() : Mat2D();
auto factory = artboard()->factory();
m_VertexRenderBufferDirty = true;
m_VertexRenderBuffer = factory->makeRenderBuffer(RenderBufferType::vertex,
RenderBufferFlags::none,
m_Vertices.size() * sizeof(Vec2D));
m_UVRenderBuffer = factory->makeRenderBuffer(RenderBufferType::vertex,
RenderBufferFlags::mappedOnceAtInitialization,
m_Vertices.size() * sizeof(Vec2D));
if (m_UVRenderBuffer)
{
float* uv = static_cast<float*>(m_UVRenderBuffer->map());
for (auto vertex : m_Vertices)
{
Vec2D xformedUV = uvTransform * Vec2D(vertex->u(), vertex->v());
*uv++ = xformedUV.x;
*uv++ = xformedUV.y;
}
m_UVRenderBuffer->unmap();
}
m_IndexRenderBuffer = factory->makeRenderBuffer(RenderBufferType::index,
RenderBufferFlags::mappedOnceAtInitialization,
m_IndexBuffer->size() * sizeof(uint16_t));
if (m_IndexRenderBuffer)
{
void* indexData = m_IndexRenderBuffer->map();
memcpy(indexData, m_IndexBuffer->data(), m_IndexRenderBuffer->sizeInBytes());
m_IndexRenderBuffer->unmap();
}
}
void Mesh::buildDependencies()
{
Super::buildDependencies();
if (skin() != nullptr)
{
skin()->addDependent(this);
}
parent()->addDependent(this);
}
void Mesh::update(ComponentDirt value)
{
if (hasDirt(value, ComponentDirt::Vertices))
{
if (skin() != nullptr)
{
skin()->deform({(Vertex**)m_Vertices.data(), m_Vertices.size()});
}
m_VertexRenderBufferDirty = true;
}
Super::update(value);
}
void Mesh::draw(Renderer* renderer, const RenderImage* image, BlendMode blendMode, float opacity)
{
if (m_VertexRenderBufferDirty && m_VertexRenderBuffer != nullptr)
{
Vec2D* mappedVertices = reinterpret_cast<Vec2D*>(m_VertexRenderBuffer->map());
for (auto vertex : m_Vertices)
{
*mappedVertices++ = vertex->renderTranslation();
}
m_VertexRenderBuffer->unmap();
m_VertexRenderBufferDirty = false;
}
if (skin() == nullptr)
{
renderer->transform(parent()->as<WorldTransformComponent>()->worldTransform());
}
renderer->drawImageMesh(image,
m_VertexRenderBuffer,
m_UVRenderBuffer,
m_IndexRenderBuffer,
static_cast<uint32_t>(m_Vertices.size()),
static_cast<uint32_t>(m_IndexBuffer->size()),
blendMode,
opacity);
}