mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-14 02:58:44 +08:00
Added IK, refactoring.
Skeleton moved from Slot to Bone. Attachments no longer take x,y to compute vertices. Bezier curves are calculated up front.
This commit is contained in:
parent
2d5b2cdb87
commit
593956b51d
@ -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
|
||||
|
||||
@ -67,7 +67,7 @@ struct spAnimationState {
|
||||
float timeScale;
|
||||
spAnimationStateListener listener;
|
||||
|
||||
int trackCount;
|
||||
int tracksCount;
|
||||
spTrackEntry** tracks;
|
||||
|
||||
void* rendererObject;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
73
spine-c/include/spine/IkConstraint.h
Normal file
73
spine-c/include/spine/IkConstraint.h
Normal file
@ -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 <spine/IkConstraintData.h>
|
||||
#include <spine/Bone.h>
|
||||
|
||||
#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_ */
|
||||
65
spine-c/include/spine/IkConstraintData.h
Normal file
65
spine-c/include/spine/IkConstraintData.h
Normal file
@ -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 <spine/BoneData.h>
|
||||
|
||||
#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_ */
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#include <spine/SkeletonData.h>
|
||||
#include <spine/Slot.h>
|
||||
#include <spine/Skin.h>
|
||||
#include <spine/IkConstraint.h>
|
||||
|
||||
#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
|
||||
|
||||
@ -36,27 +36,35 @@
|
||||
#include <spine/Skin.h>
|
||||
#include <spine/EventData.h>
|
||||
#include <spine/Animation.h>
|
||||
#include <spine/IkConstraintData.h>
|
||||
|
||||
#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__)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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. */
|
||||
|
||||
@ -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 <stdlib.h>
|
||||
@ -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
|
||||
|
||||
@ -29,20 +29,21 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include <spine/Animation.h>
|
||||
#include <spine/IkConstraint.h>
|
||||
#include <limits.h>
|
||||
#include <spine/extension.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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];
|
||||
|
||||
129
spine-c/src/spine/IkConstraint.c
Normal file
129
spine-c/src/spine/IkConstraint.c
Normal file
@ -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 <spine/IkConstraint.h>
|
||||
#include <spine/Skeleton.h>
|
||||
#include <spine/extension.h>
|
||||
|
||||
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;
|
||||
}
|
||||
46
spine-c/src/spine/IkConstraintData.c
Normal file
46
spine-c/src/spine/IkConstraintData.c
Normal file
@ -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 <spine/IkConstraintData.h>
|
||||
#include <spine/extension.h>
|
||||
|
||||
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);
|
||||
}
|
||||
@ -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];
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -32,65 +32,88 @@
|
||||
#include <string.h>
|
||||
#include <spine/extension.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -30,17 +30,15 @@
|
||||
|
||||
#include <spine/Slot.h>
|
||||
#include <spine/extension.h>
|
||||
#include <spine/Skeleton.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
251
spine-sfml/data/raptor.atlas
Normal file
251
spine-sfml/data/raptor.atlas
Normal file
@ -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
|
||||
1
spine-sfml/data/raptor.json
Normal file
1
spine-sfml/data/raptor.json
Normal file
File diff suppressed because one or more lines are too long
BIN
spine-sfml/data/raptor.png
Normal file
BIN
spine-sfml/data/raptor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 550 KiB |
@ -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();
|
||||
}
|
||||
|
||||
@ -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<Uint8>(skeleton->r * slot->r * 255);
|
||||
Uint8 g = static_cast<Uint8>(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<Uint8>(skeleton->r * slot->r * 255);
|
||||
Uint8 g = static_cast<Uint8>(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<Uint8>(skeleton->r * slot->r * 255);
|
||||
Uint8 g = static_cast<Uint8>(skeleton->g * slot->g * 255);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user