Starting to load meshes.
diff --git a/include/rive/shapes/contour_mesh_vertex.hpp b/include/rive/shapes/contour_mesh_vertex.hpp index 51d8873..fa0942f 100644 --- a/include/rive/shapes/contour_mesh_vertex.hpp +++ b/include/rive/shapes/contour_mesh_vertex.hpp
@@ -1,7 +1,7 @@ #ifndef _RIVE_CONTOUR_MESH_VERTEX_HPP_ #define _RIVE_CONTOUR_MESH_VERTEX_HPP_ #include "rive/generated/shapes/contour_mesh_vertex_base.hpp" -#include <stdio.h> + namespace rive { class ContourMeshVertex : public ContourMeshVertexBase { public:
diff --git a/include/rive/shapes/image.hpp b/include/rive/shapes/image.hpp index 84dab09..491d9ec 100644 --- a/include/rive/shapes/image.hpp +++ b/include/rive/shapes/image.hpp
@@ -4,11 +4,15 @@ #include "rive/assets/file_asset_referencer.hpp" namespace rive { class ImageAsset; + class Mesh; class Image : public ImageBase, public FileAssetReferencer { private: ImageAsset* m_ImageAsset = nullptr; + Mesh* m_Mesh = nullptr; public: + Mesh* mesh() const; + void setMesh(Mesh* mesh); ImageAsset* imageAsset() const { return m_ImageAsset; } void draw(Renderer* renderer) override; StatusCode import(ImportStack& importStack) override;
diff --git a/include/rive/shapes/mesh.hpp b/include/rive/shapes/mesh.hpp index 7e38f4f..ee3b0f2 100644 --- a/include/rive/shapes/mesh.hpp +++ b/include/rive/shapes/mesh.hpp
@@ -1,10 +1,21 @@ #ifndef _RIVE_MESH_HPP_ #define _RIVE_MESH_HPP_ #include "rive/generated/shapes/mesh_base.hpp" -#include <stdio.h> + namespace rive { + class MeshVertex; class Mesh : public MeshBase { + protected: + std::vector<MeshVertex*> m_Vertices; + public: + StatusCode onAddedDirty(CoreContext* context) override; + void markDrawableDirty(); + void addVertex(MeshVertex* vertex); + +#ifdef TESTING + std::vector<MeshVertex*>& vertices() { return m_Vertices; } +#endif }; } // namespace rive
diff --git a/include/rive/shapes/mesh_vertex.hpp b/include/rive/shapes/mesh_vertex.hpp index bd58ccd..0831fac 100644 --- a/include/rive/shapes/mesh_vertex.hpp +++ b/include/rive/shapes/mesh_vertex.hpp
@@ -5,6 +5,8 @@ namespace rive { class MeshVertex : public MeshVertexBase { public: + void markGeometryDirty() override; + StatusCode onAddedDirty(CoreContext* context) override; }; } // namespace rive
diff --git a/include/rive/shapes/path.hpp b/include/rive/shapes/path.hpp index a1e20cf..73ffdca 100644 --- a/include/rive/shapes/path.hpp +++ b/include/rive/shapes/path.hpp
@@ -39,7 +39,6 @@ public: ~Path(); Shape* shape() const { return m_Shape; } - StatusCode onAddedDirty(CoreContext* context) override; StatusCode onAddedClean(CoreContext* context) override; void buildDependencies() override; virtual const Mat2D& pathTransform() const;
diff --git a/include/rive/shapes/path_vertex.hpp b/include/rive/shapes/path_vertex.hpp index e8e37fb..7ccd4b4 100644 --- a/include/rive/shapes/path_vertex.hpp +++ b/include/rive/shapes/path_vertex.hpp
@@ -5,29 +5,10 @@ #include "rive/math/mat2d.hpp" namespace rive { class PathVertex : public PathVertexBase { - friend class Weight; - - private: - Weight* m_Weight = nullptr; - void weight(Weight* value) { m_Weight = value; } public: StatusCode onAddedDirty(CoreContext* context) override; - template <typename T> T* weight() { return m_Weight->as<T>(); } - virtual void deform(const Mat2D& worldTransform, - const float* boneTransforms); - bool hasWeight() { return m_Weight != nullptr; } - Vec2D renderTranslation(); - - protected: - void markPathDirty(); - void xChanged() override; - void yChanged() override; - -#ifdef TESTING - public: - Weight* weight() { return m_Weight; } -#endif + void markGeometryDirty() override; }; } // namespace rive
diff --git a/include/rive/shapes/vertex.hpp b/include/rive/shapes/vertex.hpp index 555d170..ec09902 100644 --- a/include/rive/shapes/vertex.hpp +++ b/include/rive/shapes/vertex.hpp
@@ -1,10 +1,32 @@ #ifndef _RIVE_VERTEX_HPP_ #define _RIVE_VERTEX_HPP_ +#include "rive/bones/weight.hpp" #include "rive/generated/shapes/vertex_base.hpp" -#include <stdio.h> +#include "rive/math/mat2d.hpp" namespace rive { class Vertex : public VertexBase { + friend class Weight; + + private: + Weight* m_Weight = nullptr; + void weight(Weight* value) { m_Weight = value; } + public: + template <typename T> T* weight() { return m_Weight->as<T>(); } + virtual void deform(const Mat2D& worldTransform, + const float* boneTransforms); + bool hasWeight() { return m_Weight != nullptr; } + Vec2D renderTranslation(); + + protected: + virtual void markGeometryDirty() = 0; + void xChanged() override; + void yChanged() override; + +#ifdef TESTING + public: + Weight* weight() { return m_Weight; } +#endif }; } // namespace rive
diff --git a/src/shapes/cubic_asymmetric_vertex.cpp b/src/shapes/cubic_asymmetric_vertex.cpp index 8ba1ab0..96fb60a 100644 --- a/src/shapes/cubic_asymmetric_vertex.cpp +++ b/src/shapes/cubic_asymmetric_vertex.cpp
@@ -29,13 +29,13 @@ void CubicAsymmetricVertex::rotationChanged() { m_InValid = false; m_OutValid = false; - markPathDirty(); + markGeometryDirty(); } void CubicAsymmetricVertex::inDistanceChanged() { m_InValid = false; - markPathDirty(); + markGeometryDirty(); } void CubicAsymmetricVertex::outDistanceChanged() { m_OutValid = false; - markPathDirty(); + markGeometryDirty(); }
diff --git a/src/shapes/cubic_detached_vertex.cpp b/src/shapes/cubic_detached_vertex.cpp index 3a76fb9..c60acc8 100644 --- a/src/shapes/cubic_detached_vertex.cpp +++ b/src/shapes/cubic_detached_vertex.cpp
@@ -28,17 +28,17 @@ void CubicDetachedVertex::inRotationChanged() { m_InValid = false; - markPathDirty(); + markGeometryDirty(); } void CubicDetachedVertex::inDistanceChanged() { m_InValid = false; - markPathDirty(); + markGeometryDirty(); } void CubicDetachedVertex::outRotationChanged() { m_OutValid = false; - markPathDirty(); + markGeometryDirty(); } void CubicDetachedVertex::outDistanceChanged() { m_OutValid = false; - markPathDirty(); + markGeometryDirty(); }
diff --git a/src/shapes/cubic_mirrored_vertex.cpp b/src/shapes/cubic_mirrored_vertex.cpp index 068887c..8757d69 100644 --- a/src/shapes/cubic_mirrored_vertex.cpp +++ b/src/shapes/cubic_mirrored_vertex.cpp
@@ -23,9 +23,9 @@ void CubicMirroredVertex::rotationChanged() { m_InValid = m_OutValid = false; - markPathDirty(); + markGeometryDirty(); } void CubicMirroredVertex::distanceChanged() { m_InValid = m_OutValid = false; - markPathDirty(); + markGeometryDirty(); }
diff --git a/src/shapes/image.cpp b/src/shapes/image.cpp index 05da6ef..d1a01e3 100644 --- a/src/shapes/image.cpp +++ b/src/shapes/image.cpp
@@ -55,3 +55,6 @@ twin->m_ImageAsset = m_ImageAsset; return twin; } + +void Image::setMesh(Mesh* mesh) { m_Mesh = mesh; } +Mesh* Image::mesh() const { return m_Mesh; } \ No newline at end of file
diff --git a/src/shapes/mesh.cpp b/src/shapes/mesh.cpp new file mode 100644 index 0000000..207410c --- /dev/null +++ b/src/shapes/mesh.cpp
@@ -0,0 +1,24 @@ +#include "rive/shapes/mesh.hpp" +#include "rive/shapes/image.hpp" + +using namespace rive; + +void Mesh::markDrawableDirty() { + // TODO: add dirty for rebuilding vertex buffer (including deform). +} + +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; + } + parent()->as<Image>()->setMesh(this); + + return StatusCode::Ok; +} \ No newline at end of file
diff --git a/src/shapes/mesh_vertex.cpp b/src/shapes/mesh_vertex.cpp new file mode 100644 index 0000000..1d2439a --- /dev/null +++ b/src/shapes/mesh_vertex.cpp
@@ -0,0 +1,19 @@ +#include "rive/shapes/mesh_vertex.hpp" +#include "rive/shapes/mesh.hpp" + +using namespace rive; +void MeshVertex::markGeometryDirty() { + parent()->as<Mesh>()->markDrawableDirty(); +} + +StatusCode MeshVertex::onAddedDirty(CoreContext* context) { + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) { + return code; + } + if (!parent()->is<Mesh>()) { + return StatusCode::MissingObject; + } + parent()->as<Mesh>()->addVertex(this); + return StatusCode::Ok; +} \ No newline at end of file
diff --git a/src/shapes/path.cpp b/src/shapes/path.cpp index 0e20a37..4f877a4 100644 --- a/src/shapes/path.cpp +++ b/src/shapes/path.cpp
@@ -12,14 +12,6 @@ Path::~Path() { delete m_CommandPath; } -StatusCode Path::onAddedDirty(CoreContext* context) { - StatusCode code = Super::onAddedDirty(context); - if (code != StatusCode::Ok) { - return code; - } - return StatusCode::Ok; -} - StatusCode Path::onAddedClean(CoreContext* context) { StatusCode code = Super::onAddedClean(context); if (code != StatusCode::Ok) { @@ -91,10 +83,10 @@ Vec2D pos = point.renderTranslation(); - Vec2D toPrev = (prev->is<CubicVertex>() - ? prev->as<CubicVertex>()->renderOut() - : prev->renderTranslation()) - - pos; + Vec2D toPrev = + (prev->is<CubicVertex>() ? prev->as<CubicVertex>()->renderOut() + : prev->renderTranslation()) - + pos; auto toPrevLength = toPrev.length(); toPrev[0] /= toPrevLength; @@ -102,10 +94,10 @@ auto next = vertices[1]; - Vec2D toNext = (next->is<CubicVertex>() - ? next->as<CubicVertex>()->renderIn() - : next->renderTranslation()) - - pos; + Vec2D toNext = + (next->is<CubicVertex>() ? next->as<CubicVertex>()->renderIn() + : next->renderTranslation()) - + pos; auto toNextLength = toNext.length(); toNext[0] /= toNextLength; toNext[1] /= toNextLength; @@ -117,8 +109,10 @@ commandPath.moveTo(startInX = startX = translation[0], startInY = startY = translation[1]); - Vec2D outPoint = Vec2D::scaleAndAdd(pos, toPrev, icircleConstant * renderRadius); - Vec2D inPoint = Vec2D::scaleAndAdd(pos, toNext, icircleConstant * renderRadius); + Vec2D outPoint = + Vec2D::scaleAndAdd(pos, toPrev, icircleConstant * renderRadius); + Vec2D inPoint = + Vec2D::scaleAndAdd(pos, toNext, icircleConstant * renderRadius); Vec2D posNext = Vec2D::scaleAndAdd(pos, toNext, renderRadius); commandPath.cubicTo(outPoint[0], outPoint[1], @@ -167,8 +161,8 @@ Vec2D toNext = (next->is<CubicVertex>() ? next->as<CubicVertex>()->renderIn() - : next->renderTranslation()) - - pos; + : next->renderTranslation()) - + pos; auto toNextLength = toNext.length(); toNext[0] /= toNextLength; toNext[1] /= toNextLength; @@ -176,7 +170,8 @@ float renderRadius = std::min(toPrevLength, std::min(toNextLength, radius)); - Vec2D translation = Vec2D::scaleAndAdd(pos, toPrev, renderRadius); + Vec2D translation = + Vec2D::scaleAndAdd(pos, toPrev, renderRadius); if (prevIsCubic) { commandPath.cubicTo(outX, outY, @@ -188,8 +183,10 @@ commandPath.lineTo(translation[0], translation[1]); } - Vec2D outPoint = Vec2D::scaleAndAdd(pos, toPrev, icircleConstant * renderRadius); - Vec2D inPoint = Vec2D::scaleAndAdd(pos, toNext, icircleConstant * renderRadius); + Vec2D outPoint = Vec2D::scaleAndAdd( + pos, toPrev, icircleConstant * renderRadius); + Vec2D inPoint = Vec2D::scaleAndAdd( + pos, toNext, icircleConstant * renderRadius); Vec2D posNext = Vec2D::scaleAndAdd(pos, toNext, renderRadius); commandPath.cubicTo(outPoint[0], outPoint[1], @@ -325,9 +322,11 @@ auto renderRadius = std::min( toPrevLength, std::min(toNextLength, point.radius())); - Vec2D translation = Vec2D::scaleAndAdd(pos, toPrev, renderRadius); + Vec2D translation = + Vec2D::scaleAndAdd(pos, toPrev, renderRadius); - Vec2D out = Vec2D::scaleAndAdd(pos, toPrev, icircleConstant * renderRadius); + Vec2D out = Vec2D::scaleAndAdd( + pos, toPrev, icircleConstant * renderRadius); { auto v1 = new DisplayCubicVertex( translation, out, translation); @@ -337,7 +336,8 @@ translation = Vec2D::scaleAndAdd(pos, toNext, renderRadius); - Vec2D in = Vec2D::scaleAndAdd(pos, toNext, icircleConstant * renderRadius); + Vec2D in = Vec2D::scaleAndAdd( + pos, toNext, icircleConstant * renderRadius); auto v2 = new DisplayCubicVertex(in, translation, translation);
diff --git a/src/shapes/path_vertex.cpp b/src/shapes/path_vertex.cpp index 32f90a4..6e070b3 100644 --- a/src/shapes/path_vertex.cpp +++ b/src/shapes/path_vertex.cpp
@@ -3,13 +3,6 @@ using namespace rive; -Vec2D PathVertex::renderTranslation() { - if (hasWeight()) { - return m_Weight->translation(); - } - return Vec2D(x(), y()); -} - StatusCode PathVertex::onAddedDirty(CoreContext* context) { StatusCode code = Super::onAddedDirty(context); if (code != StatusCode::Ok) { @@ -22,25 +15,11 @@ return StatusCode::Ok; } -void PathVertex::markPathDirty() { +void PathVertex::markGeometryDirty() { if (parent() == nullptr) { // This is an acceptable condition as the parametric paths create points // that are not part of the core context. return; } parent()->as<Path>()->markPathDirty(); -} - -void PathVertex::xChanged() { markPathDirty(); } -void PathVertex::yChanged() { markPathDirty(); } - -void PathVertex::deform(const Mat2D& worldTransform, - const float* boneTransforms) { - Weight::deform(x(), - y(), - m_Weight->indices(), - m_Weight->values(), - worldTransform, - boneTransforms, - m_Weight->translation()); } \ No newline at end of file
diff --git a/src/shapes/straight_vertex.cpp b/src/shapes/straight_vertex.cpp index 07d0d2b..30c30cd 100644 --- a/src/shapes/straight_vertex.cpp +++ b/src/shapes/straight_vertex.cpp
@@ -2,4 +2,4 @@ using namespace rive; -void StraightVertex::radiusChanged() { markPathDirty(); } +void StraightVertex::radiusChanged() { markGeometryDirty(); }
diff --git a/src/shapes/vertex.cpp b/src/shapes/vertex.cpp new file mode 100644 index 0000000..4375555 --- /dev/null +++ b/src/shapes/vertex.cpp
@@ -0,0 +1,23 @@ +#include "rive/shapes/vertex.hpp" + +using namespace rive; + +Vec2D Vertex::renderTranslation() { + if (hasWeight()) { + return m_Weight->translation(); + } + return Vec2D(x(), y()); +} + +void Vertex::xChanged() { markGeometryDirty(); } +void Vertex::yChanged() { markGeometryDirty(); } + +void Vertex::deform(const Mat2D& worldTransform, const float* boneTransforms) { + Weight::deform(x(), + y(), + m_Weight->indices(), + m_Weight->values(), + worldTransform, + boneTransforms, + m_Weight->translation()); +} \ No newline at end of file
diff --git a/test/assets/tape.riv b/test/assets/tape.riv new file mode 100644 index 0000000..cd4fd79 --- /dev/null +++ b/test/assets/tape.riv Binary files differ
diff --git a/test/image_mesh_test.cpp b/test/image_mesh_test.cpp new file mode 100644 index 0000000..3a983c7 --- /dev/null +++ b/test/image_mesh_test.cpp
@@ -0,0 +1,27 @@ +#include <rive/core/binary_reader.hpp> +#include <rive/file.hpp> +#include <rive/node.hpp> +#include <rive/shapes/clipping_shape.hpp> +#include <rive/shapes/rectangle.hpp> +#include <rive/shapes/image.hpp> +#include <rive/shapes/mesh.hpp> +#include <rive/assets/image_asset.hpp> +#include <rive/relative_local_asset_resolver.hpp> +#include "no_op_renderer.hpp" +#include "rive_file_reader.hpp" +#include <catch.hpp> +#include <cstdio> + +TEST_CASE("image with mesh loads correctly", "[assets]") { + RiveFileReader reader("../../test/assets/tape.riv"); + auto file = reader.file(); + + auto node = file->artboard()->find("Tape body.png"); + REQUIRE(node != nullptr); + REQUIRE(node->is<rive::Image>()); + auto tape = node->as<rive::Image>(); + REQUIRE(tape->imageAsset() != nullptr); + REQUIRE(tape->imageAsset()->decodedByteSize == 70903); + REQUIRE(tape->mesh() != nullptr); + REQUIRE(tape->mesh()->vertices().size() == 24); +}