From 278dfba922cee0d94746ded92cf08f4f9c3eb4c6 Mon Sep 17 00:00:00 2001 From: Pavel Platto Date: Wed, 24 Aug 2016 10:42:08 +0200 Subject: [PATCH] [c] Implement binary skeleton loader. (#680) * [c] Implement binary skeleton loader. * [sfml] Use skeleton binary loader in example. * [c] Remove spAnimation_createWithTimelines. --- spine-c/include/spine/SkeletonBinary.h | 72 ++ spine-c/include/spine/spine.h | 1 + spine-c/src/spine/SkeletonBinary.c | 1014 ++++++++++++++++++++++++ spine-c/src/spine/kvec.h | 92 +++ spine-sfml/data/goblins-mesh.skel | Bin 0 -> 17763 bytes spine-sfml/data/raptor.skel | Bin 0 -> 36802 bytes spine-sfml/data/spineboy.skel | Bin 0 -> 15529 bytes spine-sfml/data/tank.skel | Bin 0 -> 26518 bytes spine-sfml/data/vine.atlas | 2 +- spine-sfml/data/vine.json | 183 +++-- spine-sfml/data/vine.skel | Bin 0 -> 10276 bytes spine-sfml/example/main.cpp | 134 ++-- 12 files changed, 1325 insertions(+), 173 deletions(-) create mode 100644 spine-c/include/spine/SkeletonBinary.h create mode 100644 spine-c/src/spine/SkeletonBinary.c create mode 100644 spine-c/src/spine/kvec.h create mode 100644 spine-sfml/data/goblins-mesh.skel create mode 100644 spine-sfml/data/raptor.skel create mode 100644 spine-sfml/data/spineboy.skel create mode 100644 spine-sfml/data/tank.skel create mode 100644 spine-sfml/data/vine.skel diff --git a/spine-c/include/spine/SkeletonBinary.h b/spine-c/include/spine/SkeletonBinary.h new file mode 100644 index 000000000..cbdf1f0f4 --- /dev/null +++ b/spine-c/include/spine/SkeletonBinary.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.3 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to use, install, execute and perform the Spine + * Runtimes Software (the "Software") and derivative works solely for personal + * or internal use. Without the written permission of Esoteric Software (see + * Section 2 of the Spine Software License Agreement), you may not (a) modify, + * translate, adapt or otherwise create derivative works, improvements of the + * Software or develop new applications using the Software or (b) remove, + * delete, alter or obscure any trademarks or any copyright, trademark, patent + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 ESOTERIC SOFTWARE 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_SKELETONBINARY_H_ +#define SPINE_SKELETONBINARY_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spAtlasAttachmentLoader; + +typedef struct spSkeletonBinary { + float scale; + spAttachmentLoader* attachmentLoader; + const char* const error; +} spSkeletonBinary; + +spSkeletonBinary* spSkeletonBinary_createWithLoader (spAttachmentLoader* attachmentLoader); +spSkeletonBinary* spSkeletonBinary_create (spAtlas* atlas); +void spSkeletonBinary_dispose (spSkeletonBinary* self); + +spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const unsigned char* binary, const int length); +spSkeletonData* spSkeletonBinary_readSkeletonDataFile (spSkeletonBinary* self, const char* path); + +#ifdef SPINE_SHORT_NAMES +typedef spSkeletonBinary SkeletonBinary; +#define SkeletonBinary_createWithLoader(...) spSkeletonBinary_createWithLoader(__VA_ARGS__) +#define SkeletonBinary_create(...) spSkeletonBinary_create(__VA_ARGS__) +#define SkeletonBinary_dispose(...) spSkeletonBinary_dispose(__VA_ARGS__) +#define SkeletonBinary_readSkeletonData(...) spSkeletonBinary_readSkeletonData(__VA_ARGS__) +#define SkeletonBinary_readSkeletonDataFile(...) spSkeletonBinary_readSkeletonDataFile(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SPINE_SKELETONBINARY_H_ */ diff --git a/spine-c/include/spine/spine.h b/spine-c/include/spine/spine.h index c5ff57434..704e89407 100644 --- a/spine-c/include/spine/spine.h +++ b/spine-c/include/spine/spine.h @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/spine-c/src/spine/SkeletonBinary.c b/spine-c/src/spine/SkeletonBinary.c new file mode 100644 index 000000000..c8161ec8d --- /dev/null +++ b/spine-c/src/spine/SkeletonBinary.c @@ -0,0 +1,1014 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.3 + * + * Copyright (c) 2013-2015, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to use, install, execute and perform the Spine + * Runtimes Software (the "Software") and derivative works solely for personal + * or internal use. Without the written permission of Esoteric Software (see + * Section 2 of the Spine Software License Agreement), you may not (a) modify, + * translate, adapt or otherwise create derivative works, improvements of the + * Software or develop new applications using the Software or (b) remove, + * delete, alter or obscure any trademarks or any copyright, trademark, patent + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 ESOTERIC SOFTWARE 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 +#include +#include +#include "kvec.h" + +typedef struct { + const unsigned char* cursor; + const unsigned char* end; +} _dataInput; + +typedef struct { + const char* parent; + const char* skin; + int slotIndex; + spMeshAttachment* mesh; +} _spLinkedMesh; + +typedef struct { + spSkeletonBinary super; + int ownsLoader; + + int linkedMeshCount; + int linkedMeshCapacity; + _spLinkedMesh* linkedMeshes; +} _spSkeletonBinary; + +spSkeletonBinary* spSkeletonBinary_createWithLoader (spAttachmentLoader* attachmentLoader) { + spSkeletonBinary* self = SUPER(NEW(_spSkeletonBinary)); + self->scale = 1; + self->attachmentLoader = attachmentLoader; + return self; +} + +spSkeletonBinary* spSkeletonBinary_create (spAtlas* atlas) { + spAtlasAttachmentLoader* attachmentLoader = spAtlasAttachmentLoader_create(atlas); + spSkeletonBinary* self = spSkeletonBinary_createWithLoader(SUPER(attachmentLoader)); + SUB_CAST(_spSkeletonBinary, self)->ownsLoader = 1; + return self; +} + +void spSkeletonBinary_dispose (spSkeletonBinary* self) { + _spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self); + if (internal->ownsLoader) spAttachmentLoader_dispose(self->attachmentLoader); + FREE(internal->linkedMeshes); + FREE(self->error); + FREE(self); +} + +void _spSkeletonBinary_setError (spSkeletonBinary* self, const char* value1, const char* value2) { + char message[256]; + int length; + FREE(self->error); + strcpy(message, value1); + length = (int)strlen(value1); + if (value2) strncat(message + length, value2, 255 - length); + MALLOC_STR(self->error, message); +} + +static unsigned char readByte (_dataInput* input) { + return *input->cursor++; +} + +static char readSByte (_dataInput* input) { + return (char)readByte(input); +} + +static int readBoolean (_dataInput* input) { + return readByte(input) != 0; +} + +static int readInt (_dataInput* input) { + int result = readByte(input); + result <<= 8; + result |= readByte(input); + result <<= 8; + result |= readByte(input); + result <<= 8; + result |= readByte(input); + return result; +} + +static int readVarint (_dataInput* input, int/*bool*/optimizePositive) { + unsigned char b = readByte(input); + int value = b & 0x7F; + if (b & 0x80) { + b = readByte(input); + value |= (b & 0x7F) << 7; + if (b & 0x80) { + b = readByte(input); + value |= (b & 0x7F) << 14; + if (b & 0x80) { + b = readByte(input); + value |= (b & 0x7F) << 21; + if (b & 0x80) value |= (readByte(input) & 0x7F) << 28; + } + } + } + if (!optimizePositive) value = (((unsigned int)value >> 1) ^ -(value & 1)); + return value; +} + +float readFloat (_dataInput* input) { + union { + int intValue; + float floatValue; + } intToFloat; + intToFloat.intValue = readInt(input); + return intToFloat.floatValue; +} + +char* readString (_dataInput* input) { + int length = readVarint(input, 1); + char* string; + if (length == 0) { + return 0; + } + string = MALLOC(char, length); + memcpy(string, input->cursor, length - 1); + input->cursor += length - 1; + string[length - 1] = '\0'; + return string; +} + +static void readColor (_dataInput* input, float *r, float *g, float *b, float *a) { + *r = readByte(input) / 255.0f; + *g = readByte(input) / 255.0f; + *b = readByte(input) / 255.0f; + *a = readByte(input) / 255.0f; +} + +#define ATTACHMENT_REGION 0 +#define ATTACHMENT_BOUNDING_BOX 1 +#define ATTACHMENT_MESH 2 +#define ATTACHMENT_LINKED_MESH 3 +#define ATTACHMENT_PATH 4 + +#define BLEND_MODE_NORMAL 0 +#define BLEND_MODE_ADDITIVE 1 +#define BLEND_MODE_MULTIPLY 2 +#define BLEND_MODE_SCREEN 3 + +#define CURVE_LINEAR 0 +#define CURVE_STEPPED 1 +#define CURVE_BEZIER 2 + +#define BONE_ROTATE 0 +#define BONE_TRANSLATE 1 +#define BONE_SCALE 2 +#define BONE_SHEAR 3 + +#define SLOT_ATTACHMENT 0 +#define SLOT_COLOR 1 + +#define PATH_POSITION 0 +#define PATH_SPACING 1 +#define PATH_MIX 2 + +#define PATH_POSITION_FIXED 0 +#define PATH_POSITION_PERCENT 1 + +#define PATH_SPACING_LENGTH 0 +#define PATH_SPACING_FIXED 1 +#define PATH_SPACING_PERCENT 2 + +#define PATH_ROTATE_TANGENT 0 +#define PATH_ROTATE_CHAIN 1 +#define PATH_ROTATE_CHAIN_SCALE 2 + +static void readCurve (_dataInput* input, spCurveTimeline* timeline, int frameIndex) { + switch (readByte(input)) { + case CURVE_STEPPED: { + spCurveTimeline_setStepped(timeline, frameIndex); + break; + } + case CURVE_BEZIER: { + float cx1 = readFloat(input); + float cy1 = readFloat(input); + float cx2 = readFloat(input); + float cy2 = readFloat(input); + spCurveTimeline_setCurve(timeline, frameIndex, cx1, cy1, cx2, cy2); + break; + } + } +} + +static void _spSkeletonBinary_addLinkedMesh (spSkeletonBinary* self, spMeshAttachment* mesh, + const char* skin, int slotIndex, const char* parent) { + _spLinkedMesh* linkedMesh; + _spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self); + + if (internal->linkedMeshCount == internal->linkedMeshCapacity) { + _spLinkedMesh* linkedMeshes; + internal->linkedMeshCapacity *= 2; + if (internal->linkedMeshCapacity < 8) internal->linkedMeshCapacity = 8; + /* TODO Why not realloc? */ + linkedMeshes = MALLOC(_spLinkedMesh, internal->linkedMeshCapacity); + memcpy(linkedMeshes, internal->linkedMeshes, sizeof(_spLinkedMesh) * 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* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, const char* name, + _dataInput* input, spSkeletonData *skeletonData) { + kvec_t(spTimeline*) timelines; + float duration = 0; + int i, n, ii, nn, iii, nnn; + int frameIndex; + int drawOrderCount, eventCount; + spAnimation* animation; + + kv_init(timelines); + + /* Slot timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int slotIndex = readVarint(input, 1); + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + unsigned char timelineType = readByte(input); + int frameCount = readVarint(input, 1); + switch (timelineType) { + case SLOT_COLOR: { + spColorTimeline* timeline = spColorTimeline_create(frameCount); + timeline->slotIndex = slotIndex; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float r, g, b, a; + readColor(input, &r, &g, &b, &a); + spColorTimeline_setFrame(timeline, frameIndex, time, r, g, b, a); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * COLOR_ENTRIES]); + break; + } + case SLOT_ATTACHMENT: { + spAttachmentTimeline* timeline = spAttachmentTimeline_create(frameCount); + timeline->slotIndex = slotIndex; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + const char* attachmentName = readString(input); + /* TODO Avoid copying of attachmentName inside */ + spAttachmentTimeline_setFrame(timeline, frameIndex, time, attachmentName); + FREE(attachmentName); + } + kv_push(spTimeline*, timelines, SUPER(timeline)); + duration = MAX(duration, timeline->frames[frameCount - 1]); + break; + } + default: { + int i; + for (i = 0; i < kv_size(timelines); ++i) + spTimeline_dispose(kv_A(timelines, i)); + kv_destroy(timelines); + _spSkeletonBinary_setError(self, "Invalid timeline type for a slot: ", skeletonData->slots[slotIndex]->name); + return 0; + } + } + } + } + + /* Bone timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int boneIndex = readVarint(input, 1); + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + unsigned char timelineType = readByte(input); + int frameCount = readVarint(input, 1); + switch (timelineType) { + case BONE_ROTATE: { + spRotateTimeline *timeline = spRotateTimeline_create(frameCount); + timeline->boneIndex = boneIndex; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float degrees = readFloat(input); + spRotateTimeline_setFrame(timeline, frameIndex, time, degrees); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * ROTATE_ENTRIES]); + break; + } + case BONE_TRANSLATE: + case BONE_SCALE: + case BONE_SHEAR: { + float timelineScale = 1; + spTranslateTimeline *timeline = 0; + switch (timelineType) { + case BONE_SCALE: + timeline = spScaleTimeline_create(frameCount); + break; + case BONE_SHEAR: + timeline = spShearTimeline_create(frameCount); + break; + case BONE_TRANSLATE: + timeline = spTranslateTimeline_create(frameCount); + timelineScale = self->scale; + break; + default: + break; + } + timeline->boneIndex = boneIndex; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float x = readFloat(input) * timelineScale; + float y = readFloat(input) * timelineScale; + spTranslateTimeline_setFrame(timeline, frameIndex, time, x, y); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER_CAST(spTimeline, timeline)); + duration = MAX(duration, timeline->frames[(frameCount - 1) * TRANSLATE_ENTRIES]); + break; + } + default: { + int i; + for (i = 0; i < kv_size(timelines); ++i) + spTimeline_dispose(kv_A(timelines, i)); + kv_destroy(timelines); + _spSkeletonBinary_setError(self, "Invalid timeline type for a bone: ", skeletonData->bones[boneIndex]->name); + return 0; + } + } + } + } + + /* IK constraint timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int index = readVarint(input, 1); + int frameCount = readVarint(input, 1); + spIkConstraintTimeline* timeline = spIkConstraintTimeline_create(frameCount); + timeline->ikConstraintIndex = index; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float mix = readFloat(input); + char bendDirection = readSByte(input); + spIkConstraintTimeline_setFrame(timeline, frameIndex, time, mix, bendDirection); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * IKCONSTRAINT_ENTRIES]); + } + + /* Transform constraint timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int index = readVarint(input, 1); + int frameCount = readVarint(input, 1); + spTransformConstraintTimeline* timeline = spTransformConstraintTimeline_create(frameCount); + timeline->transformConstraintIndex = index; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float rotateMix = readFloat(input); + float translateMix = readFloat(input); + float scaleMix = readFloat(input); + float shearMix = readFloat(input); + spTransformConstraintTimeline_setFrame(timeline, frameIndex, time, rotateMix, translateMix, + scaleMix, shearMix); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * TRANSFORMCONSTRAINT_ENTRIES]); + } + + /* Path constraint timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int index = readVarint(input, 1); + spPathConstraintData* data = skeletonData->pathConstraints[index]; + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + unsigned char timelineType = readByte(input); + int frameCount = readVarint(input, 1); + switch (timelineType) { + case PATH_POSITION: + case PATH_SPACING: { + spPathConstraintPositionTimeline* timeline = 0; + float timelineScale = 1; + if (timelineType == PATH_SPACING) { + timeline = (spPathConstraintPositionTimeline*)spPathConstraintSpacingTimeline_create(frameCount); + if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) + timelineScale = self->scale; + } else { + timeline = spPathConstraintPositionTimeline_create(frameCount); + if (data->positionMode == SP_POSITION_MODE_FIXED) + timelineScale = self->scale; + } + timeline->pathConstraintIndex = index; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float value = readFloat(input) * timelineScale; + spPathConstraintPositionTimeline_setFrame(timeline, frameIndex, time, value); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * PATHCONSTRAINTPOSITION_ENTRIES]); + break; + } + case PATH_MIX: { + spPathConstraintMixTimeline* timeline = spPathConstraintMixTimeline_create(frameCount); + timeline->pathConstraintIndex = index; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float rotateMix = readFloat(input); + float translateMix = readFloat(input); + spPathConstraintMixTimeline_setFrame(timeline, frameIndex, time, rotateMix, translateMix); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * PATHCONSTRAINTMIX_ENTRIES]); + } + } + } + } + + /* Deform timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + spSkin* skin = skeletonData->skins[readVarint(input, 1)]; + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + int slotIndex = readVarint(input, 1); + for (iii = 0, nnn = readVarint(input, 1); iii < nnn; ++iii) { + float* tempDeform; + spDeformTimeline *timeline; + int weighted, deformLength; + const char* attachmentName = readString(input); + int frameCount; + + spVertexAttachment* attachment = SUB_CAST(spVertexAttachment, + spSkin_getAttachment(skin, slotIndex, attachmentName)); + if (!attachment) { + int i; + for (i = 0; i < kv_size(timelines); ++i) + spTimeline_dispose(kv_A(timelines, i)); + kv_destroy(timelines); + _spSkeletonBinary_setError(self, "Attachment not found: ", attachmentName); + FREE(attachmentName); + return 0; + } + FREE(attachmentName); + + weighted = attachment->bones != 0; + deformLength = weighted ? attachment->verticesCount / 3 * 2 : attachment->verticesCount; + tempDeform = MALLOC(float, deformLength); + + frameCount = readVarint(input, 1); + timeline = spDeformTimeline_create(frameCount, deformLength); + timeline->slotIndex = slotIndex; + timeline->attachment = SUPER(attachment); + + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float* deform; + int end = readVarint(input, 1); + if (!end) { + if (weighted) { + deform = tempDeform; + memset(deform, 0, sizeof(float) * deformLength); + } else + deform = attachment->vertices; + } else { + int v, start = readVarint(input, 1); + deform = tempDeform; + memset(deform, 0, sizeof(float) * start); + end += start; + if (self->scale == 1) { + for (v = start; v < end; ++v) + deform[v] = readFloat(input); + } else { + for (v = start; v < end; ++v) + deform[v] = readFloat(input) * self->scale; + } + memset(deform + v, 0, sizeof(float) * (deformLength - v)); + if (!weighted) { + float* vertices = attachment->vertices; + for (v = 0; v < deformLength; ++v) + deform[v] += vertices[v]; + } + } + spDeformTimeline_setFrame(timeline, frameIndex, time, deform); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + FREE(tempDeform); + + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[frameCount - 1]); + } + } + } + + /* Draw order timeline. */ + drawOrderCount = readVarint(input, 1); + if (drawOrderCount) { + spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrderCount, skeletonData->slotsCount); + for (i = 0; i < drawOrderCount; ++i) { + float time = readFloat(input); + int offsetCount = readVarint(input, 1); + int* drawOrder = MALLOC(int, skeletonData->slotsCount); + int* unchanged = MALLOC(int, skeletonData->slotsCount - offsetCount); + int originalIndex = 0, unchangedIndex = 0; + memset(drawOrder, -1, sizeof(int) * skeletonData->slotsCount); + for (ii = 0; ii < offsetCount; ++ii) { + int slotIndex = readVarint(input, 1); + /* Collect unchanged items. */ + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + /* Set changed items. */ + drawOrder[originalIndex + readVarint(input, 1)] = originalIndex; + ++originalIndex; + } + /* Collect remaining unchanged items. */ + while (originalIndex < skeletonData->slotsCount) + unchanged[unchangedIndex++] = originalIndex++; + /* Fill in unchanged items. */ + for (ii = skeletonData->slotsCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; + FREE(unchanged); + /* TODO Avoid copying of drawOrder inside */ + spDrawOrderTimeline_setFrame(timeline, i, time, drawOrder); + FREE(drawOrder); + } + kv_push(spTimeline*, timelines, SUPER(timeline)); + duration = MAX(duration, timeline->frames[drawOrderCount - 1]); + } + + /* Event timeline. */ + eventCount = readVarint(input, 1); + if (eventCount) { + spEventTimeline* timeline = spEventTimeline_create(eventCount); + for (i = 0; i < eventCount; ++i) { + float time = readFloat(input); + spEventData* eventData = skeletonData->events[readVarint(input, 1)]; + spEvent* event = spEvent_create(time, eventData); + event->intValue = readVarint(input, 0); + event->floatValue = readFloat(input); + if (readBoolean(input)) + event->stringValue = readString(input); + else + MALLOC_STR(event->stringValue, eventData->stringValue); + spEventTimeline_setFrame(timeline, i, event); + } + kv_push(spTimeline*, timelines, SUPER(timeline)); + duration = MAX(duration, timeline->frames[eventCount - 1]); + } + + kv_trim(spTimeline*, timelines); + + animation = spAnimation_create(name, 0); + animation->duration = duration; + animation->timelinesCount = kv_size(timelines); + animation->timelines = kv_array(timelines); + return animation; +} + +static float* _readFloatArray(_dataInput *input, int n, float scale) { + float* array = MALLOC(float, n); + int i; + if (scale == 1) + for (i = 0; i < n; ++i) + array[i] = readFloat(input); + else + for (i = 0; i < n; ++i) + array[i] = readFloat(input) * scale; + return array; +} + +static short* _readShortArray(_dataInput *input, int *length) { + int n = readVarint(input, 1); + short* array = MALLOC(short, n); + int i; + *length = n; + for (i = 0; i < n; ++i) { + array[i] = readByte(input) << 8; + array[i] |= readByte(input); + } + return array; +} + +static void _readVertices(spSkeletonBinary* self, _dataInput* input, spVertexAttachment* attachment, + int vertexCount) { + int i, ii; + int verticesLength = vertexCount << 1; + kvec_t(float) weights; + kvec_t(int) bones; + + attachment->worldVerticesLength = verticesLength; + + if (!readBoolean(input)) { + attachment->verticesCount = verticesLength; + attachment->vertices = _readFloatArray(input, verticesLength, self->scale); + attachment->bonesCount = 0; + attachment->bones = 0; + return; + } + + kv_init(weights); + kv_resize(float, weights, verticesLength * 3 * 3); + + kv_init(bones); + kv_resize(int, bones, verticesLength * 3); + + for (i = 0; i < vertexCount; ++i) { + int boneCount = readVarint(input, 1); + kv_push(int, bones, boneCount); + for (ii = 0; ii < boneCount; ++ii) { + kv_push(int, bones, readVarint(input, 1)); + kv_push(float, weights, readFloat(input) * self->scale); + kv_push(float, weights, readFloat(input) * self->scale); + kv_push(float, weights, readFloat(input)); + } + } + + kv_trim(float, weights); + attachment->verticesCount = kv_size(weights); + attachment->vertices = kv_array(weights); + + kv_trim(int, bones); + attachment->bonesCount = kv_size(bones); + attachment->bones = kv_array(bones); +} + +spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput* input, + spSkin* skin, int slotIndex, const char* attachmentName, int/*bool*/ nonessential) { + int i; + spAttachmentType type; + const char* name = readString(input); + if (!name) MALLOC_STR(name, attachmentName); + + type = (spAttachmentType)readByte(input); + + switch (type) { + case SP_ATTACHMENT_REGION: { + const char* path = readString(input); + spAttachment* attachment; + spRegionAttachment* region; + if (!path) MALLOC_STR(path, name); + attachment = spAttachmentLoader_createAttachment( + self->attachmentLoader, skin, type, name, path); + region = SUB_CAST(spRegionAttachment, attachment); + region->path = path; + region->rotation = readFloat(input); + region->x = readFloat(input) * self->scale; + region->y = readFloat(input) * self->scale; + region->scaleX = readFloat(input); + region->scaleY = readFloat(input); + region->width = readFloat(input) * self->scale; + region->height = readFloat(input) * self->scale; + readColor(input, ®ion->r, ®ion->g, ®ion->b, ®ion->a); + spRegionAttachment_updateOffset(region); + spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); + return attachment; + } + case SP_ATTACHMENT_BOUNDING_BOX: { + int vertexCount = readVarint(input, 1); + spAttachment* attachment = spAttachmentLoader_createAttachment( + self->attachmentLoader, skin, type, name, 0); + _readVertices(self, input, SUB_CAST(spVertexAttachment, attachment), vertexCount); + if (nonessential) readInt(input); /* Skip color. */ + spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); + return attachment; + } + case SP_ATTACHMENT_MESH: { + int vertexCount; + spAttachment* attachment; + spMeshAttachment* mesh; + const char* path = readString(input); + if (!path) MALLOC_STR(path, name); + attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path); + mesh = SUB_CAST(spMeshAttachment, attachment); + mesh->path = path; + readColor(input, &mesh->r, &mesh->g, &mesh->b, &mesh->a); + vertexCount = readVarint(input, 1); + mesh->regionUVs = _readFloatArray(input, vertexCount << 1, 1); + mesh->triangles = (unsigned short*)_readShortArray(input, &mesh->trianglesCount); + _readVertices(self, input, SUPER(mesh), vertexCount); + spMeshAttachment_updateUVs(mesh); + mesh->hullLength = readVarint(input, 1) << 1; + if (nonessential) { + mesh->edges = (int*)_readShortArray(input, &mesh->edgesCount); + mesh->width = readFloat(input) * self->scale; + mesh->height = readFloat(input) * self->scale; + } else { + mesh->edges = 0; + mesh->width = 0; + mesh->height = 0; + } + return attachment; + } + case SP_ATTACHMENT_LINKED_MESH: { + const char* skinName; + const char* parent; + spAttachment* attachment; + spMeshAttachment* mesh; + const char* path = readString(input); + if (!path) MALLOC_STR(path, name); + attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path); + mesh = SUB_CAST(spMeshAttachment, attachment); + mesh->path = path; + readColor(input, &mesh->r, &mesh->g, &mesh->b, &mesh->a); + skinName = readString(input); + parent = readString(input); + mesh->inheritDeform = readBoolean(input); + if (nonessential) { + mesh->width = readFloat(input) * self->scale; + mesh->height = readFloat(input) * self->scale; + } + _spSkeletonBinary_addLinkedMesh(self, mesh, skinName, slotIndex, parent); + return attachment; + } + case SP_ATTACHMENT_PATH: { + spAttachment* attachment = spAttachmentLoader_createAttachment( + self->attachmentLoader, skin, type, name, 0); + spPathAttachment* path = SUB_CAST(spPathAttachment, attachment); + int vertexCount = 0; + path->closed = readBoolean(input); + path->constantSpeed = readBoolean(input); + vertexCount = readVarint(input, 1); + _readVertices(self, input, SUPER(path), vertexCount); + path->lengthsLength = vertexCount / 3; + path->lengths = MALLOC(float, path->lengthsLength); + for (i = 0; i < path->lengthsLength; ++i) { + path->lengths[i] = readFloat(input) * self->scale; + } + if (nonessential) readInt(input); /* Skip color. */ + return attachment; + } + } + + return 0; +} + +spSkin* spSkeletonBinary_readSkin(spSkeletonBinary* self, _dataInput* input, + const char* skinName, int/*bool*/ nonessential) { + spSkin* skin; + int slotCount = readVarint(input, 1); + int i, ii, nn; + if (slotCount == 0) + return 0; + skin = spSkin_create(skinName); + for (i = 0; i < slotCount; ++i) { + int slotIndex = readVarint(input, 1); + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + const char* name = readString(input); + spSkin_addAttachment(skin, slotIndex, name, + spSkeletonBinary_readAttachment(self, input, skin, slotIndex, name, nonessential)); + FREE(name); + } + } + return skin; +} + +spSkeletonData* spSkeletonBinary_readSkeletonDataFile (spSkeletonBinary* self, const char* path) { + int length; + spSkeletonData* skeletonData; + const char* binary = _spUtil_readFile(path, &length); + if (length == 0 || !binary) { + _spSkeletonBinary_setError(self, "Unable to read skeleton file: ", path); + return 0; + } + skeletonData = spSkeletonBinary_readSkeletonData(self, (unsigned char*)binary, length); + FREE(binary); + return skeletonData; +} + +spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const unsigned char* binary, + const int length) { + int i, ii, nonessential; + spSkeletonData* skeletonData; + _spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self); + + _dataInput* input = NEW(_dataInput); + input->cursor = binary; + input->end = binary + length; + + FREE(self->error); + CONST_CAST(char*, self->error) = 0; + internal->linkedMeshCount = 0; + + skeletonData = spSkeletonData_create(); + + skeletonData->hash = readString(input); + if (!strlen(skeletonData->hash)) { + FREE(skeletonData->hash); + skeletonData->hash = 0; + } + + skeletonData->version = readString(input); + if (!strlen(skeletonData->version)) { + FREE(skeletonData->version); + skeletonData->version = 0; + } + + skeletonData->width = readFloat(input); + skeletonData->height = readFloat(input); + + nonessential = readBoolean(input); + + if (nonessential) FREE(readString(input)); /* Skip images path. */ + + /* Bones. */ + skeletonData->bonesCount = readVarint(input, 1); + skeletonData->bones = MALLOC(spBoneData*, skeletonData->bonesCount); + for (i = 0; i < skeletonData->bonesCount; ++i) { + spBoneData* data; + const char* name = readString(input); + spBoneData* parent = i == 0 ? 0 : skeletonData->bones[readVarint(input, 1)]; + /* TODO Avoid copying of name */ + data = spBoneData_create(i, name, parent); + FREE(name); + data->rotation = readFloat(input); + data->x = readFloat(input) * self->scale; + data->y = readFloat(input) * self->scale; + data->scaleX = readFloat(input); + data->scaleY = readFloat(input); + data->shearX = readFloat(input); + data->shearY = readFloat(input); + data->length = readFloat(input) * self->scale; + data->inheritRotation = readBoolean(input); + data->inheritScale = readBoolean(input); + if (nonessential) readInt(input); /* Skip bone color. */ + skeletonData->bones[i] = data; + } + + /* Slots. */ + skeletonData->slotsCount = readVarint(input, 1); + skeletonData->slots = MALLOC(spSlotData*, skeletonData->slotsCount); + for (i = 0; i < skeletonData->slotsCount; ++i) { + const char* slotName = readString(input); + spBoneData* boneData = skeletonData->bones[readVarint(input, 1)]; + /* TODO Avoid copying of slotName */ + spSlotData* slotData = spSlotData_create(i, slotName, boneData); + FREE(slotName); + readColor(input, &slotData->r, &slotData->g, &slotData->b, &slotData->a); + slotData->attachmentName = readString(input); + slotData->blendMode = (spBlendMode)readVarint(input, 1); + skeletonData->slots[i] = slotData; + } + + /* IK constraints. */ + skeletonData->ikConstraintsCount = readVarint(input, 1); + skeletonData->ikConstraints = MALLOC(spIkConstraintData*, skeletonData->ikConstraintsCount); + for (i = 0; i < skeletonData->ikConstraintsCount; ++i) { + const char* name = readString(input); + /* TODO Avoid copying of name */ + spIkConstraintData* data = spIkConstraintData_create(name); + FREE(name); + data->bonesCount = readVarint(input, 1); + data->bones = MALLOC(spBoneData*, data->bonesCount); + for (ii = 0; ii < data->bonesCount; ++ii) + data->bones[ii] = skeletonData->bones[readVarint(input, 1)]; + data->target = skeletonData->bones[readVarint(input, 1)]; + data->mix = readFloat(input); + data->bendDirection = readSByte(input); + skeletonData->ikConstraints[i] = data; + } + + /* Transform constraints. */ + skeletonData->transformConstraintsCount = readVarint(input, 1); + skeletonData->transformConstraints = MALLOC( + spTransformConstraintData*, skeletonData->transformConstraintsCount); + for (i = 0; i < skeletonData->transformConstraintsCount; ++i) { + const char* name = readString(input); + /* TODO Avoid copying of name */ + spTransformConstraintData* data = spTransformConstraintData_create(name); + FREE(name); + data->bonesCount = readVarint(input, 1); + CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount); + for (ii = 0; ii < data->bonesCount; ++ii) + data->bones[ii] = skeletonData->bones[readVarint(input, 1)]; + data->target = skeletonData->bones[readVarint(input, 1)]; + data->offsetRotation = readFloat(input); + data->offsetX = readFloat(input) * self->scale; + data->offsetY = readFloat(input) * self->scale; + data->offsetScaleX = readFloat(input); + data->offsetScaleY = readFloat(input); + data->offsetShearY = readFloat(input); + data->rotateMix = readFloat(input); + data->translateMix = readFloat(input); + data->scaleMix = readFloat(input); + data->shearMix = readFloat(input); + skeletonData->transformConstraints[i] = data; + } + + /* Path constraints */ + skeletonData->pathConstraintsCount = readVarint(input, 1); + skeletonData->pathConstraints = MALLOC(spPathConstraintData*, skeletonData->pathConstraintsCount); + for (i = 0; i < skeletonData->pathConstraintsCount; ++i) { + const char* name = readString(input); + /* TODO Avoid copying of name */ + spPathConstraintData* data = spPathConstraintData_create(name); + FREE(name); + data->bonesCount = readVarint(input, 1); + CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount); + for (ii = 0; ii < data->bonesCount; ++ii) + data->bones[ii] = skeletonData->bones[readVarint(input, 1)]; + data->target = skeletonData->slots[readVarint(input, 1)]; + data->positionMode = (spPositionMode)readVarint(input, 1); + data->spacingMode = (spSpacingMode)readVarint(input, 1); + data->rotateMode = (spRotateMode)readVarint(input, 1); + data->offsetRotation = readFloat(input); + data->position = readFloat(input); + if (data->positionMode == SP_POSITION_MODE_FIXED) data->position *= self->scale; + data->spacing = readFloat(input); + if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) data->spacing *= self->scale; + data->rotateMix = readFloat(input); + data->translateMix = readFloat(input); + skeletonData->pathConstraints[i] = data; + } + + /* Default skin. */ + skeletonData->defaultSkin = spSkeletonBinary_readSkin(self, input, "default", nonessential); + skeletonData->skinsCount = readVarint(input, 1); + + if (skeletonData->defaultSkin) + ++skeletonData->skinsCount; + + skeletonData->skins = MALLOC(spSkin*, skeletonData->skinsCount); + + if (skeletonData->defaultSkin) + skeletonData->skins[0] = skeletonData->defaultSkin; + + /* Skins. */ + for (i = skeletonData->defaultSkin ? 1 : 0; i < skeletonData->skinsCount; ++i) { + const char* skinName = readString(input); + /* TODO Avoid copying of skinName */ + skeletonData->skins[i] = spSkeletonBinary_readSkin(self, input, skinName, nonessential); + FREE(skinName); + } + + /* Linked meshes. */ + for (i = 0; i < internal->linkedMeshCount; ++i) { + _spLinkedMesh* linkedMesh = internal->linkedMeshes + i; + spSkin* skin = !linkedMesh->skin ? skeletonData->defaultSkin : spSkeletonData_findSkin(skeletonData, linkedMesh->skin); + spAttachment* parent; + if (!skin) { + FREE(input); + spSkeletonData_dispose(skeletonData); + _spSkeletonBinary_setError(self, "Skin not found: ", linkedMesh->skin); + return 0; + } + parent = spSkin_getAttachment(skin, linkedMesh->slotIndex, linkedMesh->parent); + if (!parent) { + FREE(input); + spSkeletonData_dispose(skeletonData); + _spSkeletonBinary_setError(self, "Parent mesh not found: ", linkedMesh->parent); + return 0; + } + spMeshAttachment_setParentMesh(linkedMesh->mesh, SUB_CAST(spMeshAttachment, parent)); + spMeshAttachment_updateUVs(linkedMesh->mesh); + spAttachmentLoader_configureAttachment(self->attachmentLoader, SUPER(SUPER(linkedMesh->mesh))); + } + + /* Events. */ + skeletonData->eventsCount = readVarint(input, 1); + skeletonData->events = MALLOC(spEventData*, skeletonData->eventsCount); + for (i = 0; i < skeletonData->eventsCount; ++i) { + const char* name = readString(input); + /* TODO Avoid copying of skinName */ + spEventData* eventData = spEventData_create(name); + FREE(name); + eventData->intValue = readVarint(input, 0); + eventData->floatValue = readFloat(input); + eventData->stringValue = readString(input); + skeletonData->events[i] = eventData; + } + + /* Animations. */ + skeletonData->animationsCount = readVarint(input, 1); + skeletonData->animations = MALLOC(spAnimation*, skeletonData->animationsCount); + for (i = 0; i < skeletonData->animationsCount; ++i) { + spAnimation* animation = _spSkeletonBinary_readAnimation(self, readString(input), input, skeletonData); + if (!animation) { + FREE(input); + spSkeletonData_dispose(skeletonData); + return 0; + } + skeletonData->animations[i] = animation; + } + + FREE(input); + return skeletonData; +} diff --git a/spine-c/src/spine/kvec.h b/spine-c/src/spine/kvec.h new file mode 100644 index 000000000..99f49ccb1 --- /dev/null +++ b/spine-c/src/spine/kvec.h @@ -0,0 +1,92 @@ +/* The MIT License + + Copyright (c) 2008, by Attractive Chaos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +/* + An example: + +#include "kvec.h" +int main() { + kvec_t(int) array; + kv_init(array); + kv_push(int, array, 10); // append + kv_a(int, array, 20) = 5; // dynamic + kv_A(array, 20) = 4; // static + kv_destroy(array); + return 0; +} +*/ + +/* + 2008-09-22 (0.1.0): + + * The initial version. + +*/ + +#ifndef AC_KVEC_H +#define AC_KVEC_H + +#include + +#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) + +#define kvec_t(type) struct { size_t n, m; type *a; } +#define kv_init(v) ((v).n = (v).m = 0, (v).a = 0) +#define kv_destroy(v) free((v).a) +#define kv_A(v, i) ((v).a[(i)]) +#define kv_array(v) ((v).a) +#define kv_pop(v) ((v).a[--(v).n]) +#define kv_size(v) ((v).n) +#define kv_max(v) ((v).m) + +#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m)) +#define kv_trim(type, v) (kv_resize(type, (v), kv_size(v))) + +#define kv_copy(type, v1, v0) do { \ + if ((v1).m < (v0).n) kv_resize(type, v1, (v0).n); \ + (v1).n = (v0).n; \ + memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \ + } while (0) \ + +#define kv_push(type, v, x) do { \ + if ((v).n == (v).m) { \ + (v).m = (v).m? (v).m<<1 : 2; \ + (v).a = (type*)realloc((v).a, sizeof(type) * (v).m); \ + } \ + (v).a[(v).n++] = (x); \ + } while (0) + +#define kv_pushp(type, v) (((v).n == (v).m)? \ + ((v).m = ((v).m? (v).m<<1 : 2), \ + (v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \ + : 0), ((v).a + ((v).n++)) + +#define kv_a(type, v, i) (((v).m <= (size_t)(i)? \ + ((v).m = (v).n = (i) + 1, kv_roundup32((v).m), \ + (v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \ + : (v).n <= (size_t)(i)? (v).n = (i) + 1 \ + : 0), (v).a[(i)]) + +#endif diff --git a/spine-sfml/data/goblins-mesh.skel b/spine-sfml/data/goblins-mesh.skel new file mode 100644 index 0000000000000000000000000000000000000000..98dd16a04ba96c9a8492f353459af3de380a9626 GIT binary patch literal 17763 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⋙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 Sce7S{ zgCh8JKu{Q>QCx#S(%nHp2i)crTXpLE ze&^h}%c*;BRd>Roa&hL;IeF!Ctm9@DW{$~o=HHREVzG5$X{I&Al4eayPj_A^v^WEquxmM(uIu>FXl(u(5J(jvTwj!1DNKf*c+ z){O{E36m+NAn65$dGYJo!&0B-yW8WXM22D6=F3d8f;R`FeJKS~-%G&r-grw0;?(1< zq1x~nVcPIEqdI)&Sw*F#Wu=a?($eBt6=mh5SexdDzbm==C$}#qG)dc12&F|htPJzq zhzG~lvV}G6(ar_6)lf(R(;P|BlZwjc6jzY8bo}spg5#O50#sZx&omol&b&pD=oXFP zzP%GXN1a43ESfcUUTJau($cn$>VI zJx_Y^YA(yhH#5!QvOnNOBSU&QJiT#kSXFz5WBkA7Q$|!PV`#;^MKPFn$Ar>ox8oL9 zdltPe?6%OuXU#{EIiB2W9PR^SgDbGRvREtbmn~f!lg}FYRU-^YP&R2F7TD(wXLASv zo8wV~XK`z9x;@&`1yO3z)~;I68Qrv?ZQZq?Gka)3XZ6&A&Q4H=4khJnO7Eo!ZtATG zZtkNAZb{SxxAxTp&q&e)xAoHm&rH??&+4xUo;^Sd+?+m86Wl~@EH~~)w9S~!shX@? z25Ev@2Wx_74ABI)4b=qCOw$C<8m0-JovsCLNjGVNo6MTvW{W1c1){o|*h|}t#hRfB zo?+7jw`D5uEI0^!+vr?5x43x0(1r76JBnfOR^Bp_^!&4TeR~?3q~nVy5-S~L3l_|q zU0iO;MorVc*WdOWyfD%~tC{)VW^b06vig7jq865gu+X0tmX)v^{kD$R!pfkmeKmLd zI;#^Yjr{VWW%DYQo5=0GY1p(g(%B!s3|tsqBr_p7OrM;P-u?2HhuT zP^i_9*@3o{Eigm&1I>?I4{Z^rM@>Dlw#ui`qBWX3*$=Qxd5RC*`}fo4dSpLx%UkyS z4}tx(xgKDd^Ka}28Q#}J+p6b@ieYN~SVrmbLtD4B=k+ma{a8oq@gw(#iZ#V*{bY>M zEb|8{`&6HR-1yM*S#A8bsg2)ewej1kHhyQRjo((a z@!O^{ep}Pk#&4V2_?@LPerKkujo)Uq@!PC6erKtT-&U3J+nla8e%sW>Z*!l3A!4qosq6Ke%sW>Z*$=IZERT_kj|bx+Z-(qy<5&QZD#dO{|MOx%#%l8nR%Ol zvx*6vNRPY`!cuS}g!QHyAu`6^2w@xV9}&@JqBj8{v0mjtCXP(o*`Rrn8kFVcK&Tk% z5Q=7K*|OsD1x3sA0D4K8P5EdIu|B8F`C1v4QCb<+(OMZ9W3)1C<5V$V@k=QxlL(Bj zyvwSMS}ChGr_7FDXV8akOISe358#$C^r>CEYsa|e$hH$xMqd5T9QO3<^?p?*D;d3b zv*hP`WW3_7k?m!X5sE*RDWjjSD{9Zu)mJ0i%Qgj4nQUaF;q8jrvy!oew?n9bzY>Ms{2 zdNcK>GFt`*GH5dO38XSx$t}{KL6e!>6#c2p8AAgZG+FuvQkiY!R_ASyJfn}pJ{=)< zVDiwu%_{;is8klGTHga;eBM5YMqoGDN-L1Qng9_2-^nRkMAo{Zlwd*6F)gptbVM7S zWv%j#4I{s^5sAu9vXZ`J!L)x1BmyyAy)Z3rh%lk@D>Xp~Qt}|5V+`K!dPH`@^-ET{ z%GP%?VmjkuARF8|I$)iWw8laniM3rP#ACG4c5AafZy0&g2#>v^|iGFyAjSScRSy8 zRz$*!CAR~&`N1PkX;H~saa7okN*=|N3?rVW#149i9rY4}^b&*h5<~P7L-i8F^b(DFiQ#&Q z5qgP{dWoI%5~K7IJL@Gz>m|nMCC2I{#_1)->m_#4OYEwb*iA37yIx`sy~Lh+i3xg% zz4Q`$>m~NlOH9;D?5mfUq?g!FFELp!vAlrs^dQ z(n}nympDW(aj0HmnqJ~Cy~K3AM3Y{kSufF|muS^X%+O1;=_O|BC1&X*X6q#m*GtUN zOU%_vwCg2udWpPVqM(;3>Lp5gi4MI)r(R;7Ug8M7#C*NPk$Q=v^b!kL??*eZt}d@0 zC_7~U;Nan>Gw{VlhtaxNH??EoV z*tfQ0w|PbusLY2$nZp-b$aGcg;cebAN2bEQO<4?OI_k2v zB@g+*B0JGzyf9KqxmZnfyyxxt)!aLZWUrZ?%14|!O?A?SoxAvcXN*KD6yYax(op(y z1h$ahy7!FK&%T)I+-Hq;DHgcsPjtjaO_$!KE3B+2x#m|(Zi#vqrC}>BNYBit-bHcs zqJ7evb#avE35I+gEh&+u*PgdXk5`c<%8H(=aVr}?D7+-=_NQF;@U6Vw^`3v!PawKH z&wh~Brcs-DE~9<1XWfZ9)EV-mne`Jq{o!iUV*fte?OAcb)Bjo%xA%;Z9q#_`y=TPg z>ORECaMzHO>#dSFwN*0YdkXiS@eDWGd2U(X;o^5YccH+oi78|A8^Dxj11&K_zBGP% zs>ci^X3Kj#$Nh!H;xS*W=Kj27A)DiV34UX+S}yjS#uq&`t&+I6RWgk7-67`>>-Lptd~s-$ZK5FiNsstoGO;Te)}Klk1760=F*pc{bPG5VumS zkP9!jA*gqKt0Xq<+@(l{(H{GveIAK;>zgYD$E`$xT-)e|A1{pbY?4cIwB!WeBAA41 z**(GebslkgD#@1J4HY2XollCKwKwjD6kcoc2vA(omKW^er%;k0 za7#Tk>=;)f{2)as$uZLH;2WATFRY2-++RQ;fWY1T{Yxz8ej2OTNT!37X>^RBdsqx&u;sR}J&TW60?y0p{ zWNG``*F7oMnq+Cm)l~5@rKLN!eYZ>6DfbD{x%q@qYUp=HMsAKcEj20a*SRixq*V7U z?VqA^Re@bP3^hl3kF#R=E~zo)I*}$zx%qWcsv=?8NP}eWlilAyuNz8#R>TUPr=fhF zlKZZ}L2Yqhk600;`ZLDHS+rd`Z1Zk*)K%T-xHR*)vrFSgPDk%f&NYvH?%Z5g;Cy(j z!TET>&(5dbU+;X`yvgZy)H?rG^|kZ8%3A07(TAO1Kb(*ke6d$vbo|o1ZgYRm>uY;I zZ}5Xp=Gm4UZeHKL`F7U(IUzjJur$9TWqj7f-EsXX%nN=c7c_})Y2f>lX2uN7j3Uj9 znVK21G&5#vW)y2?lxSwm(ae~unK4f@;||S?`I;FEG&2@zW|V4Xlxb!x(#%+_nNhBp zu|zYYLNjBjX2vqjj7rUnJ2f+wYi6v_%vh&$5AD%P|n6U6Ez)xV?z%KTJNx&;4c_cffuhUwAf|kL-4tAAa&B zene~!zTZnD`FkQqaA!W?$bS5~4{(q9=BK@Qp6t#4`YiXb$Hj-tj76E-{mUBeHfs+q zsK-w3TsZk306yvI_jAe*zt8>fVRt?+uZ-IxUFU;m=kUpC-MCSfaBlj#03sX`tVM@kQ;T$cvQ!D-i)Ws2?0D=bu8944@wfG$^ z60kV#8aJ=n71;L`;@-Qd#$J_+z)r1Q`b;s2aAw8ny# z*V{-ZOXQQcJ!9W9x+gzy>>;jKnt@M!V;MK|+1dP%r5^5~=kDW&MIGjj^cc;XYSwb+ zV&CK~zkI+mvCDYdmhF6Wa}%GPQotvhF7P=Qm++bQ8F}u3$M}M%vAnqLApa-02Iu)Y zesS4$5(1PxTo-P54mZ?uV=jCt@9*MozxFD3Ytu%4)Cb>ibG|R-GsjQnDs~Lule<35 zRi$m_W6~42`-aAF&0p1X_rDd&ef(q&_rO*&_sYJ@+>W&o+(Ts(xksN{!WGqa<@Qdh z;d&*F#Z~x2w>)f-j)`~v+9*V&IGzR~~hJ_Rhx;N7Y(w9V#LS(jKty0dhwu@a}LXgy{;^(-ov(_y$250@cwKIw*F2?53gc#c+U~IgE5o zBOGHO=mecM0>06tTCs~`kcfs4cJgSb-f;NFLK=&qfi)PVdp$L-k+8(En_f-EG3}ciAU93idPXru4{K7~SkOa7@!b`4VPYp^&@lbvp3IykV zZ0{Kq&_ah$=|Jy#SH+48D1}KW&@DhfoY4-GRuqW6P-z9^Vl~X(!CsiSFK#6Y1m~`W zP5}b37b5L{tRDLlN}P#v7kV3?#JsVpg`;e zO9wtmbv;OP8zQBG3IxQ3av!B!M}gQ2mR5p2=>8~$i2K1F2n6Ro03;BIy&z#9EM)CA z+EEIY65%@F1mZ#(e*$|T5PLxaT$MDp@Dk?&oCvFCE;zx%+n^!tMkq`W&;lETQBvwC zPv3)tW3Z}`DKBsZiBMy0q+w7_^|WKKL2l5skwDjqbiHd|>@7(_G)#5~a-D=|K2OQl zw!LQrI6?DuEWZu~dYvv;;U#JJM)^AX#;p|K1ieluHx%S@y9-n=(^eBA9sm^xwA}W4 zYEU5dpdRK|3(rs~L`s3s2Li!yQ;c>Lh`kW$9x$;V)|7T*z19_8LIH7M?matqp+M|~ zNC*0z5&lB$g-R)qbr1*+7c)^H_ClqVz3YV?R0haYpxF>*7!#_Mja@{(y-R zv}4F02n0v+2LiDN{o-P^unrdfAb&>jc`yM2;=etq}UzwI&n@ zj)%226wm^6)iuCc0E=xPg^Nc42Lg6gHeAXDX_~z9N+eeny}u<+gP_wJzC9pKgcRd? z7dT3SPdE4`!>0?A%W%v9IKtRJ0MZml@m`Pu=^#k)-Y^K#A&}y|VhE&Zkm9`~4bpT- z@m`V+sToqdx0oTdLW=hqE2K6^@!n&DGz(I^7iB@3%M6E47UTdo0~|Brvv9xJQ3WC! zJiC0}vSKCy#upt?uWSZB;{KH=@N-L|_^AvdNJ&Y@pL2TfoPnEqem%Faxu(G$Pa`gj0bNByb;}b(y@r&M$7Y-h*eKlk022|#;YzN-ybmB4D_y;GG ze`%0LpL*NCC*=?n@i}ozHh*$Gk#p8oF~bc^5WnfvY07%^<8$uEg#HYF4CzJ~jv#w> zY4Lc%Mvc%R$u$o11{aDlZU#OCK_DhbEDqH1N}I+rnEH zpTK+|3rlkZ3-Jdw@c>xi+0Loa_GNXnE*djzxHIO6hLUbcqUE z1W^gyTX);j8Hv!GF5F< zd~L-%!zMhW7<}Z&QOY{7euHP-FT)HhOtj?9z{R~kkvjw(NuZUEalo~_p`PIn9;|hB z8}}@Oozpe*3xTw7Zu7kJq|FKaW|$4QWRIId#;O_ z^|)PVaCLMvRjsS6q^vEMuTWLnT4{=E{)G`Bd^U9``P{%o9l1_Injl~Ai<2jNc0Rw7 z5#ahfTX)s)EKB}27CexRRl+opln5wZe6Xq|1~mpHLw4luE<6cK71-qv?@qrkgH(bd zkc^3{~xd8w|Z`7~r*Kk1_oVqryK z>hY<*3JJPq{G#!`irYRu*YJhaW#A5cx0KsAbrmmOi6WgDx<6*jmjPji|LPnJJD$vI z@aq219UA{!U**ei)215Sru(zp$23Cvpn2%XjVBgBj;d(EC}qa4U%#Po*qgpN;-81B zPRR44cn@+k}ik z1b6m_ulX@`a{UIr@^;9@DSG1!`J?_wi&PqZzck!}89pcBg)gx%8STWWD1R?JY~*Sp7IFuUeaM?$ TdX2y5lXW;R=I?#BFZlRBRQg~1 literal 0 HcmV?d00001 diff --git a/spine-sfml/data/vine.atlas b/spine-sfml/data/vine.atlas index 313213413..019a92d01 100644 --- a/spine-sfml/data/vine.atlas +++ b/spine-sfml/data/vine.atlas @@ -4,7 +4,7 @@ size: 128,1024 format: RGBA8888 filter: Linear,Linear repeat: none -images/vine +vine rotate: false xy: 2, 2 size: 68, 962 diff --git a/spine-sfml/data/vine.json b/spine-sfml/data/vine.json index a08c20022..6fc78dc14 100644 --- a/spine-sfml/data/vine.json +++ b/spine-sfml/data/vine.json @@ -1,20 +1,20 @@ { -"skeleton": { "hash": "Ww/IgnvLkO+Bc7+ljr0JS3OTq8Q", "spine": "3.4.00", "width": 227.35, "height": 841.02, "images": "" }, +"skeleton": { "hash": "OTxn8PebJnSmjY8665bH7m360tk", "spine": "3.4.02", "width": 227.32, "height": 841.06, "images": "./images/" }, "bones": [ { "name": "root" }, { "name": "vine1", "parent": "root", "length": 74, "rotation": 90, "x": 339.09, "y": -467.15, "color": "f700ffff" }, { "name": "vine2", "parent": "vine1", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine3", "parent": "vine2", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine4", "parent": "vine3", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine5", "parent": "vine4", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine6", "parent": "vine5", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine7", "parent": "vine6", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine8", "parent": "vine7", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine9", "parent": "vine8", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine10", "parent": "vine9", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine11", "parent": "vine10", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine12", "parent": "vine11", "length": 74, "x": 74, "color": "f700ffff" }, - { "name": "vine13", "parent": "vine12", "length": 74, "x": 74, "color": "f700ffff" }, + { "name": "vine3", "parent": "vine1", "length": 74, "rotation": 38.94, "x": 137.97, "y": 47.51, "color": "f700ffff" }, + { "name": "vine4", "parent": "vine1", "length": 74, "rotation": 16.67, "x": 214.29, "y": 68.52, "color": "f700ffff" }, + { "name": "vine5", "parent": "vine1", "length": 74, "rotation": -21.73, "x": 289.61, "y": 40.92, "color": "f700ffff" }, + { "name": "vine6", "parent": "vine1", "length": 74, "rotation": -50.04, "x": 341.12, "y": -15.58, "color": "f700ffff" }, + { "name": "vine7", "parent": "vine1", "length": 74, "rotation": -39.25, "x": 402.7, "y": -61.82, "color": "f700ffff" }, + { "name": "vine8", "parent": "vine1", "length": 74, "rotation": -6.18, "x": 483.27, "y": -69.84, "color": "f700ffff" }, + { "name": "vine9", "parent": "vine1", "length": 74, "rotation": 27.11, "x": 554.25, "y": -36.44, "color": "f700ffff" }, + { "name": "vine10", "parent": "vine1", "length": 74, "rotation": 48, "x": 608.62, "y": 19.05, "color": "f700ffff" }, + { "name": "vine11", "parent": "vine1", "length": 74, "rotation": 39.7, "x": 670.66, "y": 66.39, "color": "f700ffff" }, + { "name": "vine12", "parent": "vine1", "length": 74, "rotation": 10.72, "x": 750.09, "y": 80.23, "color": "f700ffff" }, + { "name": "vine13", "parent": "vine1", "length": 74, "rotation": -18.44, "x": 826.06, "y": 56.95, "color": "f700ffff" }, { "name": "vine-control1", "parent": "root", "length": 296.68, "rotation": 88.64, "x": -2.5, "y": 2.55, "color": "ff0004ff" }, { "name": "vine-control2", "parent": "vine-control1", "length": 292.59, "rotation": 0.96, "x": 296.68, "color": "ff0004ff" }, { "name": "vine-control3", "parent": "vine-control2", "length": 247.5, "rotation": 0.16, "x": 292.59, "color": "ff0004ff" }, @@ -22,7 +22,7 @@ ], "slots": [ { "name": "vine-path", "bone": "root", "attachment": "vine-path" }, - { "name": "vine", "bone": "vine1", "attachment": "images/vine" } + { "name": "vine", "bone": "vine1", "attachment": "vine" } ], "path": [ { @@ -35,10 +35,10 @@ "skins": { "default": { "vine": { - "images/vine": { + "vine": { "type": "mesh", "uvs": [ 0, 0, 0.5, 0, 1, 0, 1, 0.03846, 1, 0.07692, 1, 0.11538, 1, 0.15384, 1, 0.1923, 1, 0.23076, 1, 0.26923, 1, 0.30769, 1, 0.34615, 1, 0.38461, 1, 0.42307, 1, 0.46153, 1, 0.5, 1, 0.53846, 1, 0.57692, 1, 0.61538, 1, 0.65384, 1, 0.6923, 1, 0.73076, 1, 0.76923, 1, 0.80769, 1, 0.84615, 1, 0.88461, 1, 0.92307, 1, 0.96153, 1, 1, 0.5, 1, 0, 1, 0, 0.96153, 0, 0.92307, 0, 0.88461, 0, 0.84615, 0, 0.80769, 0, 0.76923, 0, 0.73076, 0, 0.6923, 0, 0.65384, 0, 0.61538, 0, 0.57692, 0, 0.53846, 0, 0.5, 0, 0.46153, 0, 0.42307, 0, 0.38461, 0, 0.34615, 0, 0.30769, 0, 0.26923, 0, 0.23076, 0, 0.1923, 0, 0.15384, 0, 0.11538, 0, 0.07692, 0, 0.03846, 0.5, 0.03846, 0.5, 0.07692, 0.5, 0.11538, 0.5, 0.15384, 0.5, 0.1923, 0.5, 0.23076, 0.5, 0.26923, 0.5, 0.30769, 0.5, 0.34615, 0.5, 0.38461, 0.5, 0.42307, 0.5, 0.46153, 0.5, 0.5, 0.5, 0.53846, 0.5, 0.57692, 0.5, 0.61538, 0.5, 0.65384, 0.5, 0.6923, 0.5, 0.73076, 0.5, 0.76923, 0.5, 0.80769, 0.5, 0.84615, 0.5, 0.88461, 0.5, 0.92307, 0.5, 0.96153 ], - "triangles": [ 57, 56, 3, 54, 55, 56, 56, 2, 3, 55, 1, 56, 56, 1, 2, 55, 0, 1, 54, 56, 57, 59, 58, 5, 52, 53, 58, 58, 4, 5, 53, 57, 58, 58, 57, 4, 53, 54, 57, 57, 3, 4, 61, 60, 7, 50, 51, 60, 60, 6, 7, 51, 59, 60, 60, 59, 6, 51, 52, 59, 59, 5, 6, 52, 58, 59, 63, 62, 9, 48, 49, 62, 62, 8, 9, 49, 61, 62, 62, 61, 8, 49, 50, 61, 61, 7, 8, 50, 60, 61, 65, 64, 11, 46, 47, 64, 64, 10, 11, 47, 63, 64, 64, 63, 10, 47, 48, 63, 63, 9, 10, 48, 62, 63, 67, 66, 13, 44, 45, 66, 66, 12, 13, 45, 65, 66, 66, 65, 12, 45, 46, 65, 65, 11, 12, 46, 64, 65, 69, 68, 15, 42, 43, 68, 68, 14, 15, 43, 67, 68, 68, 67, 14, 43, 44, 67, 67, 13, 14, 44, 66, 67, 71, 70, 17, 40, 41, 70, 70, 16, 17, 41, 69, 70, 70, 69, 16, 41, 42, 69, 69, 15, 16, 42, 68, 69, 73, 72, 19, 38, 39, 72, 72, 18, 19, 39, 71, 72, 72, 71, 18, 39, 40, 71, 71, 17, 18, 40, 70, 71, 75, 74, 21, 36, 37, 74, 74, 20, 21, 37, 73, 74, 74, 73, 20, 37, 38, 73, 73, 19, 20, 38, 72, 73, 77, 76, 23, 34, 35, 76, 76, 22, 23, 35, 75, 76, 76, 75, 22, 35, 36, 75, 75, 21, 22, 36, 74, 75, 78, 77, 24, 33, 34, 77, 32, 78, 79, 79, 78, 25, 32, 33, 78, 78, 24, 25, 33, 77, 78, 77, 23, 24, 34, 76, 77, 79, 25, 26, 29, 27, 28, 30, 80, 29, 29, 80, 27, 30, 31, 80, 80, 26, 27, 31, 79, 80, 80, 79, 26, 31, 32, 79 ], + "triangles": [ 55, 0, 1, 56, 1, 2, 55, 1, 56, 56, 2, 3, 54, 55, 56, 57, 56, 3, 57, 3, 4, 53, 54, 57, 58, 57, 4, 53, 57, 58, 58, 4, 5, 52, 53, 58, 59, 58, 5, 54, 56, 57, 52, 58, 59, 59, 5, 6, 51, 52, 59, 60, 59, 6, 51, 59, 60, 60, 6, 7, 50, 51, 60, 61, 60, 7, 50, 60, 61, 61, 7, 8, 49, 50, 61, 62, 61, 8, 49, 61, 62, 62, 8, 9, 48, 49, 62, 63, 62, 9, 48, 62, 63, 63, 9, 10, 47, 48, 63, 64, 63, 10, 47, 63, 64, 64, 10, 11, 46, 47, 64, 65, 64, 11, 46, 64, 65, 65, 11, 12, 45, 46, 65, 66, 65, 12, 45, 65, 66, 66, 12, 13, 44, 45, 66, 67, 66, 13, 44, 66, 67, 67, 13, 14, 43, 44, 67, 68, 67, 14, 43, 67, 68, 68, 14, 15, 42, 43, 68, 69, 68, 15, 42, 68, 69, 69, 15, 16, 41, 42, 69, 70, 69, 16, 41, 69, 70, 70, 16, 17, 40, 41, 70, 71, 70, 17, 40, 70, 71, 71, 17, 18, 39, 40, 71, 72, 71, 18, 39, 71, 72, 72, 18, 19, 38, 39, 72, 73, 72, 19, 38, 72, 73, 73, 19, 20, 37, 38, 73, 74, 73, 20, 37, 73, 74, 74, 20, 21, 36, 37, 74, 75, 74, 21, 36, 74, 75, 75, 21, 22, 35, 36, 75, 76, 75, 22, 35, 75, 76, 76, 22, 23, 34, 35, 76, 77, 76, 23, 34, 76, 77, 77, 23, 24, 33, 77, 78, 78, 24, 25, 32, 33, 78, 79, 78, 25, 32, 78, 79, 33, 34, 77, 78, 77, 24, 31, 32, 79, 80, 79, 26, 31, 79, 80, 80, 26, 27, 30, 31, 80, 29, 80, 27, 30, 80, 29, 29, 27, 28, 79, 25, 26 ], "vertices": [ 4, 10, 294, 33.89, 3.2E-4, 11, 220, 33.89, 0.01648, 12, 146, 33.89, 0.21526, 13, 72, 33.89, 0.76791, 3, 11, 220, -0.1, 0.00752, 12, 146, -0.1, 0.16869, 13, 72, -0.1, 0.82378, 4, 10, 294, -34.09999, 3.2E-4, 11, 220, -34.09999, 0.01648, 12, 146, -34.09999, 0.21526, 13, 72, -34.09999, 0.76791, 4, 10, 257, -34.09999, 0.00195, 11, 183, -34.09999, 0.04739, 12, 109, -34.09999, 0.33351, 13, 35, -34.09999, 0.61714, 5, 9, 294, -34.09999, 2.4E-4, 10, 220, -34.09999, 0.01163, 11, 146, -34.09999, 0.14109, 12, 72, -34.09999, 0.49171, 13, -1.99, -34.09999, 0.35531, 5, 9, 257, -34.09999, 0.00195, 10, 183, -34.09999, 0.04663, 11, 109, -34.09999, 0.31166, 12, 35, -34.09999, 0.48761, 13, -38.99, -34.09999, 0.15212, 6, 8, 294, -34.09999, 2.4E-4, 9, 220, -34.09999, 0.01163, 10, 146, -34.09999, 0.14101, 11, 72, -34.09999, 0.48685, 12, -1.99, -34.09999, 0.31174, 13, -75.99, -34.09999, 0.0485, 6, 8, 257, -34.09999, 0.00195, 9, 183, -34.09999, 0.04663, 10, 109, -34.09999, 0.31166, 11, 35, -34.09999, 0.48685, 12, -38.99, -34.09999, 0.14101, 13, -112.99, -34.09999, 0.01188, 7, 7, 294, -34.09999, 2.4E-4, 8, 220, -34.09999, 0.01163, 9, 146, -34.09999, 0.14101, 10, 72, -34.09999, 0.48685, 11, -1.99, -34.09999, 0.31166, 12, -75.99, -34.09999, 0.04663, 13, -149.99, -34.09999, 0.00195, 7, 7, 257, -34.09999, 0.00195, 8, 183, -34.09999, 0.04663, 9, 109, -34.09999, 0.31166, 10, 35, -34.09999, 0.48685, 11, -38.99, -34.09999, 0.14101, 12, -112.99, -34.09999, 0.01163, 13, -186.99, -34.09999, 2.4E-4, 7, 6, 294, -34.09999, 2.4E-4, 7, 220, -34.09999, 0.01163, 8, 146, -34.09999, 0.14101, 9, 72, -34.09999, 0.48685, 10, -1.99, -34.09999, 0.31166, 11, -75.99, -34.09999, 0.04663, 12, -149.99, -34.09999, 0.00195, 7, 6, 257, -34.09999, 0.00195, 7, 183, -34.09999, 0.04663, 8, 109, -34.09999, 0.31166, 9, 35, -34.09999, 0.48685, 10, -38.99, -34.09999, 0.14101, 11, -112.99, -34.09999, 0.01163, 12, -186.99, -34.09999, 2.4E-4, 7, 5, 294, -34.09999, 2.4E-4, 6, 220, -34.09999, 0.01163, 7, 146, -34.09999, 0.14101, 8, 72, -34.09999, 0.48685, 9, -1.99, -34.09999, 0.31166, 10, -75.99, -34.09999, 0.04663, 11, -149.99, -34.09999, 0.00195, 7, 5, 257, -34.09999, 0.00195, 6, 183, -34.09999, 0.04663, 7, 109, -34.09999, 0.31166, 8, 35, -34.09999, 0.48685, 9, -38.99, -34.09999, 0.14101, 10, -112.99, -34.09999, 0.01163, 11, -186.99, -34.09999, 2.4E-4, 7, 4, 294, -34.09999, 2.4E-4, 5, 220, -34.09999, 0.01163, 6, 146, -34.09999, 0.14101, 7, 72, -34.09999, 0.48685, 8, -1.99, -34.09999, 0.31166, 9, -75.99, -34.09999, 0.04663, 10, -149.99, -34.09999, 0.00195, 7, 4, 257, -34.09999, 0.00195, 5, 183, -34.09999, 0.04663, 6, 109, -34.09999, 0.31166, 7, 35, -34.09999, 0.48685, 8, -38.99, -34.09999, 0.14101, 9, -112.99, -34.09999, 0.01163, 10, -186.99, -34.09999, 2.4E-4, 7, 3, 294, -34.09999, 2.4E-4, 4, 220, -34.09999, 0.01163, 5, 146, -34.09999, 0.14101, 6, 72, -34.09999, 0.48685, 7, -1.99, -34.09999, 0.31166, 8, -75.99, -34.09999, 0.04663, 9, -149.99, -34.09999, 0.00195, 7, 3, 257, -34.09999, 0.00195, 4, 183, -34.09999, 0.04663, 5, 109, -34.09999, 0.31166, 6, 35, -34.09999, 0.48685, 7, -38.99, -34.09999, 0.14101, 8, -112.99, -34.09999, 0.01163, 9, -186.99, -34.09999, 2.4E-4, 7, 2, 294, -34.09999, 2.4E-4, 3, 220, -34.09999, 0.01163, 4, 146, -34.09999, 0.14101, 5, 72, -34.09999, 0.48685, 6, -1.99, -34.09999, 0.31166, 7, -75.99, -34.09999, 0.04663, 8, -149.99, -34.09999, 0.00195, 7, 2, 257, -34.09999, 0.00195, 3, 183, -34.09999, 0.04663, 4, 109, -34.09999, 0.31166, 5, 35, -34.09999, 0.48685, 6, -38.99, -34.09999, 0.14101, 7, -112.99, -34.09999, 0.01163, 8, -186.99, -34.09999, 2.4E-4, 7, 1, 294, -34.09999, 2.4E-4, 2, 220, -34.09999, 0.01163, 3, 146, -34.09999, 0.14101, 4, 72, -34.09999, 0.48685, 5, -1.99, -34.09999, 0.31166, 6, -75.99, -34.09999, 0.04663, 7, -149.99, -34.09999, 0.00195, 7, 1, 257, -34.09999, 0.0017, 2, 183, -34.09999, 0.04687, 3, 109, -34.09999, 0.31166, 4, 35, -34.09999, 0.48685, 5, -38.99, -34.09999, 0.14101, 6, -112.99, -34.09999, 0.01163, 7, -186.99, -34.09999, 2.4E-4, 6, 1, 220, -34.09999, 0.01033, 2, 146, -34.09999, 0.14256, 3, 72, -34.09999, 0.48685, 4, -1.99, -34.09999, 0.31166, 5, -75.99, -34.09999, 0.04663, 6, -149.99, -34.09999, 0.00195, 6, 1, 183, -34.09999, 0.04058, 2, 109, -34.09999, 0.31966, 3, 35, -34.09999, 0.48685, 4, -38.99, -34.09999, 0.14101, 5, -112.99, -34.09999, 0.01163, 6, -186.99, -34.09999, 2.4E-4, 5, 1, 146, -34.09999, 0.1274, 2, 72, -34.09999, 0.51233, 3, -1.99, -34.09999, 0.31166, 4, -75.99, -34.09999, 0.04663, 5, -149.99, -34.09999, 0.00195, 5, 1, 109, -34.09999, 0.30116, 2, 35, -34.09999, 0.54594, 3, -38.99, -34.09999, 0.14101, 4, -112.99, -34.09999, 0.01163, 5, -186.99, -34.09999, 2.4E-4, 4, 1, 72, -34.09999, 0.55403, 2, -1.99, -34.09999, 0.39738, 3, -75.99, -34.09999, 0.04663, 4, -149.99, -34.09999, 0.00195, 4, 1, 35, -34.09999, 0.77978, 2, -38.99, -34.09999, 0.20825, 3, -112.99, -34.09999, 0.01171, 4, -186.99, -34.09999, 2.4E-4, 3, 1, -1.99, -34.09999, 0.89032, 2, -75.99, -34.09999, 0.10696, 3, -149.99, -34.09999, 0.00271, 3, 1, -1.99, -0.1, 0.9264, 2, -75.99, -0.1, 0.07272, 3, -149.99, -0.1, 8.6E-4, 3, 1, -1.99, 33.89, 0.89032, 2, -75.99, 33.89, 0.10696, 3, -149.99, 33.89, 0.00271, 4, 1, 35, 33.89, 0.77978, 2, -38.99, 33.89, 0.20825, 3, -112.99, 33.89, 0.01171, 4, -186.99, 33.89, 2.4E-4, 4, 1, 72, 33.89, 0.55403, 2, -1.99, 33.89, 0.39738, 3, -75.99, 33.89, 0.04663, 4, -149.99, 33.89, 0.00195, 5, 1, 109, 33.89, 0.30116, 2, 35, 33.89, 0.54594, 3, -38.99, 33.89, 0.14101, 4, -112.99, 33.89, 0.01163, 5, -186.99, 33.89, 2.4E-4, 5, 1, 146, 33.89, 0.1274, 2, 72, 33.89, 0.51233, 3, -1.99, 33.89, 0.31166, 4, -75.99, 33.89, 0.04663, 5, -149.99, 33.89, 0.00195, 6, 1, 183, 33.89, 0.04058, 2, 109, 33.89, 0.31966, 3, 35, 33.89, 0.48685, 4, -38.99, 33.89, 0.14101, 5, -112.99, 33.89, 0.01163, 6, -186.99, 33.89, 2.4E-4, 6, 1, 220, 33.89, 0.01033, 2, 146, 33.89, 0.14256, 3, 72, 33.89, 0.48685, 4, -1.99, 33.89, 0.31166, 5, -75.99, 33.89, 0.04663, 6, -149.99, 33.89, 0.00195, 7, 1, 257, 33.89, 0.0017, 2, 183, 33.89, 0.04687, 3, 109, 33.89, 0.31166, 4, 35, 33.89, 0.48685, 5, -38.99, 33.89, 0.14101, 6, -112.99, 33.89, 0.01163, 7, -186.99, 33.89, 2.4E-4, 7, 1, 294, 33.89, 2.4E-4, 2, 220, 33.89, 0.01163, 3, 146, 33.89, 0.14101, 4, 72, 33.89, 0.48685, 5, -1.99, 33.89, 0.31166, 6, -75.99, 33.89, 0.04663, 7, -149.99, 33.89, 0.00195, 7, 2, 257, 33.89, 0.00195, 3, 183, 33.89, 0.04663, 4, 109, 33.89, 0.31166, 5, 35, 33.89, 0.48685, 6, -38.99, 33.89, 0.14101, 7, -112.99, 33.89, 0.01163, 8, -186.99, 33.89, 2.4E-4, 7, 2, 294, 33.89, 2.4E-4, 3, 220, 33.89, 0.01163, 4, 146, 33.89, 0.14101, 5, 72, 33.89, 0.48685, 6, -1.99, 33.89, 0.31166, 7, -75.99, 33.89, 0.04663, 8, -149.99, 33.89, 0.00195, 7, 3, 257, 33.89, 0.00195, 4, 183, 33.89, 0.04663, 5, 109, 33.89, 0.31166, 6, 35, 33.89, 0.48685, 7, -38.99, 33.89, 0.14101, 8, -112.99, 33.89, 0.01163, 9, -186.99, 33.89, 2.4E-4, 7, 3, 294, 33.89, 2.4E-4, 4, 220, 33.89, 0.01163, 5, 146, 33.89, 0.14101, 6, 72, 33.89, 0.48685, 7, -1.99, 33.89, 0.31166, 8, -75.99, 33.89, 0.04663, 9, -149.99, 33.89, 0.00195, 7, 4, 257, 33.89, 0.00195, 5, 183, 33.89, 0.04663, 6, 109, 33.89, 0.31166, 7, 35, 33.89, 0.48685, 8, -38.99, 33.89, 0.14101, 9, -112.99, 33.89, 0.01163, 10, -186.99, 33.89, 2.4E-4, 7, 4, 294, 33.89, 2.4E-4, 5, 220, 33.89, 0.01163, 6, 146, 33.89, 0.14101, 7, 72, 33.89, 0.48685, 8, -1.99, 33.89, 0.31166, 9, -75.99, 33.89, 0.04663, 10, -149.99, 33.89, 0.00195, 7, 5, 257, 33.89, 0.00195, 6, 183, 33.89, 0.04663, 7, 109, 33.89, 0.31166, 8, 35, 33.89, 0.48685, 9, -38.99, 33.89, 0.14101, 10, -112.99, 33.89, 0.01163, 11, -186.99, 33.89, 2.4E-4, 7, 5, 294, 33.89, 2.4E-4, 6, 220, 33.89, 0.01163, 7, 146, 33.89, 0.14101, 8, 72, 33.89, 0.48685, 9, -1.99, 33.89, 0.31166, 10, -75.99, 33.89, 0.04663, 11, -149.99, 33.89, 0.00195, 7, 6, 257, 33.89, 0.00195, 7, 183, 33.89, 0.04663, 8, 109, 33.89, 0.31166, 9, 35, 33.89, 0.48685, 10, -38.99, 33.89, 0.14101, 11, -112.99, 33.89, 0.01163, 12, -186.99, 33.89, 2.4E-4, 7, 6, 294, 33.89, 2.4E-4, 7, 220, 33.89, 0.01163, 8, 146, 33.89, 0.14101, 9, 72, 33.89, 0.48685, 10, -1.99, 33.89, 0.31166, 11, -75.99, 33.89, 0.04663, 12, -149.99, 33.89, 0.00195, 7, 7, 257, 33.89, 0.00195, 8, 183, 33.89, 0.04663, 9, 109, 33.89, 0.31166, 10, 35, 33.89, 0.48685, 11, -38.99, 33.89, 0.14101, 12, -112.99, 33.89, 0.01163, 13, -186.99, 33.89, 2.4E-4, 7, 7, 294, 33.89, 2.4E-4, 8, 220, 33.89, 0.01163, 9, 146, 33.89, 0.14101, 10, 72, 33.89, 0.48685, 11, -1.99, 33.89, 0.31166, 12, -75.99, 33.89, 0.04663, 13, -149.99, 33.89, 0.00195, 6, 8, 257, 33.89, 0.00195, 9, 183, 33.89, 0.04663, 10, 109, 33.89, 0.31166, 11, 35, 33.89, 0.48685, 12, -38.99, 33.89, 0.14101, 13, -112.99, 33.89, 0.01188, 6, 8, 294, 33.89, 2.4E-4, 9, 220, 33.89, 0.01163, 10, 146, 33.89, 0.14101, 11, 72, 33.89, 0.48685, 12, -1.99, 33.89, 0.31174, 13, -75.99, 33.89, 0.0485, 5, 9, 257, 33.89, 0.00195, 10, 183, 33.89, 0.04663, 11, 109, 33.89, 0.31166, 12, 35, 33.89, 0.48761, 13, -38.99, 33.89, 0.15212, 5, 9, 294, 33.89, 2.4E-4, 10, 220, 33.89, 0.01163, 11, 146, 33.89, 0.14109, 12, 72, 33.89, 0.49171, 13, -1.99, 33.89, 0.35531, 4, 10, 257, 33.89, 0.00195, 11, 183, 33.89, 0.04739, 12, 109, 33.89, 0.33351, 13, 35, 33.89, 0.61714, 4, 10, 257, -0.1, 6.5E-4, 11, 183, -0.1, 0.03067, 12, 109, -0.1, 0.31658, 13, 35, -0.1, 0.65209, 4, 10, 220, -0.1, 0.00542, 11, 146, -0.1, 0.11402, 12, 72, -0.1, 0.5478, 13, -1.99, -0.1, 0.33273, 5, 9, 257, -0.1, 6.5E-4, 10, 183, -0.1, 0.03045, 11, 109, -0.1, 0.30373, 12, 35, -0.1, 0.54592, 13, -38.99, -0.1, 0.11923, 5, 9, 220, -0.1, 0.00542, 10, 146, -0.1, 0.11402, 11, 72, -0.1, 0.5457, 12, -1.99, -0.1, 0.30373, 13, -75.99, -0.1, 0.0311, 6, 8, 257, -0.1, 6.5E-4, 9, 183, -0.1, 0.03045, 10, 109, -0.1, 0.30373, 11, 35, -0.1, 0.5457, 12, -38.99, -0.1, 0.11402, 13, -112.99, -0.1, 0.00542, 6, 8, 220, -0.1, 0.00542, 9, 146, -0.1, 0.11402, 10, 72, -0.1, 0.5457, 11, -1.99, -0.1, 0.30373, 12, -75.99, -0.1, 0.03045, 13, -149.99, -0.1, 6.5E-4, 6, 7, 257, -0.1, 6.5E-4, 8, 183, -0.1, 0.03045, 9, 109, -0.1, 0.30373, 10, 35, -0.1, 0.5457, 11, -38.99, -0.1, 0.11402, 12, -112.99, -0.1, 0.00542, 6, 7, 220, -0.1, 0.00542, 8, 146, -0.1, 0.11402, 9, 72, -0.1, 0.5457, 10, -1.99, -0.1, 0.30373, 11, -75.99, -0.1, 0.03045, 12, -149.99, -0.1, 6.5E-4, 6, 6, 257, -0.1, 6.5E-4, 7, 183, -0.1, 0.03045, 8, 109, -0.1, 0.30373, 9, 35, -0.1, 0.5457, 10, -38.99, -0.1, 0.11402, 11, -112.99, -0.1, 0.00542, 6, 6, 220, -0.1, 0.00542, 7, 146, -0.1, 0.11402, 8, 72, -0.1, 0.5457, 9, -1.99, -0.1, 0.30373, 10, -75.99, -0.1, 0.03045, 11, -149.99, -0.1, 6.5E-4, 6, 5, 257, -0.1, 6.5E-4, 6, 183, -0.1, 0.03045, 7, 109, -0.1, 0.30373, 8, 35, -0.1, 0.5457, 9, -38.99, -0.1, 0.11402, 10, -112.99, -0.1, 0.00542, 6, 5, 220, -0.1, 0.00542, 6, 146, -0.1, 0.11402, 7, 72, -0.1, 0.5457, 8, -1.99, -0.1, 0.30373, 9, -75.99, -0.1, 0.03045, 10, -149.99, -0.1, 6.5E-4, 6, 4, 257, -0.1, 6.5E-4, 5, 183, -0.1, 0.03045, 6, 109, -0.1, 0.30373, 7, 35, -0.1, 0.5457, 8, -38.99, -0.1, 0.11402, 9, -112.99, -0.1, 0.00542, 6, 4, 220, -0.1, 0.00542, 5, 146, -0.1, 0.11402, 6, 72, -0.1, 0.5457, 7, -1.99, -0.1, 0.30373, 8, -75.99, -0.1, 0.03045, 9, -149.99, -0.1, 6.5E-4, 6, 3, 257, -0.1, 6.5E-4, 4, 183, -0.1, 0.03045, 5, 109, -0.1, 0.30373, 6, 35, -0.1, 0.5457, 7, -38.99, -0.1, 0.11402, 8, -112.99, -0.1, 0.00542, 6, 3, 220, -0.1, 0.00542, 4, 146, -0.1, 0.11402, 5, 72, -0.1, 0.5457, 6, -1.99, -0.1, 0.30373, 7, -75.99, -0.1, 0.03045, 8, -149.99, -0.1, 6.5E-4, 6, 2, 257, -0.1, 6.5E-4, 3, 183, -0.1, 0.03045, 4, 109, -0.1, 0.30373, 5, 35, -0.1, 0.5457, 6, -38.99, -0.1, 0.11402, 7, -112.99, -0.1, 0.00542, 6, 2, 220, -0.1, 0.00542, 3, 146, -0.1, 0.11402, 4, 72, -0.1, 0.5457, 5, -1.99, -0.1, 0.30373, 6, -75.99, -0.1, 0.03045, 7, -149.99, -0.1, 6.5E-4, 6, 1, 257, -0.1, 6.5E-4, 2, 183, -0.1, 0.03045, 3, 109, -0.1, 0.30373, 4, 35, -0.1, 0.5457, 5, -38.99, -0.1, 0.11402, 6, -112.99, -0.1, 0.00542, 6, 1, 220, -0.1, 0.00477, 2, 146, -0.1, 0.11467, 3, 72, -0.1, 0.5457, 4, -1.99, -0.1, 0.30373, 5, -75.99, -0.1, 0.03045, 6, -149.99, -0.1, 6.5E-4, 5, 1, 183, -0.1, 0.02676, 2, 109, -0.1, 0.30807, 3, 35, -0.1, 0.5457, 4, -38.99, -0.1, 0.11402, 5, -112.99, -0.1, 0.00542, 5, 1, 146, -0.1, 0.09905, 2, 72, -0.1, 0.5661, 3, -1.99, -0.1, 0.30373, 4, -75.99, -0.1, 0.03045, 5, -149.99, -0.1, 6.5E-4, 4, 1, 109, -0.1, 0.27658, 2, 35, -0.1, 0.60395, 3, -38.99, -0.1, 0.11402, 4, -112.99, -0.1, 0.00542, 4, 1, 72, -0.1, 0.55929, 2, -1.99, -0.1, 0.40959, 3, -75.99, -0.1, 0.03045, 4, -149.99, -0.1, 6.5E-4, 3, 1, 35, -0.1, 0.81845, 2, -38.99, -0.1, 0.17611, 3, -112.99, -0.1, 0.00542 ], "hull": 56, "edges": [ 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14, 16, 16, 18, 18, 20, 20, 22, 22, 24, 24, 26, 26, 28, 28, 30, 30, 32, 32, 34, 34, 36, 36, 38, 38, 40, 40, 42, 42, 44, 44, 46, 46, 48, 48, 50, 50, 52, 52, 54, 54, 56, 60, 62, 62, 64, 64, 66, 66, 68, 68, 70, 70, 72, 72, 74, 74, 76, 76, 78, 78, 80, 80, 82, 82, 84, 84, 86, 86, 88, 88, 90, 90, 92, 92, 94, 94, 96, 96, 98, 98, 100, 100, 102, 102, 104, 104, 106, 106, 108, 108, 110, 110, 0, 0, 2, 58, 60, 2, 4, 56, 58, 62, 160, 160, 54, 64, 158, 158, 52, 66, 156, 156, 50, 68, 154, 154, 48, 46, 152, 152, 70, 72, 150, 150, 44, 42, 148, 148, 74, 76, 146, 146, 40, 38, 144, 144, 78, 80, 142, 142, 36, 34, 140, 140, 82, 84, 138, 138, 32, 30, 136, 136, 86, 88, 134, 134, 28, 26, 132, 132, 90, 92, 130, 130, 24, 22, 128, 128, 94, 96, 126, 126, 20, 18, 124, 124, 98, 100, 122, 122, 16, 14, 120, 120, 102, 12, 118, 118, 104, 106, 116, 116, 10, 8, 114, 114, 108, 110, 112, 112, 6 ], @@ -49,7 +49,7 @@ "vine-path": { "vine-path": { "type": "path", - "lengths": [ 223.68, 474.79, 780.31, 992.69, 1196.42, 2277.75 ], + "lengths": [ 223.68, 474.79, 780.31, 992.69, 1196.43, 2277.75 ], "vertexCount": 18, "vertices": [ 1, 14, -31.64, 22.49, 1, 1, 14, -2.73, -6.56, 1, 1, 14, 56.89, -69, 1, 1, 14, 115.57, 75.01, 1, 1, 14, 198.6, 53.37, 1, 2, 14, 332.76, 19.74, 0.8, 15, 36.41, 19.12999, 0.19999, 2, 14, 276.72, -68.37, 0.232, 15, -21.1, -68.01999, 0.76799, 1, 15, 96.09, -93.88, 1, 2, 15, 229.75, -122.63, 0.664, 16, -63.18, -122.45, 0.33599, 2, 15, 242.53, 29.31, 0.52, 16, -49.97, 29.45, 0.47999, 1, 16, 66.72, 38.65, 1, 2, 16, 183.42, 47.85, 0.80799, 17, -63.65, 48.41, 0.192, 2, 16, 177.29, -41.22, 0.77599, 17, -70.56, -40.61, 0.224, 2, 16, 265.5, -16.18, 0.488, 17, 17.86, -16.34, 0.51199, 2, 16, 343.25, 7.25, 0.21599, 17, 95.81, 6.41, 0.784, 1, 17, 138.78, 45.72, 1, 1, 17, 212.86, 5.44, 1, 1, 14, 1094.34, -1.02, 1 ] } @@ -75,15 +75,15 @@ "scale": [ { "time": 0, - "x": 1, + "x": 0, "y": 0.183, - "curve": [ 0.166, 0.22, 0.598, 0.99 ] + "curve": [ 0.302, 0.57, 0.549, 0.82 ] }, { - "time": 3.6333, - "x": 1, - "y": 1, - "curve": [ 0.25, 0, 0.75, 1 ] + "time": 3.2333, + "x": 1.218, + "y": 1.1, + "curve": [ 0.481, 0.24, 0.708, 0.46 ] }, { "time": 11.4333, "x": 1, "y": 1.438 } ] @@ -92,25 +92,25 @@ "rotate": [ { "time": 0, - "angle": 0, + "angle": 39.68, "curve": [ 0.25, 0, 0.75, 1 ] }, { - "time": 2.5666, - "angle": 2.86, + "time": 1.2, + "angle": 0.89, "curve": [ 0.25, 0, 0.75, 1 ] }, { - "time": 4.7, - "angle": -0.13, - "curve": [ 0.505, 0, 0.75, 1 ] - }, - { - "time": 6.4333, - "angle": 0.68, + "time": 2.1666, + "angle": 5.56, "curve": [ 0.25, 0, 0.75, 1 ] }, - { "time": 9.6, "angle": 0.68 } + { + "time": 3.4, + "angle": 5.65, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 7.6, "angle": 1.35 } ], "scale": [ { @@ -138,25 +138,20 @@ "rotate": [ { "time": 0, - "angle": 0, + "angle": -39.68, "curve": [ 0.25, 0, 0.75, 1 ] }, { - "time": 2.5666, - "angle": 2.86, + "time": 1.2, + "angle": -20.6, "curve": [ 0.25, 0, 0.75, 1 ] }, { - "time": 4.7, - "angle": -0.13, - "curve": [ 0.505, 0, 0.75, 1 ] - }, - { - "time": 6.4333, - "angle": 0.68, + "time": 3.4, + "angle": -8.18, "curve": [ 0.25, 0, 0.75, 1 ] }, - { "time": 9.6, "angle": 0.68 } + { "time": 7.6, "angle": -0.96 } ], "scale": [ { @@ -188,21 +183,21 @@ "curve": [ 0.25, 0, 0.75, 1 ] }, { - "time": 2.5666, - "angle": 10.88, + "time": 1.2, + "angle": 27.36, "curve": [ 0.25, 0, 0.75, 1 ] }, { - "time": 4.7, - "angle": -11.18, - "curve": [ 0.505, 0, 0.75, 1 ] - }, - { - "time": 6.4333, - "angle": -0.47, + "time": 2.1666, + "angle": 14.82, "curve": [ 0.25, 0, 0.75, 1 ] }, - { "time": 9.6, "angle": -5.23 } + { + "time": 3.4, + "angle": -15.24, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 7.6, "angle": -0.16 } ], "scale": [ { @@ -234,21 +229,21 @@ "curve": [ 0.25, 0, 0.75, 1 ] }, { - "time": 2.5666, - "angle": 10.88, + "time": 2.1666, + "angle": -11.88, "curve": [ 0.25, 0, 0.75, 1 ] }, { - "time": 4.7, - "angle": -11.18, - "curve": [ 0.505, 0, 0.75, 1 ] - }, - { - "time": 6.4333, - "angle": 7.47, + "time": 3.4, + "angle": 7.56, "curve": [ 0.25, 0, 0.75, 1 ] }, - { "time": 9.6, "angle": 2.71 } + { + "time": 6.4, + "angle": 15.02, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 7.6, "angle": -0.5 } ], "scale": [ { @@ -271,27 +266,45 @@ }, { "time": 11.4333, "x": 1, "y": 0.923 } ] - } - }, - "paths": { - "vine-path": { - "position": [ - { "time": 0, "position": -0.1 }, - { "time": 0.3333, "position": -0.025 } - ], - "spacing": [ - { "time": 0, "spacing": -100 }, - { - "time": 0.3333, - "spacing": -71.8, - "curve": [ 0.32, 0.18, 0.624, 0.6 ] - }, - { - "time": 3.1333, - "spacing": -13.199, - "curve": [ 0.251, 0.5, 0.557, 0.98 ] - }, - { "time": 6.7333, "spacing": 20.9 } + }, + "vine6": { + "rotate": [ + { "time": 0, "angle": 0 } + ] + }, + "vine7": { + "rotate": [ + { "time": 0, "angle": 0 } + ] + }, + "vine8": { + "rotate": [ + { "time": 0, "angle": 0 } + ] + }, + "vine9": { + "rotate": [ + { "time": 0, "angle": 0 } + ] + }, + "vine10": { + "rotate": [ + { "time": 0, "angle": 0 } + ] + }, + "vine11": { + "rotate": [ + { "time": 0, "angle": 0 } + ] + }, + "vine12": { + "rotate": [ + { "time": 0, "angle": 0 } + ] + }, + "vine13": { + "rotate": [ + { "time": 0, "angle": 0 } ] } } diff --git a/spine-sfml/data/vine.skel b/spine-sfml/data/vine.skel new file mode 100644 index 0000000000000000000000000000000000000000..18d4e53dc59943e2cb81792ae04cf77d5ba2ef7c GIT binary patch literal 10276 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 literal 0 HcmV?d00001 diff --git a/spine-sfml/example/main.cpp b/spine-sfml/example/main.cpp index 50f414788..618be0052 100644 --- a/spine-sfml/example/main.cpp +++ b/spine-sfml/example/main.cpp @@ -62,17 +62,47 @@ void callback (AnimationState* state, int trackIndex, EventType type, Event* eve fflush(stdout); } -void spineboy () { - // Load atlas, skeleton, and animations. - Atlas* atlas = Atlas_createFromFile("data/spineboy.atlas", 0); +SkeletonData* readSkeletonJsonData (const char* filename, Atlas* atlas, float scale) { SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = 0.6f; - SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/spineboy.json"); + json->scale = scale; + SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, filename); if (!skeletonData) { printf("%s\n", json->error); exit(0); } SkeletonJson_dispose(json); + return skeletonData; +} + +SkeletonData* readSkeletonBinaryData (const char* filename, Atlas* atlas, float scale) { + SkeletonBinary* binary = SkeletonBinary_create(atlas); + binary->scale = scale; + SkeletonData *skeletonData = SkeletonBinary_readSkeletonDataFile(binary, filename); + if (!skeletonData) { + printf("%s\n", binary->error); + exit(0); + } + SkeletonBinary_dispose(binary); + return skeletonData; +} + +void testcase (void func(SkeletonData* skeletonData, Atlas* atlas), + const char* jsonName, const char* binaryName, const char* atlasName, + float scale) { + Atlas* atlas = Atlas_createFromFile(atlasName, 0); + + SkeletonData* skeletonData = readSkeletonJsonData(jsonName, atlas, scale); + func(skeletonData, atlas); + SkeletonData_dispose(skeletonData); + + skeletonData = readSkeletonBinaryData(binaryName, atlas, scale); + func(skeletonData, atlas); + SkeletonData_dispose(skeletonData); + + Atlas_dispose(atlas); +} + +void spineboy (SkeletonData* skeletonData, Atlas* atlas) { SkeletonBounds* bounds = SkeletonBounds_create(); // Configure mixing. @@ -128,23 +158,10 @@ void spineboy () { window.display(); } - SkeletonData_dispose(skeletonData); SkeletonBounds_dispose(bounds); - Atlas_dispose(atlas); } -void goblins () { - // Load atlas, skeleton, and animations. - Atlas* atlas = Atlas_createFromFile("data/goblins-mesh.atlas", 0); - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = 1.4f; - SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/goblins-mesh.json"); - if (!skeletonData) { - printf("Error: %s\n", json->error); - exit(0); - } - SkeletonJson_dispose(json); - +void goblins (SkeletonData* skeletonData, Atlas* atlas) { SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); drawable->timeScale = 1; @@ -178,23 +195,9 @@ void goblins () { window.draw(*drawable); window.display(); } - - SkeletonData_dispose(skeletonData); - Atlas_dispose(atlas); } -void raptor () { - // Load atlas, skeleton, and animations. - Atlas* atlas = Atlas_createFromFile("data/raptor.atlas", 0); - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = 0.5f; - SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/raptor.json"); - if (!skeletonData) { - printf("Error: %s\n", json->error); - exit(0); - } - SkeletonJson_dispose(json); - +void raptor (SkeletonData* skeletonData, Atlas* atlas) { SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); drawable->timeScale = 1; @@ -223,23 +226,9 @@ void raptor () { window.draw(*drawable); window.display(); } - - SkeletonData_dispose(skeletonData); - Atlas_dispose(atlas); } -void tank () { - // Load atlas, skeleton, and animations. - Atlas* atlas = Atlas_createFromFile("data/tank.atlas", 0); - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = 0.2f; - SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/tank.json"); - if (!skeletonData) { - printf("Error: %s\n", json->error); - exit(0); - } - SkeletonJson_dispose(json); - +void tank (SkeletonData* skeletonData, Atlas* atlas) { SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); drawable->timeScale = 1; @@ -266,23 +255,9 @@ void tank () { window.draw(*drawable); window.display(); } - - SkeletonData_dispose(skeletonData); - Atlas_dispose(atlas); } -void vine () { - // Load atlas, skeleton, and animations. - Atlas* atlas = Atlas_createFromFile("data/vine.atlas", 0); - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = 0.5f; - SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/vine.json"); - if (!skeletonData) { - printf("Error: %s\n", json->error); - exit(0); - } - SkeletonJson_dispose(json); - +void vine (SkeletonData* skeletonData, Atlas* atlas) { SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); drawable->timeScale = 1; @@ -310,26 +285,12 @@ void vine () { window.draw(*drawable); window.display(); } - - SkeletonData_dispose(skeletonData); - Atlas_dispose(atlas); } /** * Used for debugging purposes during runtime development */ -void test () { - // Load atlas, skeleton, and animations. - Atlas* atlas = Atlas_createFromFile("data/tank.atlas", 0); - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = 1; - SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/tank.json"); - if (!skeletonData) { - printf("Error: %s\n", json->error); - exit(0); - } - SkeletonJson_dispose(json); - +void test (SkeletonData* skeletonData, Atlas* atlas) { spSkeleton* skeleton = Skeleton_create(skeletonData); spAnimationStateData* animData = spAnimationStateData_create(skeletonData); spAnimationState* animState = spAnimationState_create(animData); @@ -350,16 +311,15 @@ void test () { d += 0.1f; } - SkeletonData_dispose(skeletonData); Skeleton_dispose(skeleton); - Atlas_dispose(atlas); } int main () { - test(); - vine(); - tank(); - raptor(); - spineboy(); - goblins(); + testcase(test, "data/tank.json", "data/tank.skel", "data/tank.atlas", 1.0f); + testcase(vine, "data/vine.json", "data/vine.skel", "data/vine.atlas", 0.5f); + testcase(tank, "data/tank.json", "data/tank.skel", "data/tank.atlas", 0.2f); + testcase(raptor, "data/raptor.json", "data/raptor.skel", "data/raptor.atlas", 0.5f); + testcase(spineboy, "data/spineboy.json", "data/spineboy.skel", "data/spineboy.atlas", 0.6f); + testcase(goblins, "data/goblins-mesh.json", "data/goblins-mesh.skel", "data/goblins-mesh.atlas", 1.4f); + return 0; }