spine-c updated to v3.1.

This commit is contained in:
NathanSweet 2016-04-15 12:19:43 +02:00
parent ca0372c415
commit 421789e6f7
17 changed files with 416 additions and 239 deletions

View File

@ -12,7 +12,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version ## Spine version
spine-c works with data exported from the latest version of Spine, except linked meshes are [not yet supported](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes). spine-c works with data exported from the latest version of Spine.
spine-c supports all Spine features. spine-c supports all Spine features.

View File

@ -39,7 +39,12 @@ extern "C" {
struct spAttachmentLoader; struct spAttachmentLoader;
typedef enum { typedef enum {
SP_ATTACHMENT_REGION, SP_ATTACHMENT_BOUNDING_BOX, SP_ATTACHMENT_MESH, SP_ATTACHMENT_WEIGHTED_MESH SP_ATTACHMENT_REGION,
SP_ATTACHMENT_BOUNDING_BOX,
SP_ATTACHMENT_MESH,
SP_ATTACHMENT_WEIGHTED_MESH,
SP_ATTACHMENT_LINKED_MESH,
SP_ATTACHMENT_WEIGHTED_LINKED_MESH
} spAttachmentType; } spAttachmentType;
typedef struct spAttachment { typedef struct spAttachment {
@ -65,6 +70,8 @@ typedef spAttachmentType AttachmentType;
#define ATTACHMENT_BOUNDING_BOX SP_ATTACHMENT_BOUNDING_BOX #define ATTACHMENT_BOUNDING_BOX SP_ATTACHMENT_BOUNDING_BOX
#define ATTACHMENT_MESH SP_ATTACHMENT_MESH #define ATTACHMENT_MESH SP_ATTACHMENT_MESH
#define ATTACHMENT_WEIGHTED_MESH SP_ATTACHMENT_WEIGHTED_MESH #define ATTACHMENT_WEIGHTED_MESH SP_ATTACHMENT_WEIGHTED_MESH
#define ATTACHMENT_LINKED_MESH SP_ATTACHMENT_LINKED_MESH
#define ATTACHMENT_WEIGHTED_LINKED_MESH SP_ATTACHMENT_WEIGHTED_LINKED_MESH
typedef spAttachment Attachment; typedef spAttachment Attachment;
#define Attachment_dispose(...) spAttachment_dispose(__VA_ARGS__) #define Attachment_dispose(...) spAttachment_dispose(__VA_ARGS__)
#endif #endif

View File

@ -40,7 +40,8 @@
extern "C" { extern "C" {
#endif #endif
typedef struct spMeshAttachment { typedef struct spMeshAttachment spMeshAttachment;
struct spMeshAttachment {
spAttachment super; spAttachment super;
const char* path; const char* path;
@ -54,6 +55,9 @@ typedef struct spMeshAttachment {
int trianglesCount; int trianglesCount;
unsigned short* triangles; unsigned short* triangles;
spMeshAttachment* const parentMesh;
int/*bool*/inheritFFD;
float r, g, b, a; float r, g, b, a;
void* rendererObject; void* rendererObject;
@ -67,17 +71,19 @@ typedef struct spMeshAttachment {
int edgesCount; int edgesCount;
int* edges; int* edges;
float width, height; float width, height;
} spMeshAttachment; };
spMeshAttachment* spMeshAttachment_create (const char* name); spMeshAttachment* spMeshAttachment_create (const char* name);
void spMeshAttachment_updateUVs (spMeshAttachment* self); void spMeshAttachment_updateUVs (spMeshAttachment* self);
void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot, float* worldVertices); void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot, float* worldVertices);
void spMeshAttachment_setParentMesh (spMeshAttachment* self, spMeshAttachment* parentMesh);
#ifdef SPINE_SHORT_NAMES #ifdef SPINE_SHORT_NAMES
typedef spMeshAttachment MeshAttachment; typedef spMeshAttachment MeshAttachment;
#define MeshAttachment_create(...) spMeshAttachment_create(__VA_ARGS__) #define MeshAttachment_create(...) spMeshAttachment_create(__VA_ARGS__)
#define MeshAttachment_updateUVs(...) spMeshAttachment_updateUVs(__VA_ARGS__) #define MeshAttachment_updateUVs(...) spMeshAttachment_updateUVs(__VA_ARGS__)
#define MeshAttachment_computeWorldVertices(...) spMeshAttachment_computeWorldVertices(__VA_ARGS__) #define MeshAttachment_computeWorldVertices(...) spMeshAttachment_computeWorldVertices(__VA_ARGS__)
#define MeshAttachment_setParentMesh(...) spMeshAttachment_setParentMesh(__VA_ARGS__)
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -39,7 +39,8 @@
extern "C" { extern "C" {
#endif #endif
typedef struct spWeightedMeshAttachment { typedef struct spWeightedMeshAttachment spWeightedMeshAttachment;
struct spWeightedMeshAttachment {
spAttachment super; spAttachment super;
const char* path; const char* path;
@ -57,6 +58,9 @@ typedef struct spWeightedMeshAttachment {
float* uvs; float* uvs;
int hullLength; int hullLength;
spWeightedMeshAttachment* const parentMesh;
int/*bool*/inheritFFD;
float r, g, b, a; float r, g, b, a;
void* rendererObject; void* rendererObject;
@ -70,17 +74,19 @@ typedef struct spWeightedMeshAttachment {
int edgesCount; int edgesCount;
int* edges; int* edges;
float width, height; float width, height;
} spWeightedMeshAttachment; };
spWeightedMeshAttachment* spWeightedMeshAttachment_create (const char* name); spWeightedMeshAttachment* spWeightedMeshAttachment_create (const char* name);
void spWeightedMeshAttachment_updateUVs (spWeightedMeshAttachment* self); void spWeightedMeshAttachment_updateUVs (spWeightedMeshAttachment* self);
void spWeightedMeshAttachment_computeWorldVertices (spWeightedMeshAttachment* self, spSlot* slot, float* worldVertices); void spWeightedMeshAttachment_computeWorldVertices (spWeightedMeshAttachment* self, spSlot* slot, float* worldVertices);
void spWeightedMeshAttachment_setParentMesh (spWeightedMeshAttachment* self, spWeightedMeshAttachment* parentMesh);
#ifdef SPINE_SHORT_NAMES #ifdef SPINE_SHORT_NAMES
typedef spWeightedMeshAttachment WeightedMeshAttachment; typedef spWeightedMeshAttachment WeightedMeshAttachment;
#define WeightedMeshAttachment_create(...) spWeightedMeshAttachment_create(__VA_ARGS__) #define WeightedMeshAttachment_create(...) spWeightedMeshAttachment_create(__VA_ARGS__)
#define WeightedMeshAttachment_updateUVs(...) spWeightedMeshAttachment_updateUVs(__VA_ARGS__) #define WeightedMeshAttachment_updateUVs(...) spWeightedMeshAttachment_updateUVs(__VA_ARGS__)
#define WeightedMeshAttachment_computeWorldVertices(...) spWeightedMeshAttachment_computeWorldVertices(__VA_ARGS__) #define WeightedMeshAttachment_computeWorldVertices(...) spWeightedMeshAttachment_computeWorldVertices(__VA_ARGS__)
#define WeightedMeshAttachment_setParentMesh(...) spWeightedMeshAttachment_setParentMesh(__VA_ARGS__)
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -683,7 +683,24 @@ void _spFFDTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, flo
spFFDTimeline* self = (spFFDTimeline*)timeline; spFFDTimeline* self = (spFFDTimeline*)timeline;
spSlot *slot = skeleton->slots[self->slotIndex]; spSlot *slot = skeleton->slots[self->slotIndex];
if (slot->attachment != self->attachment) return;
if (slot->attachment != self->attachment) {
if (!slot->attachment) return;
switch (slot->attachment->type) {
case SP_ATTACHMENT_MESH: {
spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, slot->attachment);
if (!mesh->inheritFFD || mesh->parentMesh != (void*)self->attachment) return;
break;
}
case SP_ATTACHMENT_WEIGHTED_MESH: {
spWeightedMeshAttachment* mesh = SUB_CAST(spWeightedMeshAttachment, slot->attachment);
if (!mesh->inheritFFD || mesh->parentMesh != (void*)self->attachment) return;
break;
}
default:
return;
}
}
if (time < self->frames[0]) return; /* Time is before first frame. */ if (time < self->frames[0]) return; /* Time is before first frame. */

View File

@ -54,7 +54,8 @@ spAttachment* _spAtlasAttachmentLoader_createAttachment (spAttachmentLoader* loa
attachment->regionOriginalHeight = region->originalHeight; attachment->regionOriginalHeight = region->originalHeight;
return SUPER(attachment); return SUPER(attachment);
} }
case SP_ATTACHMENT_MESH: { case SP_ATTACHMENT_MESH:
case SP_ATTACHMENT_LINKED_MESH: {
spMeshAttachment* attachment; spMeshAttachment* attachment;
spAtlasRegion* region = spAtlas_findRegion(self->atlas, path); spAtlasRegion* region = spAtlas_findRegion(self->atlas, path);
if (!region) { if (!region) {
@ -76,7 +77,8 @@ spAttachment* _spAtlasAttachmentLoader_createAttachment (spAttachmentLoader* loa
attachment->regionOriginalHeight = region->originalHeight; attachment->regionOriginalHeight = region->originalHeight;
return SUPER(attachment); return SUPER(attachment);
} }
case SP_ATTACHMENT_WEIGHTED_MESH: { case SP_ATTACHMENT_WEIGHTED_MESH:
case SP_ATTACHMENT_WEIGHTED_LINKED_MESH: {
spWeightedMeshAttachment* attachment; spWeightedMeshAttachment* attachment;
spAtlasRegion* region = spAtlas_findRegion(self->atlas, path); spAtlasRegion* region = spAtlas_findRegion(self->atlas, path);
if (!region) { if (!region) {

View File

@ -108,7 +108,8 @@ void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rota
CONST_CAST(float, self->b) = pa * lb + pb * ld; CONST_CAST(float, self->b) = pa * lb + pb * ld;
CONST_CAST(float, self->c) = pc * la + pd * lc; CONST_CAST(float, self->c) = pc * la + pd * lc;
CONST_CAST(float, self->d) = pc * lb + pd * ld; CONST_CAST(float, self->d) = pc * lb + pd * ld;
} else if (self->data->inheritRotation) { /* No scale inheritance. */ } else {
if (self->data->inheritRotation) { /* No scale inheritance. */
pa = 1; pa = 1;
pb = 0; pb = 0;
pc = 0; pc = 0;
@ -130,14 +131,6 @@ void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rota
CONST_CAST(float, self->b) = pa * lb + pb * ld; CONST_CAST(float, self->b) = pa * lb + pb * ld;
CONST_CAST(float, self->c) = pc * la + pd * lc; CONST_CAST(float, self->c) = pc * la + pd * lc;
CONST_CAST(float, self->d) = pc * lb + pd * ld; CONST_CAST(float, self->d) = pc * lb + pd * ld;
if (self->skeleton->flipX) {
CONST_CAST(float, self->a) = -self->a;
CONST_CAST(float, self->b) = -self->b;
}
if (self->skeleton->flipY != yDown) {
CONST_CAST(float, self->c) = -self->c;
CONST_CAST(float, self->d) = -self->d;
}
} else if (self->data->inheritScale) { /* No rotation inheritance. */ } else if (self->data->inheritScale) { /* No rotation inheritance. */
pa = 1; pa = 1;
pb = 0; pb = 0;
@ -177,6 +170,12 @@ void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rota
CONST_CAST(float, self->b) = pa * lb + pb * ld; CONST_CAST(float, self->b) = pa * lb + pb * ld;
CONST_CAST(float, self->c) = pc * la + pd * lc; CONST_CAST(float, self->c) = pc * la + pd * lc;
CONST_CAST(float, self->d) = pc * lb + pd * ld; CONST_CAST(float, self->d) = pc * lb + pd * ld;
} else {
CONST_CAST(float, self->a) = la;
CONST_CAST(float, self->b) = lb;
CONST_CAST(float, self->c) = lc;
CONST_CAST(float, self->d) = ld;
}
if (self->skeleton->flipX) { if (self->skeleton->flipX) {
CONST_CAST(float, self->a) = -self->a; CONST_CAST(float, self->a) = -self->a;
CONST_CAST(float, self->b) = -self->b; CONST_CAST(float, self->b) = -self->b;
@ -185,11 +184,6 @@ void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rota
CONST_CAST(float, self->c) = -self->c; CONST_CAST(float, self->c) = -self->c;
CONST_CAST(float, self->d) = -self->d; CONST_CAST(float, self->d) = -self->d;
} }
} else {
CONST_CAST(float, self->a) = la;
CONST_CAST(float, self->b) = lb;
CONST_CAST(float, self->c) = lc;
CONST_CAST(float, self->d) = ld;
} }
} }

View File

@ -80,47 +80,54 @@ void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float al
} }
void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, float alpha) { void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, float alpha) {
float px = parent->x, py = parent->y, psx = parent->scaleX, psy = parent->scaleY, csx = child->scaleX, cy = child->y; float px = parent->x, py = parent->y, psx = parent->scaleX, psy = parent->scaleY;
int offset1, offset2, sign2; float cx = child->x, cy = child->y, csx = child->appliedScaleX, cwx = child->worldX, cwy = child->worldY;
int o1, o2, s2, u;
spBone* pp = parent->parent; spBone* pp = parent->parent;
float tx, ty, dx, dy, l1, l2, a1, a2, psd, r; float tx, ty, dx, dy, l1, l2, a1, a2, r;
if (alpha == 0) return; if (alpha == 0) return;
if (psx < 0) { if (psx < 0) {
psx = -psx; psx = -psx;
offset1 = 180; o1 = 180;
sign2 = -1; s2 = -1;
} else { } else {
offset1 = 0; o1 = 0;
sign2 = 1; s2 = 1;
} }
if (psy < 0) { if (psy < 0) {
psy = -psy; psy = -psy;
sign2 = -sign2; s2 = -s2;
}
u = psx - psy;
u = u < 0 ? -u : u <= 0.0001f;
if (!u && cy != 0) {
cwx = parent->a * cx + parent->worldX;
cwy = parent->c * cx + parent->worldY;
cy = 0;
} }
if (csx < 0) { if (csx < 0) {
csx = -csx; csx = -csx;
offset2 = 180; o2 = 180;
} else } else
offset2 = 0; o2 = 0;
if (!pp) { if (!pp) {
tx = targetX - px; tx = targetX - px;
ty = targetY - py; ty = targetY - py;
dx = child->worldX - px; dx = cwx - px;
dy = child->worldY - py; dy = cwy - py;
} else { } else {
float a = pp->a, b = pp->b, c = pp->c, d = pp->d, invDet = 1 / (a * d - b * c); float a = pp->a, b = pp->b, c = pp->c, d = pp->d, invDet = 1 / (a * d - b * c);
float wx = pp->worldX, wy = pp->worldY, x = targetX - wx, y = targetY - wy; float wx = pp->worldX, wy = pp->worldY, x = targetX - wx, y = targetY - wy;
tx = (x * d - y * b) * invDet - px; tx = (x * d - y * b) * invDet - px;
ty = (y * a - x * c) * invDet - py; ty = (y * a - x * c) * invDet - py;
x = child->worldX - wx; x = cwx - wx;
y = child->worldY - wy; y = cwy - wy;
dx = (x * d - y * b) * invDet - px; dx = (x * d - y * b) * invDet - px;
dy = (y * a - x * c) * invDet - py; dy = (y * a - x * c) * invDet - py;
} }
l1 = SQRT(dx * dx + dy * dy); l1 = SQRT(dx * dx + dy * dy);
l2 = child->data->length * csx; l2 = child->data->length * csx;
psd = psx - psy; if (u) {
if (psd < 0 ? -psd : psd <= 0.0001f) {
float cos, a, o; float cos, a, o;
l2 *= psx; l2 *= psx;
cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2);
@ -138,7 +145,6 @@ void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float
float minAngle = 0, minDist = FLT_MAX, minX = 0, minY = 0; float minAngle = 0, minDist = FLT_MAX, minX = 0, minY = 0;
float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0;
float x = l1 + a, dist = x * x, angle, y; float x = l1 + a, dist = x * x, angle, y;
cy = 0;
if (d >= 0) { if (d >= 0) {
float q = SQRT(d), r0, r1, ar0, ar1;; float q = SQRT(d), r0, r1, ar0, ar1;;
if (c1 < 0) q = -q; if (c1 < 0) q = -q;
@ -192,16 +198,16 @@ void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float
} }
} }
outer: { outer: {
float offset = ATAN2(cy, child->x) * sign2; float offset = ATAN2(cy, child->x) * s2;
a1 = (a1 - offset) * RAD_DEG + offset1; a1 = (a1 - offset) * RAD_DEG + o1;
a2 = (a2 + offset) * RAD_DEG * sign2 + offset2; a2 = (a2 + offset) * RAD_DEG * s2 + o2;
if (a1 > 180) a1 -= 360; if (a1 > 180) a1 -= 360;
else if (a1 < -180) a1 += 360; else if (a1 < -180) a1 += 360;
if (a2 > 180) a2 -= 360; if (a2 > 180) a2 -= 360;
else if (a2 < -180) a2 += 360; else if (a2 < -180) a2 += 360;
r = parent->rotation; r = parent->rotation;
spBone_updateWorldTransformWith(parent, parent->x, parent->y, r + (a1 - r) * alpha, parent->scaleX, parent->scaleY); spBone_updateWorldTransformWith(parent, px, py, r + (a1 - r) * alpha, parent->appliedScaleX, parent->appliedScaleY);
r = child->rotation; r = child->rotation;
spBone_updateWorldTransformWith(child, child->x, cy, r + (a2 - r) * alpha, child->scaleX, child->scaleY); spBone_updateWorldTransformWith(child, cx, cy, r + (a2 - r) * alpha, child->appliedScaleX, child->appliedScaleY);
} }
} }

View File

@ -36,11 +36,13 @@ void _spMeshAttachment_dispose (spAttachment* attachment) {
spMeshAttachment* self = SUB_CAST(spMeshAttachment, attachment); spMeshAttachment* self = SUB_CAST(spMeshAttachment, attachment);
_spAttachment_deinit(attachment); _spAttachment_deinit(attachment);
FREE(self->path); FREE(self->path);
FREE(self->uvs);
if (!self->parentMesh) {
FREE(self->vertices); FREE(self->vertices);
FREE(self->regionUVs); FREE(self->regionUVs);
FREE(self->uvs);
FREE(self->triangles); FREE(self->triangles);
FREE(self->edges); FREE(self->edges);
}
FREE(self); FREE(self);
} }
@ -84,3 +86,23 @@ void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot
worldVertices[i + 1] = vx * bone->c + vy * bone->d + y; worldVertices[i + 1] = vx * bone->c + vy * bone->d + y;
} }
} }
void spMeshAttachment_setParentMesh (spMeshAttachment* self, spMeshAttachment* parentMesh) {
CONST_CAST(spMeshAttachment*, self->parentMesh) = parentMesh;
if (parentMesh) {
self->vertices = parentMesh->vertices;
self->regionUVs = parentMesh->regionUVs;
self->verticesCount = parentMesh->verticesCount;
self->triangles = parentMesh->triangles;
self->trianglesCount = parentMesh->trianglesCount;
self->hullLength = parentMesh->hullLength;
self->edges = parentMesh->edges;
self->edgesCount = parentMesh->edgesCount;
self->width = parentMesh->width;
self->height = parentMesh->height;
}
}

View File

@ -37,12 +37,16 @@ typedef enum {
SP_UPDATE_BONE, SP_UPDATE_IK_CONSTRAINT, SP_UPDATE_TRANSFORM_CONSTRAINT SP_UPDATE_BONE, SP_UPDATE_IK_CONSTRAINT, SP_UPDATE_TRANSFORM_CONSTRAINT
} _spUpdateType; } _spUpdateType;
typedef struct {
_spUpdateType type;
void* object;
} _spUpdate;
typedef struct { typedef struct {
spSkeleton super; spSkeleton super;
int updateCacheCount; int updateCacheCount;
void** updateCache; _spUpdate* updateCache;
_spUpdateType* updateCacheType;
} _spSkeleton; } _spSkeleton;
spSkeleton* spSkeleton_create (spSkeletonData* data) { spSkeleton* spSkeleton_create (spSkeletonData* data) {
@ -115,7 +119,6 @@ void spSkeleton_dispose (spSkeleton* self) {
_spSkeleton* internal = SUB_CAST(_spSkeleton, self); _spSkeleton* internal = SUB_CAST(_spSkeleton, self);
FREE(internal->updateCache); FREE(internal->updateCache);
FREE(internal->updateCacheType);
for (i = 0; i < self->bonesCount; ++i) for (i = 0; i < self->bonesCount; ++i)
spBone_dispose(self->bones[i]); spBone_dispose(self->bones[i]);
@ -139,24 +142,25 @@ void spSkeleton_dispose (spSkeleton* self) {
void spSkeleton_updateCache (const spSkeleton* self) { void spSkeleton_updateCache (const spSkeleton* self) {
int i, ii; int i, ii;
_spUpdate* update;
_spSkeleton* internal = SUB_CAST(_spSkeleton, self); _spSkeleton* internal = SUB_CAST(_spSkeleton, self);
int capacity = self->bonesCount + self->transformConstraintsCount + self->ikConstraintsCount;
FREE(internal->updateCache); FREE(internal->updateCache);
FREE(internal->updateCacheType); internal->updateCache = MALLOC(_spUpdate, capacity);
int capacity = self->bonesCount + self->transformConstraintsCount + self->ikConstraintsCount;
internal->updateCache = MALLOC(void*, capacity);
internal->updateCacheType = MALLOC(_spUpdateType, capacity);
internal->updateCacheCount = 0; internal->updateCacheCount = 0;
for (i = 0; i < self->bonesCount; ++i) { for (i = 0; i < self->bonesCount; ++i) {
spBone* bone = self->bones[i]; spBone* bone = self->bones[i];
internal->updateCache[internal->updateCacheCount] = bone; update = internal->updateCache + internal->updateCacheCount++;
internal->updateCacheType[internal->updateCacheCount++] = SP_UPDATE_BONE; update->type = SP_UPDATE_BONE;
update->object = bone;
for (ii = 0; ii < self->ikConstraintsCount; ++ii) { for (ii = 0; ii < self->ikConstraintsCount; ++ii) {
spIkConstraint* ikConstraint = self->ikConstraints[ii]; spIkConstraint* ikConstraint = self->ikConstraints[ii];
if (bone == ikConstraint->bones[ikConstraint->bonesCount - 1]) { if (bone == ikConstraint->bones[ikConstraint->bonesCount - 1]) {
internal->updateCache[internal->updateCacheCount] = ikConstraint; update = internal->updateCache + internal->updateCacheCount++;
internal->updateCacheType[internal->updateCacheCount++] = SP_UPDATE_IK_CONSTRAINT; update->type = SP_UPDATE_IK_CONSTRAINT;
update->object = ikConstraint;
break; break;
} }
} }
@ -165,17 +169,14 @@ void spSkeleton_updateCache (const spSkeleton* self) {
for (i = 0; i < self->transformConstraintsCount; ++i) { for (i = 0; i < self->transformConstraintsCount; ++i) {
spTransformConstraint* transformConstraint = self->transformConstraints[i]; spTransformConstraint* transformConstraint = self->transformConstraints[i];
for (ii = internal->updateCacheCount - 1; ii >= 0; --ii) { for (ii = internal->updateCacheCount - 1; ii >= 0; --ii) {
void* updatable = internal->updateCache[ii]; void* object = internal->updateCache[ii].object;
if (updatable == transformConstraint->bone || updatable == transformConstraint->target) { if (object == transformConstraint->bone || object == transformConstraint->target) {
int insertIndex = ii + 1; int insertIndex = ii + 1;
int moveCount = (capacity-2) - insertIndex; update = internal->updateCache + insertIndex;
if (moveCount > 0) { memmove(update + 1, update, (internal->updateCacheCount - insertIndex) * sizeof(_spUpdate));
memmove(internal->updateCache + (insertIndex + 1), internal->updateCache + insertIndex, moveCount * sizeof(void*)); update->type = SP_UPDATE_TRANSFORM_CONSTRAINT;
memmove(internal->updateCacheType + (insertIndex + 1), internal->updateCacheType + insertIndex, moveCount * sizeof(_spUpdateType)); update->object = transformConstraint;
}
internal->updateCacheCount++; internal->updateCacheCount++;
internal->updateCache[insertIndex] = transformConstraint;
internal->updateCacheType[insertIndex] = SP_UPDATE_TRANSFORM_CONSTRAINT;
break; break;
} }
} }
@ -187,15 +188,16 @@ void spSkeleton_updateWorldTransform (const spSkeleton* self) {
_spSkeleton* internal = SUB_CAST(_spSkeleton, self); _spSkeleton* internal = SUB_CAST(_spSkeleton, self);
for (i = 0; i < internal->updateCacheCount; ++i) { for (i = 0; i < internal->updateCacheCount; ++i) {
switch (internal->updateCacheType[i]) { _spUpdate* update = internal->updateCache + i;
switch (update->type) {
case SP_UPDATE_BONE: case SP_UPDATE_BONE:
spBone_updateWorldTransform((spBone*)internal->updateCache[i]); spBone_updateWorldTransform((spBone*)update->object);
break; break;
case SP_UPDATE_IK_CONSTRAINT: case SP_UPDATE_IK_CONSTRAINT:
spIkConstraint_apply((spIkConstraint*)internal->updateCache[i]); spIkConstraint_apply((spIkConstraint*)update->object);
break; break;
case SP_UPDATE_TRANSFORM_CONSTRAINT: case SP_UPDATE_TRANSFORM_CONSTRAINT:
spTransformConstraint_apply((spTransformConstraint*)internal->updateCache[i]); spTransformConstraint_apply((spTransformConstraint*)update->object);
break; break;
} }
} }

View File

@ -36,9 +36,20 @@
#include <spine/extension.h> #include <spine/extension.h>
#include <spine/AtlasAttachmentLoader.h> #include <spine/AtlasAttachmentLoader.h>
typedef struct {
const char* parent;
const char* skin;
int slotIndex;
spAttachment* mesh;
} _spLinkedMesh;
typedef struct { typedef struct {
spSkeletonJson super; spSkeletonJson super;
int ownsLoader; int ownsLoader;
int linkedMeshCount;
int linkedMeshCapacity;
_spLinkedMesh* linkedMeshes;
} _spSkeletonJson; } _spSkeletonJson;
spSkeletonJson* spSkeletonJson_createWithLoader (spAttachmentLoader* attachmentLoader) { spSkeletonJson* spSkeletonJson_createWithLoader (spAttachmentLoader* attachmentLoader) {
@ -56,7 +67,9 @@ spSkeletonJson* spSkeletonJson_create (spAtlas* atlas) {
} }
void spSkeletonJson_dispose (spSkeletonJson* self) { void spSkeletonJson_dispose (spSkeletonJson* self) {
if (SUB_CAST(_spSkeletonJson, self)->ownsLoader) spAttachmentLoader_dispose(self->attachmentLoader); _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self);
if (internal->ownsLoader) spAttachmentLoader_dispose(self->attachmentLoader);
FREE(internal->linkedMeshes);
FREE(self->error); FREE(self->error);
FREE(self); FREE(self);
} }
@ -103,6 +116,28 @@ static void readCurve (spCurveTimeline* timeline, int frameIndex, Json* frame) {
} }
} }
static void _spSkeletonJson_addLinkedMesh (spSkeletonJson* self, spAttachment* mesh, const char* skin, int slotIndex,
const char* parent) {
_spLinkedMesh* linkedMesh;
_spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self);
if (internal->linkedMeshCount == internal->linkedMeshCapacity) {
_spLinkedMesh* linkedMeshes;
internal->linkedMeshCapacity *= 2;
if (internal->linkedMeshCapacity < 8) internal->linkedMeshCapacity = 8;
linkedMeshes = MALLOC(_spLinkedMesh, internal->linkedMeshCapacity);
memcpy(linkedMeshes, internal->linkedMeshes, internal->linkedMeshCount);
FREE(internal->linkedMeshes);
internal->linkedMeshes = linkedMeshes;
}
linkedMesh = internal->linkedMeshes + internal->linkedMeshCount++;
linkedMesh->mesh = mesh;
linkedMesh->skin = skin;
linkedMesh->slotIndex = slotIndex;
linkedMesh->parent = parent;
}
static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* root, spSkeletonData *skeletonData) { static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* root, spSkeletonData *skeletonData) {
int i; int i;
spAnimation* animation; spAnimation* animation;
@ -132,7 +167,6 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
animation = spAnimation_create(root->name, timelinesCount); animation = spAnimation_create(root->name, timelinesCount);
animation->timelinesCount = 0; animation->timelinesCount = 0;
skeletonData->animations[skeletonData->animationsCount++] = animation;
/* Slot timelines. */ /* Slot timelines. */
for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) { for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) {
@ -409,9 +443,11 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
spSkeletonData* skeletonData; spSkeletonData* skeletonData;
Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *slots, *skins, *animations, *events; Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *slots, *skins, *animations, *events;
char* oldLocale; char* oldLocale;
_spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self);
FREE(self->error); FREE(self->error);
CONST_CAST(char*, self->error) = 0; CONST_CAST(char*, self->error) = 0;
internal->linkedMeshCount = 0;
oldLocale = setlocale(LC_NUMERIC, "C"); oldLocale = setlocale(LC_NUMERIC, "C");
root = Json_create(json); root = Json_create(json);
@ -584,13 +620,12 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
skins = Json_getItem(root, "skins"); skins = Json_getItem(root, "skins");
if (skins) { if (skins) {
Json *slotMap; Json *slotMap;
skeletonData->skinsCount = skins->size;
skeletonData->skins = MALLOC(spSkin*, skins->size); skeletonData->skins = MALLOC(spSkin*, skins->size);
for (slotMap = skins->child, i = 0; slotMap; slotMap = slotMap->next, ++i) { for (slotMap = skins->child, i = 0; slotMap; slotMap = slotMap->next, ++i) {
Json *attachmentsMap; Json *attachmentsMap;
spSkin *skin = spSkin_create(slotMap->name); spSkin *skin = spSkin_create(slotMap->name);
skeletonData->skins[i] = skin; skeletonData->skins[skeletonData->skinsCount++] = skin;
if (strcmp(slotMap->name, "default") == 0) skeletonData->defaultSkin = skin; if (strcmp(slotMap->name, "default") == 0) skeletonData->defaultSkin = skin;
for (attachmentsMap = slotMap->child; attachmentsMap; attachmentsMap = attachmentsMap->next) { for (attachmentsMap = slotMap->child; attachmentsMap; attachmentsMap = attachmentsMap->next) {
@ -614,6 +649,10 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
type = SP_ATTACHMENT_MESH; type = SP_ATTACHMENT_MESH;
else if (strcmp(typeString, "weightedmesh") == 0 || strcmp(typeString, "skinnedmesh") == 0) else if (strcmp(typeString, "weightedmesh") == 0 || strcmp(typeString, "skinnedmesh") == 0)
type = SP_ATTACHMENT_WEIGHTED_MESH; type = SP_ATTACHMENT_WEIGHTED_MESH;
else if (strcmp(typeString, "linkedmesh") == 0)
type = SP_ATTACHMENT_LINKED_MESH;
else if (strcmp(typeString, "weightedlinkedmesh") == 0)
type = SP_ATTACHMENT_WEIGHTED_LINKED_MESH;
else if (strcmp(typeString, "boundingbox") == 0) else if (strcmp(typeString, "boundingbox") == 0)
type = SP_ATTACHMENT_BOUNDING_BOX; type = SP_ATTACHMENT_BOUNDING_BOX;
else { else {
@ -655,11 +694,25 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
spRegionAttachment_updateOffset(region); spRegionAttachment_updateOffset(region);
break; break;
} }
case SP_ATTACHMENT_MESH: { case SP_ATTACHMENT_MESH:
case SP_ATTACHMENT_LINKED_MESH: {
spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, attachment); spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, attachment);
MALLOC_STR(mesh->path, path); MALLOC_STR(mesh->path, path);
color = Json_getString(attachmentMap, "color", 0);
if (color) {
mesh->r = toColor(color, 0);
mesh->g = toColor(color, 1);
mesh->b = toColor(color, 2);
mesh->a = toColor(color, 3);
}
mesh->width = Json_getFloat(attachmentMap, "width", 32) * self->scale;
mesh->height = Json_getFloat(attachmentMap, "height", 32) * self->scale;
entry = Json_getItem(attachmentMap, "parent");
if (!entry) {
entry = Json_getItem(attachmentMap, "vertices"); entry = Json_getItem(attachmentMap, "vertices");
mesh->verticesCount = entry->size; mesh->verticesCount = entry->size;
mesh->vertices = MALLOC(float, entry->size); mesh->vertices = MALLOC(float, entry->size);
@ -679,14 +732,6 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
spMeshAttachment_updateUVs(mesh); spMeshAttachment_updateUVs(mesh);
color = Json_getString(attachmentMap, "color", 0);
if (color) {
mesh->r = toColor(color, 0);
mesh->g = toColor(color, 1);
mesh->b = toColor(color, 2);
mesh->a = toColor(color, 3);
}
mesh->hullLength = Json_getInt(attachmentMap, "hull", 0); mesh->hullLength = Json_getInt(attachmentMap, "hull", 0);
entry = Json_getItem(attachmentMap, "edges"); entry = Json_getItem(attachmentMap, "edges");
@ -696,18 +741,34 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
for (entry = entry->child, i = 0; entry; entry = entry->next, ++i) for (entry = entry->child, i = 0; entry; entry = entry->next, ++i)
mesh->edges[i] = entry->valueInt; mesh->edges[i] = entry->valueInt;
} }
} else {
mesh->width = Json_getFloat(attachmentMap, "width", 32) * self->scale; mesh->inheritFFD = Json_getInt(attachmentMap, "ffd", 1);
mesh->height = Json_getFloat(attachmentMap, "height", 32) * self->scale; _spSkeletonJson_addLinkedMesh(self, attachment, Json_getString(attachmentMap, "skin", 0), slotIndex,
entry->valueString);
}
break; break;
} }
case SP_ATTACHMENT_WEIGHTED_MESH: { case SP_ATTACHMENT_WEIGHTED_MESH:
case SP_ATTACHMENT_WEIGHTED_LINKED_MESH: {
spWeightedMeshAttachment* mesh = SUB_CAST(spWeightedMeshAttachment, attachment); spWeightedMeshAttachment* mesh = SUB_CAST(spWeightedMeshAttachment, attachment);
int verticesCount, b, w, nn; int verticesCount, b, w, nn;
float* vertices; float* vertices;
MALLOC_STR(mesh->path, path); MALLOC_STR(mesh->path, path);
color = Json_getString(attachmentMap, "color", 0);
if (color) {
mesh->r = toColor(color, 0);
mesh->g = toColor(color, 1);
mesh->b = toColor(color, 2);
mesh->a = toColor(color, 3);
}
mesh->width = Json_getFloat(attachmentMap, "width", 32) * self->scale;
mesh->height = Json_getFloat(attachmentMap, "height", 32) * self->scale;
entry = Json_getItem(attachmentMap, "parent");
if (!entry) {
entry = Json_getItem(attachmentMap, "uvs"); entry = Json_getItem(attachmentMap, "uvs");
mesh->uvsCount = entry->size; mesh->uvsCount = entry->size;
mesh->regionUVs = MALLOC(float, entry->size); mesh->regionUVs = MALLOC(float, entry->size);
@ -750,14 +811,6 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
spWeightedMeshAttachment_updateUVs(mesh); spWeightedMeshAttachment_updateUVs(mesh);
color = Json_getString(attachmentMap, "color", 0);
if (color) {
mesh->r = toColor(color, 0);
mesh->g = toColor(color, 1);
mesh->b = toColor(color, 2);
mesh->a = toColor(color, 3);
}
mesh->hullLength = Json_getInt(attachmentMap, "hull", 0); mesh->hullLength = Json_getInt(attachmentMap, "hull", 0);
entry = Json_getItem(attachmentMap, "edges"); entry = Json_getItem(attachmentMap, "edges");
@ -767,9 +820,11 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
for (entry = entry->child, i = 0; entry; entry = entry->next, ++i) for (entry = entry->child, i = 0; entry; entry = entry->next, ++i)
mesh->edges[i] = entry->valueInt; mesh->edges[i] = entry->valueInt;
} }
} else {
mesh->width = Json_getFloat(attachmentMap, "width", 32) * self->scale; mesh->inheritFFD = Json_getInt(attachmentMap, "ffd", 1);
mesh->height = Json_getFloat(attachmentMap, "height", 32) * self->scale; _spSkeletonJson_addLinkedMesh(self, attachment, Json_getString(attachmentMap, "skin", 0), slotIndex,
entry->valueString);
}
break; break;
} }
case SP_ATTACHMENT_BOUNDING_BOX: { case SP_ATTACHMENT_BOUNDING_BOX: {
@ -791,6 +846,33 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
} }
} }
/* Linked meshes. */
for (i = 0; i < internal->linkedMeshCount; i++) {
spAttachment* parent;
_spLinkedMesh* linkedMesh = internal->linkedMeshes + i;
spSkin* skin = !linkedMesh->skin ? skeletonData->defaultSkin : spSkeletonData_findSkin(skeletonData, linkedMesh->skin);
if (!skin) {
spSkeletonData_dispose(skeletonData);
_spSkeletonJson_setError(self, 0, "Skin not found: ", linkedMesh->skin);
return 0;
}
parent = spSkin_getAttachment(skin, linkedMesh->slotIndex, linkedMesh->parent);
if (!skin) {
spSkeletonData_dispose(skeletonData);
_spSkeletonJson_setError(self, 0, "Parent mesh not found: ", linkedMesh->parent);
return 0;
}
if (linkedMesh->mesh->type == SP_ATTACHMENT_MESH) {
spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, linkedMesh->mesh);
spMeshAttachment_setParentMesh(mesh, SUB_CAST(spMeshAttachment, parent));
spMeshAttachment_updateUVs(mesh);
} else {
spWeightedMeshAttachment* mesh = SUB_CAST(spWeightedMeshAttachment, linkedMesh->mesh);
spWeightedMeshAttachment_setParentMesh(mesh, SUB_CAST(spWeightedMeshAttachment, parent));
spWeightedMeshAttachment_updateUVs(mesh);
}
}
/* Events. */ /* Events. */
events = Json_getItem(root, "events"); events = Json_getItem(root, "events");
if (events) { if (events) {
@ -813,8 +895,14 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
if (animations) { if (animations) {
Json *animationMap; Json *animationMap;
skeletonData->animations = MALLOC(spAnimation*, animations->size); skeletonData->animations = MALLOC(spAnimation*, animations->size);
for (animationMap = animations->child; animationMap; animationMap = animationMap->next) for (animationMap = animations->child; animationMap; animationMap = animationMap->next) {
_spSkeletonJson_readAnimation(self, animationMap, skeletonData); spAnimation* animation = _spSkeletonJson_readAnimation(self, animationMap, skeletonData);
if (!animation) {
spSkeletonData_dispose(skeletonData);
return 0;
}
skeletonData->animations[skeletonData->animationsCount++] = animation;
}
} }
Json_dispose(root); Json_dispose(root);

View File

@ -36,12 +36,14 @@ void _spWeightedMeshAttachment_dispose (spAttachment* attachment) {
spWeightedMeshAttachment* self = SUB_CAST(spWeightedMeshAttachment, attachment); spWeightedMeshAttachment* self = SUB_CAST(spWeightedMeshAttachment, attachment);
_spAttachment_deinit(attachment); _spAttachment_deinit(attachment);
FREE(self->path); FREE(self->path);
FREE(self->uvs);
if (!self->parentMesh) {
FREE(self->regionUVs);
FREE(self->bones); FREE(self->bones);
FREE(self->weights); FREE(self->weights);
FREE(self->regionUVs);
FREE(self->uvs);
FREE(self->triangles); FREE(self->triangles);
FREE(self->edges); FREE(self->edges);
}
FREE(self); FREE(self);
} }
@ -108,3 +110,28 @@ void spWeightedMeshAttachment_computeWorldVertices (spWeightedMeshAttachment* se
} }
} }
} }
void spWeightedMeshAttachment_setParentMesh (spWeightedMeshAttachment* self, spWeightedMeshAttachment* parentMesh) {
CONST_CAST(spWeightedMeshAttachment*, self->parentMesh) = parentMesh;
if (parentMesh) {
self->bones = parentMesh->bones;
self->bonesCount = parentMesh->bonesCount;
self->weights = parentMesh->weights;
self->weightsCount = parentMesh->weightsCount;
self->regionUVs = parentMesh->regionUVs;
self->uvsCount = parentMesh->uvsCount;
self->triangles = parentMesh->triangles;
self->trianglesCount = parentMesh->trianglesCount;
self->hullLength = parentMesh->hullLength;
self->edges = parentMesh->edges;
self->edgesCount = parentMesh->edgesCount;
self->width = parentMesh->width;
self->height = parentMesh->height;
}
}

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version ## Spine version
spine-cocos2d-iphone v2 works with data exported from the latest version of Spine, except linked meshes are [not yet supported](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes). spine-cocos2d-iphone v2 works with data exported from the latest version of Spine.
spine-cocos2d-iphone v2 supports all Spine features. spine-cocos2d-iphone v2 supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version ## Spine version
spine-cocos2d-iphone v3 works with data exported from the latest version of Spine, except linked meshes are [not yet supported](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes). spine-cocos2d-iphone v3 works with data exported from the latest version of Spine.
spine-cocos2d-iphone v3 supports all Spine features. spine-cocos2d-iphone v3 supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version ## Spine version
spine-cocos2dx v2 works with data exported from the latest version of Spine, except linked meshes are [not yet supported](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes). spine-cocos2dx v2 works with data exported from the latest version of Spine.
spine-cocos2dx v2 supports all Spine features. spine-cocos2dx v2 supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version ## Spine version
spine-cocos2dx v3 works with data exported from the latest version of Spine, except linked meshes are [not yet supported](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes). spine-cocos2dx v3 works with data exported from the latest version of Spine.
spine-cocos2dx v3 supports all Spine features. spine-cocos2dx v3 supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version ## Spine version
spine-sfml works with data exported from the latest version of Spine, except linked meshes are [not yet supported](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes). spine-sfml works with data exported from the latest version of Spine.
spine-sfml supports all Spine features. spine-sfml supports all Spine features.