Keyable draw order for spine-c.

This commit is contained in:
NathanSweet 2013-09-24 11:29:58 +02:00
parent 2b86668f4e
commit 63f8e4ddaf
15 changed files with 383 additions and 181 deletions

View File

@ -307,10 +307,7 @@
{ "slot": "eyes", "offset": -12 }
]
},
{
"time": 3.5862,
"offsets": []
}
{ "time": 3.5862 }
]
},
"jump": {

View File

@ -62,13 +62,19 @@ int main (void) {
SkeletonJson* json = SkeletonJson_create(atlas);
SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/spineboy.json");
if (!skeletonData) printf("Error: %s\n", json->error);
if (!skeletonData) {
printf("Error: %s\n", json->error);
exit(0);
}
printf("Default skin name: %s\n", skeletonData->defaultSkin->name);
Skeleton* skeleton = Skeleton_create(skeletonData);
Animation* animation = SkeletonData_findAnimation(skeletonData, "walk");
if (!animation) printf("Error: %s\n", json->error);
if (!animation) {
printf("Error: Animation not found: walk\n");
exit(0);
}
printf("Animation timelineCount: %d\n", animation->timelineCount);
Skeleton_dispose(skeleton);

View File

@ -137,6 +137,21 @@ AttachmentTimeline* AttachmentTimeline_create (int frameCount);
/* @param attachmentName May be 0. */
void AttachmentTimeline_setFrame (AttachmentTimeline* self, int frameIndex, float time, const char* attachmentName);
/**/
typedef struct {
Timeline super;
int const framesLength;
float* const frames; /* time, ... */
int slotIndex;
const int** const drawOrders;
int const slotCount;
} DrawOrderTimeline;
DrawOrderTimeline* DrawOrderTimeline_create (int frameCount, int slotCount);
void DrawOrderTimeline_setFrame (DrawOrderTimeline* self, int frameIndex, float time, const int* drawOrder);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,59 @@
/******************************************************************************
* Spine Runtime Software License - Version 1.0
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* Redistribution and use in source and binary forms in whole or in part, with
* or without modification, are permitted provided that the following conditions
* are met:
*
* 1. A Spine Single User License or Spine Professional License must be
* purchased from Esoteric Software and the license must remain valid:
* http://esotericsoftware.com/
* 2. Redistributions of source code must retain this license, which is the
* above copyright notice, this declaration of conditions and the following
* disclaimer.
* 3. Redistributions in binary form must reproduce this license, which is the
* above copyright notice, this declaration of conditions and the following
* disclaimer, in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#ifndef SPINE_BOUNDINGBOXATTACHMENT_H_
#define SPINE_BOUNDINGBOXATTACHMENT_H_
#include <spine/Attachment.h>
#include <spine/Atlas.h>
#include <spine/Slot.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct BoundingBoxAttachment BoundingBoxAttachment;
struct BoundingBoxAttachment {
Attachment super;
float* vertices;
int verticesCount;
};
BoundingBoxAttachment* BoundingBoxAttachment_create (const char* name);
void BoundingBoxAttachment_computeWorldVertices (BoundingBoxAttachment* self, float x, float y, Bone* bone, float* vertices);
#ifdef __cplusplus
}
#endif
#endif /* SPINE_BOUNDINGBOXATTACHMENT_H_ */

View File

@ -92,6 +92,7 @@
#include <string.h>
#include <spine/Skeleton.h>
#include <spine/RegionAttachment.h>
#include <spine/BoundingBoxAttachment.h>
#include <spine/Animation.h>
#include <spine/Atlas.h>
#include <spine/AttachmentLoader.h>

View File

@ -86,11 +86,11 @@ typedef struct _TimelineVtable {
} _TimelineVtable;
void _Timeline_init (Timeline* self, /**/
void (*dispose) (Timeline* self), /**/
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
void (*dispose) (Timeline* self), /**/
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
CONST_CAST(_TimelineVtable*, self->vtable) = NEW(_TimelineVtable);
VTABLE(Timeline, self) ->dispose = dispose;
VTABLE(Timeline, self) ->apply = apply;
VTABLE(Timeline, self)->dispose = dispose;
VTABLE(Timeline, self)->apply = apply;
}
void _Timeline_deinit (Timeline* self) {
@ -98,11 +98,11 @@ void _Timeline_deinit (Timeline* self) {
}
void Timeline_dispose (Timeline* self) {
VTABLE(Timeline, self) ->dispose(self);
VTABLE(Timeline, self)->dispose(self);
}
void Timeline_apply (const Timeline* self, Skeleton* skeleton, float time, float alpha) {
VTABLE(Timeline, self) ->apply(self, skeleton, time, alpha);
VTABLE(Timeline, self)->apply(self, skeleton, time, alpha);
}
/**/
@ -112,8 +112,8 @@ static const float CURVE_STEPPED = -1;
static const int CURVE_SEGMENTS = 10;
void _CurveTimeline_init (CurveTimeline* self, int frameCount, /**/
void (*dispose) (Timeline* self), /**/
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
void (*dispose) (Timeline* self), /**/
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
_Timeline_init(SUPER(self), dispose, apply);
self->curves = CALLOC(float, (frameCount - 1) * 6);
}
@ -226,7 +226,7 @@ void _BaseTimeline_dispose (Timeline* timeline) {
/* Many timelines have structure identical to struct BaseTimeline and extend CurveTimeline. **/
struct BaseTimeline* _BaseTimeline_create (int frameCount, int frameSize, /**/
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
struct BaseTimeline* self = NEW(struct BaseTimeline);
_CurveTimeline_init(SUPER(self), frameCount, _BaseTimeline_dispose, apply);
@ -349,7 +349,7 @@ void _ScaleTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float t
float lastFrameX, lastFrameY, frameTime, percent;
ScaleTimeline* self = SUB_CAST(ScaleTimeline, timeline);
if (time < self->frames[0]) return; /* Time is before first frame. */
bone = skeleton->bones[self->boneIndex];
@ -469,11 +469,10 @@ void _AttachmentTimeline_apply (const Timeline* timeline, Skeleton* skeleton, fl
}
void _AttachmentTimeline_dispose (Timeline* timeline) {
AttachmentTimeline* self;
AttachmentTimeline* self = SUB_CAST(AttachmentTimeline, timeline);
int i;
_Timeline_deinit(timeline);
self = (AttachmentTimeline*)timeline;
for (i = 0; i < self->framesLength; ++i)
FREE(self->attachmentNames[i]);
@ -495,9 +494,73 @@ AttachmentTimeline* AttachmentTimeline_create (int frameCount) {
void AttachmentTimeline_setFrame (AttachmentTimeline* self, int frameIndex, float time, const char* attachmentName) {
self->frames[frameIndex] = time;
FREE(self->attachmentNames[frameIndex]);
if (attachmentName)
MALLOC_STR(self->attachmentNames[frameIndex], attachmentName);
else
self->attachmentNames[frameIndex] = 0;
}
/**/
#include <stdio.h>
void _DrawOrderTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
int i;
int frameIndex;
const int* drawOrderToSetupIndex;
DrawOrderTimeline* self = (DrawOrderTimeline*)timeline;
if (time < self->frames[0]) return; /* Time is before first frame. */
if (time >= self->frames[self->framesLength - 1]) /* Time is after last frame. */
frameIndex = self->framesLength - 1;
else
frameIndex = binarySearch(self->frames, self->framesLength, time, 1) - 1;
drawOrderToSetupIndex = self->drawOrders[frameIndex];
if (!drawOrderToSetupIndex)
memcpy(skeleton->drawOrder, skeleton->slots, self->slotCount * sizeof(int));
else {
for (i = 0; i < self->slotCount; i++)
skeleton->drawOrder[i] = skeleton->slots[drawOrderToSetupIndex[i]];
}
}
void _DrawOrderTimeline_dispose (Timeline* timeline) {
DrawOrderTimeline* self = SUB_CAST(DrawOrderTimeline, timeline);
int i;
_Timeline_deinit(timeline);
for (i = 0; i < self->framesLength; ++i)
FREE(self->drawOrders[i]);
FREE(self->drawOrders);
FREE(self->frames);
FREE(self);
}
DrawOrderTimeline* DrawOrderTimeline_create (int frameCount, int slotCount) {
DrawOrderTimeline* self = NEW(DrawOrderTimeline);
_Timeline_init(SUPER(self), _DrawOrderTimeline_dispose, _DrawOrderTimeline_apply);
CONST_CAST(int**, self->drawOrders) = CALLOC(int*, frameCount);
CONST_CAST(int, self->framesLength) = frameCount;
CONST_CAST(float*, self->frames) = CALLOC(float, frameCount);
CONST_CAST(int, self->slotCount) = slotCount;
return self;
}
void DrawOrderTimeline_setFrame (DrawOrderTimeline* self, int frameIndex, float time, const int* drawOrder) {
self->frames[frameIndex] = time;
FREE(self->drawOrders[frameIndex]);
if (!drawOrder)
self->drawOrders[frameIndex] = 0;
else {
self->drawOrders[frameIndex] = MALLOC(int, self->slotCount);
memcpy(CONST_CAST(int*, self->drawOrders[frameIndex]), drawOrder, self->slotCount * sizeof(int));
}
}

View File

@ -55,9 +55,8 @@ Attachment* _AtlasAttachmentLoader_newAttachment (AttachmentLoader* loader, Skin
attachment->regionOriginalHeight = region->originalHeight;
return SUPER(attachment);
}
case ATTACHMENT_BOUNDING_BOX: {
return 0; // BOZO - Implement bounding boxes.
}
case ATTACHMENT_BOUNDING_BOX:
return SUPER(BoundingBoxAttachment_create(name));
default:
_AttachmentLoader_setUnknownTypeError(loader, type);
return 0;

View File

@ -0,0 +1,57 @@
/******************************************************************************
* Spine Runtime Software License - Version 1.0
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* Redistribution and use in source and binary forms in whole or in part, with
* or without modification, are permitted provided that the following conditions
* are met:
*
* 1. A Spine Single User License or Spine Professional License must be
* purchased from Esoteric Software and the license must remain valid:
* http://esotericsoftware.com/
* 2. Redistributions of source code must retain this license, which is the
* above copyright notice, this declaration of conditions and the following
* disclaimer.
* 3. Redistributions in binary form must reproduce this license, which is the
* above copyright notice, this declaration of conditions and the following
* disclaimer, in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#include <spine/BoundingBoxAttachment.h>
#include <math.h>
#include <spine/extension.h>
BoundingBoxAttachment* BoundingBoxAttachment_create (const char* name) {
BoundingBoxAttachment* self = NEW(BoundingBoxAttachment);
_Attachment_init(SUPER(self), name, ATTACHMENT_BOUNDING_BOX, _Attachment_deinit);
return self;
}
void BoundingBoxAttachment_computeVertices (BoundingBoxAttachment* self, float x, float y, Bone* bone, float* worldVertices) {
int i;
float px, py;
float* vertices = self->vertices;
x += bone->worldX;
y += bone->worldY;
for (i = 0; i < self->verticesCount; i += 2) {
px = vertices[i];
py = vertices[i + 1];
worldVertices[i] = px * bone->m00 + py * bone->m01 + x;
worldVertices[i + 1] = px * bone->m10 + py * bone->m11 + y;
}
}

View File

@ -54,7 +54,7 @@ void Json_dispose (Json *c) {
while (c) {
next = c->next;
if (c->child) Json_dispose(c->child);
if (c->valuestring) FREE(c->valuestring);
if (c->valueString) FREE(c->valueString);
if (c->name) FREE(c->name);
FREE(c);
c = next;
@ -90,8 +90,8 @@ static const char* parse_number (Json *item, const char* num) {
n = sign * n * (float)pow(10.0f, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
item->valuefloat = n;
item->valueint = (int)n;
item->valueFloat = n;
item->valueInt = (int)n;
item->type = Json_Number;
return num;
}
@ -185,7 +185,7 @@ static const char* parse_string (Json *item, const char* str) {
}
*ptr2 = 0;
if (*ptr == '\"') ptr++;
item->valuestring = out;
item->valueString = out;
item->type = Json_String;
return ptr;
}
@ -231,7 +231,7 @@ static const char* parse_value (Json *item, const char* value) {
}
if (!strncmp(value, "true", 4)) {
item->type = Json_True;
item->valueint = 1;
item->valueInt = 1;
return value + 4;
}
if (*value == '\"') {
@ -267,6 +267,7 @@ static const char* parse_array (Json *item, const char* value) {
if (!item->child) return 0; /* memory fail */
value = skip(parse_value(child, skip(value))); /* skip any spacing, get the value. */
if (!value) return 0;
item->size = 1;
while (*value == ',') {
Json *new_item;
@ -276,6 +277,7 @@ static const char* parse_array (Json *item, const char* value) {
child = new_item;
value = skip(parse_value(child, skip(value + 1)));
if (!value) return 0; /* memory fail */
item->size++;
}
if (*value == ']') return value + 1; /* end of array */
@ -299,14 +301,15 @@ static const char* parse_object (Json *item, const char* value) {
if (!item->child) return 0;
value = skip(parse_string(child, skip(value)));
if (!value) return 0;
child->name = child->valuestring;
child->valuestring = 0;
child->name = child->valueString;
child->valueString = 0;
if (*value != ':') {
ep = value;
return 0;
} /* fail! */
value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
if (!value) return 0;
item->size = 1;
while (*value == ',') {
Json *new_item;
@ -316,14 +319,15 @@ static const char* parse_object (Json *item, const char* value) {
child = new_item;
value = skip(parse_string(child, skip(value + 1)));
if (!value) return 0;
child->name = child->valuestring;
child->valuestring = 0;
child->name = child->valueString;
child->valueString = 0;
if (*value != ':') {
ep = value;
return 0;
} /* fail! */
value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
if (!value) return 0;
item->size++;
}
if (*value == '}') return value + 1; /* end of array */
@ -331,22 +335,6 @@ static const char* parse_object (Json *item, const char* value) {
return 0; /* malformed. */
}
/* Get Array size/item / object item. */
int Json_getSize (Json *array) {
Json *c = array->child;
int i = 0;
while (c)
i++, c = c->next;
return i;
}
Json *Json_getItemAt (Json *array, int item) {
Json *c = array->child;
while (c && item > 0)
item--, c = c->next;
return c;
}
Json *Json_getItem (Json *object, const char* string) {
Json *c = object->child;
while (c && Json_strcasecmp(c->name, string))
@ -356,16 +344,16 @@ Json *Json_getItem (Json *object, const char* string) {
const char* Json_getString (Json* object, const char* name, const char* defaultValue) {
object = Json_getItem(object, name);
if (object) return object->valuestring;
if (object) return object->valueString;
return defaultValue;
}
float Json_getFloat (Json* value, const char* name, float defaultValue) {
value = Json_getItem(value, name);
return value ? value->valuefloat : defaultValue;
return value ? value->valueFloat : defaultValue;
}
int Json_getInt (Json* value, const char* name, int defaultValue) {
value = Json_getItem(value, name);
return value ? (int)value->valuefloat : defaultValue;
return value ? (int)value->valueFloat : defaultValue;
}

View File

@ -41,14 +41,15 @@ extern "C" {
/* The Json structure: */
typedef struct Json {
struct Json* next;
struct Json* prev; /* next/prev allow you to walk array/object chains. Alternatively, use getSize/getItemAt/getItem */
struct Json* prev; /* next/prev allow you to walk array/object chains. Alternatively, use getSize/getItem */
struct Json* child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
int size; /* The number of children. */
const char* valuestring; /* The item's string, if type==Json_String */
int valueint; /* The item's number, if type==Json_Number */
float valuefloat; /* The item's number, if type==Json_Number */
const char* valueString; /* The item's string, if type==Json_String */
int valueInt; /* The item's number, if type==Json_Number */
float valueFloat; /* The item's number, if type==Json_Number */
const char* name; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} Json;
@ -59,12 +60,6 @@ Json* Json_create (const char* value);
/* Delete a Json entity and all subentities. */
void Json_dispose (Json* json);
/* Returns the number of items in an array (or object). */
int Json_getSize (Json* json);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
Json* Json_getItemAt (Json* json, int item);
/* Get item "string" from object. Case insensitive. */
Json* Json_getItem (Json* json, const char* string);
const char* Json_getString (Json* json, const char* name, const char* defaultValue);

View File

@ -55,12 +55,12 @@ SkeletonJson* SkeletonJson_createWithLoader (AttachmentLoader* attachmentLoader)
SkeletonJson* SkeletonJson_create (Atlas* atlas) {
AtlasAttachmentLoader* attachmentLoader = AtlasAttachmentLoader_create(atlas);
SkeletonJson* self = SkeletonJson_createWithLoader(SUPER(attachmentLoader));
SUB_CAST(_Internal, self) ->ownsLoader = 1;
SUB_CAST(_Internal, self)->ownsLoader = 1;
return self;
}
void SkeletonJson_dispose (SkeletonJson* self) {
if (SUB_CAST(_Internal, self) ->ownsLoader) AttachmentLoader_dispose(self->attachmentLoader);
if (SUB_CAST(_Internal, self)->ownsLoader) AttachmentLoader_dispose(self->attachmentLoader);
FREE(self->error);
FREE(self);
}
@ -83,7 +83,7 @@ static float toColor (const char* value, int index) {
if (strlen(value) != 8) return -1;
value += index * 2;
digits[0] = *value;
digits[1] = *(value + 1);
digits[2] = '\0';
@ -95,145 +95,179 @@ static float toColor (const char* value, int index) {
static void readCurve (CurveTimeline* timeline, int frameIndex, Json* frame) {
Json* curve = Json_getItem(frame, "curve");
if (!curve) return;
if (curve->type == Json_String && strcmp(curve->valuestring, "stepped") == 0)
if (curve->type == Json_String && strcmp(curve->valueString, "stepped") == 0)
CurveTimeline_setStepped(timeline, frameIndex);
else if (curve->type == Json_Array) {
CurveTimeline_setCurve(timeline, frameIndex, Json_getItemAt(curve, 0)->valuefloat, Json_getItemAt(curve, 1)->valuefloat,
Json_getItemAt(curve, 2)->valuefloat, Json_getItemAt(curve, 3)->valuefloat);
Json* child0 = curve->child;
Json* child1 = child0->next;
Json* child2 = child1->next;
Json* child3 = child2->next;
CurveTimeline_setCurve(timeline, frameIndex, child0->valueFloat, child1->valueFloat, child2->valueFloat,
child3->valueFloat);
}
}
static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, SkeletonData *skeletonData) {
int i;
Animation* animation;
Json* bones = Json_getItem(root, "bones");
int boneCount = bones ? Json_getSize(bones) : 0;
Json* slots = Json_getItem(root, "slots");
int slotCount = slots ? Json_getSize(slots) : 0;
Json* drawOrder = Json_getItem(root, "draworder");
Json *boneMap, *slotMap, *timelineArray;
int timelineCount = 0;
int i, ii, iii;
for (i = 0; i < boneCount; ++i)
timelineCount += Json_getSize(Json_getItemAt(bones, i));
for (i = 0; i < slotCount; ++i)
timelineCount += Json_getSize(Json_getItemAt(slots, i));
for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next)
timelineCount += boneMap->size;
for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next)
timelineCount += slotMap->size;
if (drawOrder) ++timelineCount;
animation = Animation_create(root->name, timelineCount);
animation->timelineCount = 0;
skeletonData->animations[skeletonData->animationCount] = animation;
skeletonData->animationCount++;
++skeletonData->animationCount;
for (i = 0; i < boneCount; ++i) {
int timelineCount;
Json* boneMap = Json_getItemAt(bones, i);
const char* boneName = boneMap->name;
int boneIndex = SkeletonData_findBoneIndex(skeletonData, boneName);
for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next) {
int boneIndex = SkeletonData_findBoneIndex(skeletonData, boneMap->name);
if (boneIndex == -1) {
Animation_dispose(animation);
_SkeletonJson_setError(self, root, "Bone not found: ", boneName);
_SkeletonJson_setError(self, root, "Bone not found: ", boneMap->name);
return 0;
}
timelineCount = Json_getSize(boneMap);
for (ii = 0; ii < timelineCount; ++ii) {
for (timelineArray = boneMap->child; timelineArray; timelineArray = timelineArray->next) {
Json* frame;
float duration;
Json* timelineArray = Json_getItemAt(boneMap, ii);
int frameCount = Json_getSize(timelineArray);
const char* timelineType = timelineArray->name;
if (strcmp(timelineType, "rotate") == 0) {
RotateTimeline *timeline = RotateTimeline_create(frameCount);
if (strcmp(timelineArray->name, "rotate") == 0) {
RotateTimeline *timeline = RotateTimeline_create(timelineArray->size);
timeline->boneIndex = boneIndex;
for (iii = 0; iii < frameCount; ++iii) {
Json* frame = Json_getItemAt(timelineArray, iii);
RotateTimeline_setFrame(timeline, iii, Json_getFloat(frame, "time", 0), Json_getFloat(frame, "angle", 0));
readCurve(SUPER(timeline), iii, frame);
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i) {
RotateTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), Json_getFloat(frame, "angle", 0));
readCurve(SUPER(timeline), i, frame);
}
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
duration = timeline->frames[frameCount * 2 - 2];
duration = timeline->frames[timelineArray->size * 2 - 2];
if (duration > animation->duration) animation->duration = duration;
} else {
int isScale = strcmp(timelineType, "scale") == 0;
if (isScale || strcmp(timelineType, "translate") == 0) {
int isScale = strcmp(timelineArray->name, "scale") == 0;
if (isScale || strcmp(timelineArray->name, "translate") == 0) {
float scale = isScale ? 1 : self->scale;
TranslateTimeline *timeline = isScale ? ScaleTimeline_create(frameCount) : TranslateTimeline_create(frameCount);
TranslateTimeline *timeline =
isScale ? ScaleTimeline_create(timelineArray->size) : TranslateTimeline_create(timelineArray->size);
timeline->boneIndex = boneIndex;
for (iii = 0; iii < frameCount; ++iii) {
Json* frame = Json_getItemAt(timelineArray, iii);
TranslateTimeline_setFrame(timeline, iii, Json_getFloat(frame, "time", 0), Json_getFloat(frame, "x", 0) * scale,
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i) {
TranslateTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), Json_getFloat(frame, "x", 0) * scale,
Json_getFloat(frame, "y", 0) * scale);
readCurve(SUPER(timeline), iii, frame);
readCurve(SUPER(timeline), i, frame);
}
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
duration = timeline->frames[frameCount * 3 - 3];
duration = timeline->frames[timelineArray->size * 3 - 3];
if (duration > animation->duration) animation->duration = duration;
} else {
Animation_dispose(animation);
_SkeletonJson_setError(self, 0, "Invalid timeline type for a bone: ", timelineType);
_SkeletonJson_setError(self, 0, "Invalid timeline type for a bone: ", timelineArray->name);
return 0;
}
}
}
}
for (i = 0; i < slotCount; ++i) {
int timelineCount;
Json* slotMap = Json_getItemAt(slots, i);
const char* slotName = slotMap->name;
int slotIndex = SkeletonData_findSlotIndex(skeletonData, slotName);
for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) {
int slotIndex = SkeletonData_findSlotIndex(skeletonData, slotMap->name);
if (slotIndex == -1) {
Animation_dispose(animation);
_SkeletonJson_setError(self, root, "Slot not found: ", slotName);
_SkeletonJson_setError(self, root, "Slot not found: ", slotMap->name);
return 0;
}
timelineCount = Json_getSize(slotMap);
for (ii = 0; ii < timelineCount; ++ii) {
for (timelineArray = slotMap->child; timelineArray; timelineArray = timelineArray->next) {
Json* frame;
float duration;
Json* timelineArray = Json_getItemAt(slotMap, ii);
int frameCount = Json_getSize(timelineArray);
const char* timelineType = timelineArray->name;
if (strcmp(timelineType, "color") == 0) {
ColorTimeline *timeline = ColorTimeline_create(frameCount);
if (strcmp(timelineArray->name, "color") == 0) {
ColorTimeline *timeline = ColorTimeline_create(timelineArray->size);
timeline->slotIndex = slotIndex;
for (iii = 0; iii < frameCount; ++iii) {
Json* frame = Json_getItemAt(timelineArray, iii);
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i) {
const char* s = Json_getString(frame, "color", 0);
ColorTimeline_setFrame(timeline, iii, Json_getFloat(frame, "time", 0), toColor(s, 0), toColor(s, 1), toColor(s, 2),
ColorTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), toColor(s, 0), toColor(s, 1), toColor(s, 2),
toColor(s, 3));
readCurve(SUPER(timeline), iii, frame);
readCurve(SUPER(timeline), i, frame);
}
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
duration = timeline->frames[frameCount * 5 - 5];
duration = timeline->frames[timelineArray->size * 5 - 5];
if (duration > animation->duration) animation->duration = duration;
} else if (strcmp(timelineType, "attachment") == 0) {
AttachmentTimeline *timeline = AttachmentTimeline_create(frameCount);
} else if (strcmp(timelineArray->name, "attachment") == 0) {
AttachmentTimeline *timeline = AttachmentTimeline_create(timelineArray->size);
timeline->slotIndex = slotIndex;
for (iii = 0; iii < frameCount; ++iii) {
Json* frame = Json_getItemAt(timelineArray, iii);
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i) {
Json* name = Json_getItem(frame, "name");
AttachmentTimeline_setFrame(timeline, iii, Json_getFloat(frame, "time", 0),
name->type == Json_NULL ? 0 : name->valuestring);
AttachmentTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0),
name->type == Json_NULL ? 0 : name->valueString);
}
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
duration = timeline->frames[frameCount - 1];
duration = timeline->frames[timelineArray->size - 1];
if (duration > animation->duration) animation->duration = duration;
} else {
Animation_dispose(animation);
_SkeletonJson_setError(self, 0, "Invalid timeline type for a slot: ", timelineType);
_SkeletonJson_setError(self, 0, "Invalid timeline type for a slot: ", timelineArray->name);
return 0;
}
}
}
if (drawOrder) {
Json* frame;
float duration;
DrawOrderTimeline* timeline = DrawOrderTimeline_create(drawOrder->size, skeletonData->slotCount);
for (frame = drawOrder->child, i = 0; frame; frame = frame->next, ++i) {
int ii;
int* drawOrder = 0;
Json* offsets = Json_getItem(frame, "offsets");
if (offsets) {
Json* offsetMap;
int* unchanged = MALLOC(int, skeletonData->slotCount - offsets->size);
int originalIndex = 0, unchangedIndex = 0;
drawOrder = MALLOC(int, skeletonData->slotCount);
for (ii = skeletonData->slotCount - 1; ii >= 0; --ii)
drawOrder[ii] = -1;
for (offsetMap = offsets->child; offsetMap; offsetMap = offsetMap->next) {
int slotIndex = SkeletonData_findSlotIndex(skeletonData, Json_getString(offsetMap, "slot", 0));
if (slotIndex == -1) {
Animation_dispose(animation);
_SkeletonJson_setError(self, 0, "Slot not found: ", Json_getString(offsetMap, "slot", 0));
return 0;
}
/* Collect unchanged items. */
while (originalIndex != slotIndex)
unchanged[unchangedIndex++] = originalIndex++;
/* Set changed items. */
drawOrder[originalIndex + Json_getInt(offsetMap, "offset", 0)] = originalIndex;
++originalIndex;
}
/* Collect remaining unchanged items. */
while (originalIndex < skeletonData->slotCount)
unchanged[unchangedIndex++] = originalIndex++;
/* Fill in unchanged items. */
for (ii = skeletonData->slotCount - 1; ii >= 0; ii--)
if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex];
FREE(unchanged);
}
DrawOrderTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), drawOrder);
FREE(drawOrder);
}
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
duration = timeline->frames[drawOrder->size - 1];
if (duration > animation->duration) animation->duration = duration;
}
return animation;
}
@ -251,9 +285,9 @@ SkeletonData* SkeletonJson_readSkeletonDataFile (SkeletonJson* self, const char*
}
SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* json) {
int i;
SkeletonData* skeletonData;
Json *root, *bones;
int i, ii, iii, boneCount;
Json *root, *bones, *boneMap, *slotMap, *attachmentsMap, *attachmentMap, *animationMap;
Json* slots;
Json* skinsMap;
Json* animations;
@ -270,14 +304,10 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
skeletonData = SkeletonData_create();
bones = Json_getItem(root, "bones");
boneCount = Json_getSize(bones);
skeletonData->bones = MALLOC(BoneData*, boneCount);
for (i = 0; i < boneCount; ++i) {
Json* boneMap = Json_getItemAt(bones, i);
skeletonData->bones = MALLOC(BoneData*, bones->size);
for (boneMap = bones->child, i = 0; boneMap; boneMap = boneMap->next, ++i) {
BoneData* boneData;
const char* boneName = Json_getString(boneMap, "name", 0);
BoneData* parent = 0;
const char* parentName = Json_getString(boneMap, "parent", 0);
if (parentName) {
@ -289,7 +319,7 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
}
}
boneData = BoneData_create(boneName, parent);
boneData = BoneData_create(Json_getString(boneMap, "name", 0), parent);
boneData->length = Json_getFloat(boneMap, "length", 0) * self->scale;
boneData->x = Json_getFloat(boneMap, "x", 0) * self->scale;
boneData->y = Json_getFloat(boneMap, "y", 0) * self->scale;
@ -298,20 +328,16 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
boneData->scaleY = Json_getFloat(boneMap, "scaleY", 1);
skeletonData->bones[i] = boneData;
skeletonData->boneCount++;
++skeletonData->boneCount;
}
slots = Json_getItem(root, "slots");
if (slots) {
int slotCount = Json_getSize(slots);
skeletonData->slots = MALLOC(SlotData*, slotCount);
for (i = 0; i < slotCount; ++i) {
skeletonData->slots = MALLOC(SlotData*, slots->size);
for (slotMap = slots->child, i = 0; slotMap; slotMap = slotMap->next, ++i) {
SlotData* slotData;
const char* color;
Json *attachmentItem;
Json* slotMap = Json_getItemAt(slots, i);
const char* slotName = Json_getString(slotMap, "name", 0);
const char* boneName = Json_getString(slotMap, "bone", 0);
BoneData* boneData = SkeletonData_findBone(skeletonData, boneName);
@ -321,7 +347,7 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
return 0;
}
slotData = SlotData_create(slotName, boneData);
slotData = SlotData_create(Json_getString(slotMap, "name", 0), boneData);
color = Json_getString(slotMap, "color", 0);
if (color) {
@ -332,37 +358,28 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
}
attachmentItem = Json_getItem(slotMap, "attachment");
if (attachmentItem) SlotData_setAttachmentName(slotData, attachmentItem->valuestring);
if (attachmentItem) SlotData_setAttachmentName(slotData, attachmentItem->valueString);
skeletonData->slots[i] = slotData;
skeletonData->slotCount++;
++skeletonData->slotCount;
}
}
skinsMap = Json_getItem(root, "skins");
if (skinsMap) {
int skinCount = Json_getSize(skinsMap);
skeletonData->skins = MALLOC(Skin*, skinCount);
for (i = 0; i < skinCount; ++i) {
Json* slotMap = Json_getItemAt(skinsMap, i);
const char* skinName = slotMap->name;
Skin *skin = Skin_create(skinName);
int slotNameCount;
skeletonData->skins = MALLOC(Skin*, skinsMap->size);
for (slotMap = skinsMap->child, i = 0; slotMap; slotMap = slotMap->next, ++i) {
Skin *skin = Skin_create(slotMap->name);
skeletonData->skins[i] = skin;
skeletonData->skinCount++;
if (strcmp(skinName, "default") == 0) skeletonData->defaultSkin = skin;
++skeletonData->skinCount;
if (strcmp(slotMap->name, "default") == 0) skeletonData->defaultSkin = skin;
slotNameCount = Json_getSize(slotMap);
for (ii = 0; ii < slotNameCount; ++ii) {
Json* attachmentsMap = Json_getItemAt(slotMap, ii);
const char* slotName = attachmentsMap->name;
int slotIndex = SkeletonData_findSlotIndex(skeletonData, slotName);
for (attachmentsMap = slotMap->child; attachmentsMap; attachmentsMap = attachmentsMap->next) {
int slotIndex = SkeletonData_findSlotIndex(skeletonData, attachmentsMap->name);
int attachmentCount = Json_getSize(attachmentsMap);
for (iii = 0; iii < attachmentCount; ++iii) {
for (attachmentMap = attachmentsMap->child; attachmentMap; attachmentMap = attachmentMap->next) {
Attachment* attachment;
Json* attachmentMap = Json_getItemAt(attachmentsMap, iii);
const char* skinAttachmentName = attachmentMap->name;
const char* attachmentName = Json_getString(attachmentMap, "name", skinAttachmentName);
@ -410,12 +427,9 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
animations = Json_getItem(root, "animations");
if (animations) {
int animationCount = Json_getSize(animations);
skeletonData->animations = MALLOC(Animation*, animationCount);
for (i = 0; i < animationCount; ++i) {
Json* animationMap = Json_getItemAt(animations, i);
skeletonData->animations = MALLOC(Animation*, animations->size);
for (animationMap = animations->child; animationMap; animationMap = animationMap->next)
_SkeletonJson_readAnimation(self, animationMap, skeletonData);
}
}
Json_dispose(root);

View File

@ -300,7 +300,14 @@
{ "slot": "eyes", "offset": 3 }
]
},
{ "time": 2 }
{
"time": 2.6206,
"offsets": [
{ "slot": "head", "offset": -12 },
{ "slot": "eyes", "offset": -12 }
]
},
{ "time": 3.5862 }
]
},
"jump": {

View File

@ -307,10 +307,7 @@
{ "slot": "eyes", "offset": -12 }
]
},
{
"time": 3.5862,
"offsets": []
}
{ "time": 3.5862 }
]
},
"jump": {

View File

@ -68,9 +68,13 @@ void spineboy () {
skeleton->root->y = 420;
Skeleton_updateWorldTransform(skeleton);
AnimationState_setAnimationByName(drawable->state, "walk", true);
AnimationState_addAnimationByName(drawable->state, "jump", false, 0);
AnimationState_addAnimationByName(drawable->state, "walk", true, 0);
if (true) {
AnimationState_setAnimationByName(drawable->state, "drawOrder", true);
} else {
AnimationState_setAnimationByName(drawable->state, "walk", true);
AnimationState_addAnimationByName(drawable->state, "jump", false, 0);
AnimationState_addAnimationByName(drawable->state, "walk", true, 0);
}
sf::RenderWindow window(sf::VideoMode(640, 480), "Spine SFML");
window.setFramerateLimit(60);

View File

@ -89,7 +89,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
vertexArray->clear();
float vertexPositions[8];
for (int i = 0; i < skeleton->slotCount; ++i) {
Slot* slot = skeleton->slots[i];
Slot* slot = skeleton->drawOrder[i];
Attachment* attachment = slot->attachment;
if (!attachment || attachment->type != ATTACHMENT_REGION) continue;
RegionAttachment* regionAttachment = (RegionAttachment*)attachment;