Skip to content

Commit

Permalink
Merge branch 'main' into editor-save-value
Browse files Browse the repository at this point in the history
  • Loading branch information
matgis committed May 20, 2024
2 parents a7cfcd8 + abc75a1 commit c9b8689
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 464 deletions.
245 changes: 174 additions & 71 deletions defold-spine/commonsrc/vertices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@

#include <spine/extension.h>
#include <spine/Skeleton.h>
#include <spine/SkeletonClipping.h>
#include <spine/Slot.h>
#include <spine/Attachment.h>
#include <spine/MeshAttachment.h>
#include <spine/RegionAttachment.h>

#include <float.h> // using FLT_MAX
#include <dmsdk/dlib/math.h>

namespace dmSpine
{
static const uint32_t ATTACHMENT_REGION_NUM_FLOATS = 4*2;
static const uint16_t QUAD_INDICES[] = {0, 1, 2, 2, 3, 0};

static inline void addVertex(dmSpine::SpineVertex* vertex, float x, float y, float u, float v, float r, float g, float b, float a, float page_index)
{
Expand Down Expand Up @@ -38,11 +42,20 @@ static uint32_t EnsureArrayFitsNumber(dmArray<T>& array, uint32_t num_to_add)
return prev_size;
}

template <typename T>
static void EnsureArraySize(dmArray<T>& array, uint32_t size)
{
if (array.Capacity() < size)
{
array.SetCapacity(size);
}
array.SetSize(size);
}

void GetSkeletonBounds(const spSkeleton* skeleton, SpineModelBounds& bounds)
{
dmArray<float> scratch; // scratch buffer
EnsureArrayFitsNumber(scratch, 4*2); // this is enough for "SP_ATTACHMENT_REGION"
EnsureArrayFitsNumber(scratch, ATTACHMENT_REGION_NUM_FLOATS); // this is enough for "SP_ATTACHMENT_REGION"

// a "negative" bounding rectangle for starters
bounds.minX = FLT_MAX;
Expand Down Expand Up @@ -111,36 +124,109 @@ void GetSkeletonBounds(const spSkeleton* skeleton, SpineModelBounds& bounds)
}
}
}
}

static void CalcAndAddVertexBufferAttachment(spAttachment* attachment, uint32_t* out_count, uint32_t* out_max_triangle_count)
{
if (attachment->type == SP_ATTACHMENT_REGION)
{
*out_count += 6;
}
else if (attachment->type == SP_ATTACHMENT_MESH)
{
spMeshAttachment* mesh = (spMeshAttachment*)attachment;
uint32_t num_tri_vertices = SUPER(mesh)->worldVerticesLength;
*out_count += (uint32_t)mesh->trianglesCount; // It's a list of indices, where each 3-tuple define a triangle

if (num_tri_vertices > *out_max_triangle_count)
{
*out_max_triangle_count = num_tri_vertices;
}
}
}

uint32_t CalcVertexBufferSize(const spSkeleton* skeleton, uint32_t* out_max_triangle_count)
static void CalcAndAddVertexBufferAttachmentByClipper(dmArray<float>& scratch, spSlot* slot, spAttachment* attachment, spSkeletonClipping* skeleton_clipper, uint32_t* out_count, uint32_t* out_max_triangle_count)
{
uint32_t count = 0;
float page_index = 0;
uint16_t* indices = 0;
uint32_t vertex_count = 0;
uint32_t indices_count = 0;
float* uvs = 0;
float* vertices = 0;

if (attachment->type == SP_ATTACHMENT_REGION)
{
EnsureArraySize(scratch, ATTACHMENT_REGION_NUM_FLOATS);
spRegionAttachment* regionAttachment = (spRegionAttachment*)attachment;
spRegionAttachment_computeWorldVertices(regionAttachment, slot, scratch.Begin(), 0, 2);

vertex_count = 4;
uvs = regionAttachment->uvs;
indices = (uint16_t*) QUAD_INDICES;
indices_count = 6;
vertices = scratch.Begin();
}
else if (attachment->type == SP_ATTACHMENT_MESH)
{
spMeshAttachment *mesh = (spMeshAttachment *) attachment;
EnsureArraySize(scratch, mesh->super.worldVerticesLength);
spVertexAttachment_computeWorldVertices(SUPER(mesh), slot, 0, mesh->super.worldVerticesLength, scratch.Begin(), 0, 2);

vertex_count = mesh->super.worldVerticesLength >> 1;
uvs = mesh->uvs;
indices = mesh->triangles;
indices_count = mesh->trianglesCount;
vertices = scratch.Begin();
}

spSkeletonClipping_clipTriangles(skeleton_clipper, vertices, vertex_count << 1, indices, indices_count, uvs, 2);
vertex_count = skeleton_clipper->clippedVertices->size >> 1;
indices_count = skeleton_clipper->clippedTriangles->size;

*out_count += indices_count;
*out_max_triangle_count = dmMath::Max(*out_max_triangle_count, indices_count) * 2;
}

uint32_t CalcVertexBufferSize(const spSkeleton* skeleton, spSkeletonClipping* skeleton_clipper, uint32_t* out_max_triangle_count)
{
// This scratch buffer is used to calculate number of verties if the skeleton has a clipper attachment
// We don't know the number of vertices and indices unless we do the actual clipping, so we need somewhere
// to store the intermediate position floats until clipping is done.
dmArray<float> scratch_attachment;
uint32_t vertex_count = 0;
uint32_t max_triangle_count = 8;

for (int s = 0; s < skeleton->slotsCount; ++s)
{
spSlot* slot = skeleton->drawOrder[s];

spAttachment* attachment = slot->attachment;
if (!attachment)continue;
if (attachment->type == SP_ATTACHMENT_REGION)

if (!attachment)
{
count += 6;
continue;
}
else if (attachment->type == SP_ATTACHMENT_MESH)

if (attachment->type == SP_ATTACHMENT_CLIPPING)
{
spMeshAttachment* mesh = (spMeshAttachment*)attachment;
uint32_t num_tri_vertices = SUPER(mesh)->worldVerticesLength;
spClippingAttachment* clip = (spClippingAttachment*) attachment;
spSkeletonClipping_clipStart(skeleton_clipper, slot, clip);
continue;
}

count += (uint32_t)mesh->trianglesCount; // It's a list of indices, where each 3-tuple define a triangle
if (num_tri_vertices > max_triangle_count)
max_triangle_count = num_tri_vertices;
if (spSkeletonClipping_isClipping(skeleton_clipper))
{
CalcAndAddVertexBufferAttachmentByClipper(scratch_attachment, slot, attachment, skeleton_clipper, &vertex_count, &max_triangle_count);
}
else
{
CalcAndAddVertexBufferAttachment(attachment, &vertex_count, &max_triangle_count);
}
}
if (out_max_triangle_count)
{
*out_max_triangle_count = max_triangle_count;
return count;
}
return vertex_count;
}

uint32_t CalcDrawDescCount(const spSkeleton* skeleton)
Expand All @@ -150,25 +236,24 @@ uint32_t CalcDrawDescCount(const spSkeleton* skeleton)
{
spSlot* slot = skeleton->drawOrder[s];
spAttachment* attachment = slot->attachment;
if (!attachment)

if (attachment && (attachment->type == SP_ATTACHMENT_REGION || attachment->type == SP_ATTACHMENT_MESH))
{
continue;
count++;
}
count++;
}
return count;
}

uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleton* skeleton, const dmVMath::Matrix4& world, dmArray<SpineDrawDesc>* draw_descs_out)
uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleton* skeleton, spSkeletonClipping* skeleton_clipper, const dmVMath::Matrix4& world, dmArray<SpineDrawDesc>* draw_descs_out)
{
dmArray<float> scratch; // scratch buffer

int vindex = vertex_buffer.Size();
int vindex_start = vindex;

dmArray<float> scratch_vertex_floats;
int vindex = vertex_buffer.Size();
int vindex_start = vindex;
uint32_t max_triangle_count = 0;
uint32_t estimated_vcount = CalcVertexBufferSize(skeleton, &max_triangle_count);
EnsureArrayFitsNumber(scratch, max_triangle_count);
uint32_t estimated_vcount = CalcVertexBufferSize(skeleton, skeleton_clipper, &max_triangle_count);

EnsureArrayFitsNumber(scratch_vertex_floats, max_triangle_count);
EnsureArrayFitsNumber(vertex_buffer, estimated_vcount);

// For each slot in the draw order array of the skeleton
Expand Down Expand Up @@ -196,74 +281,84 @@ uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleto
float tintB = skeleton->color.b * slot->color.b;
float tintA = skeleton->color.a * slot->color.a;

float page_index = 0;
spColor* color = 0x0;
uint16_t* indices = 0;
uint32_t vertex_count = 0;
uint32_t indices_count = 0;
float* uvs = 0;
float* vertices = 0;

// Fill the vertices array depending on the type of attachment
//Texture* texture = 0;
if (attachment->type == SP_ATTACHMENT_REGION)
{
// Cast to an spRegionAttachment so we can get the rendererObject
// and compute the world vertices
spRegionAttachment* regionAttachment = (spRegionAttachment*)attachment;
const float* uvs = regionAttachment->uvs;

float colorR = tintR * regionAttachment->color.r;
float colorG = tintG * regionAttachment->color.g;
float colorB = tintB * regionAttachment->color.b;
float colorA = tintA * regionAttachment->color.a;

float page_index = 0;

// Computed the world vertices positions for the 4 vertices that make up
// the rectangular region attachment. This assumes the world transform of the
// bone to which the slot (and hence attachment) is attached has been calculated
// before rendering via spSkeleton_updateWorldTransform
spRegionAttachment_computeWorldVertices(regionAttachment, slot, scratch.Begin(), 0, 2);

// Create 2 triangles, with 3 vertices each from the region's
// world vertex positions and its UV coordinates (in the range [0-1]).
addVertex(&vertex_buffer[vindex++], scratch[0], scratch[1], uvs[0], uvs[1], colorR, colorG, colorB, colorA, page_index);
addVertex(&vertex_buffer[vindex++], scratch[2], scratch[3], uvs[2], uvs[3], colorR, colorG, colorB, colorA, page_index);
addVertex(&vertex_buffer[vindex++], scratch[4], scratch[5], uvs[4], uvs[5], colorR, colorG, colorB, colorA, page_index);

addVertex(&vertex_buffer[vindex++], scratch[4], scratch[5], uvs[4], uvs[5], colorR, colorG, colorB, colorA, page_index);
addVertex(&vertex_buffer[vindex++], scratch[6], scratch[7], uvs[6], uvs[7], colorR, colorG, colorB, colorA, page_index);
addVertex(&vertex_buffer[vindex++], scratch[0], scratch[1], uvs[0], uvs[1], colorR, colorG, colorB, colorA, page_index);
spRegionAttachment_computeWorldVertices(regionAttachment, slot, scratch_vertex_floats.Begin(), 0, 2);

vertex_count = 4;
uvs = regionAttachment->uvs;
indices = (uint16_t*) QUAD_INDICES;
indices_count = 6;
color = &regionAttachment->color;
vertices = scratch_vertex_floats.Begin();
}
else if (attachment->type == SP_ATTACHMENT_MESH)
{
// Cast to an spMeshAttachment so we can get the rendererObject
// and compute the world vertices
spMeshAttachment* mesh = (spMeshAttachment*)attachment;
spMeshAttachment* mesh = (spMeshAttachment*) attachment;

int num_world_vertices = SUPER(mesh)->worldVerticesLength / 2;
spVertexAttachment_computeWorldVertices(SUPER(mesh), slot, 0, mesh->super.worldVerticesLength, scratch_vertex_floats.Begin(), 0, 2);

vertex_count = num_world_vertices;
uvs = mesh->uvs;
indices = mesh->triangles;
indices_count = mesh->trianglesCount;
color = &mesh->color;
vertices = scratch_vertex_floats.Begin();
}
else if (attachment->type == SP_ATTACHMENT_CLIPPING)
{
// Clipper setup is very similar to this:
// https://github.com/EsotericSoftware/spine-runtimes/blob/4.0/spine-sfml/c/src/spine/spine-sfml.cpp#L293
spClippingAttachment* clip = (spClippingAttachment*) attachment;
spSkeletonClipping_clipStart(skeleton_clipper, slot, clip);
continue;
}
else
{
continue;
}

// Computed the world vertices positions for the vertices that make up
// the mesh attachment. This assumes the world transform of the
// bone to which the slot (and hence attachment) is attached has been calculated
// before rendering via spSkeleton_updateWorldTransform

spVertexAttachment_computeWorldVertices(SUPER(mesh), slot, 0, num_world_vertices*2, scratch.Begin(), 0, 2);

//dmLogWarning("Get num_world_vertices %u scratch size: %u", num_world_vertices*2, scratch.Size());

// Mesh attachments use an array of vertices, and an array of indices to define which
// 3 vertices make up each triangle. We loop through all triangle indices
// and simply emit a vertex for each triangle's vertex.

float colorR = tintR * mesh->color.r;
float colorG = tintG * mesh->color.g;
float colorB = tintB * mesh->color.b;
float colorA = tintA * mesh->color.a;
if (spSkeletonClipping_isClipping(skeleton_clipper))
{
spSkeletonClipping_clipTriangles(skeleton_clipper, vertices, vertex_count << 1, indices, indices_count, uvs, 2);

float page_index = 0;
vertices = skeleton_clipper->clippedVertices->items;
vertex_count = skeleton_clipper->clippedVertices->size >> 1;
uvs = skeleton_clipper->clippedUVs->items;
indices = skeleton_clipper->clippedTriangles->items;
indices_count = skeleton_clipper->clippedTriangles->size;
}

const float* uvs = mesh->uvs;
int tri_count = mesh->trianglesCount;
for (int t = 0; t < tri_count; ++t)
{
int index = mesh->triangles[t] << 1;
const float colorR = tintR * color->r;
const float colorG = tintG * color->g;
const float colorB = tintB * color->b;
const float colorA = tintA * color->a;

addVertex(&vertex_buffer[vindex++], scratch[index], scratch[index + 1], uvs[index], uvs[index + 1], colorR, colorG, colorB, colorA, page_index);
}
for (int i = 0; i < indices_count; ++i)
{
int index = indices[i] << 1;
addVertex(&vertex_buffer[vindex++], vertices[index], vertices[index + 1], uvs[index], uvs[index + 1], colorR, colorG, colorB, colorA, page_index);
}

if (draw_descs_out)
Expand All @@ -274,8 +369,11 @@ uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleto
desc.m_VertexCount = vindex - batch_vindex_start;
draw_descs_out->Push(desc);
}

spSkeletonClipping_clipEnd(skeleton_clipper, slot);
}
scratch.SetSize(0);

spSkeletonClipping_clipEnd2(skeleton_clipper);

const dmVMath::Matrix4& w = world;

Expand Down Expand Up @@ -303,6 +401,11 @@ void MergeDrawDescs(const dmArray<SpineDrawDesc>& src, dmArray<SpineDrawDesc>& d
dst.SetCapacity(src.Size());
dst.SetSize(src.Size());

if (src.Size() == 0)
{
return;
}

SpineDrawDesc* current_draw_desc = dst.Begin();
*current_draw_desc = src[0];

Expand Down
5 changes: 3 additions & 2 deletions defold-spine/include/common/vertices.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <dmsdk/dlib/vmath.h>

struct spSkeleton;
struct spSkeletonClipping;

namespace dmSpine
{
Expand Down Expand Up @@ -33,9 +34,9 @@ struct SpineDrawDesc
uint32_t m_BlendMode; // spBlendMode
};

uint32_t CalcVertexBufferSize(const spSkeleton* skeleton, uint32_t* out_max_triangle_count);
uint32_t CalcVertexBufferSize(const spSkeleton* skeleton, spSkeletonClipping* skeleton_clipper, uint32_t* out_max_triangle_count);
uint32_t CalcDrawDescCount(const spSkeleton* skeleton);
uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleton* skeleton, const dmVMath::Matrix4& world, dmArray<SpineDrawDesc>* draw_descs);
uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleton* skeleton, spSkeletonClipping* skeleton_clipper, const dmVMath::Matrix4& world, dmArray<SpineDrawDesc>* draw_descs);
void GetSkeletonBounds(const spSkeleton* skeleton, SpineModelBounds& bounds);
void MergeDrawDescs(const dmArray<SpineDrawDesc>& src, dmArray<SpineDrawDesc>& dst);

Expand Down
Binary file modified defold-spine/plugins/lib/arm64-osx/libSpineExt.dylib
Binary file not shown.
Binary file modified defold-spine/plugins/lib/x86_64-linux/libSpineExt.so
Binary file not shown.
Binary file modified defold-spine/plugins/lib/x86_64-osx/libSpineExt.dylib
Binary file not shown.
Binary file modified defold-spine/plugins/lib/x86_64-win32/libSpineExt.dll
Binary file not shown.
Binary file modified defold-spine/plugins/share/pluginSpineExt.jar
Binary file not shown.
Loading

0 comments on commit c9b8689

Please sign in to comment.