diff --git a/spine-c/include/spine/Animation.h b/spine-c/include/spine/Animation.h index 17bbf550d..576fcefe9 100644 --- a/spine-c/include/spine/Animation.h +++ b/spine-c/include/spine/Animation.h @@ -45,25 +45,25 @@ typedef struct { const char* const name; float duration; - int timelineCount; + int timelinesCount; spTimeline** timelines; } spAnimation; -spAnimation* spAnimation_create (const char* name, int timelineCount); +spAnimation* spAnimation_create (const char* name, int timelinesCount); void spAnimation_dispose (spAnimation* self); /** Poses the skeleton at the specified time for this animation. * @param lastTime The last time the animation was applied. * @param events Any triggered events are added. */ void spAnimation_apply (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop, - spEvent** events, int* eventCount); + spEvent** events, int* eventsCount); /** Poses the skeleton at the specified time for this animation mixed with the current pose. * @param lastTime The last time the animation was applied. * @param events Any triggered events are added. * @param alpha The amount of this animation that affects the current pose. */ void spAnimation_mix (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop, - spEvent** events, int* eventCount, float alpha); + spEvent** events, int* eventsCount, float alpha); #ifdef SPINE_SHORT_NAMES typedef spAnimation Animation; @@ -83,7 +83,8 @@ typedef enum { SP_TIMELINE_ATTACHMENT, SP_TIMELINE_EVENT, SP_TIMELINE_DRAWORDER, - SP_TIMELINE_FFD + SP_TIMELINE_FFD, + SP_TIMELINE_IKCONSTRAINT } spTimelineType; struct spTimeline { @@ -94,7 +95,7 @@ struct spTimeline { void spTimeline_dispose (spTimeline* self); void spTimeline_apply (const spTimeline* self, struct spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha); + int* eventsCount, float alpha); #ifdef SPINE_SHORT_NAMES typedef spTimeline Timeline; @@ -113,7 +114,7 @@ typedef spTimeline Timeline; typedef struct { spTimeline super; - float* curves; /* dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... */ + float* curves; /* type, x, y, ... */ } spCurveTimeline; void spCurveTimeline_setLinear (spCurveTimeline* self, int frameIndex); @@ -142,7 +143,7 @@ typedef struct spBaseTimeline { int boneIndex; } spRotateTimeline; -spRotateTimeline* spRotateTimeline_create (int frameCount); +spRotateTimeline* spRotateTimeline_create (int framesCount); void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float time, float angle); @@ -156,7 +157,7 @@ typedef spRotateTimeline RotateTimeline; typedef struct spBaseTimeline spTranslateTimeline; -spTranslateTimeline* spTranslateTimeline_create (int frameCount); +spTranslateTimeline* spTranslateTimeline_create (int framesCount); void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, float time, float x, float y); @@ -170,7 +171,7 @@ typedef spTranslateTimeline TranslateTimeline; typedef struct spBaseTimeline spScaleTimeline; -spScaleTimeline* spScaleTimeline_create (int frameCount); +spScaleTimeline* spScaleTimeline_create (int framesCount); void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time, float x, float y); @@ -189,7 +190,7 @@ typedef struct { int slotIndex; } spColorTimeline; -spColorTimeline* spColorTimeline_create (int frameCount); +spColorTimeline* spColorTimeline_create (int framesCount); void spColorTimeline_setFrame (spColorTimeline* self, int frameIndex, float time, float r, float g, float b, float a); @@ -209,7 +210,7 @@ typedef struct { const char** const attachmentNames; } spAttachmentTimeline; -spAttachmentTimeline* spAttachmentTimeline_create (int frameCount); +spAttachmentTimeline* spAttachmentTimeline_create (int framesCount); /* @param attachmentName May be 0. */ void spAttachmentTimeline_setFrame (spAttachmentTimeline* self, int frameIndex, float time, const char* attachmentName); @@ -229,7 +230,7 @@ typedef struct { spEvent** const events; } spEventTimeline; -spEventTimeline* spEventTimeline_create (int frameCount); +spEventTimeline* spEventTimeline_create (int framesCount); void spEventTimeline_setFrame (spEventTimeline* self, int frameIndex, float time, spEvent* event); @@ -246,10 +247,10 @@ typedef struct { int const framesCount; float* const frames; /* time, ... */ const int** const drawOrders; - int const slotCount; + int const slotsCount; } spDrawOrderTimeline; -spDrawOrderTimeline* spDrawOrderTimeline_create (int frameCount, int slotCount); +spDrawOrderTimeline* spDrawOrderTimeline_create (int framesCount, int slotsCount); void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, float time, const int* drawOrder); @@ -271,7 +272,7 @@ typedef struct { spAttachment* attachment; } spFFDTimeline; -spFFDTimeline* spFFDTimeline_create (int frameCount, int frameVerticesCount); +spFFDTimeline* spFFDTimeline_create (int framesCount, int frameVerticesCount); void spFFDTimeline_setFrame (spFFDTimeline* self, int frameIndex, float time, float* vertices); @@ -281,6 +282,28 @@ typedef spFFDTimeline FFDTimeline; #define FFDTimeline_setFrame(...) spFFDTimeline_setFrame(__VA_ARGS__) #endif +/**/ + +typedef struct { + spCurveTimeline super; + int const framesCount; + float* const frames; /* time, mix, bendDirection, ... */ + int ikConstraintIndex; +} spIkConstraintTimeline; + +spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount); + +/* @param attachmentName May be 0. */ +void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection); + +#ifdef SPINE_SHORT_NAMES +typedef spIkConstraintTimeline IkConstraintTimeline; +#define IkConstraintTimeline_create(...) spIkConstraintTimeline_create(__VA_ARGS__) +#define IkConstraintTimeline_setFrame(...) spIkConstraintTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + #ifdef __cplusplus } #endif diff --git a/spine-c/include/spine/AnimationState.h b/spine-c/include/spine/AnimationState.h index ca9ce553f..7952bc80b 100644 --- a/spine-c/include/spine/AnimationState.h +++ b/spine-c/include/spine/AnimationState.h @@ -67,7 +67,7 @@ struct spAnimationState { float timeScale; spAnimationStateListener listener; - int trackCount; + int tracksCount; spTrackEntry** tracks; void* rendererObject; diff --git a/spine-c/include/spine/Bone.h b/spine-c/include/spine/Bone.h index f934ae404..33160ecd4 100644 --- a/spine-c/include/spine/Bone.h +++ b/spine-c/include/spine/Bone.h @@ -37,13 +37,17 @@ extern "C" { #endif +struct spSkeleton; + typedef struct spBone spBone; struct spBone { spBoneData* const data; + struct spSkeleton* const skeleton; spBone* const parent; float x, y; - float rotation; + float rotation, rotationIK; float scaleX, scaleY; + int/*bool*/flipX, flipY; float const m00, m01, worldX; /* a b x */ float const m10, m11, worldY; /* c d y */ @@ -54,12 +58,15 @@ struct spBone { void spBone_setYDown (int/*bool*/yDown); /* @param parent May be 0. */ -spBone* spBone_create (spBoneData* data, spBone* parent); +spBone* spBone_create (spBoneData* data, struct spSkeleton* skeleton, spBone* parent); void spBone_dispose (spBone* self); void spBone_setToSetupPose (spBone* self); -void spBone_updateWorldTransform (spBone* self, int/*bool*/flipX, int/*bool*/flipY); +void spBone_updateWorldTransform (spBone* self); + +void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY); +void spBone_localToWorld (spBone* self, float localX, float localY, float* worldX, float* worldY); #ifdef SPINE_SHORT_NAMES typedef spBone Bone; @@ -68,6 +75,8 @@ typedef spBone Bone; #define Bone_dispose(...) spBone_dispose(__VA_ARGS__) #define Bone_setToSetupPose(...) spBone_setToSetupPose(__VA_ARGS__) #define Bone_updateWorldTransform(...) spBone_updateWorldTransform(__VA_ARGS__) +#define Bone_worldToLocal(...) spBone_worldToLocal(__VA_ARGS__) +#define Bone_localToWorld(...) spBone_localToWorld(__VA_ARGS__) #endif #ifdef __cplusplus diff --git a/spine-c/include/spine/BoundingBoxAttachment.h b/spine-c/include/spine/BoundingBoxAttachment.h index eab343810..e67db6c77 100644 --- a/spine-c/include/spine/BoundingBoxAttachment.h +++ b/spine-c/include/spine/BoundingBoxAttachment.h @@ -47,7 +47,7 @@ struct spBoundingBoxAttachment { }; spBoundingBoxAttachment* spBoundingBoxAttachment_create (const char* name); -void spBoundingBoxAttachment_computeWorldVertices (spBoundingBoxAttachment* self, float x, float y, spBone* bone, float* vertices); +void spBoundingBoxAttachment_computeWorldVertices (spBoundingBoxAttachment* self, spBone* bone, float* vertices); #ifdef SPINE_SHORT_NAMES typedef spBoundingBoxAttachment BoundingBoxAttachment; diff --git a/spine-c/include/spine/IkConstraint.h b/spine-c/include/spine/IkConstraint.h new file mode 100644 index 000000000..b5cd89b59 --- /dev/null +++ b/spine-c/include/spine/IkConstraint.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), 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 SOFTARE 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_IKCONSTRAINT_H_ +#define SPINE_IKCONSTRAINT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spSkeleton; + +typedef struct spIkConstraint spIkConstraint; +struct spIkConstraint { + spIkConstraintData* const data; + + int bonesCount; + spBone** bones; + + spBone* target; + int bendDirection; + float mix; +}; + +spIkConstraint* spIkConstraint_create (spIkConstraintData* data, const struct spSkeleton* skeleton); +void spIkConstraint_dispose (spIkConstraint* self); + +void spIkConstraint_apply (spIkConstraint* self); + +void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float alpha); +void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDirection, float alpha); + +#ifdef SPINE_SHORT_NAMES +typedef spIkConstraint IkConstraint; +#define IkConstraint_create(...) spIkConstraint_create(__VA_ARGS__) +#define IkConstraint_dispose(...) spIkConstraint_dispose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SPINE_IKCONSTRAINT_H_ */ diff --git a/spine-c/include/spine/IkConstraintData.h b/spine-c/include/spine/IkConstraintData.h new file mode 100644 index 000000000..7cacd369d --- /dev/null +++ b/spine-c/include/spine/IkConstraintData.h @@ -0,0 +1,65 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), 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 SOFTARE 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_IKCONSTRAINTDATA_H_ +#define SPINE_IKCONSTRAINTDATA_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spIkConstraintData spIkConstraintData; +struct spIkConstraintData { + const char* const name; + + int bonesCount; + spBoneData** bones; + + spBoneData* target; + int bendDirection; + float mix; +}; + +spIkConstraintData* spIkConstraintData_create (const char* name); +void spIkConstraintData_dispose (spIkConstraintData* self); + +#ifdef SPINE_SHORT_NAMES +typedef spIkConstraintData IkConstraintData; +#define IkConstraintData_create(...) spIkConstraintData_create(__VA_ARGS__) +#define IkConstraintData_dispose(...) spIkConstraintData_dispose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SPINE_IKCONSTRAINTDATA_H_ */ diff --git a/spine-c/include/spine/MeshAttachment.h b/spine-c/include/spine/MeshAttachment.h index f0cf29ed8..5948d84ae 100644 --- a/spine-c/include/spine/MeshAttachment.h +++ b/spine-c/include/spine/MeshAttachment.h @@ -71,7 +71,7 @@ struct spMeshAttachment { spMeshAttachment* spMeshAttachment_create (const char* name); void spMeshAttachment_updateUVs (spMeshAttachment* self); -void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, float x, float y, spSlot* slot, float* worldVertices); +void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot, float* worldVertices); #ifdef SPINE_SHORT_NAMES typedef spMeshAttachment MeshAttachment; diff --git a/spine-c/include/spine/RegionAttachment.h b/spine-c/include/spine/RegionAttachment.h index 9b91d50e0..22def9486 100644 --- a/spine-c/include/spine/RegionAttachment.h +++ b/spine-c/include/spine/RegionAttachment.h @@ -62,7 +62,7 @@ struct spRegionAttachment { spRegionAttachment* spRegionAttachment_create (const char* name); void spRegionAttachment_setUVs (spRegionAttachment* self, float u, float v, float u2, float v2, int/*bool*/rotate); void spRegionAttachment_updateOffset (spRegionAttachment* self); -void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, float x, float y, spBone* bone, float* vertices); +void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices); #ifdef SPINE_SHORT_NAMES typedef spVertexIndex VertexIndex; diff --git a/spine-c/include/spine/Skeleton.h b/spine-c/include/spine/Skeleton.h index 0df09e033..34517c8ff 100644 --- a/spine-c/include/spine/Skeleton.h +++ b/spine-c/include/spine/Skeleton.h @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -43,14 +44,17 @@ typedef struct spSkeleton spSkeleton; struct spSkeleton { spSkeletonData* const data; - int boneCount; + int bonesCount; spBone** bones; spBone* const root; - int slotCount; + int slotsCount; spSlot** slots; spSlot** drawOrder; + int ikConstraintsCount; + spIkConstraint** ikConstraints; + spSkin* const skin; float r, g, b, a; float time; @@ -61,6 +65,8 @@ struct spSkeleton { spSkeleton* spSkeleton_create (spSkeletonData* data); void spSkeleton_dispose (spSkeleton* self); +/* Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. */ +void spSkeleton_updateCache (const spSkeleton* self); void spSkeleton_updateWorldTransform (const spSkeleton* self); void spSkeleton_setToSetupPose (const spSkeleton* self); @@ -92,6 +98,9 @@ spAttachment* spSkeleton_getAttachmentForSlotIndex (const spSkeleton* self, int /* Returns 0 if the slot or attachment was not found. */ int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char* attachmentName); +/* Returns 0 if the IK constraint was not found. */ +spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* ikConstraintName); + void spSkeleton_update (spSkeleton* self, float deltaTime); #ifdef SPINE_SHORT_NAMES diff --git a/spine-c/include/spine/SkeletonData.h b/spine-c/include/spine/SkeletonData.h index a5a807ba2..1c9822fe4 100644 --- a/spine-c/include/spine/SkeletonData.h +++ b/spine-c/include/spine/SkeletonData.h @@ -36,27 +36,35 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { #endif typedef struct { - int boneCount; + const char* version; + const char* hash; + float width, height; + + int bonesCount; spBoneData** bones; - int slotCount; + int slotsCount; spSlotData** slots; - int skinCount; + int skinsCount; spSkin** skins; spSkin* defaultSkin; - int eventCount; + int eventsCount; spEventData** events; - int animationCount; + int animationsCount; spAnimation** animations; + + int ikConstraintsCount; + spIkConstraintData** ikConstraints; } spSkeletonData; spSkeletonData* spSkeletonData_create (); @@ -74,6 +82,8 @@ spEventData* spSkeletonData_findEvent (const spSkeletonData* self, const char* e spAnimation* spSkeletonData_findAnimation (const spSkeletonData* self, const char* animationName); +spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* ikConstraintName); + #ifdef SPINE_SHORT_NAMES typedef spSkeletonData SkeletonData; #define SkeletonData_create(...) spSkeletonData_create(__VA_ARGS__) diff --git a/spine-c/include/spine/SkinnedMeshAttachment.h b/spine-c/include/spine/SkinnedMeshAttachment.h index 9e3966edb..9d60565e6 100644 --- a/spine-c/include/spine/SkinnedMeshAttachment.h +++ b/spine-c/include/spine/SkinnedMeshAttachment.h @@ -74,7 +74,7 @@ struct spSkinnedMeshAttachment { spSkinnedMeshAttachment* spSkinnedMeshAttachment_create (const char* name); void spSkinnedMeshAttachment_updateUVs (spSkinnedMeshAttachment* self); -void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self, float x, float y, spSlot* bone, float* worldVertices); +void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self, spSlot* slot, float* worldVertices); #ifdef SPINE_SHORT_NAMES typedef spSkinnedMeshAttachment SkinnedMeshAttachment; diff --git a/spine-c/include/spine/Slot.h b/spine-c/include/spine/Slot.h index bb4cce6ee..9e5c66da4 100644 --- a/spine-c/include/spine/Slot.h +++ b/spine-c/include/spine/Slot.h @@ -39,11 +39,8 @@ extern "C" { #endif -struct spSkeleton; - typedef struct spSlot { spSlotData* const data; - struct spSkeleton* const skeleton; spBone* const bone; float r, g, b, a; spAttachment* const attachment; @@ -53,7 +50,7 @@ typedef struct spSlot { float* attachmentVertices; } spSlot; -spSlot* spSlot_create (spSlotData* data, struct spSkeleton* skeleton, spBone* bone); +spSlot* spSlot_create (spSlotData* data, spBone* bone); void spSlot_dispose (spSlot* self); /* @param attachment May be 0 to clear the attachment for the slot. */ diff --git a/spine-c/include/spine/extension.h b/spine-c/include/spine/extension.h index b8ce9ee80..281d63212 100644 --- a/spine-c/include/spine/extension.h +++ b/spine-c/include/spine/extension.h @@ -57,10 +57,24 @@ /* Allocates a new char[], assigns it to TO, and copies FROM to it. Can be used on const types. */ #define MALLOC_STR(TO,FROM) strcpy(CONST_CAST(char*, TO) = (char*)MALLOC(char, strlen(FROM) + 1), FROM) +#define PI 3.1415926535897932385f +#define DEG_RAD (PI / 180) +#define RAD_DEG (180 / PI) + #ifdef __STDC_VERSION__ #define FMOD(A,B) fmodf(A, B) +#define ATAN2(A,B) atan2f(A, B) +#define SIN(A) sinf(A) +#define COS(A) cosf(A) +#define SQRT(A) sqrtf(A) +#define ACOS(A) acosf(A) #else #define FMOD(A,B) (float)fmod(A, B) +#define ATAN2(A,B) (float)atan2(A, B) +#define COS(A) (float)cos(A) +#define SIN(A) (float)sin(A) +#define SQRT(A) (float)sqrt(A) +#define ACOS(A) (float)acos(A) #endif #include @@ -154,7 +168,7 @@ void _spAttachment_deinit (spAttachment* self); void _spTimeline_init (spTimeline* self, spTimelineType type, /**/ void (*dispose) (spTimeline* self), /**/ void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha)); + int* eventsCount, float alpha)); void _spTimeline_deinit (spTimeline* self); #ifdef SPINE_SHORT_NAMES @@ -164,10 +178,10 @@ void _spTimeline_deinit (spTimeline* self); /**/ -void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int frameCount, /**/ +void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, /**/ void (*dispose) (spTimeline* self), /**/ void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha)); + int* eventsCount, float alpha)); void _spCurveTimeline_deinit (spCurveTimeline* self); #ifdef SPINE_SHORT_NAMES diff --git a/spine-c/src/spine/Animation.c b/spine-c/src/spine/Animation.c index 68a8ca2a5..2a719214c 100644 --- a/spine-c/src/spine/Animation.c +++ b/spine-c/src/spine/Animation.c @@ -29,20 +29,21 @@ *****************************************************************************/ #include +#include #include #include -spAnimation* spAnimation_create (const char* name, int timelineCount) { +spAnimation* spAnimation_create (const char* name, int timelinesCount) { spAnimation* self = NEW(spAnimation); MALLOC_STR(self->name, name); - self->timelineCount = timelineCount; - self->timelines = MALLOC(spTimeline*, timelineCount); + self->timelinesCount = timelinesCount; + self->timelines = MALLOC(spTimeline*, timelinesCount); return self; } void spAnimation_dispose (spAnimation* self) { int i; - for (i = 0; i < self->timelineCount; ++i) + for (i = 0; i < self->timelinesCount; ++i) spTimeline_dispose(self->timelines[i]); FREE(self->timelines); FREE(self->name); @@ -50,8 +51,8 @@ void spAnimation_dispose (spAnimation* self) { } void spAnimation_apply (const spAnimation* self, spSkeleton* skeleton, float lastTime, float time, int loop, spEvent** events, - int* eventCount) { - int i, n = self->timelineCount; + int* eventsCount) { + int i, n = self->timelinesCount; if (loop && self->duration) { time = FMOD(time, self->duration); @@ -59,12 +60,12 @@ void spAnimation_apply (const spAnimation* self, spSkeleton* skeleton, float las } for (i = 0; i < n; ++i) - spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventCount, 1); + spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, 1); } void spAnimation_mix (const spAnimation* self, spSkeleton* skeleton, float lastTime, float time, int loop, spEvent** events, - int* eventCount, float alpha) { - int i, n = self->timelineCount; + int* eventsCount, float alpha) { + int i, n = self->timelinesCount; if (loop && self->duration) { time = FMOD(time, self->duration); @@ -72,21 +73,21 @@ void spAnimation_mix (const spAnimation* self, spSkeleton* skeleton, float lastT } for (i = 0; i < n; ++i) - spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventCount, alpha); + spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, alpha); } /**/ typedef struct _spTimelineVtable { void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha); + int* eventsCount, float alpha); void (*dispose) (spTimeline* self); } _spTimelineVtable; void _spTimeline_init (spTimeline* self, spTimelineType type, /**/ void (*dispose) (spTimeline* self), /**/ void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha)) { + int* eventsCount, float alpha)) { CONST_CAST(spTimelineType, self->type) = type; CONST_CAST(_spTimelineVtable*, self->vtable) = NEW(_spTimelineVtable); VTABLE(spTimeline, self)->dispose = dispose; @@ -102,22 +103,21 @@ void spTimeline_dispose (spTimeline* self) { } void spTimeline_apply (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha) { - VTABLE(spTimeline, self)->apply(self, skeleton, lastTime, time, firedEvents, eventCount, alpha); + int* eventsCount, float alpha) { + VTABLE(spTimeline, self)->apply(self, skeleton, lastTime, time, firedEvents, eventsCount, alpha); } /**/ -static const float CURVE_LINEAR = 0; -static const float CURVE_STEPPED = -1; -static const int CURVE_SEGMENTS = 10; +static const float CURVE_LINEAR = 0, CURVE_STEPPED = 1, CURVE_BEZIER = 2; +static const int BEZIER_SEGMENTS = 10, BEZIER_SIZE = 10 * 2 - 1; -void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int frameCount, /**/ +void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, /**/ void (*dispose) (spTimeline* self), /**/ void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha)) { + int* eventsCount, float alpha)) { _spTimeline_init(SUPER(self), type, dispose, apply); - self->curves = CALLOC(float, (frameCount - 1) * 6); + self->curves = CALLOC(float, (framesCount - 1) * BEZIER_SIZE); } void _spCurveTimeline_deinit (spCurveTimeline* self) { @@ -126,61 +126,28 @@ void _spCurveTimeline_deinit (spCurveTimeline* self) { } void spCurveTimeline_setLinear (spCurveTimeline* self, int frameIndex) { - self->curves[frameIndex * 6] = CURVE_LINEAR; + self->curves[frameIndex * BEZIER_SIZE] = CURVE_LINEAR; } void spCurveTimeline_setStepped (spCurveTimeline* self, int frameIndex) { - self->curves[frameIndex * 6] = CURVE_STEPPED; + self->curves[frameIndex * BEZIER_SIZE] = CURVE_STEPPED; } void spCurveTimeline_setCurve (spCurveTimeline* self, int frameIndex, float cx1, float cy1, float cx2, float cy2) { - float subdiv_step = 1.0f / CURVE_SEGMENTS; - float subdiv_step2 = subdiv_step * subdiv_step; - float subdiv_step3 = subdiv_step2 * subdiv_step; - float pre1 = 3 * subdiv_step; - float pre2 = 3 * subdiv_step2; - float pre4 = 6 * subdiv_step2; - float pre5 = 6 * subdiv_step3; - float tmp1x = -cx1 * 2 + cx2; - float tmp1y = -cy1 * 2 + cy2; - float tmp2x = (cx1 - cx2) * 3 + 1; - float tmp2y = (cy1 - cy2) * 3 + 1; - int i = frameIndex * 6; - self->curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; - self->curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; - self->curves[i + 2] = tmp1x * pre4 + tmp2x * pre5; - self->curves[i + 3] = tmp1y * pre4 + tmp2y * pre5; - self->curves[i + 4] = tmp2x * pre5; - self->curves[i + 5] = tmp2y * pre5; -} + float subdiv1 = 1.0f / BEZIER_SEGMENTS, subdiv2 = subdiv1 * subdiv1, subdiv3 = subdiv2 * subdiv1; + float pre1 = 3 * subdiv1, pre2 = 3 * subdiv2, pre4 = 6 * subdiv2, pre5 = 6 * subdiv3; + float tmp1x = -cx1 * 2 + cx2, tmp1y = -cy1 * 2 + cy2, tmp2x = (cx1 - cx2) * 3 + 1, tmp2y = (cy1 - cy2) * 3 + 1; + float dfx = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv3, dfy = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv3; + float ddfx = tmp1x * pre4 + tmp2x * pre5, ddfy = tmp1y * pre4 + tmp2y * pre5; + float dddfx = tmp2x * pre5, dddfy = tmp2y * pre5; + float x = dfx, y = dfy; -float spCurveTimeline_getCurvePercent (const spCurveTimeline* self, int frameIndex, float percent) { - float dfy; - float ddfx; - float ddfy; - float dddfx; - float dddfy; - float x, y; - int i; - int curveIndex = frameIndex * 6; - float dfx = self->curves[curveIndex]; - if (dfx == CURVE_LINEAR) return percent; - if (dfx == CURVE_STEPPED) return 0; - dfy = self->curves[curveIndex + 1]; - ddfx = self->curves[curveIndex + 2]; - ddfy = self->curves[curveIndex + 3]; - dddfx = self->curves[curveIndex + 4]; - dddfy = self->curves[curveIndex + 5]; - x = dfx, y = dfy; - i = CURVE_SEGMENTS - 2; - while (1) { - if (x >= percent) { - float lastX = x - dfx; - float lastY = y - dfy; - return lastY + (y - lastY) * (percent - lastX) / (x - lastX); - } - if (i == 0) break; - i--; + int i = frameIndex * BEZIER_SIZE, n = i + BEZIER_SIZE - 1; + self->curves[i++] = CURVE_BEZIER; + + for (; i < n; i += 2) { + self->curves[i] = x; + self->curves[i + 1] = y; dfx += ddfx; dfy += ddfy; ddfx += dddfx; @@ -188,6 +155,31 @@ float spCurveTimeline_getCurvePercent (const spCurveTimeline* self, int frameInd x += dfx; y += dfy; } +} + +float spCurveTimeline_getCurvePercent (const spCurveTimeline* self, int frameIndex, float percent) { + float x, y; + int i = frameIndex * BEZIER_SIZE, start, n; + float type = self->curves[i]; + if (type == CURVE_LINEAR) return percent; + if (type == CURVE_STEPPED) return 0; + i++; + x = 0; + for (start = i, n = i + BEZIER_SIZE - 1; i < n; i += 2) { + x = self->curves[i]; + if (x >= percent) { + float prevX, prevY; + if (i == start) { + prevX = 0; + prevY = 0; + } else { + prevX = self->curves[i - 2]; + prevY = self->curves[i - 1]; + } + return prevY + (self->curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); + } + } + y = self->curves[i - 1]; return y + (1 - y) * (percent - x) / (1 - x); /* Last point is 1,1. */ } @@ -208,6 +200,23 @@ static int binarySearch (float *values, int valuesLength, float target, int step return 0; } +/* @param target After the first and before the last entry. */ +static int binarySearch1 (float *values, int valuesLength, float target) { + int low = 0, current; + int high = valuesLength - 2; + if (high == 0) return 1; + current = high >> 1; + while (1) { + if (values[(current + 1)] <= target) + low = current + 1; + else + high = current; + if (low == high) return low + 1; + current = (low + high) >> 1; + } + return 0; +} + /*static int linearSearch (float *values, int valuesLength, float target, int step) { int i, last = valuesLength - step; for (i = 0; i <= last; i += step) { @@ -227,13 +236,13 @@ void _spBaseTimeline_dispose (spTimeline* timeline) { } /* Many timelines have structure identical to struct spBaseTimeline and extend spCurveTimeline. **/ -struct spBaseTimeline* _spBaseTimeline_create (int frameCount, spTimelineType type, int frameSize, /**/ +struct spBaseTimeline* _spBaseTimeline_create (int framesCount, spTimelineType type, int frameSize, /**/ void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha)) { + int* eventsCount, float alpha)) { struct spBaseTimeline* self = NEW(struct spBaseTimeline); - _spCurveTimeline_init(SUPER(self), type, frameCount, _spBaseTimeline_dispose, apply); + _spCurveTimeline_init(SUPER(self), type, framesCount, _spBaseTimeline_dispose, apply); - CONST_CAST(int, self->framesCount) = frameCount * frameSize; + CONST_CAST(int, self->framesCount) = framesCount * frameSize; CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount); return self; @@ -241,14 +250,14 @@ struct spBaseTimeline* _spBaseTimeline_create (int frameCount, spTimelineType ty /**/ -static const int ROTATE_LAST_FRAME_TIME = -2; +static const int ROTATE_PREV_FRAME_TIME = -2; static const int ROTATE_FRAME_VALUE = 1; void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha) { + int* eventsCount, float alpha) { spBone *bone; int frameIndex; - float lastFrameValue, frameTime, percent, amount; + float prevFrameValue, frameTime, percent, amount; spRotateTimeline* self = SUB_CAST(spRotateTimeline, timeline); @@ -268,17 +277,17 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, /* Interpolate between the previous frame and the current frame. */ frameIndex = binarySearch(self->frames, self->framesCount, time, 2); - lastFrameValue = self->frames[frameIndex - 1]; + prevFrameValue = self->frames[frameIndex - 1]; frameTime = self->frames[frameIndex]; - percent = 1 - (time - frameTime) / (self->frames[frameIndex + ROTATE_LAST_FRAME_TIME] - frameTime); - percent = spCurveTimeline_getCurvePercent(SUPER(self), frameIndex / 2 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); + percent = 1 - (time - frameTime) / (self->frames[frameIndex + ROTATE_PREV_FRAME_TIME] - frameTime); + percent = spCurveTimeline_getCurvePercent(SUPER(self), (frameIndex >> 1) - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); - amount = self->frames[frameIndex + ROTATE_FRAME_VALUE] - lastFrameValue; + amount = self->frames[frameIndex + ROTATE_FRAME_VALUE] - prevFrameValue; while (amount > 180) amount -= 360; while (amount < -180) amount += 360; - amount = bone->data->rotation + (lastFrameValue + amount * percent) - bone->rotation; + amount = bone->data->rotation + (prevFrameValue + amount * percent) - bone->rotation; while (amount > 180) amount -= 360; while (amount < -180) @@ -286,8 +295,8 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, bone->rotation += amount * alpha; } -spRotateTimeline* spRotateTimeline_create (int frameCount) { - return _spBaseTimeline_create(frameCount, SP_TIMELINE_ROTATE, 2, _spRotateTimeline_apply); +spRotateTimeline* spRotateTimeline_create (int framesCount) { + return _spBaseTimeline_create(framesCount, SP_TIMELINE_ROTATE, 2, _spRotateTimeline_apply); } void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float time, float angle) { @@ -298,15 +307,15 @@ void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float ti /**/ -static const int TRANSLATE_LAST_FRAME_TIME = -3; +static const int TRANSLATE_PREV_FRAME_TIME = -3; static const int TRANSLATE_FRAME_X = 1; static const int TRANSLATE_FRAME_Y = 2; void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha) { spBone *bone; int frameIndex; - float lastFrameX, lastFrameY, frameTime, percent; + float prevFrameX, prevFrameY, frameTime, percent; spTranslateTimeline* self = SUB_CAST(spTranslateTimeline, timeline); @@ -322,20 +331,20 @@ void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto /* Interpolate between the previous frame and the current frame. */ frameIndex = binarySearch(self->frames, self->framesCount, time, 3); - lastFrameX = self->frames[frameIndex - 2]; - lastFrameY = self->frames[frameIndex - 1]; + prevFrameX = self->frames[frameIndex - 2]; + prevFrameY = self->frames[frameIndex - 1]; frameTime = self->frames[frameIndex]; - percent = 1 - (time - frameTime) / (self->frames[frameIndex + TRANSLATE_LAST_FRAME_TIME] - frameTime); + percent = 1 - (time - frameTime) / (self->frames[frameIndex + TRANSLATE_PREV_FRAME_TIME] - frameTime); percent = spCurveTimeline_getCurvePercent(SUPER(self), frameIndex / 3 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); - bone->x += (bone->data->x + lastFrameX + (self->frames[frameIndex + TRANSLATE_FRAME_X] - lastFrameX) * percent - bone->x) + bone->x += (bone->data->x + prevFrameX + (self->frames[frameIndex + TRANSLATE_FRAME_X] - prevFrameX) * percent - bone->x) * alpha; - bone->y += (bone->data->y + lastFrameY + (self->frames[frameIndex + TRANSLATE_FRAME_Y] - lastFrameY) * percent - bone->y) + bone->y += (bone->data->y + prevFrameY + (self->frames[frameIndex + TRANSLATE_FRAME_Y] - prevFrameY) * percent - bone->y) * alpha; } -spTranslateTimeline* spTranslateTimeline_create (int frameCount) { - return _spBaseTimeline_create(frameCount, SP_TIMELINE_TRANSLATE, 3, _spTranslateTimeline_apply); +spTranslateTimeline* spTranslateTimeline_create (int framesCount) { + return _spBaseTimeline_create(framesCount, SP_TIMELINE_TRANSLATE, 3, _spTranslateTimeline_apply); } void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, float time, float x, float y) { @@ -348,10 +357,10 @@ void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, fl /**/ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha) { + int* eventsCount, float alpha) { spBone *bone; int frameIndex; - float lastFrameX, lastFrameY, frameTime, percent; + float prevFrameX, prevFrameY, frameTime, percent; spScaleTimeline* self = SUB_CAST(spScaleTimeline, timeline); @@ -366,20 +375,20 @@ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f /* Interpolate between the previous frame and the current frame. */ frameIndex = binarySearch(self->frames, self->framesCount, time, 3); - lastFrameX = self->frames[frameIndex - 2]; - lastFrameY = self->frames[frameIndex - 1]; + prevFrameX = self->frames[frameIndex - 2]; + prevFrameY = self->frames[frameIndex - 1]; frameTime = self->frames[frameIndex]; - percent = 1 - (time - frameTime) / (self->frames[frameIndex + TRANSLATE_LAST_FRAME_TIME] - frameTime); + percent = 1 - (time - frameTime) / (self->frames[frameIndex + TRANSLATE_PREV_FRAME_TIME] - frameTime); percent = spCurveTimeline_getCurvePercent(SUPER(self), frameIndex / 3 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); - bone->scaleX += (bone->data->scaleX - 1 + lastFrameX + (self->frames[frameIndex + TRANSLATE_FRAME_X] - lastFrameX) * percent + bone->scaleX += (bone->data->scaleX - 1 + prevFrameX + (self->frames[frameIndex + TRANSLATE_FRAME_X] - prevFrameX) * percent - bone->scaleX) * alpha; - bone->scaleY += (bone->data->scaleY - 1 + lastFrameY + (self->frames[frameIndex + TRANSLATE_FRAME_Y] - lastFrameY) * percent + bone->scaleY += (bone->data->scaleY - 1 + prevFrameY + (self->frames[frameIndex + TRANSLATE_FRAME_Y] - prevFrameY) * percent - bone->scaleY) * alpha; } -spScaleTimeline* spScaleTimeline_create (int frameCount) { - return _spBaseTimeline_create(frameCount, SP_TIMELINE_SCALE, 3, _spScaleTimeline_apply); +spScaleTimeline* spScaleTimeline_create (int framesCount) { + return _spBaseTimeline_create(framesCount, SP_TIMELINE_SCALE, 3, _spScaleTimeline_apply); } void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time, float x, float y) { @@ -388,17 +397,17 @@ void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time /**/ -static const int COLOR_LAST_FRAME_TIME = -5; +static const int COLOR_PREV_FRAME_TIME = -5; static const int COLOR_FRAME_R = 1; static const int COLOR_FRAME_G = 2; static const int COLOR_FRAME_B = 3; static const int COLOR_FRAME_A = 4; void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha) { + int* eventsCount, float alpha) { spSlot *slot; int frameIndex; - float lastFrameR, lastFrameG, lastFrameB, lastFrameA, percent, frameTime; + float prevFrameR, prevFrameG, prevFrameB, prevFrameA, percent, frameTime; float r, g, b, a; spColorTimeline* self = (spColorTimeline*)timeline; @@ -414,18 +423,18 @@ void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f } else { /* Interpolate between the previous frame and the current frame. */ frameIndex = binarySearch(self->frames, self->framesCount, time, 5); - lastFrameR = self->frames[frameIndex - 4]; - lastFrameG = self->frames[frameIndex - 3]; - lastFrameB = self->frames[frameIndex - 2]; - lastFrameA = self->frames[frameIndex - 1]; + prevFrameR = self->frames[frameIndex - 4]; + prevFrameG = self->frames[frameIndex - 3]; + prevFrameB = self->frames[frameIndex - 2]; + prevFrameA = self->frames[frameIndex - 1]; frameTime = self->frames[frameIndex]; - percent = 1 - (time - frameTime) / (self->frames[frameIndex + COLOR_LAST_FRAME_TIME] - frameTime); + percent = 1 - (time - frameTime) / (self->frames[frameIndex + COLOR_PREV_FRAME_TIME] - frameTime); percent = spCurveTimeline_getCurvePercent(SUPER(self), frameIndex / 5 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); - r = lastFrameR + (self->frames[frameIndex + COLOR_FRAME_R] - lastFrameR) * percent; - g = lastFrameG + (self->frames[frameIndex + COLOR_FRAME_G] - lastFrameG) * percent; - b = lastFrameB + (self->frames[frameIndex + COLOR_FRAME_B] - lastFrameB) * percent; - a = lastFrameA + (self->frames[frameIndex + COLOR_FRAME_A] - lastFrameA) * percent; + r = prevFrameR + (self->frames[frameIndex + COLOR_FRAME_R] - prevFrameR) * percent; + g = prevFrameG + (self->frames[frameIndex + COLOR_FRAME_G] - prevFrameG) * percent; + b = prevFrameB + (self->frames[frameIndex + COLOR_FRAME_B] - prevFrameB) * percent; + a = prevFrameA + (self->frames[frameIndex + COLOR_FRAME_A] - prevFrameA) * percent; } slot = skeleton->slots[self->slotIndex]; if (alpha < 1) { @@ -441,8 +450,8 @@ void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f } } -spColorTimeline* spColorTimeline_create (int frameCount) { - return (spColorTimeline*)_spBaseTimeline_create(frameCount, SP_TIMELINE_COLOR, 5, _spColorTimeline_apply); +spColorTimeline* spColorTimeline_create (int framesCount) { + return (spColorTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_COLOR, 5, _spColorTimeline_apply); } void spColorTimeline_setFrame (spColorTimeline* self, int frameIndex, float time, float r, float g, float b, float a) { @@ -457,17 +466,20 @@ void spColorTimeline_setFrame (spColorTimeline* self, int frameIndex, float time /**/ void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha) { int frameIndex; const char* attachmentName; spAttachmentTimeline* self = (spAttachmentTimeline*)timeline; - if (time < self->frames[0]) return; /* Time is before first frame. */ + if (time < self->frames[0]) { + if (lastTime > time) _spAttachmentTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, 0, 0, 0); + return; + } else if (lastTime > time) /**/ + lastTime = -1; - if (time >= self->frames[self->framesCount - 1]) /* Time is after last frame. */ - frameIndex = self->framesCount - 1; - else - frameIndex = binarySearch(self->frames, self->framesCount, time, 1) - 1; + frameIndex = time >= self->frames[self->framesCount - 1] ? + self->framesCount - 1 : binarySearch1(self->frames, self->framesCount, time) - 1; + if (self->frames[frameIndex] <= lastTime) return; attachmentName = self->attachmentNames[frameIndex]; spSlot_setAttachment(skeleton->slots[self->slotIndex], @@ -487,13 +499,13 @@ void _spAttachmentTimeline_dispose (spTimeline* timeline) { FREE(self); } -spAttachmentTimeline* spAttachmentTimeline_create (int frameCount) { +spAttachmentTimeline* spAttachmentTimeline_create (int framesCount) { spAttachmentTimeline* self = NEW(spAttachmentTimeline); _spTimeline_init(SUPER(self), SP_TIMELINE_ATTACHMENT, _spAttachmentTimeline_dispose, _spAttachmentTimeline_apply); - CONST_CAST(int, self->framesCount) = frameCount; - CONST_CAST(float*, self->frames) = CALLOC(float, frameCount); - CONST_CAST(char**, self->attachmentNames) = CALLOC(char*, frameCount); + CONST_CAST(int, self->framesCount) = framesCount; + CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); + CONST_CAST(char**, self->attachmentNames) = CALLOC(char*, framesCount); return self; } @@ -512,13 +524,13 @@ void spAttachmentTimeline_setFrame (spAttachmentTimeline* self, int frameIndex, /** Fires events for frames > lastTime and <= time. */ void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha) { + int* eventsCount, float alpha) { spEventTimeline* self = (spEventTimeline*)timeline; int frameIndex; if (!firedEvents) return; if (lastTime > time) { /* Fire events after last time for looped animations. */ - _spEventTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, firedEvents, eventCount, alpha); + _spEventTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, firedEvents, eventsCount, alpha); lastTime = -1; } else if (lastTime >= self->frames[self->framesCount - 1]) /* Last time is after last frame. */ return; @@ -528,7 +540,7 @@ void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f frameIndex = 0; else { float frame; - frameIndex = binarySearch(self->frames, self->framesCount, lastTime, 1); + frameIndex = binarySearch1(self->frames, self->framesCount, lastTime); frame = self->frames[frameIndex]; while (frameIndex > 0) { /* Fire multiple events with the same frame. */ if (self->frames[frameIndex - 1] != frame) break; @@ -536,8 +548,8 @@ void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f } } for (; frameIndex < self->framesCount && time >= self->frames[frameIndex]; ++frameIndex) { - firedEvents[*eventCount] = self->events[frameIndex]; - (*eventCount)++; + firedEvents[*eventsCount] = self->events[frameIndex]; + (*eventsCount)++; } } @@ -554,13 +566,13 @@ void _spEventTimeline_dispose (spTimeline* timeline) { FREE(self); } -spEventTimeline* spEventTimeline_create (int frameCount) { +spEventTimeline* spEventTimeline_create (int framesCount) { spEventTimeline* self = NEW(spEventTimeline); _spTimeline_init(SUPER(self), SP_TIMELINE_EVENT, _spEventTimeline_dispose, _spEventTimeline_apply); - CONST_CAST(int, self->framesCount) = frameCount; - CONST_CAST(float*, self->frames) = CALLOC(float, frameCount); - CONST_CAST(spEvent**, self->events) = CALLOC(spEvent*, frameCount); + CONST_CAST(int, self->framesCount) = framesCount; + CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); + CONST_CAST(spEvent**, self->events) = CALLOC(spEvent*, framesCount); return self; } @@ -575,7 +587,7 @@ void spEventTimeline_setFrame (spEventTimeline* self, int frameIndex, float time /**/ void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha) { int i; int frameIndex; const int* drawOrderToSetupIndex; @@ -586,13 +598,13 @@ void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto if (time >= self->frames[self->framesCount - 1]) /* Time is after last frame. */ frameIndex = self->framesCount - 1; else - frameIndex = binarySearch(self->frames, self->framesCount, time, 1) - 1; + frameIndex = binarySearch1(self->frames, self->framesCount, time) - 1; drawOrderToSetupIndex = self->drawOrders[frameIndex]; if (!drawOrderToSetupIndex) - memcpy(skeleton->drawOrder, skeleton->slots, self->slotCount * sizeof(int)); + memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(int)); else { - for (i = 0; i < self->slotCount; ++i) + for (i = 0; i < self->slotsCount; ++i) skeleton->drawOrder[i] = skeleton->slots[drawOrderToSetupIndex[i]]; } } @@ -610,14 +622,14 @@ void _spDrawOrderTimeline_dispose (spTimeline* timeline) { FREE(self); } -spDrawOrderTimeline* spDrawOrderTimeline_create (int frameCount, int slotCount) { +spDrawOrderTimeline* spDrawOrderTimeline_create (int framesCount, int slotsCount) { spDrawOrderTimeline* self = NEW(spDrawOrderTimeline); _spTimeline_init(SUPER(self), SP_TIMELINE_DRAWORDER, _spDrawOrderTimeline_dispose, _spDrawOrderTimeline_apply); - CONST_CAST(int, self->framesCount) = frameCount; - CONST_CAST(float*, self->frames) = CALLOC(float, frameCount); - CONST_CAST(int**, self->drawOrders) = CALLOC(int*, frameCount); - CONST_CAST(int, self->slotCount) = slotCount; + CONST_CAST(int, self->framesCount) = framesCount; + CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); + CONST_CAST(int**, self->drawOrders) = CALLOC(int*, framesCount); + CONST_CAST(int, self->slotsCount) = slotsCount; return self; } @@ -629,15 +641,15 @@ void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, fl 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)); + self->drawOrders[frameIndex] = MALLOC(int, self->slotsCount); + memcpy(CONST_CAST(int*, self->drawOrders[frameIndex]), drawOrder, self->slotsCount * sizeof(int)); } } /**/ void _spFFDTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventCount, float alpha) { + int* eventsCount, float alpha) { int frameIndex, i; float percent, frameTime; const float* prevVertices; @@ -674,7 +686,7 @@ void _spFFDTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, flo } /* Interpolate between the previous frame and the current frame. */ - frameIndex = binarySearch(self->frames, self->framesCount, time, 1); + frameIndex = binarySearch1(self->frames, self->framesCount, time); frameTime = self->frames[frameIndex]; percent = 1 - (time - frameTime) / (self->frames[frameIndex - 1] - frameTime); percent = spCurveTimeline_getCurvePercent(SUPER(self), frameIndex - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); @@ -708,12 +720,12 @@ void _spFFDTimeline_dispose (spTimeline* timeline) { FREE(self); } -spFFDTimeline* spFFDTimeline_create (int frameCount, int frameVerticesCount) { +spFFDTimeline* spFFDTimeline_create (int framesCount, int frameVerticesCount) { spFFDTimeline* self = NEW(spFFDTimeline); - _spCurveTimeline_init(SUPER(self), SP_TIMELINE_FFD, frameCount, _spFFDTimeline_dispose, _spFFDTimeline_apply); - CONST_CAST(int, self->framesCount) = frameCount; + _spCurveTimeline_init(SUPER(self), SP_TIMELINE_FFD, framesCount, _spFFDTimeline_dispose, _spFFDTimeline_apply); + CONST_CAST(int, self->framesCount) = framesCount; CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount); - CONST_CAST(float**, self->frameVertices) = CALLOC(float*, frameCount); + CONST_CAST(float**, self->frameVertices) = CALLOC(float*, framesCount); CONST_CAST(int, self->frameVerticesCount) = frameVerticesCount; return self; } @@ -729,3 +741,49 @@ void spFFDTimeline_setFrame (spFFDTimeline* self, int frameIndex, float time, fl memcpy(CONST_CAST(float*, self->frameVertices[frameIndex]), vertices, self->frameVerticesCount * sizeof(float)); } } + + +/**/ + +static const int IKCONSTRAINT_PREV_FRAME_TIME = -3; +static const int IKCONSTRAINT_FRAME_MIX = 1; +static const int IKCONSTRAINT_FRAME_BEND_DIRECTION = 2; + +void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, + spEvent** firedEvents, int* eventsCount, float alpha) { + int frameIndex; + spIkConstraint* ikConstraint; + spIkConstraintTimeline* self = (spIkConstraintTimeline*)timeline; + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + ikConstraint = skeleton->ikConstraints[self->ikConstraintIndex]; + + if (time >= self->frames[self->framesCount - 3]) { /* Time is after last frame. */ + ikConstraint->mix += (self->frames[self->framesCount - 2] - ikConstraint->mix) * alpha; + ikConstraint->bendDirection = (int)self->frames[self->framesCount - 1]; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frameIndex = binarySearch(self->frames, self->framesCount, time, 3); + float prevFrameMix = self->frames[frameIndex - 2]; + float frameTime = self->frames[frameIndex]; + float percent = 1 - (time - frameTime) / (self->frames[frameIndex + IKCONSTRAINT_PREV_FRAME_TIME] - frameTime); + percent = spCurveTimeline_getCurvePercent(SUPER(self), frameIndex / 3 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); + + float mix = prevFrameMix + (self->frames[frameIndex + IKCONSTRAINT_FRAME_MIX] - prevFrameMix) * percent; + ikConstraint->mix += (mix - ikConstraint->mix) * alpha; + ikConstraint->bendDirection = (int)self->frames[frameIndex + IKCONSTRAINT_FRAME_BEND_DIRECTION]; +} + +spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount) { + return (spIkConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_IKCONSTRAINT, 3, _spIkConstraintTimeline_apply); +} + +void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection) { + frameIndex *= 3; + self->frames[frameIndex] = time; + self->frames[frameIndex + 1] = mix; + self->frames[frameIndex + 2] = bendDirection; +} diff --git a/spine-c/src/spine/AnimationState.c b/spine-c/src/spine/AnimationState.c index 0d2ea8dec..419c4594f 100644 --- a/spine-c/src/spine/AnimationState.c +++ b/spine-c/src/spine/AnimationState.c @@ -80,7 +80,7 @@ void spAnimationState_dispose (spAnimationState* self) { int i; _spAnimationState* internal = SUB_CAST(_spAnimationState, self); FREE(internal->events); - for (i = 0; i < self->trackCount; ++i) + for (i = 0; i < self->tracksCount; ++i) _spAnimationState_disposeAllEntries(self, self->tracks[i]); FREE(self->tracks); FREE(self); @@ -92,7 +92,7 @@ void spAnimationState_update (spAnimationState* self, float delta) { int i; float previousDelta; delta *= self->timeScale; - for (i = 0; i < self->trackCount; ++i) { + for (i = 0; i < self->tracksCount; ++i) { spTrackEntry* current = self->tracks[i]; if (!current) continue; @@ -117,15 +117,15 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { _spAnimationState* internal = SUB_CAST(_spAnimationState, self); int i, ii; - int eventCount; + int eventsCount; int entryChanged; float time; spTrackEntry* previous; - for (i = 0; i < self->trackCount; ++i) { + for (i = 0; i < self->tracksCount; ++i) { spTrackEntry* current = self->tracks[i]; if (!current) continue; - eventCount = 0; + eventsCount = 0; time = current->time; if (!current->loop && time > current->endTime) time = current->endTime; @@ -134,10 +134,10 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { if (!previous) { if (current->mix == 1) { spAnimation_apply(current->animation, skeleton, current->lastTime, time, - current->loop, internal->events, &eventCount); + current->loop, internal->events, &eventsCount); } else { spAnimation_mix(current->animation, skeleton, current->lastTime, time, - current->loop, internal->events, &eventCount, current->mix); + current->loop, internal->events, &eventsCount, current->mix); } } else { float alpha = current->mixTime / current->mixDuration * current->mix; @@ -152,11 +152,11 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { current->previous = 0; } spAnimation_mix(current->animation, skeleton, current->lastTime, time, - current->loop, internal->events, &eventCount, alpha); + current->loop, internal->events, &eventsCount, alpha); } entryChanged = 0; - for (ii = 0; ii < eventCount; ++ii) { + for (ii = 0; ii < eventsCount; ++ii) { spEvent* event = internal->events[ii]; if (current->listener) { current->listener(self, i, SP_ANIMATION_EVENT, event, 0); @@ -195,14 +195,14 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { void spAnimationState_clearTracks (spAnimationState* self) { int i; - for (i = 0; i < self->trackCount; ++i) + for (i = 0; i < self->tracksCount; ++i) spAnimationState_clearTrack(self, i); - self->trackCount = 0; + self->tracksCount = 0; } void spAnimationState_clearTrack (spAnimationState* self, int trackIndex) { spTrackEntry* current; - if (trackIndex >= self->trackCount) return; + if (trackIndex >= self->tracksCount) return; current = self->tracks[trackIndex]; if (!current) return; @@ -216,12 +216,12 @@ void spAnimationState_clearTrack (spAnimationState* self, int trackIndex) { spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index) { spTrackEntry** newTracks; - if (index < self->trackCount) return self->tracks[index]; + if (index < self->tracksCount) return self->tracks[index]; newTracks = CALLOC(spTrackEntry*, index + 1); - memcpy(newTracks, self->tracks, self->trackCount * sizeof(spTrackEntry*)); + memcpy(newTracks, self->tracks, self->tracksCount * sizeof(spTrackEntry*)); FREE(self->tracks); self->tracks = newTracks; - self->trackCount = index + 1; + self->tracksCount = index + 1; return 0; } @@ -317,6 +317,6 @@ spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIn } spTrackEntry* spAnimationState_getCurrent (spAnimationState* self, int trackIndex) { - if (trackIndex >= self->trackCount) return 0; + if (trackIndex >= self->tracksCount) return 0; return self->tracks[trackIndex]; } diff --git a/spine-c/src/spine/Bone.c b/spine-c/src/spine/Bone.c index 271b30a97..1b2f8c495 100644 --- a/spine-c/src/spine/Bone.c +++ b/spine-c/src/spine/Bone.c @@ -37,9 +37,10 @@ void spBone_setYDown (int value) { yDown = value; } -spBone* spBone_create (spBoneData* data, spBone* parent) { +spBone* spBone_create (spBoneData* data, spSkeleton* skeleton, spBone* parent) { spBone* self = NEW(spBone); CONST_CAST(spBoneData*, self->data) = data; + CONST_CAST(spSkeleton*, self->skeleton) = skeleton; CONST_CAST(spBone*, self->parent) = parent; spBone_setToSetupPose(self); return self; @@ -49,15 +50,7 @@ void spBone_dispose (spBone* self) { FREE(self); } -void spBone_setToSetupPose (spBone* self) { - self->x = self->data->x; - self->y = self->data->y; - self->rotation = self->data->rotation; - self->scaleX = self->data->scaleX; - self->scaleY = self->data->scaleY; -} - -void spBone_updateWorldTransform (spBone* self, int flipX, int flipY) { +void spBone_updateWorldTransform (spBone* self) { float radians, cosine, sine; if (self->parent) { CONST_CAST(float, self->worldX) = self->x * self->parent->m00 + self->y * self->parent->m01 + self->parent->worldX; @@ -70,32 +63,55 @@ void spBone_updateWorldTransform (spBone* self, int flipX, int flipY) { CONST_CAST(float, self->worldScaleY) = self->scaleY; } CONST_CAST(float, self->worldRotation) = - self->data->inheritRotation ? self->parent->worldRotation + self->rotation : self->rotation; + self->data->inheritRotation ? self->parent->worldRotation + self->rotationIK : self->rotationIK; } else { - CONST_CAST(float, self->worldX) = flipX ? -self->x : self->x; - CONST_CAST(float, self->worldY) = flipY != yDown ? -self->y : self->y; + CONST_CAST(float, self->worldX) = self->flipX ? -self->x : self->x; + CONST_CAST(float, self->worldY) = self->flipY != yDown ? -self->y : self->y; CONST_CAST(float, self->worldScaleX) = self->scaleX; CONST_CAST(float, self->worldScaleY) = self->scaleY; - CONST_CAST(float, self->worldRotation) = self->rotation; + CONST_CAST(float, self->worldRotation) = self->rotationIK; } - radians = (float)(self->worldRotation * 3.1415926535897932385 / 180); -#ifdef __STDC_VERSION__ - cosine = cosf(radians); - sine = sinf(radians); -#else - cosine = (float)cos(radians); - sine = (float)sin(radians); -#endif - CONST_CAST(float, self->m00) = cosine * self->worldScaleX; - CONST_CAST(float, self->m10) = sine * self->worldScaleX; - CONST_CAST(float, self->m01) = -sine * self->worldScaleY; - CONST_CAST(float, self->m11) = cosine * self->worldScaleY; - if (flipX) { - CONST_CAST(float, self->m00) = -self->m00; - CONST_CAST(float, self->m01) = -self->m01; + radians = self->worldRotation * DEG_RAD; + cosine = COS(radians); + sine = SIN(radians); + if (self->flipX) { + CONST_CAST(float, self->m00) = -cosine * self->worldScaleX; + CONST_CAST(float, self->m01) = sine * self->worldScaleY; + } else { + CONST_CAST(float, self->m00) = cosine * self->worldScaleX; + CONST_CAST(float, self->m01) = -sine * self->worldScaleY; } - if (flipY != yDown) { - CONST_CAST(float, self->m10) = -self->m10; - CONST_CAST(float, self->m11) = -self->m11; + if (self->flipY != yDown) { + CONST_CAST(float, self->m10) = -sine * self->worldScaleX; + CONST_CAST(float, self->m11) = -cosine * self->worldScaleY; + } else { + CONST_CAST(float, self->m10) = sine * self->worldScaleX; + CONST_CAST(float, self->m11) = cosine * self->worldScaleY; } } + +void spBone_setToSetupPose (spBone* self) { + self->x = self->data->x; + self->y = self->data->y; + self->rotation = self->data->rotation; + self->rotationIK = self->rotation; + self->scaleX = self->data->scaleX; + self->scaleY = self->data->scaleY; +} + +void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY) { + float dx = worldX - self->worldX, dy = worldY - self->worldY; + float m00 = self->m00, m11 = self->m11; + if (self->flipX != (self->flipY != yDown)) { + m00 *= -1; + m11 *= -1; + } + float invDet = 1 / (m00 * m11 - self->m01 * self->m10); + *localX = (dx * m00 * invDet - dy * self->m01 * invDet); + *localY = (dy * m11 * invDet - dx * self->m10 * invDet); +} + +void spBone_localToWorld (spBone* self, float localX, float localY, float* worldX, float* worldY) { + *worldX = localX * self->m00 + localY * self->m01 + self->worldX; + *worldY = localX * self->m10 + localY * self->m11 + self->worldY; +} diff --git a/spine-c/src/spine/BoundingBoxAttachment.c b/spine-c/src/spine/BoundingBoxAttachment.c index 7deb5c793..6df38ed32 100644 --- a/spine-c/src/spine/BoundingBoxAttachment.c +++ b/spine-c/src/spine/BoundingBoxAttachment.c @@ -46,13 +46,11 @@ spBoundingBoxAttachment* spBoundingBoxAttachment_create (const char* name) { return self; } -void spBoundingBoxAttachment_computeWorldVertices (spBoundingBoxAttachment* self, float x, float y, spBone* bone, float* worldVertices) { +void spBoundingBoxAttachment_computeWorldVertices (spBoundingBoxAttachment* self, spBone* bone, float* worldVertices) { int i; float px, py; float* vertices = self->vertices; - - x += bone->worldX; - y += bone->worldY; + float x = bone->skeleton->x + bone->worldX, y = bone->skeleton->y + bone->worldY; for (i = 0; i < self->verticesCount; i += 2) { px = vertices[i]; py = vertices[i + 1]; diff --git a/spine-c/src/spine/IkConstraint.c b/spine-c/src/spine/IkConstraint.c new file mode 100644 index 000000000..c7db55c3c --- /dev/null +++ b/spine-c/src/spine/IkConstraint.c @@ -0,0 +1,129 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), 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 SOFTARE 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 + +spIkConstraint* spIkConstraint_create (spIkConstraintData* data, const spSkeleton* skeleton) { + int i; + + spIkConstraint* self = NEW(spIkConstraint); + CONST_CAST(spIkConstraintData*, self->data) = data; + self->bendDirection = data->bendDirection; + self->mix = data->mix; + + self->bonesCount = self->data->bonesCount; + self->bones = MALLOC(spBone*, self->bonesCount); + for (i = 0; i < self->bonesCount; ++i) + self->bones[i] = spSkeleton_findBone(skeleton, self->data->bones[i]->name); + self->target = spSkeleton_findBone(skeleton, self->data->target->name); + + return self; +} + +void spIkConstraint_dispose (spIkConstraint* self) { + FREE(self->bones); + FREE(self); +} + +void spIkConstraint_apply (spIkConstraint* self) { + switch (self->bonesCount) { + case 1: + spIkConstraint_apply1(self->bones[0], self->target->worldX, self->target->worldY, self->mix); + break; + case 2: + spIkConstraint_apply2(self->bones[0], self->bones[1], self->target->worldX, self->target->worldY, self->bendDirection, + self->mix); + break; + } +} + +void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float alpha) { + float parentRotation = (!bone->data->inheritRotation || !bone->parent) ? 0 : bone->parent->worldRotation; + float rotation = bone->rotation; + float rotationIK = ATAN2(targetY - bone->worldY, targetX - bone->worldX) * RAD_DEG - parentRotation; + bone->rotationIK = rotation + (rotationIK - rotation) * alpha; +} + +void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDirection, float alpha) { + float childRotation = child->rotation, parentRotation = parent->rotation; + if (alpha == 0) { + child->rotationIK = childRotation; + parent->rotationIK = parentRotation; + return; + } + float positionX, positionY; + spBone* parentParent = parent->parent; + if (parentParent) { + spBone_worldToLocal(parentParent, targetX, targetY, &positionX, &positionY); + targetX = (positionX - parent->x) * parentParent->worldScaleX; + targetY = (positionY - parent->y) * parentParent->worldScaleY; + } else { + targetX -= parent->x; + targetY -= parent->y; + } + if (child->parent == parent) { + positionX = child->x; + positionY = child->y; + } else { + spBone_localToWorld(child->parent, child->x, child->y, &positionX, &positionY); + spBone_worldToLocal(parent, positionX, positionY, &positionX, &positionY); + } + float childX = positionX * parent->worldScaleX, childY = positionY * parent->worldScaleY; + float offset = ATAN2(childY, childX); + float len1 = SQRT(childX * childX + childY * childY); + float len2 = child->data->length * child->worldScaleX; + /* Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett, http://www.ryanjuckett.com/ */ + float cosDenom = 2 * len1 * len2; + if (cosDenom < 0.0001f) { + child->rotationIK = childRotation + (ATAN2(targetY, targetX) * RAD_DEG - parentRotation - childRotation) * alpha; + return; + } + float cos = (targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom; + if (cos < -1) + cos = -1; + else if (cos > 1) cos = 1; + float childAngle = ACOS(cos) * bendDirection; + float adjacent = len1 + len2 * cos, opposite = len2 * SIN(childAngle); + float parentAngle = ATAN2(targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite); + float rotation = (parentAngle - offset) * RAD_DEG - parentRotation; + if (rotation > 180) + rotation -= 360; + else if (rotation < -180) /**/ + rotation += 360; + parent->rotationIK = parentRotation + rotation * alpha; + rotation = (childAngle + offset) * RAD_DEG - childRotation; + if (rotation > 180) + rotation -= 360; + else if (rotation < -180) /**/ + rotation += 360; + child->rotationIK = childRotation + (rotation + parent->worldRotation - child->parent->worldRotation) * alpha; +} diff --git a/spine-c/src/spine/IkConstraintData.c b/spine-c/src/spine/IkConstraintData.c new file mode 100644 index 000000000..f25b6eb30 --- /dev/null +++ b/spine-c/src/spine/IkConstraintData.c @@ -0,0 +1,46 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), 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 SOFTARE 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 + +spIkConstraintData* spIkConstraintData_create (const char* name) { + spIkConstraintData* self = NEW(spIkConstraintData); + MALLOC_STR(self->name, name); + self->bendDirection = 1; + self->mix = 1; + return self; +} + +void spIkConstraintData_dispose (spIkConstraintData* self) { + FREE(self->name); + FREE(self->bones); + FREE(self); +} diff --git a/spine-c/src/spine/MeshAttachment.c b/spine-c/src/spine/MeshAttachment.c index 631e6d0c4..0ca41fbc0 100644 --- a/spine-c/src/spine/MeshAttachment.c +++ b/spine-c/src/spine/MeshAttachment.c @@ -71,12 +71,11 @@ void spMeshAttachment_updateUVs (spMeshAttachment* self) { } } -void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, float x, float y, spSlot* slot, float* worldVertices) { +void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot, float* worldVertices) { int i; float* vertices = self->vertices; const spBone* bone = slot->bone; - x += bone->worldX; - y += bone->worldY; + float x = bone->skeleton->x + bone->worldX, y = bone->skeleton->y + bone->worldY; if (slot->attachmentVerticesCount == self->verticesCount) vertices = slot->attachmentVertices; for (i = 0; i < self->verticesCount; i += 2) { const float vx = vertices[i], vy = vertices[i + 1]; diff --git a/spine-c/src/spine/RegionAttachment.c b/spine-c/src/spine/RegionAttachment.c index eb15f0e46..6b1030518 100644 --- a/spine-c/src/spine/RegionAttachment.c +++ b/spine-c/src/spine/RegionAttachment.c @@ -79,14 +79,8 @@ void spRegionAttachment_updateOffset (spRegionAttachment* self) { float localY = -self->height / 2 * self->scaleY + self->regionOffsetY * regionScaleY; float localX2 = localX + self->regionWidth * regionScaleX; float localY2 = localY + self->regionHeight * regionScaleY; - float radians = (float)(self->rotation * 3.1415926535897932385 / 180); -#ifdef __STDC_VERSION__ - float cosine = cosf(radians); - float sine = sinf(radians); -#else - float cosine = (float)cos(radians); - float sine = (float)sin(radians); -#endif + float radians = self->rotation * DEG_RAD; + float cosine = COS(radians), sine = SIN(radians); float localXCos = localX * cosine + self->x; float localXSin = localX * sine; float localYCos = localY * cosine + self->y; @@ -105,10 +99,9 @@ void spRegionAttachment_updateOffset (spRegionAttachment* self) { self->offset[SP_VERTEX_Y4] = localYCos + localX2Sin; } -void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, float x, float y, spBone* bone, float* vertices) { +void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices) { const float* offset = self->offset; - x += bone->worldX; - y += bone->worldY; + float x = bone->skeleton->x + bone->worldX, y = bone->skeleton->y + bone->worldY; vertices[SP_VERTEX_X1] = offset[SP_VERTEX_X1] * bone->m00 + offset[SP_VERTEX_Y1] * bone->m01 + x; vertices[SP_VERTEX_Y1] = offset[SP_VERTEX_X1] * bone->m10 + offset[SP_VERTEX_Y1] * bone->m11 + y; vertices[SP_VERTEX_X2] = offset[SP_VERTEX_X2] * bone->m00 + offset[SP_VERTEX_Y2] * bone->m01 + x; diff --git a/spine-c/src/spine/Skeleton.c b/spine-c/src/spine/Skeleton.c index be7fc423d..9e3d6fca3 100644 --- a/spine-c/src/spine/Skeleton.c +++ b/spine-c/src/spine/Skeleton.c @@ -32,65 +32,88 @@ #include #include +typedef struct { + spSkeleton super; + + int boneCacheCount; + int* boneCacheCounts; + spBone*** boneCache; +} _spSkeleton; + spSkeleton* spSkeleton_create (spSkeletonData* data) { int i, ii; - spSkeleton* self = NEW(spSkeleton); + _spSkeleton* internal = NEW(_spSkeleton); + spSkeleton* self = SUPER(internal); CONST_CAST(spSkeletonData*, self->data) = data; - self->boneCount = self->data->boneCount; - self->bones = MALLOC(spBone*, self->boneCount); + self->bonesCount = self->data->bonesCount; + self->bones = MALLOC(spBone*, self->bonesCount); - for (i = 0; i < self->boneCount; ++i) { + for (i = 0; i < self->bonesCount; ++i) { spBoneData* boneData = self->data->bones[i]; spBone* parent = 0; if (boneData->parent) { /* Find parent bone. */ - for (ii = 0; ii < self->boneCount; ++ii) { + for (ii = 0; ii < self->bonesCount; ++ii) { if (data->bones[ii] == boneData->parent) { parent = self->bones[ii]; break; } } } - self->bones[i] = spBone_create(boneData, parent); + self->bones[i] = spBone_create(boneData, self, parent); } CONST_CAST(spBone*, self->root) = self->bones[0]; - self->slotCount = data->slotCount; - self->slots = MALLOC(spSlot*, self->slotCount); - for (i = 0; i < self->slotCount; ++i) { + self->slotsCount = data->slotsCount; + self->slots = MALLOC(spSlot*, self->slotsCount); + for (i = 0; i < self->slotsCount; ++i) { spSlotData *slotData = data->slots[i]; /* Find bone for the slotData's boneData. */ spBone* bone = 0; - for (ii = 0; ii < self->boneCount; ++ii) { + for (ii = 0; ii < self->bonesCount; ++ii) { if (data->bones[ii] == slotData->boneData) { bone = self->bones[ii]; break; } } - self->slots[i] = spSlot_create(slotData, self, bone); + self->slots[i] = spSlot_create(slotData, bone); } - self->drawOrder = MALLOC(spSlot*, self->slotCount); - memcpy(self->drawOrder, self->slots, sizeof(spSlot*) * self->slotCount); + self->drawOrder = MALLOC(spSlot*, self->slotsCount); + memcpy(self->drawOrder, self->slots, sizeof(spSlot*) * self->slotsCount); self->r = 1; self->g = 1; self->b = 1; self->a = 1; + self->ikConstraintsCount = data->ikConstraintsCount; + self->ikConstraints = MALLOC(spIkConstraint*, self->ikConstraintsCount); + for (i = 0; i < self->data->ikConstraintsCount; ++i) + self->ikConstraints[i] = spIkConstraint_create(self->data->ikConstraints[i], self); + + spSkeleton_updateCache(self); + return self; } void spSkeleton_dispose (spSkeleton* self) { int i; - for (i = 0; i < self->boneCount; ++i) + _spSkeleton* internal = SUB_CAST(_spSkeleton, self); + + for (i = 0; i < internal->boneCacheCount; ++i) + FREE(internal->boneCache[i]); + FREE(internal->boneCache); + FREE(internal->boneCacheCounts); + + for (i = 0; i < self->bonesCount; ++i) spBone_dispose(self->bones[i]); FREE(self->bones); - for (i = 0; i < self->slotCount; ++i) + for (i = 0; i < self->slotsCount; ++i) spSlot_dispose(self->slots[i]); FREE(self->slots); @@ -98,10 +121,89 @@ void spSkeleton_dispose (spSkeleton* self) { FREE(self); } +void spSkeleton_updateCache (const spSkeleton* self) { + int i, ii; + _spSkeleton* internal = SUB_CAST(_spSkeleton, self); + + for (i = 0; i < internal->boneCacheCount; ++i) + FREE(internal->boneCache[i]); + FREE(internal->boneCache); + FREE(internal->boneCacheCounts); + + internal->boneCacheCount = self->ikConstraintsCount + 1; + internal->boneCache = MALLOC(spBone**, internal->boneCacheCount); + internal->boneCacheCounts = CALLOC(int, internal->boneCacheCount); + + /* Compute array sizes. */ + for (i = 0; i < self->bonesCount; ++i) { + spBone* current = self->bones[i]; + do { + for (ii = 0; ii < self->ikConstraintsCount; ++ii) { + spIkConstraint* ikConstraint = self->ikConstraints[ii]; + spBone* parent = ikConstraint->bones[0]; + spBone* child = ikConstraint->bones[ikConstraint->bonesCount - 1]; + while (1) { + if (current == child) { + internal->boneCacheCounts[ii]++; + internal->boneCacheCounts[ii + 1]++; + goto outer1; + } + if (child == parent) break; + child = child->parent; + } + } + current = current->parent; + } while (current); + internal->boneCacheCounts[0]++; + outer1: {} + } + + for (i = 0; i < internal->boneCacheCount; ++i) + internal->boneCache[i] = MALLOC(spBone*, internal->boneCacheCounts[i]); + memset(internal->boneCacheCounts, 0, internal->boneCacheCount * sizeof(int)); + + /* Populate arrays. */ + for (i = 0; i < self->bonesCount; ++i) { + spBone* bone = self->bones[i]; + spBone* current = bone; + do { + for (ii = 0; ii < self->ikConstraintsCount; ++ii) { + spIkConstraint* ikConstraint = self->ikConstraints[ii]; + spBone* parent = ikConstraint->bones[0]; + spBone* child = ikConstraint->bones[ikConstraint->bonesCount - 1]; + while (1) { + if (current == child) { + internal->boneCache[ii][internal->boneCacheCounts[ii]++] = bone; + internal->boneCache[ii + 1][internal->boneCacheCounts[ii + 1]++] = bone; + goto outer2; + } + if (child == parent) break; + child = child->parent; + } + } + current = current->parent; + } while (current); + internal->boneCache[0][internal->boneCacheCounts[0]++] = bone; + outer2: {} + } +} + void spSkeleton_updateWorldTransform (const spSkeleton* self) { - int i; - for (i = 0; i < self->boneCount; ++i) - spBone_updateWorldTransform(self->bones[i], self->flipX, self->flipY); + int i, ii, nn, last; + _spSkeleton* internal = SUB_CAST(_spSkeleton, self); + + for (i = 0; i < self->bonesCount; ++i) + self->bones[i]->rotationIK = self->bones[i]->rotation; + + i = 0; + last = internal->boneCacheCount - 1; + while (1) { + for (ii = 0, nn = internal->boneCacheCounts[i]; ii < nn; ++ii) + spBone_updateWorldTransform(internal->boneCache[i][ii]); + if (i == last) break; + spIkConstraint_apply(self->ikConstraints[i]); + i++; + } } void spSkeleton_setToSetupPose (const spSkeleton* self) { @@ -111,41 +213,47 @@ void spSkeleton_setToSetupPose (const spSkeleton* self) { void spSkeleton_setBonesToSetupPose (const spSkeleton* self) { int i; - for (i = 0; i < self->boneCount; ++i) + for (i = 0; i < self->bonesCount; ++i) spBone_setToSetupPose(self->bones[i]); + + for (i = 0; i < self->ikConstraintsCount; ++i) { + spIkConstraint* ikConstraint = self->ikConstraints[i]; + ikConstraint->bendDirection = ikConstraint->data->bendDirection; + ikConstraint->mix = ikConstraint->data->mix; + } } void spSkeleton_setSlotsToSetupPose (const spSkeleton* self) { int i; - memcpy(self->drawOrder, self->slots, self->slotCount * sizeof(spSlot*)); - for (i = 0; i < self->slotCount; ++i) + memcpy(self->drawOrder, self->slots, self->slotsCount * sizeof(spSlot*)); + for (i = 0; i < self->slotsCount; ++i) spSlot_setToSetupPose(self->slots[i]); } spBone* spSkeleton_findBone (const spSkeleton* self, const char* boneName) { int i; - for (i = 0; i < self->boneCount; ++i) + for (i = 0; i < self->bonesCount; ++i) if (strcmp(self->data->bones[i]->name, boneName) == 0) return self->bones[i]; return 0; } int spSkeleton_findBoneIndex (const spSkeleton* self, const char* boneName) { int i; - for (i = 0; i < self->boneCount; ++i) + for (i = 0; i < self->bonesCount; ++i) if (strcmp(self->data->bones[i]->name, boneName) == 0) return i; return -1; } spSlot* spSkeleton_findSlot (const spSkeleton* self, const char* slotName) { int i; - for (i = 0; i < self->slotCount; ++i) + for (i = 0; i < self->slotsCount; ++i) if (strcmp(self->data->slots[i]->name, slotName) == 0) return self->slots[i]; return 0; } int spSkeleton_findSlotIndex (const spSkeleton* self, const char* slotName) { int i; - for (i = 0; i < self->slotCount; ++i) + for (i = 0; i < self->slotsCount; ++i) if (strcmp(self->data->slots[i]->name, slotName) == 0) return i; return -1; } @@ -169,7 +277,7 @@ void spSkeleton_setSkin (spSkeleton* self, spSkin* newSkin) { else { /* No previous skin, attach setup pose attachments. */ int i; - for (i = 0; i < self->slotCount; ++i) { + for (i = 0; i < self->slotsCount; ++i) { spSlot* slot = self->slots[i]; if (slot->data->attachmentName) { spAttachment* attachment = spSkin_getAttachment(newSkin, i, slot->data->attachmentName); @@ -201,7 +309,7 @@ spAttachment* spSkeleton_getAttachmentForSlotIndex (const spSkeleton* self, int int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char* attachmentName) { int i; - for (i = 0; i < self->slotCount; ++i) { + for (i = 0; i < self->slotsCount; ++i) { spSlot *slot = self->slots[i]; if (strcmp(slot->data->name, slotName) == 0) { if (!attachmentName) @@ -217,6 +325,13 @@ int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char return 0; } +spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* ikConstraintName) { + int i; + for (i = 0; i < self->ikConstraintsCount; ++i) + if (strcmp(self->ikConstraints[i]->data->name, ikConstraintName) == 0) return self->ikConstraints[i]; + return 0; +} + void spSkeleton_update (spSkeleton* self, float deltaTime) { self->time += deltaTime; } diff --git a/spine-c/src/spine/SkeletonBounds.c b/spine-c/src/spine/SkeletonBounds.c index 21b311a37..16c35facc 100644 --- a/spine-c/src/spine/SkeletonBounds.c +++ b/spine-c/src/spine/SkeletonBounds.c @@ -105,18 +105,18 @@ void spSkeletonBounds_update (spSkeletonBounds* self, spSkeleton* skeleton, int/ int i; _spSkeletonBounds* internal = SUB_CAST(_spSkeletonBounds, self); - if (internal->capacity < skeleton->slotCount) { + if (internal->capacity < skeleton->slotsCount) { spPolygon** newPolygons; FREE(self->boundingBoxes); - self->boundingBoxes = MALLOC(spBoundingBoxAttachment*, skeleton->slotCount); + self->boundingBoxes = MALLOC(spBoundingBoxAttachment*, skeleton->slotsCount); - newPolygons = CALLOC(spPolygon*, skeleton->slotCount); + newPolygons = CALLOC(spPolygon*, skeleton->slotsCount); memcpy(newPolygons, self->polygons, internal->capacity); FREE(self->polygons); self->polygons = newPolygons; - internal->capacity = skeleton->slotCount; + internal->capacity = skeleton->slotsCount; } self->minX = (float)INT_MAX; @@ -125,7 +125,7 @@ void spSkeletonBounds_update (spSkeletonBounds* self, spSkeleton* skeleton, int/ self->maxY = (float)INT_MIN; self->count = 0; - for (i = 0; i < skeleton->slotCount; ++i) { + for (i = 0; i < skeleton->slotsCount; ++i) { spPolygon* polygon; spBoundingBoxAttachment* boundingBox; @@ -141,7 +141,7 @@ void spSkeletonBounds_update (spSkeletonBounds* self, spSkeleton* skeleton, int/ self->polygons[self->count] = polygon = spPolygon_create(boundingBox->verticesCount); } polygon->count = boundingBox->verticesCount; - spBoundingBoxAttachment_computeWorldVertices(boundingBox, skeleton->x, skeleton->y, slot->bone, polygon->vertices); + spBoundingBoxAttachment_computeWorldVertices(boundingBox, slot->bone, polygon->vertices); if (updateAabb) { int ii = 0; @@ -155,7 +155,7 @@ void spSkeletonBounds_update (spSkeletonBounds* self, spSkeleton* skeleton, int/ } } - ++self->count; + self->count++; } } diff --git a/spine-c/src/spine/SkeletonData.c b/spine-c/src/spine/SkeletonData.c index 7a7a30364..d586415b7 100644 --- a/spine-c/src/spine/SkeletonData.c +++ b/spine-c/src/spine/SkeletonData.c @@ -38,74 +38,85 @@ spSkeletonData* spSkeletonData_create () { void spSkeletonData_dispose (spSkeletonData* self) { int i; - for (i = 0; i < self->boneCount; ++i) + for (i = 0; i < self->bonesCount; ++i) spBoneData_dispose(self->bones[i]); FREE(self->bones); - for (i = 0; i < self->slotCount; ++i) + for (i = 0; i < self->slotsCount; ++i) spSlotData_dispose(self->slots[i]); FREE(self->slots); - for (i = 0; i < self->skinCount; ++i) + for (i = 0; i < self->skinsCount; ++i) spSkin_dispose(self->skins[i]); FREE(self->skins); - for (i = 0; i < self->animationCount; ++i) + for (i = 0; i < self->eventsCount; ++i) + spEventData_dispose(self->events[i]); + FREE(self->events); + + for (i = 0; i < self->animationsCount; ++i) spAnimation_dispose(self->animations[i]); FREE(self->animations); - for (i = 0; i < self->eventCount; ++i) - spEventData_dispose(self->events[i]); - FREE(self->events); + for (i = 0; i < self->ikConstraintsCount; ++i) + spIkConstraintData_dispose(self->ikConstraints[i]); + FREE(self->ikConstraints); FREE(self); } spBoneData* spSkeletonData_findBone (const spSkeletonData* self, const char* boneName) { int i; - for (i = 0; i < self->boneCount; ++i) + for (i = 0; i < self->bonesCount; ++i) if (strcmp(self->bones[i]->name, boneName) == 0) return self->bones[i]; return 0; } int spSkeletonData_findBoneIndex (const spSkeletonData* self, const char* boneName) { int i; - for (i = 0; i < self->boneCount; ++i) + for (i = 0; i < self->bonesCount; ++i) if (strcmp(self->bones[i]->name, boneName) == 0) return i; return -1; } spSlotData* spSkeletonData_findSlot (const spSkeletonData* self, const char* slotName) { int i; - for (i = 0; i < self->slotCount; ++i) + for (i = 0; i < self->slotsCount; ++i) if (strcmp(self->slots[i]->name, slotName) == 0) return self->slots[i]; return 0; } int spSkeletonData_findSlotIndex (const spSkeletonData* self, const char* slotName) { int i; - for (i = 0; i < self->slotCount; ++i) + for (i = 0; i < self->slotsCount; ++i) if (strcmp(self->slots[i]->name, slotName) == 0) return i; return -1; } spSkin* spSkeletonData_findSkin (const spSkeletonData* self, const char* skinName) { int i; - for (i = 0; i < self->skinCount; ++i) + for (i = 0; i < self->skinsCount; ++i) if (strcmp(self->skins[i]->name, skinName) == 0) return self->skins[i]; return 0; } spEventData* spSkeletonData_findEvent (const spSkeletonData* self, const char* eventName) { int i; - for (i = 0; i < self->eventCount; ++i) + for (i = 0; i < self->eventsCount; ++i) if (strcmp(self->events[i]->name, eventName) == 0) return self->events[i]; return 0; } spAnimation* spSkeletonData_findAnimation (const spSkeletonData* self, const char* animationName) { int i; - for (i = 0; i < self->animationCount; ++i) + for (i = 0; i < self->animationsCount; ++i) if (strcmp(self->animations[i]->name, animationName) == 0) return self->animations[i]; return 0; } + +spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* ikConstraintName) { + int i; + for (i = 0; i < self->ikConstraintsCount; ++i) + if (strcmp(self->ikConstraints[i]->name, ikConstraintName) == 0) return self->ikConstraints[i]; + return 0; +} diff --git a/spine-c/src/spine/SkeletonJson.c b/spine-c/src/spine/SkeletonJson.c index ea121487d..80382907b 100644 --- a/spine-c/src/spine/SkeletonJson.c +++ b/spine-c/src/spine/SkeletonJson.c @@ -109,27 +109,29 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r Json* bones = Json_getItem(root, "bones"); Json* slots = Json_getItem(root, "slots"); + Json* ik = Json_getItem(root, "ik"); Json* ffd = Json_getItem(root, "ffd"); Json* drawOrder = Json_getItem(root, "draworder"); Json* events = Json_getItem(root, "events"); - Json *boneMap, *slotMap, *ffdMap; + Json *boneMap, *slotMap, *ikMap, *ffdMap; - int timelineCount = 0; + int timelinesCount = 0; for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next) - timelineCount += boneMap->size; + timelinesCount += boneMap->size; for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) - timelineCount += slotMap->size; + timelinesCount += slotMap->size; + timelinesCount += ik ? ik->size : 0; for (ffdMap = ffd ? ffd->child : 0; ffdMap; ffdMap = ffdMap->next) for (slotMap = ffdMap->child; slotMap; slotMap = slotMap->next) - timelineCount += slotMap->size; - if (events) ++timelineCount; - if (drawOrder) ++timelineCount; + timelinesCount += slotMap->size; + if (events) ++timelinesCount; + if (drawOrder) ++timelinesCount; - animation = spAnimation_create(root->name, timelineCount); - animation->timelineCount = 0; - skeletonData->animations[skeletonData->animationCount] = animation; - ++skeletonData->animationCount; + animation = spAnimation_create(root->name, timelinesCount); + animation->timelinesCount = 0; + skeletonData->animations[skeletonData->animationsCount++] = animation; + /* Slot timelines. */ for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) { Json *timelineArray; @@ -150,7 +152,7 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r toColor(s, 3)); readCurve(SUPER(timeline), i, frame); } - animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline); + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); duration = timeline->frames[timelineArray->size * 5 - 5]; if (duration > animation->duration) animation->duration = duration; @@ -162,7 +164,7 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r spAttachmentTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), name->type == Json_NULL ? 0 : name->valueString); } - animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline); + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); duration = timeline->frames[timelineArray->size - 1]; if (duration > animation->duration) animation->duration = duration; @@ -174,13 +176,14 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r } } + /* Bone timelines. */ for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next) { Json *timelineArray; int boneIndex = spSkeletonData_findBoneIndex(skeletonData, boneMap->name); if (boneIndex == -1) { spAnimation_dispose(animation); - _spSkeletonJson_setError(self, root, "spBone not found: ", boneMap->name); + _spSkeletonJson_setError(self, root, "Bone not found: ", boneMap->name); return 0; } @@ -192,7 +195,7 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r spRotateTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), Json_getFloat(frame, "angle", 0)); readCurve(SUPER(timeline), i, frame); } - animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline); + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); duration = timeline->frames[timelineArray->size * 2 - 2]; if (duration > animation->duration) animation->duration = duration; @@ -208,7 +211,7 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r Json_getFloat(frame, "y", 0) * scale); readCurve(SUPER(timeline), i, frame); } - animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline); + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); duration = timeline->frames[timelineArray->size * 3 - 3]; if (duration > animation->duration) animation->duration = duration; } else { @@ -220,6 +223,27 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r } } + /* IK timelines. */ + for (ikMap = ik ? ik->child : 0; ikMap; ikMap = ikMap->next) { + spIkConstraintData* ikConstraint = spSkeletonData_findIkConstraint(skeletonData, ikMap->name); + spIkConstraintTimeline* timeline = spIkConstraintTimeline_create(ikMap->size); + for (i = 0; i < skeletonData->ikConstraintsCount; ++i) { + if (ikConstraint == skeletonData->ikConstraints[i]) { + timeline->ikConstraintIndex = i; + break; + } + } + for (frame = events->child, i = 0; frame; frame = frame->next, ++i) { + spIkConstraintTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), Json_getFloat(frame, "mix", 0), + Json_getFloat(frame, "bendPositive", 1) ? 1 : -1); + readCurve(SUPER(timeline), i, frame); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + duration = timeline->frames[ikMap->size * 3 - 3]; + if (duration > animation->duration) animation->duration = duration; + } + + /* FFD timelines. */ for (ffdMap = ffd ? ffd->child : 0; ffdMap; ffdMap = ffdMap->next) { spSkin* skin = spSkeletonData_findSkin(skeletonData, ffdMap->name); for (slotMap = ffdMap->child; slotMap; slotMap = slotMap->next) { @@ -281,26 +305,27 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r } FREE(tempVertices); - animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline); + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); duration = timeline->frames[timelineArray->size - 1]; if (duration > animation->duration) animation->duration = duration; } } } + /* Draw order timeline. */ if (drawOrder) { - spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrder->size, skeletonData->slotCount); + spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrder->size, skeletonData->slotsCount); 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* unchanged = MALLOC(int, skeletonData->slotsCount - offsets->size); int originalIndex = 0, unchangedIndex = 0; - drawOrder = MALLOC(int, skeletonData->slotCount); - for (ii = skeletonData->slotCount - 1; ii >= 0; --ii) + drawOrder = MALLOC(int, skeletonData->slotsCount); + for (ii = skeletonData->slotsCount - 1; ii >= 0; --ii) drawOrder[ii] = -1; for (offsetMap = offsets->child; offsetMap; offsetMap = offsetMap->next) { @@ -315,24 +340,25 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r unchanged[unchangedIndex++] = originalIndex++; /* Set changed items. */ drawOrder[originalIndex + Json_getInt(offsetMap, "offset", 0)] = originalIndex; - ++originalIndex; + originalIndex++; } /* Collect remaining unchanged items. */ - while (originalIndex < skeletonData->slotCount) + while (originalIndex < skeletonData->slotsCount) unchanged[unchangedIndex++] = originalIndex++; /* Fill in unchanged items. */ - for (ii = skeletonData->slotCount - 1; ii >= 0; ii--) + for (ii = skeletonData->slotsCount - 1; ii >= 0; ii--) if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; FREE(unchanged); } spDrawOrderTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), drawOrder); FREE(drawOrder); } - animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline); + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); duration = timeline->frames[drawOrder->size - 1]; if (duration > animation->duration) animation->duration = duration; } + /* Event timeline. */ if (events) { Json* frame; @@ -353,7 +379,7 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r if (stringValue) MALLOC_STR(event->stringValue, stringValue); spEventTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), event); } - animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline); + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); duration = timeline->frames[events->size - 1]; if (duration > animation->duration) animation->duration = duration; } @@ -375,9 +401,9 @@ spSkeletonData* spSkeletonJson_readSkeletonDataFile (spSkeletonJson* self, const } spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const char* json) { - int i; + int i, ii; spSkeletonData* skeletonData; - Json *root, *bones, *boneMap, *slots, *skins, *animations, *events; + Json *root, *skeleton, *bones, *boneMap, *ik, *slots, *skins, *animations, *events; FREE(self->error); CONST_CAST(char*, self->error) = 0; @@ -390,6 +416,15 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha skeletonData = spSkeletonData_create(); + skeleton = Json_getItem(root, "skeleton"); + if (skeleton) { + skeletonData->hash = Json_getString(skeleton, "hash", 0); + skeletonData->version = Json_getString(skeleton, "spine", 0); + skeletonData->width = Json_getFloat(skeleton, "width", 0); + skeletonData->height = Json_getFloat(skeleton, "height", 0); + } + + /* Bones. */ bones = Json_getItem(root, "bones"); skeletonData->bones = MALLOC(spBoneData*, bones->size); for (boneMap = bones->child, i = 0; boneMap; boneMap = boneMap->next, ++i) { @@ -417,12 +452,49 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha boneData->inheritRotation = Json_getInt(boneMap, "inheritRotation", 1); skeletonData->bones[i] = boneData; - ++skeletonData->boneCount; + skeletonData->bonesCount++; } + /* IK constraints. */ + ik = Json_getItem(root, "ik"); + if (ik) { + Json *ikMap; + skeletonData->ikConstraintsCount = ik->size; + skeletonData->ikConstraints = MALLOC(spIkConstraintData*, ik->size); + for (ikMap = ik->child, i = 0; ikMap; ikMap = ikMap->next, ++i) { + spIkConstraintData* ikConstraintData = spIkConstraintData_create(Json_getString(ikMap, "name", 0)); + boneMap = Json_getItem(ikMap, "bones"); + ikConstraintData->bonesCount = boneMap->size; + ikConstraintData->bones = MALLOC(spBoneData*, boneMap->size); + for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { + ikConstraintData->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); + if (!ikConstraintData->bones[ii]) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "IK bone not found: ", boneMap->valueString); + return 0; + } + } + + const char* targetName = Json_getString(ikMap, "target", 0); + ikConstraintData->target = spSkeletonData_findBone(skeletonData, targetName); + if (!ikConstraintData->target) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "Target bone not found: ", boneMap->name); + return 0; + } + + ikConstraintData->bendDirection = Json_getInt(ikMap, "bendPositive", 1) ? 1 : -1; + ikConstraintData->mix = Json_getFloat(ikMap, "mix", 1); + + skeletonData->ikConstraints[i] = ikConstraintData; + } + } + + /* Slots. */ slots = Json_getItem(root, "slots"); if (slots) { Json *slotMap; + skeletonData->slotsCount = slots->size; skeletonData->slots = MALLOC(spSlotData*, slots->size); for (slotMap = slots->child, i = 0; slotMap; slotMap = slotMap->next, ++i) { spSlotData* slotData; @@ -433,7 +505,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha spBoneData* boneData = spSkeletonData_findBone(skeletonData, boneName); if (!boneData) { spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "spSlot bone not found: ", boneName); + _spSkeletonJson_setError(self, root, "Slot bone not found: ", boneName); return 0; } @@ -453,20 +525,20 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha slotData->additiveBlending = Json_getInt(slotMap, "additive", 0); skeletonData->slots[i] = slotData; - ++skeletonData->slotCount; } } + /* Skins. */ skins = Json_getItem(root, "skins"); if (skins) { Json *slotMap; + skeletonData->skinsCount = skins->size; skeletonData->skins = MALLOC(spSkin*, skins->size); for (slotMap = skins->child, i = 0; slotMap; slotMap = slotMap->next, ++i) { Json *attachmentsMap; spSkin *skin = spSkin_create(slotMap->name); skeletonData->skins[i] = skin; - ++skeletonData->skinCount; if (strcmp(slotMap->name, "default") == 0) skeletonData->defaultSkin = skin; for (attachmentsMap = slotMap->child; attachmentsMap; attachmentsMap = attachmentsMap->next) { @@ -597,18 +669,18 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha vertices[i] = entry->valueFloat; for (i = 0; i < verticesCount;) { - int boneCount = (int)vertices[i]; - mesh->bonesCount += boneCount + 1; - mesh->weightsCount += boneCount * 3; - i += 1 + boneCount * 4; + int bonesCount = (int)vertices[i]; + mesh->bonesCount += bonesCount + 1; + mesh->weightsCount += bonesCount * 3; + i += 1 + bonesCount * 4; } mesh->bones = MALLOC(int, mesh->bonesCount); mesh->weights = MALLOC(float, mesh->weightsCount); for (i = 0, b = 0, w = 0; i < verticesCount;) { - int boneCount = (int)vertices[i++]; - mesh->bones[b++] = boneCount; - for (nn = i + boneCount * 4; i < nn; i += 4, ++b, w += 3) { + int bonesCount = (int)vertices[i++]; + mesh->bones[b++] = bonesCount; + for (nn = i + bonesCount * 4; i < nn; i += 4, ++b, w += 3) { mesh->bones[b] = (int)vertices[i]; mesh->weights[w] = vertices[i + 1] * self->scale; mesh->weights[w + 1] = vertices[i + 2] * self->scale; @@ -670,14 +742,15 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha if (events) { Json *eventMap; const char* stringValue; + skeletonData->eventsCount = events->size; skeletonData->events = MALLOC(spEventData*, events->size); - for (eventMap = events->child; eventMap; eventMap = eventMap->next) { + for (eventMap = events->child, i = 0; eventMap; eventMap = eventMap->next, ++i) { spEventData* eventData = spEventData_create(eventMap->name); eventData->intValue = Json_getInt(eventMap, "int", 0); eventData->floatValue = Json_getFloat(eventMap, "float", 0); stringValue = Json_getString(eventMap, "string", 0); if (stringValue) MALLOC_STR(eventData->stringValue, stringValue); - skeletonData->events[skeletonData->eventCount++] = eventData; + skeletonData->events[i] = eventData; } } diff --git a/spine-c/src/spine/SkinnedMeshAttachment.c b/spine-c/src/spine/SkinnedMeshAttachment.c index 0d162fc13..1697d7948 100644 --- a/spine-c/src/spine/SkinnedMeshAttachment.c +++ b/spine-c/src/spine/SkinnedMeshAttachment.c @@ -72,10 +72,10 @@ void spSkinnedMeshAttachment_updateUVs (spSkinnedMeshAttachment* self) { } } -void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self, float x, float y, spSlot* slot, - float* worldVertices) { +void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self, spSlot* slot, float* worldVertices) { int w = 0, v = 0, b = 0, f = 0; - spBone** skeletonBones = slot->skeleton->bones; + float x = slot->bone->skeleton->x, y = slot->bone->skeleton->y; + spBone** skeletonBones = slot->bone->skeleton->bones; if (slot->attachmentVerticesCount == 0) { for (; v < self->bonesCount; w += 2) { float wx = 0, wy = 0; diff --git a/spine-c/src/spine/Slot.c b/spine-c/src/spine/Slot.c index 32c0dd530..bab8b5b43 100644 --- a/spine-c/src/spine/Slot.c +++ b/spine-c/src/spine/Slot.c @@ -30,17 +30,15 @@ #include #include -#include typedef struct { spSlot super; float attachmentTime; } _spSlot; -spSlot* spSlot_create (spSlotData* data, spSkeleton* skeleton, spBone* bone) { +spSlot* spSlot_create (spSlotData* data, spBone* bone) { spSlot* self = SUPER(NEW(_spSlot)); CONST_CAST(spSlotData*, self->data) = data; - CONST_CAST(spSkeleton*, self->skeleton) = skeleton; CONST_CAST(spBone*, self->bone) = bone; spSlot_setToSetupPose(self); return self; @@ -53,15 +51,15 @@ void spSlot_dispose (spSlot* self) { void spSlot_setAttachment (spSlot* self, spAttachment* attachment) { CONST_CAST(spAttachment*, self->attachment) = attachment; - SUB_CAST(_spSlot, self) ->attachmentTime = self->skeleton->time; + SUB_CAST(_spSlot, self) ->attachmentTime = self->bone->skeleton->time; } void spSlot_setAttachmentTime (spSlot* self, float time) { - SUB_CAST(_spSlot, self) ->attachmentTime = self->skeleton->time - time; + SUB_CAST(_spSlot, self) ->attachmentTime = self->bone->skeleton->time - time; } float spSlot_getAttachmentTime (const spSlot* self) { - return self->skeleton->time - SUB_CAST(_spSlot, self) ->attachmentTime; + return self->bone->skeleton->time - SUB_CAST(_spSlot, self) ->attachmentTime; } void spSlot_setToSetupPose (spSlot* self) { @@ -74,9 +72,9 @@ void spSlot_setToSetupPose (spSlot* self) { if (self->data->attachmentName) { /* Find slot index. */ int i; - for (i = 0; i < self->skeleton->data->slotCount; ++i) { - if (self->data == self->skeleton->data->slots[i]) { - attachment = spSkeleton_getAttachmentForSlotIndex(self->skeleton, i, self->data->attachmentName); + for (i = 0; i < self->bone->skeleton->data->slotsCount; ++i) { + if (self->data == self->bone->skeleton->data->slots[i]) { + attachment = spSkeleton_getAttachmentForSlotIndex(self->bone->skeleton, i, self->data->attachmentName); break; } } diff --git a/spine-sfml/data/raptor.atlas b/spine-sfml/data/raptor.atlas new file mode 100644 index 000000000..560d3d48c --- /dev/null +++ b/spine-sfml/data/raptor.atlas @@ -0,0 +1,251 @@ + +raptor.png +size: 1022,1022 +format: RGBA8888 +filter: Linear,Linear +repeat: none +images/back_arm + rotate: false + xy: 410, 545 + size: 46, 29 + orig: 46, 29 + offset: 0, 0 + index: -1 +images/back_bracer + rotate: false + xy: 540, 548 + size: 39, 28 + orig: 39, 28 + offset: 0, 0 + index: -1 +images/back_hand + rotate: true + xy: 504, 538 + size: 36, 34 + orig: 36, 34 + offset: 0, 0 + index: -1 +images/back_knee + rotate: false + xy: 299, 478 + size: 49, 67 + orig: 49, 67 + offset: 0, 0 + index: -1 +images/back_thigh + rotate: true + xy: 140, 247 + size: 39, 24 + orig: 39, 24 + offset: 0, 0 + index: -1 +images/eyes_open + rotate: true + xy: 2, 2 + size: 47, 45 + orig: 47, 45 + offset: 0, 0 + index: -1 +images/front_arm + rotate: false + xy: 360, 544 + size: 48, 30 + orig: 48, 30 + offset: 0, 0 + index: -1 +images/front_bracer + rotate: false + xy: 538, 578 + size: 41, 29 + orig: 41, 29 + offset: 0, 0 + index: -1 +images/front_hand + rotate: false + xy: 538, 609 + size: 41, 38 + orig: 41, 38 + offset: 0, 0 + index: -1 +images/front_open_hand + rotate: false + xy: 894, 782 + size: 43, 44 + orig: 43, 44 + offset: 0, 0 + index: -1 +images/front_thigh + rotate: false + xy: 942, 849 + size: 57, 29 + orig: 57, 29 + offset: 0, 0 + index: -1 +images/gun + rotate: false + xy: 785, 774 + size: 107, 103 + orig: 107, 103 + offset: 0, 0 + index: -1 +images/gun_nohand + rotate: false + xy: 614, 703 + size: 105, 102 + orig: 105, 102 + offset: 0, 0 + index: -1 +images/head + rotate: false + xy: 2, 137 + size: 136, 149 + orig: 136, 149 + offset: 0, 0 + index: -1 +images/lower_leg + rotate: true + xy: 780, 699 + size: 73, 98 + orig: 73, 98 + offset: 0, 0 + index: -1 +images/mouth_smile + rotate: true + xy: 49, 2 + size: 47, 30 + orig: 47, 30 + offset: 0, 0 + index: -1 +images/neck + rotate: true + xy: 1001, 860 + size: 18, 21 + orig: 18, 21 + offset: 0, 0 + index: -1 +images/raptor_arm_back + rotate: false + xy: 940, 936 + size: 82, 86 + orig: 82, 86 + offset: 0, 0 + index: -1 +images/raptor_body + rotate: false + xy: 2, 737 + size: 610, 285 + orig: 610, 285 + offset: 0, 0 + index: -1 +images/raptor_front_arm + rotate: true + xy: 195, 464 + size: 81, 102 + orig: 81, 102 + offset: 0, 0 + index: -1 +images/raptor_front_leg + rotate: false + xy: 2, 478 + size: 191, 257 + orig: 191, 257 + offset: 0, 0 + index: -1 +images/raptor_hindleg_back + rotate: false + xy: 614, 807 + size: 169, 215 + orig: 169, 215 + offset: 0, 0 + index: -1 +images/raptor_horn + rotate: false + xy: 360, 655 + size: 182, 80 + orig: 182, 80 + offset: 0, 0 + index: -1 +images/raptor_horn_back + rotate: false + xy: 360, 576 + size: 176, 77 + orig: 176, 77 + offset: 0, 0 + index: -1 +images/raptor_jaw + rotate: false + xy: 785, 879 + size: 153, 143 + orig: 153, 143 + offset: 0, 0 + index: -1 +images/raptor_saddle_noshadow + rotate: false + xy: 2, 288 + size: 163, 188 + orig: 163, 188 + offset: 0, 0 + index: -1 +images/raptor_saddle_strap_front + rotate: false + xy: 721, 710 + size: 57, 95 + orig: 57, 95 + offset: 0, 0 + index: -1 +images/raptor_saddle_strap_rear + rotate: true + xy: 940, 880 + size: 54, 74 + orig: 54, 74 + offset: 0, 0 + index: -1 +images/raptor_saddle_w_shadow + rotate: false + xy: 195, 547 + size: 163, 188 + orig: 163, 188 + offset: 0, 0 + index: -1 +images/raptor_tongue + rotate: true + xy: 544, 649 + size: 86, 64 + orig: 86, 64 + offset: 0, 0 + index: -1 +images/stirrup_back + rotate: false + xy: 458, 539 + size: 44, 35 + orig: 44, 35 + offset: 0, 0 + index: -1 +images/stirrup_front + rotate: true + xy: 81, 4 + size: 45, 50 + orig: 45, 50 + offset: 0, 0 + index: -1 +images/stirrup_strap + rotate: true + xy: 894, 828 + size: 49, 46 + orig: 49, 46 + offset: 0, 0 + index: -1 +images/torso + rotate: true + xy: 610, 647 + size: 54, 91 + orig: 54, 91 + offset: 0, 0 + index: -1 +images/visor + rotate: false + xy: 2, 51 + size: 131, 84 + orig: 131, 84 + offset: 0, 0 + index: -1 diff --git a/spine-sfml/data/raptor.json b/spine-sfml/data/raptor.json new file mode 100644 index 000000000..37324b094 --- /dev/null +++ b/spine-sfml/data/raptor.json @@ -0,0 +1 @@ +{"skeleton":{"spine":"Dev","hash":"gpnuCmS4cM+VWprF3iClFQcYxeQ","width":1243.46,"height":1062.38},"bones":[{"name":"root"},{"name":"front_foot_goal","parent":"root","x":-45.79,"y":-28.67,"rotation":-0.94,"color":"ff0000ff"},{"name":"hip","parent":"root","x":-136.78,"y":415.47,"rotation":3.15,"color":"fbff00ff"},{"name":"rear_foot_goal","parent":"root","x":33.43,"y":30.81,"color":"ff0000ff"},{"name":"front_leg1","parent":"hip","length":251.74,"x":27.36,"y":-28.27,"rotation":-51.5,"color":"15ff00ff"},{"name":"front_leg_goal","parent":"front_foot_goal","x":-106.06,"y":115.58,"color":"ff0000ff"},{"name":"rear_leg1","parent":"hip","length":226.27,"x":55.19,"y":-71.25,"rotation":-54.76,"color":"e07800ff"},{"name":"rear_leg_goal","parent":"rear_foot_goal","x":-127.51,"y":75.99,"color":"ff0000ff"},{"name":"tail1","parent":"hip","length":162.53,"x":-20.86,"y":6.87,"rotation":162.92,"color":"eaff00ff"},{"name":"torso1","parent":"hip","length":126.25,"x":30.03,"y":-0.4,"rotation":-4.97,"color":"eaff00ff"},{"name":"front_leg2","parent":"front_leg1","length":208.54,"x":251.03,"y":0.16,"rotation":261.93,"color":"15ff00ff"},{"name":"rear_leg2","parent":"rear_leg1","length":172.58,"x":226.32,"y":0.23,"rotation":-92.25,"color":"e07800ff"},{"name":"saddle","parent":"torso1","length":50.91,"x":4.56,"y":71.86,"rotation":91.8,"color":"ff7300ff"},{"name":"tail2","parent":"tail1","length":130.02,"x":162.53,"y":-0.82,"rotation":30.3,"color":"eaff00ff"},{"name":"torso2","parent":"torso1","length":121.2,"x":126.25,"y":-0.37,"rotation":39.84,"color":"eaff00ff"},{"name":"front_arm1","parent":"torso2","length":109.99,"x":46.37,"y":-84.61,"rotation":224.54,"color":"15ff00ff"},{"name":"front_leg3","parent":"front_leg2","length":118.18,"x":208.5,"y":-1.63,"rotation":85.46,"color":"15ff00ff"},{"name":"neck","parent":"torso2","length":70.59,"x":121.19,"y":0.34,"rotation":41.37,"color":"eaff00ff"},{"name":"rear_arm1","parent":"torso2","length":109.56,"x":57.05,"y":-95.38,"rotation":-124.71,"color":"e07800ff"},{"name":"rear_leg3","parent":"rear_leg2","length":103.05,"x":172.31,"y":2.21,"rotation":82.81,"color":"e07800ff"},{"name":"saddle_strap_front1","parent":"saddle","length":97.27,"x":-27.36,"y":-73.38,"rotation":-148.11,"color":"ff7300ff"},{"name":"saddle_strap_rear1","parent":"saddle","length":38.62,"x":-33.34,"y":87.32,"rotation":151.13,"color":"ff7300ff"},{"name":"spineboy_front_arm_goal","parent":"saddle","x":-50.7,"y":-96.93,"color":"ff0004ff"},{"name":"spineboy_hip","parent":"saddle","length":0.52,"x":81.88,"y":2.68,"rotation":90.01,"color":"ffffffff"},{"name":"spineboy_rear_arm_goal","parent":"saddle","x":-30.43,"y":-100.08,"color":"ff0001ff"},{"name":"stirrup","parent":"saddle","length":78.17,"x":-81.94,"y":-103.38,"rotation":-68.85,"color":"ff7300ff"},{"name":"stirrup_strap1","parent":"saddle","length":43.69,"x":-20.38,"y":-29.37,"rotation":-135,"color":"ff7300ff"},{"name":"tail3","parent":"tail2","length":141.06,"x":130.02,"y":0.1,"rotation":6.88,"color":"eaff00ff"},{"name":"back_thigh","parent":"spineboy_hip","length":71.15,"x":-9.57,"y":2.31,"rotation":160.75,"color":"ffffffff"},{"name":"front_arm2","parent":"front_arm1","length":86.33,"x":109.99,"y":0.2,"rotation":105.23,"color":"15ff00ff"},{"name":"front_foot1","parent":"front_leg3","length":57.79,"x":118.19,"y":-0.79,"scaleX":1.126,"rotation":54.46,"color":"15ff00ff"},{"name":"front_thigh","parent":"spineboy_hip","length":77.79,"x":15.51,"y":17.01,"rotation":163.34,"color":"ffffffff"},{"name":"gun","parent":"spineboy_hip","length":181.35,"x":16.86,"y":-7.89,"scaleX":0.816,"scaleY":0.816,"rotation":107.11,"color":"ffffffff"},{"name":"head","parent":"neck","length":105.5,"x":70.59,"y":0.03,"rotation":9.82,"color":"eaff00ff"},{"name":"rear_arm2","parent":"rear_arm1","length":85.8,"x":109.56,"rotation":123.56,"color":"e07800ff"},{"name":"rear_foot1","parent":"rear_leg3","length":84.51,"x":102.37,"y":-0.02,"rotation":75.43,"color":"e07800ff"},{"name":"saddle_strap_front2","parent":"saddle_strap_front1","length":102.74,"x":97.29,"y":0.3,"rotation":-11.13,"color":"ff7300ff"},{"name":"saddle_strap_rear2","parent":"saddle_strap_rear1","length":54.36,"x":38.63,"y":-0.02,"color":"ff7300ff"},{"name":"spineboy_torso","parent":"spineboy_hip","length":122.45,"x":1.05,"y":-2.1,"rotation":-75.85,"color":"ffffffff"},{"name":"stirrup_strap2","parent":"stirrup_strap1","length":51.62,"x":43.7,"rotation":9.38,"color":"ff7300ff"},{"name":"tail4","parent":"tail3","length":126.25,"x":141.05,"y":0.64,"rotation":-18.86,"color":"eaff00ff"},{"name":"back_arm","parent":"spineboy_torso","length":67.21,"x":96.33,"y":-38.46,"rotation":-120.89,"color":"ffffffff"},{"name":"back_knee","parent":"back_thigh","length":97.17,"x":71.15,"y":-0.28,"rotation":-54.97,"color":"ffffffff"},{"name":"front_arm","parent":"spineboy_torso","length":74.51,"x":101.37,"y":9.78,"rotation":-118.16,"color":"ffffffff"},{"name":"front_foot2","parent":"front_foot1","length":56.19,"x":57.78,"y":-0.02,"scaleX":0.73,"scaleY":0.823,"rotation":-0.46,"inheritRotation":false,"color":"15ff00ff"},{"name":"front_hand","parent":"front_arm2","length":47.55,"x":86.33,"y":0.06,"rotation":-56.83,"color":"15ff00ff"},{"name":"horn_front","parent":"head","length":87.48,"x":82.09,"y":-221.36,"rotation":49.36,"color":"15ff00ff"},{"name":"horn_rear","parent":"head","length":73.78,"x":99.27,"y":-226.79,"rotation":44.31,"color":"e07800ff"},{"name":"jaw","parent":"head","length":203.76,"x":29.36,"y":-40.15,"rotation":-140.14,"inheritScale":false,"color":"ffff00ff"},{"name":"lower_leg","parent":"front_thigh","length":111.5,"x":77.92,"y":-0.1,"rotation":-49.62,"color":"ffffffff"},{"name":"neck2","parent":"spineboy_torso","length":32.04,"x":113.44,"y":-15.21,"rotation":-45.22,"color":"ffffffff"},{"name":"rear_foot2","parent":"rear_foot1","length":102.31,"x":84.49,"y":-0.34,"rotation":-6.13,"inheritRotation":false,"color":"e07800ff"},{"name":"rear_hand","parent":"rear_arm2","length":45.8,"x":85.8,"y":0.1,"rotation":-76.28,"color":"e07800ff"},{"name":"saddle_strap_rear3","parent":"saddle_strap_rear2","length":44.04,"x":54.86,"y":0.19,"rotation":3.63,"color":"ff7300ff"},{"name":"tail5","parent":"tail4","length":91.06,"x":126.25,"y":-0.47,"rotation":-22.34,"color":"eaff00ff"},{"name":"tongue1","parent":"head","length":55.11,"x":20.81,"y":-104.75,"rotation":-129.04,"color":"ffff00ff"},{"name":"back_bracer","parent":"back_arm","length":43.68,"x":67.21,"y":-0.31,"rotation":17.48,"color":"ffffffff"},{"name":"bone","parent":"horn_front","x":294.58,"y":234.17,"rotation":-138.59,"color":"15ff00ff"},{"name":"bone2","parent":"horn_rear","x":232.68,"y":245.84,"rotation":-133.55,"color":"e07800ff"},{"name":"front_bracer","parent":"front_arm","length":39.85,"x":74.52,"y":-0.41,"rotation":20.3,"color":"ffffffff"},{"name":"front_foot3","parent":"front_foot2","length":129.88,"x":49.71,"y":20.65,"scaleX":1.154,"rotation":-3.16,"inheritRotation":false,"color":"15ff00ff"},{"name":"head2","parent":"neck2","length":249.64,"x":23.01,"y":3.47,"rotation":11.65,"color":"ffffffff"},{"name":"tongue2","parent":"tongue1","length":44.66,"x":55.59,"y":0.93,"rotation":8.93,"color":"fff200ff"},{"name":"back_hand","parent":"back_bracer","length":41.97,"x":43.68,"y":0.06,"rotation":9.2,"inheritRotation":false,"color":"ffffffff"},{"name":"front_hand2","parent":"front_bracer","length":58.18,"x":39.98,"y":-0.89,"rotation":13.9,"inheritRotation":false,"color":"ffffffff"},{"name":"tongue3","parent":"tongue2","length":43.64,"x":44.26,"y":-0.2,"rotation":12.86,"color":"fff200ff"}],"ik":[{"name":"front_leg_goal","bones":["front_leg1","front_leg2"],"target":"front_leg_goal","bendPositive":false},{"name":"rear_leg_goal","bones":["rear_leg1","rear_leg2"],"target":"rear_leg_goal","bendPositive":false},{"name":"front_foot_goal","bones":["front_leg3","front_foot1"],"target":"front_foot_goal"},{"name":"rear_foot_goal","bones":["rear_leg3","rear_foot1"],"target":"rear_foot_goal"},{"name":"stirrup","bones":["stirrup_strap1","stirrup_strap2"],"target":"stirrup"},{"name":"spineboy_rear_leg_goal","bones":["back_thigh","back_knee"],"target":"spineboy_rear_arm_goal","bendPositive":false},{"name":"spineboy_front_leg_goal","bones":["front_thigh","lower_leg"],"target":"spineboy_front_arm_goal","bendPositive":false},{"name":"rear_arm_goal","bones":["back_arm","back_bracer"],"target":"bone2"},{"name":"front_arm_goal","bones":["front_arm","front_bracer"],"target":"bone"}],"slots":[{"name":"back_hand","bone":"back_hand","attachment":"images/back_hand"},{"name":"back_arm","bone":"back_arm","attachment":"images/back_arm"},{"name":"back_bracer","bone":"back_bracer","attachment":"images/back_bracer"},{"name":"back_knee","bone":"back_knee","attachment":"images/back_knee"},{"name":"raptor_horn_back","bone":"horn_rear","attachment":"images/raptor_horn_back"},{"name":"raptor_tongue","bone":"root","attachment":"images/raptor_tongue"},{"name":"raptor_hindleg_back","bone":"rear_leg1","attachment":"images/raptor_hindleg_back"},{"name":"raptor_arm_back","bone":"root","attachment":"images/raptor_arm_back"},{"name":"raptor_body","bone":"torso1","attachment":"images/raptor_body"},{"name":"back_thigh","bone":"back_thigh","attachment":"images/back_thigh"},{"name":"raptor_saddle_strap_front","bone":"saddle_strap_front1","attachment":"images/raptor_saddle_strap_front"},{"name":"raptor_saddle_strap_rear","bone":"saddle_strap_rear1","attachment":"images/raptor_saddle_strap_rear"},{"name":"raptor_saddle_w_shadow","bone":"saddle","attachment":"images/raptor_saddle_w_shadow"},{"name":"raptor_saddle_noshadow","bone":"saddle"},{"name":"raptor_front_arm","bone":"root","attachment":"images/raptor_front_arm"},{"name":"raptor_front_leg","bone":"front_leg1","attachment":"images/raptor_front_leg"},{"name":"raptor_jaw","bone":"jaw","attachment":"images/raptor_jaw"},{"name":"neck","bone":"neck2","attachment":"images/neck"},{"name":"spineboy_torso","bone":"spineboy_torso","attachment":"images/torso"},{"name":"head","bone":"head2","attachment":"images/head"},{"name":"eyes_open","bone":"head2","attachment":"images/eyes_open"},{"name":"mouth_smile","bone":"head2","attachment":"images/mouth_smile"},{"name":"visor","bone":"head2","attachment":"images/visor"},{"name":"raptor_horn","bone":"horn_front","attachment":"images/raptor_horn"},{"name":"front_thigh","bone":"front_thigh","attachment":"images/front_thigh"},{"name":"stirrup_back","bone":"stirrup","attachment":"images/stirrup_back"},{"name":"lower_leg","bone":"lower_leg","attachment":"images/lower_leg"},{"name":"stirrup_strap","bone":"stirrup","attachment":"images/stirrup_strap"},{"name":"stirrup_front","bone":"stirrup","attachment":"images/stirrup_front"},{"name":"gun","bone":"gun","attachment":"images/gun_nohand"},{"name":"front_arm","bone":"front_arm","attachment":"images/front_arm"},{"name":"front_bracer","bone":"front_bracer","attachment":"images/front_bracer"},{"name":"front_hand","bone":"front_hand2","attachment":"images/front_hand"}],"skins":{"default":{"back_arm":{"images/back_arm":{"x":29.71,"y":2.04,"rotation":16.75,"width":91,"height":57}},"back_bracer":{"images/back_bracer":{"x":13.19,"y":-4.28,"rotation":-0.72,"width":77,"height":55}},"back_hand":{"images/back_hand":{"x":18.6,"y":4.23,"rotation":-10.99,"width":72,"height":68}},"back_knee":{"images/back_knee":{"x":45.77,"y":20.47,"rotation":74.22,"width":97,"height":134}},"back_thigh":{"images/back_thigh":{"x":37.85,"y":-4.36,"rotation":19.24,"width":78,"height":47}},"eyes_open":{"images/eyes_open":{"x":93.23,"y":-25.45,"rotation":-70.57,"width":93,"height":89}},"front_arm":{"images/front_arm":{"x":31.38,"y":5.09,"rotation":14.02,"width":96,"height":60}},"front_bracer":{"images/front_bracer":{"x":11.68,"y":-1.36,"rotation":-6.28,"width":81,"height":58}},"front_hand":{"images/front_hand":{"x":35.7,"y":7.84,"rotation":-13.96,"width":82,"height":75},"images/front_open_hand":{"x":42.54,"y":4.62,"rotation":62.19,"width":86,"height":87},"images/gun":{"x":98.9,"y":22.97,"rotation":56.34,"width":213,"height":206}},"front_thigh":{"images/front_thigh":{"x":45.7,"y":-3.1,"rotation":16.65,"width":114,"height":58}},"gun":{"images/gun_nohand":{"type":"mesh","uvs":[0.71081,0.16149,0.85807,0.41784,1,0.6649,1,1,0.71457,1,0.49802,0.6905,0.30182,0.41009,0,0.58226,0,0.1174,0.27187,0.12429,0.24857,0,0.36658,0,0.61804,0,0.70575,0.53546,0.53668,0.26855],"triangles":[3,13,2,5,13,4,3,4,13,13,6,14,13,5,6,13,1,2,6,8,9,6,7,8,13,14,1,14,0,1,6,9,14,9,11,14,14,12,0,14,11,12,9,10,11],"vertices":[23.48,50.63,83.86,46.32,142.05,42.17,197.91,3.34,163.7,-45.86,86.15,-47.34,15.9,-48.68,8.42,-120.68,-69.06,-66.81,-35.32,-20.73,-58.83,-10.35,-44.69,9.99,-14.55,53.35,85.21,6.43,20.45,8.2],"hull":13,"edges":[14,12,6,8,6,4,14,16,16,18,18,20,20,22,22,24,8,10,10,12,6,26,10,26,4,2,26,2,22,28,28,26,12,28,2,0,0,24,28,0,18,12],"width":210,"height":203}},"head":{"images/head":{"x":132.33,"y":1.19,"rotation":-70.57,"width":271,"height":298}},"lower_leg":{"images/lower_leg":{"x":76.2,"y":22.2,"rotation":66.28,"width":146,"height":195}},"mouth_smile":{"images/mouth_smile":{"x":27.66,"y":-31.33,"rotation":-70.57,"width":93,"height":59}},"neck":{"images/neck":{"x":15.09,"y":-1.66,"rotation":-58.91,"width":36,"height":41}},"raptor_arm_back":{"images/raptor_arm_back":{"type":"skinnedmesh","uvs":[0.38711,0.29362,0.31382,0.46513,0.29242,0.51521,0.32475,0.4931,0.57587,0.32138,0.63254,0.28263,0.71632,0.34507,0.94948,0.51888,1,0.65257,1,0.90624,0.95462,0.99934,0.88957,0.83204,0.80294,0.99998,0.75236,0.75696,0.6654,0.713,0.62288,0.63242,0.58194,0.65031,0.22478,0.80641,0.07791,0.73315,0.07825,0.66549,0.07984,0.34306,0,0.29728,0,0,0.32334,0,0.94947,0.60129],"triangles":[15,16,4,12,13,11,10,11,9,11,8,9,11,24,8,11,13,24,13,14,24,24,14,7,24,7,8,6,7,14,5,15,4,5,6,15,6,14,15,17,3,16,17,2,3,17,18,2,16,3,4,18,19,2,2,19,1,1,19,20,1,20,0,0,20,23,23,20,22,20,21,22],"vertices":[2,18,36.95,33.31,0.91666,34,68.53,41.05,0.08333,2,18,66.02,20.35,0.76813,34,41.41,24.39,0.23186,2,18,74.51,16.57,0.64468,34,33.49,19.53,0.35531,3,18,70.89,21.97,0.27669,34,39.99,19.46,0.67508,52,-29.67,-39.91,0.04822,3,18,42.77,63.89,0.11483,34,90.47,18.95,0.60854,52,-17.2,9,0.27661,2,34,101.86,18.83,0.45955,52,-14.38,20.04,0.54044,2,34,106.47,2.08,0.0625,52,2.98,20.56,0.9375,1,52,51.32,21.98,1,1,52,72.39,9.61,1,1,52,100.37,-23.87,1,1,52,104.96,-40.9,1,1,52,78.37,-25.61,1,1,52,86.05,-56.84,1,1,52,52.92,-30.04,1,2,34,62.24,-43.92,0.0625,52,37.19,-33.33,0.9375,2,34,64.89,-28.65,0.3125,52,22.98,-27.14,0.6875,2,34,57.69,-27.17,0.30612,52,19.83,-33.78,0.69387,2,18,124.19,3.83,0.19395,34,-5.09,-14.23,0.80604,2,18,110.77,-19.65,0.3125,34,-16.88,10.1,0.6875,2,18,99.14,-19.2,0.51613,34,-9.93,19.44,0.48386,2,18,43.73,-17.03,0.9375,34,23.17,63.92,0.0625,1,18,35.41,-29.77,1,1,18,-15.68,-28.02,1,1,18,-13.87,24.65,1,1,52,60.41,11.1,1],"hull":24,"edges":[42,44,42,40,36,34,30,28,28,26,26,24,22,20,16,48,48,14,44,46,36,4,6,4,6,34,40,38,38,36,4,2,2,0,38,2,10,30,34,32,32,30,10,8,8,6,32,8,14,12,12,10,12,28,14,16,16,18,20,18,24,22,46,0],"width":163,"height":172}},"raptor_body":{"images/raptor_body":{"type":"skinnedmesh","uvs":[0.89014,0.11136,1,0.22194,1,0.42847,0.88179,0.38589,0.874,0.47986,0.84783,0.51728,0.82504,0.54984,0.82403,0.61606,0.82305,0.67972,0.74042,0.86709,0.61596,0.93097,0.49649,0.90968,0.41186,0.71379,0.36955,0.70086,0.32823,0.68824,0.27515,0.71028,0.25301,0.71948,0.22568,0.73082,0.19092,0.7164,0.15952,0.70337,0.1301,0.69116,0.09227,0.67546,0.06029,0.63165,0.02855,0.58817,0,0.49874,0.05045,0.53494,0.08267,0.54507,0.11815,0.55623,0.14733,0.54161,0.17913,0.52568,0.20324,0.5136,0.22867,0.50087,0.24871,0.47664,0.27523,0.44458,0.32026,0.39015,0.37517,0.35747,0.43476,0.32201,0.4893,0.35534,0.56021,0.39867,0.61587,0.40674,0.67769,0.4157,0.69094,0.31314,0.69362,0.14742,0.79219,0.08354,0.51541,0.74573,0.62393,0.75425,0.70856,0.7287,0.76132,0.63288,0.7566,0.49454,0.80613,0.27517,0.65885,0.59037,0.53929,0.54937,0.42632,0.52207,0.3246,0.55241,0.22715,0.618,0.10574,0.61341,0.03969,0.56109,0.77916,0.39461,0.37556,0.53721,0.27743,0.58416,0.16958,0.61582,0.07259,0.58715,0.87545,0.31683,0.85488,0.21417,0.81012,0.17403,0.83214,0.25662,0.83823,0.32214,0.84622,0.41719,0.59954,0.57003,0.49074,0.53763,0.76917,0.43888,0.75912,0.56845,0.871,0.3701,0.85431,0.43545,0.89558,0.32412,0.90105,0.22877,0.91523,0.20564,0.93086,0.219,0.93446,0.25858,0.91956,0.2776,0.9061,0.26423,0.9415,0.25929,0.93589,0.21545,0.91669,0.19192,0.89297,0.22201,0.90245,0.28513,0.92006,0.281,0.92143,0.29619,0.94856,0.2643,0.19894,0.61694,0.13973,0.61469,0.25158,0.60156],"triangles":[12,58,52,12,69,44,44,68,45,11,12,44,45,11,44,10,11,45,56,24,25,26,56,25,61,26,27,61,56,26,23,24,56,23,56,61,55,61,27,22,23,61,22,61,55,21,22,55,90,27,28,55,27,90,60,28,29,90,28,60,89,60,29,90,21,55,20,21,90,60,20,90,19,20,60,19,60,89,33,59,32,32,91,31,30,31,54,32,59,91,89,29,30,89,30,54,31,91,54,15,91,59,18,19,89,16,54,91,54,18,89,18,54,17,91,15,16,16,17,54,58,34,35,34,53,33,35,52,58,34,58,53,13,14,53,59,53,14,58,13,53,13,58,12,33,53,59,14,15,59,36,37,52,36,52,35,69,52,37,38,69,37,51,69,38,51,38,39,12,52,69,44,69,51,64,43,0,49,42,43,1,82,83,63,64,0,63,0,84,0,83,84,83,0,1,76,83,82,76,84,83,75,84,76,75,76,77,65,64,63,81,78,77,82,81,77,75,77,78,82,88,81,80,75,78,1,88,82,64,49,43,49,64,65,79,80,78,80,84,75,85,80,79,85,84,80,88,87,86,88,86,81,85,86,87,41,42,49,84,62,63,63,62,65,84,74,62,66,65,62,49,65,66,85,74,84,74,85,87,72,66,62,72,62,74,3,72,74,57,41,49,57,49,66,67,57,66,72,67,66,73,67,72,88,1,2,87,88,2,74,87,2,3,74,2,3,73,72,4,73,3,73,57,67,4,57,73,4,5,70,57,4,70,57,40,41,70,40,57,48,40,70,5,48,70,6,48,5,71,48,6,50,68,40,48,50,40,71,50,48,7,71,6,47,71,7,50,71,47,8,47,7,46,50,47,46,47,8,45,50,46,68,51,39,68,39,40,44,51,68,45,68,50,9,46,8,45,46,9,10,45,9],"vertices":[1,33,147.48,-145.48,1,1,33,89.4,-281.62,1,1,33,-28.24,-285.93,1,1,33,-14.58,-194.68,1,5,9,363.21,87.73,0.02179,14,238.39,-84.13,0.20397,17,32.1,-140.85,0.18915,33,-61.96,-132.26,0.41197,48,129.57,6.39,0.1731,5,9,332.7,63.71,0.06905,14,199.57,-83.03,0.29424,17,3.69,-114.37,0.2194,33,-85.43,-101.32,0.30859,48,127.34,-26.64,0.1087,5,9,307.08,43.5,0.11018,14,166.95,-82.13,0.37282,17,-20.18,-92.14,0.24572,33,-105.18,-75.34,0.21862,48,123.08,-64.79,0.05264,5,9,307.75,5.7,0.18146,14,143.25,-111.59,0.56512,17,-57.43,-98.57,0.12044,33,-142.98,-75.33,0.10715,48,154.85,-83.49,0.0258,2,9,308.7,-30.55,0.25,14,120.75,-140.04,0.75,2,9,213.94,-142.7,0.75,14,-23.83,-165.45,0.25,3,9,64.45,-187.34,0.31139,8,-158.45,158.33,0.10379,2,84.16,-190.98,0.5848,1,2,-61.47,-178.84,1,1,2,-166.91,-67.95,1,6,9,-246.26,-74,0.04136,8,170.4,123.13,0.2858,13,66.71,104.77,0.57052,27,-53.08,110.21,0.10163,40,-220.11,35.3,5.1E-4,54,-331.4,-106.89,1.5E-4,6,9,-297.45,-69.74,0.01855,8,221.11,131.31,0.14592,13,115.07,87.47,0.47026,27,-6.58,88.39,0.30085,40,-168.92,31,0.06162,54,-282.82,-90.19,0.00276,6,9,-359.24,-85.1,0.00915,8,277.38,161.09,0.07914,13,178.73,86.41,0.35008,27,56.68,81.29,0.38638,40,-107.13,46.31,0.15555,54,-232.44,-51.26,0.01966,6,9,-376.16,-107.83,0.0043,8,294.31,176.47,0.03904,13,203.26,86.51,0.25323,27,83.06,77.02,0.42283,40,-79.56,53.53,0.23684,54,-210.89,-28.3,0.04374,6,9,-416.83,-99.41,0.00211,8,329.83,188.85,0.0196,13,238.06,85.41,0.18217,27,115.65,74.66,0.41374,40,-49.53,60.58,0.30031,54,-185.49,-14.98,0.08205,6,9,-449.42,-116.23,0.00122,8,364.17,200.07,0.01106,13,275.48,71.62,0.13243,27,152.97,53.58,0.37336,40,-5.82,53.94,0.34144,54,-142.85,0.11,0.14047,6,9,-498.22,-88.19,7.8E-4,8,411.52,197.55,0.00669,13,313.81,53.61,0.09623,27,188.04,35.82,0.32105,40,31.84,49.3,0.36432,54,-106.46,7.49,0.21089,6,9,-524.31,-113.4,5.8E-4,8,437.98,213.03,0.00423,13,345.74,45.54,0.06864,27,219.6,19.28,0.26387,40,68.31,43.02,0.36996,54,-70.13,18.19,0.2927,6,9,-580.94,-76.79,4.7E-4,8,494.56,206.4,0.00237,13,390.81,21.3,0.0452,27,261.62,-3.66,0.20066,40,114.55,37.83,0.35931,54,-26.15,30.34,0.39196,6,9,-621.23,-53.98,4.4E-4,8,539.16,193.96,0.00115,13,423.87,-11.11,0.02629,27,291.46,-39.06,0.13478,40,154.83,14.99,0.33453,54,19.91,25.67,0.50278,6,9,-661.22,-31.34,4.6E-4,8,583.41,181.62,5.6E-4,13,456.68,-43.27,0.01512,27,321.06,-74.2,0.08778,40,194.79,-7.66,0.31014,54,65.62,21.04,0.58591,6,9,-698.76,17.64,4.7E-4,8,631.64,143.1,4.0E-4,13,480.34,-100.28,0.01183,27,339.2,-133.2,0.07247,40,232.3,-56.69,0.30126,54,119.7,-8.69,0.61353,6,9,-636.21,0.4,4.5E-4,8,566.79,144.78,5.5E-4,13,424.34,-67.52,0.01513,27,286.57,-95.27,0.08778,40,169.77,-39.4,0.31045,54,55.51,-18.08,0.5856,6,9,-596.68,-3.21,4.2E-4,8,527.55,138.78,0.00111,13,387.08,-53.84,0.02607,27,250.77,-78.11,0.13421,40,130.24,-35.75,0.33502,54,17.87,-30.67,0.50314,6,9,-553.14,-7.2,4.2E-4,8,484.33,132.17,0.00229,13,346.04,-38.78,0.04477,27,211.34,-59.22,0.19954,40,86.7,-31.72,0.3598,54,-23.59,-44.54,0.39316,6,9,-516.96,-25.93,4.7E-4,8,449.17,125.97,0.00408,13,311.45,-35.25,0.06808,27,175.89,-56.83,0.26228,40,51.53,-43.14,0.37032,54,-52.88,-67.87,0.29473,6,9,-479.88,14.24,6.0E-4,8,418.38,93.72,0.00651,13,269.72,-40.64,0.09608,27,135.19,-53.82,0.32015,40,13.42,-53.11,0.36453,54,-82.03,-93.66,0.21211,6,9,-451.64,0.32,8.3E-4,8,390.82,86.58,0.01046,13,241.19,-39.8,0.13162,27,105.59,-52.93,0.37317,40,-16.25,-62.16,0.34265,54,-108.34,-111.24,0.14123,6,9,-420.35,31.66,0.00137,8,364.8,62.48,0.01849,13,207.71,-42.14,0.18078,27,73.33,-49.43,0.41415,40,-46.11,-70.49,0.30264,54,-129.51,-133.56,0.08254,6,9,-399.11,28.98,0.00258,8,345.49,47.53,0.03705,13,182.34,-50.62,0.25183,27,45.87,-56.62,0.4234,40,-71.57,-84.96,0.24035,54,-150.85,-153.35,0.04477,6,9,-365.43,66.79,0.00485,8,319.95,15.15,0.07594,13,145.6,-61.95,0.35325,27,9.61,-63.26,0.38742,40,-101.06,-105.58,0.15807,54,-165.65,-187.83,0.02044,6,9,-312.31,100.78,0.00731,8,276.58,-30.61,0.13928,13,85.52,-81.11,0.48508,27,-52.01,-76.62,0.30338,40,-154.2,-139.52,0.06214,54,-200.6,-240.31,0.00279,6,9,-242.48,124.41,0.00974,8,214.5,-70.36,0.27055,13,11.97,-85.98,0.61489,27,-125.69,-74.48,0.10409,40,-224.04,-163.1,5.4E-4,54,-255.01,-290.05,1.5E-4,6,9,-166.71,150.07,0.02469,8,147.14,-113.5,0.57033,13,-67.84,-91.26,0.38714,27,-205.65,-72.16,0.01755,40,-299.83,-188.7,2.0E-4,54,-314.05,-344.03,5.0E-5,2,9,-113.14,135.84,0.24192,8,91.72,-112.59,0.75807,2,9,-42.12,116.77,0.14515,8,18.2,-111.17,0.85484,1,9,44.2,107.1,1,2,9,140.09,96.35,0.22579,14,72.59,65.41,0.7742,4,9,137.69,169.35,0.05644,14,117.5,123,0.24355,17,78.3,94.48,0.2125,33,23.7,91.74,0.4875,2,17,171.15,111.98,0.25,33,118.17,93.15,0.75,1,33,158.96,-25.58,1,1,2,-40.63,-86.01,1,3,9,67.34,-86.66,0.33215,8,-137.02,59.92,0.08303,2,92.54,-90.61,0.5848,2,9,170.13,-66.29,0.75,14,-8.53,-78.72,0.25,2,9,231.74,-8.12,0.4,14,76.03,-73.52,0.6,5,9,222.04,70.41,0.16894,14,118.9,-7,0.5373,17,-6.58,-3.99,0.17075,33,-76.73,9.18,0.08551,48,45.05,-108.02,0.03748,1,33,50.43,-46.56,1,1,14,-9.88,20.65,1,2,9,-53.22,20.53,0.2,8,5.8,-15.09,0.8,6,9,-180.71,32.22,0.0849,8,132.35,4.24,0.55723,13,-23.98,19.01,0.34911,27,-151.51,33.44,0.0085,40,-285.75,-70.86,1.8E-4,54,-348.66,-230.51,5.0E-5,6,9,-304.22,7.95,0.01243,8,246.39,57.53,0.13635,13,101.61,10.65,0.48532,27,-27.28,13.2,0.30559,40,-162.22,-46.69,0.05823,54,-245.36,-158.59,0.00205,6,9,-418.56,-35.1,0.00168,8,346.99,126.85,0.01839,13,223.17,22.83,0.18014,27,94.88,13.77,0.41602,40,-47.85,-3.72,0.30281,54,-158.02,-73.16,0.08093,6,9,-566.47,-40.57,4.4E-4,8,489.24,167.77,0.00225,13,367.51,-9.96,0.04446,27,235.45,-32.57,0.20024,40,100.06,1.62,0.36103,54,-24.81,-8.63,0.39156,6,9,-648.5,-15.19,4.5E-4,8,574.96,162.88,5.5E-4,13,440.24,-55.6,0.01566,27,303.52,-84.91,0.09149,40,182.07,-23.8,0.3135,54,60.48,1.14,0.57832,3,14,174.99,22.22,0.2,17,54.82,-19.14,0.6,33,-18.8,-16.2,0.2,6,9,-242.34,20.11,0.02478,8,189.25,30.83,0.26443,13,38.68,14.84,0.61556,27,-89.52,23.34,0.09454,40,-224.1,-58.8,5.1E-4,54,-297.11,-194.62,1.4E-4,6,9,-359.57,-12.88,0.00674,8,295.08,91.08,0.07453,13,160.45,16.54,0.35139,27,31.85,13.48,0.39116,40,-106.86,-25.89,0.15674,54,-203.08,-117.24,0.01941,6,9,-488.69,-37.69,6.7E-4,8,414.43,146.25,0.00642,13,291.61,7.27,0.09534,27,161.53,-8.2,0.32068,40,22.27,-1.18,0.36568,54,-94.86,-42.56,0.21117,6,9,-607.64,-27.83,4.3E-4,8,532.26,165.32,0.00108,13,404.01,-32.87,0.02584,27,269.61,-58.84,0.13469,40,141.21,-11.13,0.33582,54,17.98,-3.72,0.50211,1,33,26.4,-166.06,1,1,33,87.21,-106.12,1,1,33,108.19,-49.62,1,2,33,61.73,-82.13,0.50021,48,4.42,52.83,0.49978,2,33,22.84,-109.4,0.50021,48,51.52,46.73,0.49978,5,9,348.39,119.13,0.00694,14,247.12,-50.52,0.065,17,60.86,-121.4,0.06027,33,-30.3,-118,0.48738,48,96.58,17.22,0.38039,1,9,26.73,14.8,1,2,9,-107.97,25.67,0.24192,8,60.17,-6.91,0.75807,5,9,235.53,102.96,0.07484,14,150.1,9.35,0.34943,17,27.64,-12.34,0.40983,33,-44.43,-4.87,0.14928,48,34.03,-74.39,0.0166,5,9,227.15,28.49,0.29239,14,95.96,-42.46,0.5708,17,-47.23,-15.44,0.07952,33,-118.74,4.84,0.03982,48,84.85,-129.5,0.01745,2,33,5.19,-153.1,0.87618,48,90.96,71.21,0.12381,5,9,351.78,108.85,0.01127,14,243.13,-60.59,0.10548,17,51.21,-126.33,0.09782,33,-40.65,-121.21,0.46541,48,105.71,17.33,0.32,1,33,23.69,-185.21,1,1,33,79.64,-175.94,1,1,33,93.96,-187.56,1,1,33,87.07,-206.55,1,1,33,64.2,-216.74,1,1,33,52.23,-203.68,1,1,33,59.24,-187.03,1,1,33,64.26,-223.8,1,1,33,89.44,-211.41,1,1,33,102.04,-186.95,1,1,33,83.1,-166.14,1,1,33,46.84,-186.41,1,1,33,50.32,-204.36,1,1,33,41.7,-206.59,1,1,33,61.87,-230.97,1,6,9,-448.12,-58.75,9.7E-4,8,374.97,143.6,0.01016,13,256.29,17.42,0.13074,27,127.43,2.07,0.37548,40,-13.35,-3.05,0.34387,54,-128.14,-55.46,0.13875,6,9,-519.55,-68.54,5.1E-4,8,442.75,168.18,0.00402,13,327.21,4.42,0.06791,27,196.28,-19.32,0.26429,40,58.71,-1.05,0.3719,54,-62.24,-26.21,0.29134,6,9,-386.43,-41.35,0.00321,8,318.32,113.62,0.03567,13,192.26,20.14,0.25008,27,64.19,12.44,0.42824,40,-76.55,-13.67,0.24036,54,-182.56,-89.31,0.0424],"hull":44,"edges":[22,20,20,18,18,16,6,4,4,2,86,84,50,48,48,46,24,22,24,88,88,22,88,90,90,20,90,92,92,18,92,94,94,16,12,96,96,80,98,84,98,86,80,100,100,90,94,100,76,102,102,88,72,104,104,24,68,106,106,28,62,108,108,34,54,110,110,42,50,112,112,46,84,82,82,80,114,98,82,114,8,6,114,8,24,26,26,28,104,116,116,106,26,116,68,70,70,72,116,70,28,30,106,118,30,118,66,68,118,66,38,120,120,58,42,44,44,46,110,122,122,112,44,122,50,52,52,54,122,52,124,126,126,128,128,130,132,98,130,132,132,134,76,78,78,80,100,136,136,102,78,136,72,74,74,76,102,138,138,104,74,138,8,10,10,12,96,140,140,114,10,140,12,14,14,16,94,142,142,96,14,142,6,144,144,132,8,146,146,134,144,146,6,148,144,148,124,148,0,86,0,2,150,152,152,154,154,156,156,158,158,160,160,150,162,164,164,166,0,168,168,148,166,168,168,170,170,172,172,162,148,174,174,176,176,2,58,60,60,62,108,178,178,120,60,178,34,36,36,38,178,36,54,56,56,58,110,180,180,120,56,180,38,40,40,42,180,40,62,64,64,66,108,182,182,118,64,182,30,32,32,34,182,32],"width":1219,"height":570}},"raptor_front_arm":{"images/raptor_front_arm":{"type":"skinnedmesh","uvs":[0.39562,0.1396,0.3877,0.30212,0.3123,0.41784,0.27287,0.47835,0.33388,0.4507,0.54879,0.35328,0.64092,0.31152,0.73024,0.36529,1,0.5277,1,0.86606,0.93242,1,0.86176,0.80967,0.75576,0.99765,0.71748,1,0.70276,0.77442,0.62031,0.73448,0.58792,0.64519,0.53561,0.6582,0.13448,0.75798,0,0.69218,0.01846,0.56357,0.05498,0.30917,0,0.27863,0,0.12423,0,0,0.19596,0,0.40242,0,0.24536,0.1924,0.21678,0.0811],"triangles":[23,24,25,28,25,26,23,25,28,0,28,26,10,11,9,13,14,12,12,14,11,11,8,9,11,14,8,8,14,7,7,14,15,15,16,7,6,16,5,6,7,16,18,4,17,18,3,4,18,19,3,16,17,5,17,4,5,19,20,3,3,20,2,2,20,21,2,21,1,21,27,1,21,22,27,1,27,0,27,23,28,27,22,23,27,28,0],"vertices":[2,15,3.06,31.88,0.51075,14,66.56,-109.48,0.48924,1,15,35.87,35.62,1,2,15,60.94,27.12,0.8464,29,46.49,31.12,0.15359,3,15,74.05,22.67,0.34375,29,36.5,21.53,0.64062,45,-45.25,-29.96,0.01562,3,15,67,31.58,0.10937,29,47.66,23.68,0.78125,45,-40.93,-19.44,0.10937,3,15,42.17,62.99,0.01562,29,86.98,31.24,0.64062,45,-25.75,17.61,0.34375,2,29,103.83,34.49,0.34375,45,-19.24,33.49,0.65625,2,29,114.04,19.51,0.10937,45,-1.11,33.84,0.89062,2,29,144.85,-25.73,0.02083,45,53.62,34.88,0.97916,1,45,96.03,-19.16,1,1,45,104.2,-47.31,1,1,45,71.34,-23.98,1,1,45,81.39,-64.61,1,1,45,76.8,-68.81,1,2,29,83.18,-57.72,0.02083,45,46.65,-34.25,0.97916,2,29,73.13,-45.76,0.10937,45,31.14,-36.12,0.89062,2,29,73.98,-26.9,0.34375,45,15.82,-25.09,0.65625,3,15,103.67,70.28,0.01562,29,65.1,-26.69,0.64062,45,10.78,-32.41,0.34375,3,15,133.56,9.13,0.10937,29,-2.94,-25.03,0.78125,45,-27.84,-88.47,0.10937,3,15,123.67,-14.42,0.34375,29,-19.29,-5.39,0.64062,45,-53.23,-91.41,0.01562,2,15,97.41,-15.43,0.8464,29,-8.08,18.37,0.15359,1,15,45.46,-17.43,1,2,15,40.69,-27.17,0.45035,14,-1.69,-93.8,0.54964,2,15,-2.74,-29.63,0.44352,14,18.99,-72.93,0.55647,1,14,32.11,-48.45,1,1,14,57.56,-67.43,1,1,14,84.38,-87.42,1,2,15,16.44,5.21,0.7182,14,46.31,-101.86,0.28179,2,15,-4.51,5.32,0.48851,14,52.82,-81.94,0.51148],"hull":27,"edges":[38,36,32,30,30,28,28,26,24,26,24,22,22,20,20,18,18,16,44,42,38,6,38,40,40,42,6,4,4,2,40,4,8,6,36,8,32,12,42,2,52,0,0,2,16,14,14,12,30,14,36,34,34,32,12,10,10,8,34,10,48,50,50,52,0,54,54,44,54,42,44,46,46,48,50,56,56,54,46,56,56,52],"width":162,"height":203}},"raptor_front_leg":{"images/raptor_front_leg":{"type":"skinnedmesh","uvs":[0.55116,0.17817,0.6279,0.36027,0.6671,0.4533,0.64879,0.51527,0.53553,0.56893,0.32335,0.66946,0.28674,0.72086,0.32538,0.804,0.36258,0.80144,0.42056,0.79744,0.61015,0.78435,0.84813,0.84028,1,0.93854,0.62439,0.91738,0.72812,1,0.58574,1,0.36707,0.96667,0.26306,0.95082,0.16266,0.93552,0.03859,0.72237,0,0.66946,0.0374,0.62999,0.1647,0.49562,0.23731,0.4568,0.27019,0.43923,0.28063,0.43364,0.223,0.4057,0.12565,0.35851,0,0.29759,0,0.1524,0,0,0.32132,0,0.32222,0.22778,0.4493,0.38031,0.47664,0.44361,0.4615,0.47375,0.35106,0.53247,0.20091,0.65256,0.18527,0.72148,0.25222,0.86314,0.30941,0.88124,0.55694,0.89613,0.55857,0.89207,0.47493,0.85339,0.6059,0.91526,0.39705,0.89129,0.13229,0.09352,0.36997,0.45345,0.37163,0.43827,0.32515,0.39424,0.23759,0.34425,0.34065,0.47414],"triangles":[46,30,31,13,11,12,11,13,10,10,13,42,13,44,42,41,43,42,42,43,10,43,9,10,13,14,44,14,15,44,16,45,15,15,45,44,17,40,16,16,40,45,45,41,44,45,43,41,41,42,44,40,8,45,45,9,43,45,8,9,18,39,17,17,39,40,18,38,39,18,19,38,40,7,8,40,39,7,39,6,7,39,38,6,20,21,19,19,21,38,38,37,6,38,21,37,6,37,5,5,36,4,5,37,36,21,22,37,37,22,36,36,35,4,4,35,3,36,47,35,22,23,36,23,51,36,36,51,47,35,34,3,3,34,2,23,24,51,51,24,47,47,48,35,35,48,34,24,25,47,47,25,48,34,1,2,48,33,34,34,33,1,25,49,48,48,49,33,25,26,49,26,50,49,26,27,50,33,49,32,49,50,32,33,0,1,33,32,0,50,27,32,32,27,28,28,46,32,28,29,46,46,31,32,32,31,0,29,30,46],"vertices":[3,4,128.03,88.47,0.83908,10,-70.2,-134.13,0.01331,2,158.83,-71.91,0.1476,2,4,219.55,53.15,0.77988,10,-48.04,-38.58,0.22011,3,4,266.3,35.1,0.53531,10,-36.73,10.22,0.46443,30,127.25,245.46,2.4E-4,4,4,286.89,9.79,0.35076,10,-14.56,34.14,0.64667,30,125.69,212.88,0.0023,44,101.39,199.13,2.5E-4,4,4,281.54,-41.24,0.09169,10,36.71,36,0.90196,30,87.64,178.44,0.00513,44,58.29,171.29,0.00119,5,4,271.53,-136.86,0.05608,10,132.77,39.48,0.69232,16,34.99,78.76,0.22087,30,16.38,113.93,0.0224,44,-22.45,119.13,0.0083,5,4,283.51,-164.25,0.01987,10,158.21,55.17,0.50334,16,52.65,54.63,0.3617,30,7.01,85.54,0.08322,44,-36.28,92.63,0.03184,6,4,326.15,-179.3,0.00798,10,167.14,99.49,0.21327,16,97.55,49.25,0.35075,30,28.72,45.87,0.14107,44,-21.26,49.99,0.22311,60,-72.29,25.96,0.0638,6,4,333.96,-167.35,0.00242,10,154.22,105.55,0.07519,16,102.57,62.6,0.22995,30,42.51,49.55,0.2831,44,-7.06,51.39,0.2694,60,-58.17,28.03,0.13992,6,4,344.19,-149.68,4.9E-4,10,134.24,114.44,0.0176,16,109.72,83.39,0.11397,30,64.09,55.23,0.07976,44,15.12,53.51,0.36292,60,-36.09,31.19,0.42523,1,60,35.8,41.81,1,1,60,128.11,17.93,1,1,60,188.72,-29.42,1,1,60,44.86,-26.17,1,1,44,133.17,-49.83,1,1,44,78.78,-50.15,1,5,4,399.32,-220.02,2.2E-4,10,195.56,179.43,0.01703,16,179.46,27.52,0.2372,30,58.34,-33.93,0.2023,44,-4.91,-33.55,0.54324,5,4,370.41,-244.91,3.2E-4,10,225.9,152.49,0.02513,16,155.04,-5.13,0.35003,30,17.88,-32.5,0.29852,44,-44.62,-25.61,0.32598,5,4,340.37,-270.04,0.00251,10,254.98,126.27,0.10129,16,131.21,-36.2,0.54075,30,-21.24,-31.17,0.2082,44,-83.02,-17.97,0.14723,5,4,225.1,-238.94,0.01529,10,240.33,7.81,0.24036,16,11.94,-30.98,0.57881,30,-86.31,68.9,0.12023,44,-131.06,91.29,0.04528,5,4,194.64,-233.55,0.04819,10,239.26,-23.1,0.40427,16,-18.96,-32.37,0.48451,30,-105.4,93.25,0.04604,44,-145.97,118.4,0.01697,5,4,187.65,-209.73,0.09565,10,216.66,-33.35,0.57617,16,-30.97,-10.65,0.30651,30,-94.71,115.65,0.01788,44,-131.8,138.78,0.00376,4,4,163.85,-128.67,0.19533,10,139.75,-68.26,0.8011,30,-58.32,191.88,0.00327,44,-83.58,208.13,2.9E-4,4,4,165.74,-94.49,0.31921,10,105.59,-71.26,0.6795,30,-5.04,220.72,0.00117,44,-56.32,275.96,1.0E-4,4,4,166.39,-79.07,0.46205,10,90.23,-72.76,0.53752,30,5.55,230.48,3.9E-4,44,-40.61,286.16,2.0E-5,3,4,166.49,-74.17,0.53779,10,85.42,-73.28,0.46208,30,-19.99,230.7,1.2E-4,2,4,141.54,-82.46,0.73138,10,97.13,-96.82,0.26861,3,4,99.76,-97.08,0.81379,10,117.34,-136.23,0.13997,2,-2.56,-164.19,0.04623,3,4,45.01,-114.56,0.8186,10,142.41,-187.89,0.02098,2,-51.09,-135.29,0.1604,3,4,-16.2,-74.76,0.62389,10,113.82,-253.08,0.00952,2,-42.95,-58.38,0.36658,2,4,-74.73,-19.33,0.31468,2,-52.66,17.55,0.68531,2,4,1.67,76.75,0.25576,2,70.07,18.78,0.74423,1,4,93.54,4.13,1,2,4,185.14,-6.66,0.75461,10,15.98,-64.27,0.24538,2,4,217.11,-18.75,0.50845,10,23.47,-30.93,0.49154,3,4,225.63,-32.92,0.32512,10,36.3,-20.5,0.6744,30,51.57,221.95,4.7E-4,4,4,223,-84.73,0.20061,10,87.96,-15.86,0.79287,30,15.03,185.13,0.00581,44,-12.28,189.61,6.9E-4,5,4,235.61,-168.06,0.07777,10,168.69,8.29,0.54931,16,6.74,40.47,0.33413,30,-31.18,114.66,0.0321,44,-69.27,127.55,0.00667,5,4,259.63,-194.79,0.01921,10,191.79,35.8,0.30498,16,36,19.62,0.53642,30,-31.14,78.74,0.09568,44,-75.03,92.09,0.04369,5,4,332.55,-220.1,0.00292,10,206.64,111.53,0.10776,16,112.69,10.82,0.51915,30,6.25,11.23,0.23449,44,-49.03,19.43,0.13566,4,10,192.51,130.62,0.03213,16,130.6,26.41,0.33941,30,29.35,5.71,0.27333,44,-27.12,10.25,0.35511,1,44,67.46,3.16,1,1,60,19.07,-14.51,1,6,4,381.55,-150.4,3.0E-4,10,130.71,150.34,0.00811,16,145.36,89.53,0.04102,30,89.29,30.41,0.02558,44,36,24.95,0.37636,60,-13.89,3.64,0.54861,1,44,86.23,-6.55,1,4,10,164.9,153.55,0.02263,16,151.18,56,0.23908,30,65.44,5.55,0.19254,44,8.45,4.27,0.54574,2,4,-9.28,-17.5,0.59606,2,7.72,-30.85,0.40393,3,4,195.9,-53.81,0.42356,10,61.11,-47.06,0.57613,30,39.7,225.21,2.9E-4,3,4,190.1,-48.45,0.53227,10,56.61,-53.56,0.46765,30,39.83,233.12,6.0E-5,2,4,161.26,-48.26,0.79873,10,60.44,-82.13,0.20126,3,4,120.37,-58.54,0.8485,10,76.31,-121.18,0.14441,2,41.04,-161.4,0.00707,4,4,197.37,-69.23,0.33487,10,76.17,-43.46,0.66324,30,30.34,213.88,0.0017,44,-9.09,262.42,1.8E-4],"hull":32,"edges":[40,38,38,36,28,30,28,26,26,24,24,22,22,20,14,12,12,10,6,4,60,62,0,62,40,42,42,44,34,36,16,14,52,50,4,2,2,0,10,8,8,6,0,64,64,56,2,66,64,66,4,68,66,68,6,70,68,70,8,72,72,44,70,72,10,74,74,42,72,74,12,76,76,38,74,76,14,78,78,36,76,78,16,80,80,34,78,80,26,84,86,84,86,20,26,88,82,88,88,28,80,90,90,88,16,18,18,20,18,90,30,32,32,34,90,32,86,18,82,86,56,58,58,60,60,92,92,64,58,92,92,62,94,70,50,96,96,68,94,96,52,98,98,66,96,98,52,54,54,56,54,100,100,98,100,64,48,50,94,48,44,46,46,48,46,102,102,72,102,94],"width":382,"height":514}},"raptor_hindleg_back":{"images/raptor_hindleg_back":{"type":"skinnedmesh","uvs":[0.45041,0.09352,0.56933,0.23361,0.65294,0.47296,0.66353,0.50822,0.63174,0.54254,0.32383,0.69723,0.30068,0.73875,0.27934,0.77704,0.30417,0.83513,0.31058,0.85014,0.341,0.85046,0.45165,0.85163,0.59555,0.81881,0.91176,0.92548,1,1,0.56336,0.96426,0.48349,0.9826,0.29878,0.98027,0.22808,0.98389,0.15997,0.98737,0.15423,0.95546,0.13894,0.87047,0.07371,0.78726,0,0.75299,0,0.7049,0,0.671,0.11875,0.64652,0.16535,0.52659,0.28495,0.47397,0.2901,0.45773,0.29427,0.4446,0.20635,0.40396,0.06128,0.33691,0,0.25247,0,0,0.30793,0,0.27599,0.20261,0.40397,0.31121,0.48439,0.45963,0.48317,0.48383,0.47029,0.51062,0.22698,0.67328,0.17141,0.7242,0.17122,0.78241,0.22995,0.89469,0.24677,0.90829,0.28672,0.9146,0.46582,0.91414],"triangles":[15,47,12,15,13,14,15,12,13,16,47,15,47,11,12,18,45,46,17,47,16,18,46,17,47,46,10,17,46,47,47,10,11,46,9,10,45,18,19,44,45,20,20,45,19,20,21,44,46,45,9,45,44,9,21,43,44,44,8,9,44,7,8,44,43,7,21,22,43,43,22,42,43,42,7,22,23,24,40,29,39,24,42,22,7,42,6,40,39,4,28,29,40,42,41,6,6,41,5,24,26,42,42,26,41,24,25,26,5,40,4,5,41,40,41,28,40,26,27,41,41,27,28,4,39,3,39,2,3,29,30,39,39,38,2,39,30,38,38,1,2,30,37,38,38,37,1,30,31,37,31,36,37,31,32,36,32,33,36,37,0,1,37,36,0,33,34,36,36,35,0,36,34,35],"vertices":[1,6,53.94,69.15,1,1,6,126.23,67.31,1,2,6,226.42,31.13,0.9375,11,-30.87,-1.11,0.0625,2,6,240.84,25.33,0.7,11,-25.64,13.52,0.3,2,6,246.67,8.05,0.3,11,-8.61,20.02,0.7,3,6,240.81,-115.25,0.0625,11,114.8,19.01,0.875,19,9.48,59.16,0.0625,2,11,131.07,29.69,0.7,19,22.11,44.35,0.3,2,11,146.06,39.54,0.3,19,33.76,30.71,0.7,4,11,152.6,65.01,0.12438,19,59.85,27.41,0.74434,35,15.85,48.05,0.12104,51,-80.52,23.87,0.01022,4,11,154.28,71.59,0.0519,19,66.59,26.56,0.74749,35,16.72,41.31,0.15401,51,-77.54,17.76,0.04658,4,11,145.73,77.3,0.02193,19,71.19,35.76,0.63296,35,26.78,39.17,0.1288,51,-67.32,18.96,0.21628,3,19,87.93,69.21,0.0625,35,63.37,31.39,0.675,51,-30.17,23.3,0.26249,2,35,113.82,35.72,0.1038,51,16.23,43.56,0.89619,1,51,128.14,12.02,1,1,51,161.85,-15.81,1,2,35,90.98,-23.36,0.0138,51,13.52,-19.72,0.98619,2,35,62.97,-25.81,0.7,51,-12.23,-31.02,0.3,3,19,115.12,-1.33,0.08333,35,1.93,-12.66,0.83333,51,-74.26,-38.1,0.08333,2,19,106.11,-23.53,0.3,35,-21.8,-9.52,0.7,2,19,97.43,-44.9,0.7,35,-44.67,-6.51,0.3,2,19,84.26,-40.69,0.9375,35,-43.9,7.29,0.0625,1,19,49.18,-29.46,1,2,11,206.75,5.37,0.13333,19,7.44,-33.77,0.86666,2,11,219.64,-20.52,0.36111,19,-16.64,-49.8,0.63888,2,11,208.4,-37.82,0.72083,19,-35.22,-40.82,0.27916,2,11,200.49,-50.02,0.91666,19,-48.31,-34.48,0.08333,1,11,161.1,-36.97,1,2,6,150.1,-116.76,0.08333,11,119.88,-71.55,0.91666,2,6,154.99,-70.71,0.42846,11,73.68,-68.47,0.57153,2,6,150.3,-65.27,0.35604,11,68.42,-73.36,0.64395,2,6,146.51,-60.87,0.59147,11,64.17,-77.32,0.40852,2,6,115.12,-75.08,0.8446,11,79.61,-108.13,0.15539,1,6,63.33,-98.53,1,1,6,21.78,-94.55,1,1,6,-66.69,-32.04,1,1,6,-6.62,52.97,1,1,6,58.14,-6,1,1,6,121.17,2.44,1,2,6,188.87,-12.1,0.96,11,13.79,-36.92,0.04,2,6,197.11,-18.42,0.7,11,19.79,-28.44,0.3,2,6,203.98,-28.61,0.3,11,29.69,-21.17,0.7,3,6,213.53,-136.06,0.04,11,136.67,-7.42,0.91999,19,-14.02,34.16,0.04,2,11,164.32,0.66,0.7,19,-2.53,7.73,0.3,2,11,177.97,21.57,0.25,19,19.92,-3.19,0.75,3,11,187.55,72.78,0.04,19,71.93,-6.29,0.91999,35,-13.72,27.87,0.04,2,19,79.66,-3.72,0.7,35,-9.28,21.04,0.3,3,19,87.98,7.25,0.3,35,3.42,15.76,0.66,51,-81.96,-10.7,0.04,3,19,114.16,61.85,0.04,35,62.84,4.15,0.7,51,-21.95,-2.66,0.26],"hull":36,"edges":[66,68,66,64,56,54,54,52,52,50,46,44,44,42,34,32,32,30,30,28,28,26,26,24,24,22,10,8,8,6,6,4,4,2,2,0,68,70,0,70,46,48,48,50,14,12,12,10,60,58,58,56,42,40,40,38,18,16,16,14,22,20,20,18,38,36,36,34,60,62,62,64,0,72,72,64,68,72,2,74,74,62,72,74,4,76,76,60,74,76,6,78,78,58,76,78,8,80,80,56,78,80,10,82,82,52,80,82,12,84,84,48,82,84,14,86,86,44,84,86,16,88,88,40,86,88,18,90,90,38,88,90,20,92,92,36,90,92,92,94,94,22,94,32,30,24,94,24],"width":338,"height":429}},"raptor_horn":{"images/raptor_horn":{"x":156.2,"y":74.1,"rotation":-137.26,"width":363,"height":159}},"raptor_horn_back":{"images/raptor_horn_back":{"x":121.42,"y":83.01,"rotation":-132.21,"width":351,"height":153}},"raptor_jaw":{"images/raptor_jaw":{"type":"skinnedmesh","uvs":[0.40984,0.22169,0.42214,0.3988,0.67894,0.53819,0.7589,0.62838,0.99999,0.4726,1,0.53491,0.87731,0.77925,0.63281,0.94487,0.39908,0.96947,0.19456,0.89404,0.21609,0.6497,0,0.46111,0,0,0.26069,0,0.19456,0.29385,0.31758,0.50047],"triangles":[11,14,15,14,0,1,5,3,4,6,3,5,2,15,1,7,2,3,7,3,6,15,8,10,15,2,8,8,9,10,2,7,8,15,14,1,10,11,15,14,13,0,14,12,13,11,12,14],"vertices":[1,48,28.6,68.85,1,1,48,69.65,38.95,1,1,48,150.72,72.88,1,1,48,186.16,74.79,1,1,48,199.76,159.69,1,1,48,213.35,148.16,1,1,48,242.43,74.42,1,1,48,230.31,-13.08,1,1,48,189.56,-71.99,1,1,48,132.76,-105.6,1,1,48,83.71,-55.39,1,2,33,-18.31,12.1,0.67732,48,-0.04,-70.76,0.32267,1,33,113.44,16.95,1,1,33,116.36,-62.48,1,1,48,1.86,5.43,1,1,48,71.19,-4.17,1],"hull":14,"edges":[22,24,22,20,20,18,18,16,16,14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,24,26,0,26,24,28,28,30,30,20,22,28,28,0,30,2],"width":305,"height":286}},"raptor_saddle_noshadow":{"images/raptor_saddle_noshadow":{"x":80.83,"y":10.63,"rotation":-88.64,"width":326,"height":375}},"raptor_saddle_strap_front":{"images/raptor_saddle_strap_front":{"x":128.83,"y":-4.71,"rotation":61.29,"width":114,"height":189}},"raptor_saddle_strap_rear":{"images/raptor_saddle_strap_rear":{"type":"skinnedmesh","uvs":[0.85499,0.06802,1,0.13237,1,0.20266,0.95981,0.26524,0.88583,0.38045,0.80684,0.46413,0.74038,0.53453,0.81676,0.5895,0.51961,1,0.4516,1,0.01739,0.8407,0,0.80889,0.24645,0.36639,0.3792,0.39151,0.42457,0.32099,0.49229,0.21571,0.57673,0.10986,0.66437,0,0.70168,0,0.56028,0.46321,0.68822,0.29772,0.76845,0.18722,0.61529,0.39206],"triangles":[7,8,6,9,10,13,13,11,12,6,8,19,8,9,19,9,13,19,13,10,11,19,22,6,13,14,19,19,14,22,6,22,5,20,21,4,15,16,20,22,20,5,5,20,4,14,15,22,22,15,20,4,21,3,20,16,21,2,3,0,3,21,0,0,1,2,21,16,18,16,17,18,21,18,0],"vertices":[1,21,3.9,-3.27,1,1,21,4.25,15.05,1,1,21,13.24,20.28,1,2,21,23.42,21.2,0.7,37,-15.2,21.22,0.3,3,21,41.11,22.87,0.3,37,2.48,22.89,0.6375,53,-33.83,24.96,0.0625,3,21,52.07,21.72,0.0625,37,13.43,21.74,0.6375,53,-22.97,23.11,0.3,2,37,18.39,20.76,0.25,53,-18.09,21.82,0.75,1,53,-18.76,33.09,1,1,53,49.92,31.57,1,1,53,53.21,25,1,1,53,53.11,-27.48,1,1,53,49.74,-31.27,1,1,53,-20.73,-36.76,1,1,53,-23.82,-22.28,1,3,21,53.48,-24.61,0.0625,37,14.84,-24.59,0.575,53,-24.51,-23.21,0.3625,3,21,41.44,-26.12,0.3,37,2.81,-26.09,0.6375,53,-36.62,-23.95,0.0625,2,21,24.38,-26.12,0.7,37,-14.24,-26.1,0.3,1,21,5.57,-26.12,1,1,21,3.54,-22.64,1,1,53,-23.08,-0.04,1,3,21,41.66,-1.72,0.3,37,3.03,-1.7,0.66,53,-34.85,0.38,0.04,2,21,23.85,-2.46,0.7,37,-14.77,-2.44,0.3,3,21,52.58,-1.52,0.04,37,13.95,-1.5,0.62,53,-23.94,-0.11,0.34],"hull":19,"edges":[26,24,24,22,22,20,20,18,16,18,16,14,14,12,4,2,34,36,12,38,38,26,8,40,40,30,2,0,0,36,30,32,32,34,0,42,42,40,32,42,4,6,6,8,42,6,26,28,28,30,38,44,44,40,28,44,8,10,10,12,44,10],"width":108,"height":148}},"raptor_saddle_w_shadow":{"images/raptor_saddle_w_shadow":{"x":80.83,"y":10.63,"rotation":-88.64,"width":326,"height":375}},"raptor_tongue":{"images/raptor_tongue":{"type":"skinnedmesh","uvs":[0.35242,0.2156,0.4794,0.44245,0.62071,0.61176,0.80562,0.75373,1,0.90297,1,1,0.8971,1,0.72054,0.92254,0.50668,0.82872,0.30401,0.70725,0.10537,0.57888,0,0.50622,0,0,0.26224,0],"triangles":[7,8,3,6,7,3,4,6,3,6,4,5,8,7,6,9,1,2,8,9,2,9,10,1,8,2,3,0,11,12,0,12,13,10,11,0,1,10,0],"vertices":[2,55,3.63,27.04,0.6875,62,-47.26,33.87,0.3125,3,55,39.09,19.45,0.3125,62,-13.41,20.86,0.625,65,-51.54,33.37,0.0625,3,55,71.56,19.02,0.0625,62,18.58,15.39,0.625,65,-21.56,20.92,0.3125,2,62,55.03,16.85,0.3125,65,14.29,14.23,0.6875,2,62,93.34,18.39,0.08333,65,51.98,7.21,0.91666,1,65,56.09,-4.5,1,2,62,85.06,-1.49,0.08333,65,39.48,-10.33,0.91666,2,62,54.22,-9.18,0.3125,65,7.71,-10.96,0.6875,3,55,75.14,-14.72,0.0625,62,16.87,-18.5,0.625,65,-30.77,-11.73,0.3125,3,55,38.8,-25.8,0.3125,62,-20.74,-23.8,0.625,65,-68.62,-8.53,0.0625,2,55,2.4,-35.77,0.6875,62,-58.25,-27.99,0.3125,2,55,-17.28,-40.62,0.91666,62,-78.45,-29.71,0.08333,1,55,-59.91,8.18,1,2,55,-26.13,37.69,0.91666,62,-75.02,49.02,0.08333],"hull":14,"edges":[22,24,10,12,10,8,24,26,16,4,18,16,2,4,18,2,22,20,0,26,20,0,0,2,12,14,14,16,4,6,6,8,14,6,20,18],"width":171,"height":128}},"spineboy_torso":{"images/torso":{"x":55.88,"y":4.86,"rotation":-104.14,"width":108,"height":182}},"stirrup_back":{"images/stirrup_back":{"x":53.2,"y":31.34,"rotation":-21.12,"width":87,"height":69}},"stirrup_front":{"images/stirrup_front":{"x":36.13,"y":20.39,"rotation":-21.12,"width":89,"height":100}},"stirrup_strap":{"images/stirrup_strap":{"type":"skinnedmesh","uvs":[0.36822,0.27893,0.45737,0.38897,0.54451,0.49651,0.67872,0.59135,0.81977,0.69102,1,0.77344,1,1,0.77956,1,0.63729,0.81629,0.53364,0.72348,0.40534,0.6086,0.30886,0.52535,0.21049,0.44047,0,0.26245,0,0,0.30637,0,0.20241,0.23],"triangles":[7,5,6,7,4,5,7,8,4,8,3,4,8,9,3,9,2,3,9,10,2,2,10,1,10,11,1,11,12,1,13,16,12,12,0,1,12,16,0,16,15,0,13,14,16,16,14,15],"vertices":[2,26,24.71,8.03,0.80344,39,-17.42,11.02,0.19655,2,26,37.95,8.04,0.59978,39,-4.36,8.87,0.40021,2,26,50.88,8.04,0.36895,39,8.39,6.77,0.63104,2,26,65.92,12.27,0.17748,39,23.91,8.48,0.82251,2,26,81.72,16.7,0.05943,39,40.23,10.28,0.94056,2,26,98.82,25.04,0.01209,39,58.46,15.71,0.9879,2,26,114.44,11.57,0.00191,39,71.67,-0.11,0.99808,2,26,100.47,-4.61,0.01817,39,55.25,-13.81,0.98182,2,26,78.79,-4.14,0.07487,39,33.94,-9.81,0.92512,2,26,65.83,-6.24,0.2028,39,20.81,-9.76,0.79719,2,26,49.78,-8.83,0.39971,39,4.55,-9.7,0.60028,2,26,37.93,-10.97,0.62658,39,-7.48,-9.88,0.37341,2,26,25.85,-13.15,0.82034,39,-19.75,-10.06,0.17965,2,26,0.25,-18.03,0.95288,39,-45.81,-10.7,0.04711,2,26,-17.83,-2.43,0.97709,39,-61.11,7.63,0.0229,2,26,1.57,20.07,0.94774,39,-38.29,26.67,0.05225,2,26,10.84,-1.23,0.97709,39,-32.62,4.14,0.0229],"hull":16,"edges":[28,30,30,0,12,10,8,10,12,14,14,16,26,28,24,26,26,32,32,30,20,22,22,24,0,2,2,4,4,6,6,8,16,18,18,20],"width":97,"height":91}},"visor":{"images/visor":{"x":99.13,"y":6.51,"rotation":-70.57,"width":261,"height":168}}}},"animations":{"walk":{"bones":{"root":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_foot_goal":{"rotate":[{"time":0,"angle":0},{"time":0.2666,"angle":-51.26},{"time":0.4,"angle":-65.17},{"time":0.5333,"angle":-76.28},{"time":0.8,"angle":-76.52},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":343.28,"y":36.5},{"time":0.2666,"x":86.5,"y":36.99},{"time":0.5333,"x":-173.36,"y":37.42},{"time":0.6,"x":-68.15,"y":141.15},{"time":0.7333,"x":91.78,"y":238.01},{"time":0.8,"x":155.89,"y":190.91},{"time":0.9666,"x":303.28,"y":94.4},{"time":1.0666,"x":343.28,"y":36.5}]},"hip":{"rotate":[{"time":0,"angle":-4.78},{"time":0.0666,"angle":-3.99},{"time":0.2666,"angle":-12.49},{"time":0.5333,"angle":-4.78},{"time":0.6,"angle":-3.99},{"time":0.8,"angle":-12.49},{"time":1.0666,"angle":-4.78}],"translate":[{"time":0,"x":161.93,"y":4.89,"curve":[0.27,0.37,0.62,0.4]},{"time":0.0666,"x":165.04,"y":-5.99,"curve":[0.244,0,0.757,1]},{"time":0.2666,"x":178.8,"y":136.52,"curve":[0.25,0,0.841,0.8]},{"time":0.5333,"x":161.93,"y":4.89,"curve":[0.27,0.37,0.62,0.4]},{"time":0.6,"x":165.04,"y":-5.99,"curve":[0.244,0,0.757,1]},{"time":0.8,"x":178.8,"y":136.52,"curve":[0.25,0,0.858,0.82]},{"time":1.0666,"x":161.93,"y":4.89}]},"rear_foot_goal":{"rotate":[{"time":0,"angle":-62.73},{"time":0.2666,"angle":-107.17},{"time":0.4666,"angle":-40.51},{"time":0.8,"angle":-97.15},{"time":1.0666,"angle":-62.73}],"translate":[{"time":0,"x":-266.69,"y":-15.46},{"time":0.1333,"x":-87.88,"y":124.85},{"time":0.2666,"x":88.35,"y":134.06},{"time":0.3666,"x":198.39,"y":90.64},{"time":0.4666,"x":308.19,"y":-26.42},{"time":0.6,"x":167.06,"y":-26.42},{"time":1.0666,"x":-266.69,"y":-15.46}]},"front_leg1":{"rotate":[{"time":0,"angle":27.07,"curve":"stepped"},{"time":1.0666,"angle":27.07}],"translate":[{"time":0,"x":0,"y":0},{"time":0.0666,"x":-0.21,"y":15.19},{"time":0.5333,"x":-0.33,"y":12.15},{"time":0.7333,"x":-4.74,"y":31.93},{"time":1.0666,"x":0,"y":0}]},"front_leg_goal":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":-18.04,"y":-2.88},{"time":0.4333,"x":-42.2,"y":-88.63},{"time":0.5333,"x":-27.31,"y":-43.9},{"time":0.7333,"x":-1.52,"y":-94.28},{"time":0.8,"x":-24.29,"y":-116.41},{"time":1,"x":-41.88,"y":-93.3},{"time":1.0666,"x":-18.04,"y":-2.88}]},"rear_leg1":{"rotate":[{"time":0,"angle":-45.71,"curve":"stepped"},{"time":1.0666,"angle":-45.71}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_leg_goal":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":-2.05,"y":15.12},{"time":0.2666,"x":17.49,"y":-150.43},{"time":0.4666,"x":-40.21,"y":-81.76},{"time":0.5333,"x":-31.68,"y":-82.43},{"time":0.8,"x":2.65,"y":-169.21},{"time":0.9333,"x":-16.76,"y":-98.31},{"time":1.0666,"x":-2.05,"y":15.12}]},"tail1":{"rotate":[{"time":0,"angle":1.3},{"time":0.0666,"angle":4.13},{"time":0.3333,"angle":-5.77},{"time":0.6333,"angle":4.13},{"time":0.9,"angle":-5.77},{"time":1.0666,"angle":1.3}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"torso1":{"rotate":[{"time":0,"angle":7.21},{"time":0.2666,"angle":4.19},{"time":0.5333,"angle":7.21},{"time":0.8,"angle":4.19},{"time":1.0666,"angle":7.21}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_leg2":{"rotate":[{"time":0,"angle":-347.28,"curve":"stepped"},{"time":1.0666,"angle":-347.28}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_leg2":{"rotate":[{"time":0,"angle":9.92,"curve":"stepped"},{"time":1.0666,"angle":9.92}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle":{"rotate":[{"time":0,"angle":-2.51},{"time":0.2666,"angle":-4.17},{"time":0.5333,"angle":-3.85},{"time":0.8,"angle":-3.09},{"time":1.0666,"angle":-2.51}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.2666,"x":0,"y":0,"curve":[0.149,0.28,0.75,1]},{"time":0.3333,"x":-0.03,"y":5.91,"curve":[0.421,0,0.85,0.78]},{"time":0.5333,"x":0,"y":0},{"time":0.6,"x":-0.2,"y":-2.35},{"time":0.8,"x":0,"y":0,"curve":[0.149,0.28,0.75,1]},{"time":0.8666,"x":-0.03,"y":5.91,"curve":[0.421,0,0.85,0.78]},{"time":1.0666,"x":0,"y":0}]},"tail2":{"rotate":[{"time":0,"angle":-6.57},{"time":0.0666,"angle":-1.96},{"time":0.3333,"angle":-18.09},{"time":0.6333,"angle":-1.96},{"time":0.9,"angle":-18.09},{"time":1.0666,"angle":-6.57}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}],"scale":[{"time":0,"x":1.024,"y":1},{"time":0.0666,"x":1.072,"y":1},{"time":0.3333,"x":0.947,"y":1},{"time":0.6333,"x":1.072,"y":1},{"time":0.9,"x":0.903,"y":1},{"time":1.0666,"x":1.024,"y":1}]},"torso2":{"rotate":[{"time":0,"angle":8.6},{"time":0.2666,"angle":9.52,"curve":[0.25,0,0.75,1]},{"time":0.5333,"angle":8.01},{"time":0.8,"angle":5.48,"curve":[0.25,0,0.75,1]},{"time":1.0666,"angle":8.6}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_arm1":{"rotate":[{"time":0,"angle":0},{"time":0.5,"angle":-367.82},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":20.64,"y":-7.55},{"time":0.5,"x":-2.86,"y":3.32},{"time":0.8,"x":24.09,"y":-1.47},{"time":0.9333,"x":21.73,"y":-3.7},{"time":1.0666,"x":20.64,"y":-7.55}]},"front_leg3":{"rotate":[{"time":0,"angle":1.14,"curve":"stepped"},{"time":1.0666,"angle":1.14}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"neck":{"rotate":[{"time":0,"angle":6.5},{"time":0.2666,"angle":12.71},{"time":0.5333,"angle":6.5},{"time":0.8,"angle":12.71},{"time":1.0666,"angle":6.5}],"translate":[{"time":0,"x":12.59,"y":-31.3},{"time":0.2666,"x":-10.84,"y":-72.28,"curve":[0.204,0.01,0.861,0.86]},{"time":0.5333,"x":12.59,"y":-31.3},{"time":0.8,"x":-10.84,"y":-72.28,"curve":[0.204,0.01,0.861,0.86]},{"time":1.0666,"x":12.59,"y":-31.3}]},"rear_arm1":{"rotate":[{"time":0,"angle":0},{"time":0.5,"angle":13.71},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0},{"time":0.5,"x":11.12,"y":-13.38},{"time":1.0666,"x":0,"y":0}]},"rear_leg3":{"rotate":[{"time":0,"angle":-23.18,"curve":"stepped"},{"time":1.0666,"angle":-23.18}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_front1":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_rear1":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"tail3":{"rotate":[{"time":0,"angle":-14.83},{"time":0.0666,"angle":-24.31},{"time":0.3333,"angle":8.86},{"time":0.6333,"angle":-24.31},{"time":0.9,"angle":8.86},{"time":1.0666,"angle":-14.83}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}],"scale":[{"time":0,"x":0.995,"y":1},{"time":0.0666,"x":1,"y":1},{"time":0.3333,"x":0.947,"y":1},{"time":1.0666,"x":0.995,"y":1}]},"front_arm2":{"rotate":[{"time":0,"angle":0},{"time":0.5,"angle":22.44},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_foot1":{"rotate":[{"time":0,"angle":-41.33,"curve":"stepped"},{"time":1.0666,"angle":-41.33}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"head":{"rotate":[{"time":0,"angle":-7.36},{"time":0.1333,"angle":-12.99,"curve":[0.25,0,0.75,1]},{"time":0.4,"angle":-6.12},{"time":0.5333,"angle":-7.36},{"time":0.6666,"angle":-12.99,"curve":[0.25,0,0.75,1]},{"time":0.9333,"angle":-6.12},{"time":1.0666,"angle":-7.36}],"translate":[{"time":0,"x":-3.88,"y":-32.87},{"time":0.9333,"x":-3.33,"y":-22.81},{"time":1.0666,"x":-3.88,"y":-32.87}]},"rear_arm2":{"rotate":[{"time":0,"angle":0},{"time":0.5,"angle":-30.2},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_foot1":{"rotate":[{"time":0,"angle":2.07,"curve":"stepped"},{"time":1.0666,"angle":2.07}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_front2":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_rear2":{"rotate":[{"time":0,"angle":-4.44},{"time":0.1,"angle":-2.66},{"time":0.3,"angle":-0.35},{"time":0.4333,"angle":-1.7},{"time":0.6333,"angle":-2.54},{"time":0.9,"angle":-0.51},{"time":1.0666,"angle":-4.44}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"stirrup":{"rotate":[{"time":0,"angle":0},{"time":0.2666,"angle":-4.95},{"time":0.5333,"angle":0},{"time":0.8,"angle":-4.95},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":8.97,"y":4.99},{"time":0.2666,"x":4.85,"y":0.99},{"time":0.5333,"x":7.75,"y":-2.99},{"time":0.8,"x":4.85,"y":0.99},{"time":1.0666,"x":8.97,"y":4.99}]},"tail4":{"rotate":[{"time":0,"angle":16.99},{"time":0.0666,"angle":7.36},{"time":0.3333,"angle":41.06},{"time":0.6333,"angle":7.36},{"time":0.9,"angle":41.06},{"time":1.0666,"angle":16.99}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}],"scale":[{"time":0,"x":0.995,"y":1},{"time":0.0666,"x":1,"y":1},{"time":0.3333,"x":0.947,"y":1},{"time":1.0666,"x":0.995,"y":1}]},"front_foot2":{"rotate":[{"time":0,"angle":44.18},{"time":0.0666,"angle":7.88},{"time":0.1333,"angle":4.66},{"time":0.4,"angle":7.59},{"time":0.5333,"angle":8.08},{"time":0.6666,"angle":-67.33},{"time":0.7333,"angle":-65.23},{"time":1,"angle":42.33},{"time":1.0666,"angle":44.18}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_hand":{"rotate":[{"time":0,"angle":9.49},{"time":0.5,"angle":-48.6},{"time":1.0666,"angle":9.49}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"horn_front":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0},{"time":0.2666,"x":-7.18,"y":-1.38},{"time":0.5333,"x":0,"y":0},{"time":0.8,"x":-7.18,"y":-1.38},{"time":1.0666,"x":0,"y":0}]},"horn_rear":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0},{"time":0.2666,"x":12.34,"y":9.16},{"time":0.5333,"x":0,"y":0},{"time":0.8,"x":12.34,"y":9.16},{"time":1.0666,"x":0,"y":0}]},"jaw":{"rotate":[{"time":0,"angle":25.56},{"time":0.2,"angle":21.27},{"time":0.3333,"angle":21.35},{"time":0.6666,"angle":15.6},{"time":0.8666,"angle":22.96},{"time":1.0666,"angle":25.56}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_foot2":{"rotate":[{"time":0,"angle":0},{"time":0.1333,"angle":-82.37},{"time":0.2666,"angle":-110.3},{"time":0.4333,"angle":36.21},{"time":0.5333,"angle":2.1},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_hand":{"rotate":[{"time":0,"angle":-28.89},{"time":0.5,"angle":12.19},{"time":1.0666,"angle":-28.89}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_rear3":{"rotate":[{"time":0,"angle":-1.31},{"time":0.1,"angle":0.46},{"time":0.3,"angle":2.77},{"time":0.4333,"angle":1.42},{"time":0.6333,"angle":0.58},{"time":0.9,"angle":2.61},{"time":1.0666,"angle":-1.31}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"tail5":{"rotate":[{"time":0,"angle":-15.7},{"time":0.0666,"angle":-38.39},{"time":0.3333,"angle":41.03},{"time":0.6333,"angle":-38.39},{"time":0.9,"angle":41.03},{"time":1.0666,"angle":-15.7}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}],"scale":[{"time":0,"x":0.995,"y":1},{"time":0.0666,"x":1,"y":1},{"time":0.3333,"x":0.947,"y":1},{"time":1.0666,"x":0.995,"y":1}]},"tongue1":{"rotate":[{"time":0,"angle":0},{"time":0.3333,"angle":7.55},{"time":0.6666,"angle":-1.68},{"time":0.9333,"angle":8.11},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_foot3":{"rotate":[{"time":0,"angle":27.59},{"time":0.0666,"angle":-5.29},{"time":0.1333,"angle":-3.94},{"time":0.2666,"angle":-3.81},{"time":0.5333,"angle":-5.89},{"time":0.6,"angle":-21.2},{"time":0.6666,"angle":-73.63},{"time":0.7333,"angle":-102.81},{"time":0.8333,"angle":-41.3},{"time":1,"angle":27.59},{"time":1.0666,"angle":27.59}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"tongue2":{"rotate":[{"time":0,"angle":0},{"time":0.3333,"angle":7.55},{"time":0.6666,"angle":-1.68},{"time":0.9333,"angle":8.11},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"tongue3":{"rotate":[{"time":0,"angle":0},{"time":0.3333,"angle":7.55},{"time":0.6666,"angle":-1.68},{"time":0.9333,"angle":8.11},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"head2":{"rotate":[{"time":0,"angle":38.59},{"time":0.2666,"angle":43.18},{"time":0.5333,"angle":38.59},{"time":0.8,"angle":43.18},{"time":1.0666,"angle":38.59}]},"neck2":{"rotate":[{"time":0,"angle":9.65},{"time":0.2666,"angle":14.71},{"time":0.5333,"angle":9.65},{"time":0.8,"angle":14.71},{"time":1.0666,"angle":9.65}]},"spineboy_hip":{"translate":[{"time":0,"x":32.54,"y":1.34,"curve":[0.412,0,0.872,0.78]},{"time":0.2666,"x":-12.88,"y":0.58,"curve":[0.138,0.17,0.75,1]},{"time":0.5333,"x":32.54,"y":1.34,"curve":[0.367,0,0.867,0.81]},{"time":0.8,"x":-12.88,"y":0.58,"curve":[0.164,0.17,0.75,1]},{"time":1.0666,"x":32.54,"y":1.34}]},"spineboy_torso":{"rotate":[{"time":0,"angle":-37.93},{"time":0.2666,"angle":-29.47,"curve":[0.492,0,0.75,1]},{"time":0.5333,"angle":-37.93},{"time":0.8,"angle":-29.47,"curve":[0.492,0,0.75,1]},{"time":1.0666,"angle":-37.71}]},"front_arm":{"translate":[{"time":0,"x":0,"y":0},{"time":0.3333,"x":-14.43,"y":-11.03},{"time":0.5333,"x":0,"y":0},{"time":0.8,"x":-14.43,"y":-11.03},{"time":1.0666,"x":0,"y":0}]},"gun":{"rotate":[{"time":0,"angle":-11.68,"curve":[0.379,0.6,0.724,1]},{"time":0.0666,"angle":-17.59},{"time":0.3333,"angle":14.45,"curve":[0.25,0,0.75,1]},{"time":0.6,"angle":-24.74,"curve":[0.326,0,0.715,1]},{"time":0.8666,"angle":14.45,"curve":[0.242,0,0.666,0.66]},{"time":1.0666,"angle":-11.68}],"translate":[{"time":0,"x":0.84,"y":-3.81},{"time":0.0666,"x":0,"y":0},{"time":0.3333,"x":3.37,"y":-15.27},{"time":0.6,"x":0,"y":0},{"time":0.8666,"x":3.37,"y":-15.27},{"time":1.0666,"x":0.84,"y":-3.81}]}},"ffd":{"default":{"raptor_body":{"images/raptor_body":[{"time":0},{"time":0.2666,"offset":368,"vertices":[-16.78,15.47,-0.63,22.82,18.11,13.89,19.32,12.15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3.24,0.81,-3.24,0.81,-3.24,0.81,-3.24,0.81,-3.24,0.81,-3.24,0.81,0,0,0,0,0,0,-3.24,0.81,0,0,-3.24,0.81]},{"time":0.5333},{"time":0.8,"offset":368,"vertices":[-16.78,15.47,-0.63,22.82,18.11,13.89,19.32,12.15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3.24,0.81,-3.24,0.81,-3.24,0.81,-3.24,0.81,-3.24,0.81,-3.24,0.81,0,0,0,0,0,0,-3.24,0.81,0,0,-3.24,0.81]},{"time":1.0666}]},"raptor_front_leg":{"images/raptor_front_leg":[{"time":0,"curve":"stepped"},{"time":0.2666},{"time":0.5333,"offset":216,"vertices":[-2.23,21.95,21.54,-4.75]},{"time":0.6,"offset":216,"vertices":[7.17,15.14,15.26,-6.91]},{"time":0.7333,"offset":176,"vertices":[-0.82,0.73,-0.01,-1.1,-0.27,1.06,-1.28,0.39,0,0,0,0,0,0,1.48,-2.59,0.98,2.82,2.73,-10.49,6.12,8.95,-3.72,-10.18,-2.6,-2.28,3.43,-0.47,-3.44,-0.39,-2.28,-4.76,5.08,1.4,-4.58,-2.61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1.37,-1.75,2.22,0.1,-1.86,-0.75,-2.86,-0.77,2.45,-1.65]},{"time":0.8,"curve":"stepped"},{"time":0.9666,"curve":"stepped"},{"time":1.0666}]}}}}}} \ No newline at end of file diff --git a/spine-sfml/data/raptor.png b/spine-sfml/data/raptor.png new file mode 100644 index 000000000..861dbce1a Binary files /dev/null and b/spine-sfml/data/raptor.png differ diff --git a/spine-sfml/example/main.cpp b/spine-sfml/example/main.cpp index 223e26f73..817226845 100644 --- a/spine-sfml/example/main.cpp +++ b/spine-sfml/example/main.cpp @@ -101,7 +101,7 @@ void spineboy () { AnimationState_addAnimationByName(drawable->state, 0, "run", true, 0); } - sf::RenderWindow window(sf::VideoMode(640, 480), "Spine SFML"); + sf::RenderWindow window(sf::VideoMode(640, 480), "Spine SFML - spineboy"); window.setFramerateLimit(60); sf::Event event; sf::Clock deltaClock; @@ -163,7 +163,52 @@ void goblins () { AnimationState_setAnimation(drawable->state, 0, walkAnimation, true); - sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML"); + sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - goblins"); + window.setFramerateLimit(60); + sf::Event event; + sf::Clock deltaClock; + while (window.isOpen()) { + while (window.pollEvent(event)) + if (event.type == sf::Event::Closed) window.close(); + + float delta = deltaClock.getElapsedTime().asSeconds(); + deltaClock.restart(); + + drawable->update(delta); + + window.clear(); + 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); + } + Animation* walkAnimation = SkeletonData_findAnimation(skeletonData, "walk"); + SkeletonJson_dispose(json); + + SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); + drawable->timeScale = 1; + + Skeleton* skeleton = drawable->skeleton; + skeleton->x = 320; + skeleton->y = 590; + Skeleton_updateWorldTransform(skeleton); + + AnimationState_setAnimation(drawable->state, 0, walkAnimation, true); + + sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - raptor"); window.setFramerateLimit(60); sf::Event event; sf::Clock deltaClock; @@ -186,6 +231,7 @@ void goblins () { } int main () { + raptor(); spineboy(); goblins(); } diff --git a/spine-sfml/src/spine/spine-sfml.cpp b/spine-sfml/src/spine/spine-sfml.cpp index e1f5615cd..a4c794963 100644 --- a/spine-sfml/src/spine/spine-sfml.cpp +++ b/spine-sfml/src/spine/spine-sfml.cpp @@ -66,7 +66,7 @@ namespace spine { SkeletonDrawable::SkeletonDrawable (SkeletonData* skeletonData, AnimationStateData* stateData) : timeScale(1), - vertexArray(new VertexArray(Triangles, skeletonData->boneCount * 4)), + vertexArray(new VertexArray(Triangles, skeletonData->bonesCount * 4)), worldVertices(0) { Bone_setYDown(true); worldVertices = MALLOC(float, SPINE_MESH_VERTEX_COUNT_MAX); @@ -94,7 +94,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { sf::Vertex vertices[4]; sf::Vertex vertex; - for (int i = 0; i < skeleton->slotCount; ++i) { + for (int i = 0; i < skeleton->slotsCount; ++i) { Slot* slot = skeleton->drawOrder[i]; Attachment* attachment = slot->attachment; if (!attachment) continue; @@ -102,7 +102,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { if (attachment->type == ATTACHMENT_REGION) { RegionAttachment* regionAttachment = (RegionAttachment*)attachment; texture = (Texture*)((AtlasRegion*)regionAttachment->rendererObject)->page->rendererObject; - RegionAttachment_computeWorldVertices(regionAttachment, slot->skeleton->x, slot->skeleton->y, slot->bone, worldVertices); + RegionAttachment_computeWorldVertices(regionAttachment, slot->bone, worldVertices); Uint8 r = static_cast(skeleton->r * slot->r * 255); Uint8 g = static_cast(skeleton->g * slot->g * 255); @@ -157,7 +157,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { MeshAttachment* mesh = (MeshAttachment*)attachment; if (mesh->verticesCount > SPINE_MESH_VERTEX_COUNT_MAX) continue; texture = (Texture*)((AtlasRegion*)mesh->rendererObject)->page->rendererObject; - MeshAttachment_computeWorldVertices(mesh, slot->skeleton->x, slot->skeleton->y, slot, worldVertices); + MeshAttachment_computeWorldVertices(mesh, slot, worldVertices); Uint8 r = static_cast(skeleton->r * slot->r * 255); Uint8 g = static_cast(skeleton->g * slot->g * 255); @@ -182,7 +182,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { SkinnedMeshAttachment* mesh = (SkinnedMeshAttachment*)attachment; if (mesh->uvsCount > SPINE_MESH_VERTEX_COUNT_MAX) continue; texture = (Texture*)((AtlasRegion*)mesh->rendererObject)->page->rendererObject; - SkinnedMeshAttachment_computeWorldVertices(mesh, slot->skeleton->x, slot->skeleton->y, slot, worldVertices); + SkinnedMeshAttachment_computeWorldVertices(mesh, slot, worldVertices); Uint8 r = static_cast(skeleton->r * slot->r * 255); Uint8 g = static_cast(skeleton->g * slot->g * 255);