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);
+}