diff --git a/spine-c/data/spineboy.json b/spine-c/data/spineboy.json index 7619ab6b6..113e72c33 100644 --- a/spine-c/data/spineboy.json +++ b/spine-c/data/spineboy.json @@ -307,10 +307,7 @@ { "slot": "eyes", "offset": -12 } ] }, - { - "time": 3.5862, - "offsets": [] - } + { "time": 3.5862 } ] }, "jump": { diff --git a/spine-c/example/main.c b/spine-c/example/main.c index 660181d77..726614e48 100644 --- a/spine-c/example/main.c +++ b/spine-c/example/main.c @@ -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); diff --git a/spine-c/include/spine/Animation.h b/spine-c/include/spine/Animation.h index 896441342..1f2a5e510 100644 --- a/spine-c/include/spine/Animation.h +++ b/spine-c/include/spine/Animation.h @@ -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 diff --git a/spine-c/include/spine/BoundingBoxAttachment.h b/spine-c/include/spine/BoundingBoxAttachment.h new file mode 100644 index 000000000..f13e150a9 --- /dev/null +++ b/spine-c/include/spine/BoundingBoxAttachment.h @@ -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 +#include +#include + +#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_ */ diff --git a/spine-c/include/spine/extension.h b/spine-c/include/spine/extension.h index 53c8ec610..73a21aa31 100644 --- a/spine-c/include/spine/extension.h +++ b/spine-c/include/spine/extension.h @@ -92,6 +92,7 @@ #include #include #include +#include #include #include #include diff --git a/spine-c/src/spine/Animation.c b/spine-c/src/spine/Animation.c index 0ac753858..dcb6e6b1e 100644 --- a/spine-c/src/spine/Animation.c +++ b/spine-c/src/spine/Animation.c @@ -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 + +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)); + } +} diff --git a/spine-c/src/spine/AtlasAttachmentLoader.c b/spine-c/src/spine/AtlasAttachmentLoader.c index 2441ad610..195351ebb 100644 --- a/spine-c/src/spine/AtlasAttachmentLoader.c +++ b/spine-c/src/spine/AtlasAttachmentLoader.c @@ -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; diff --git a/spine-c/src/spine/BoundingBoxAttachment.c b/spine-c/src/spine/BoundingBoxAttachment.c new file mode 100644 index 000000000..3f4f8252b --- /dev/null +++ b/spine-c/src/spine/BoundingBoxAttachment.c @@ -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 +#include +#include + +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; + } +} diff --git a/spine-c/src/spine/Json.c b/spine-c/src/spine/Json.c index 91f498341..f2ded6ae5 100644 --- a/spine-c/src/spine/Json.c +++ b/spine-c/src/spine/Json.c @@ -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; } diff --git a/spine-c/src/spine/Json.h b/spine-c/src/spine/Json.h index 0c5d9b3f3..bc11a81ac 100644 --- a/spine-c/src/spine/Json.h +++ b/spine-c/src/spine/Json.h @@ -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); diff --git a/spine-c/src/spine/SkeletonJson.c b/spine-c/src/spine/SkeletonJson.c index 2fb533e37..038fefb3b 100644 --- a/spine-c/src/spine/SkeletonJson.c +++ b/spine-c/src/spine/SkeletonJson.c @@ -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); diff --git a/spine-libgdx/test/spineboy.json b/spine-libgdx/test/spineboy.json index acba1f13a..113e72c33 100644 --- a/spine-libgdx/test/spineboy.json +++ b/spine-libgdx/test/spineboy.json @@ -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": { diff --git a/spine-sfml/data/spineboy.json b/spine-sfml/data/spineboy.json index 7619ab6b6..113e72c33 100644 --- a/spine-sfml/data/spineboy.json +++ b/spine-sfml/data/spineboy.json @@ -307,10 +307,7 @@ { "slot": "eyes", "offset": -12 } ] }, - { - "time": 3.5862, - "offsets": [] - } + { "time": 3.5862 } ] }, "jump": { diff --git a/spine-sfml/example/main.cpp b/spine-sfml/example/main.cpp index bf1d30454..89772e601 100644 --- a/spine-sfml/example/main.cpp +++ b/spine-sfml/example/main.cpp @@ -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); diff --git a/spine-sfml/src/spine/spine-sfml.cpp b/spine-sfml/src/spine/spine-sfml.cpp index 0dc7f0388..b101184a1 100644 --- a/spine-sfml/src/spine/spine-sfml.cpp +++ b/spine-sfml/src/spine/spine-sfml.cpp @@ -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;