mirror of https://github.com/axmolengine/axmol.git
Merge pull request #2746 from dumganhar/update-spine-runtime-master
fixed #2252: Updating spine-runtime to the latest version. [master]
This commit is contained in:
commit
d421c262ef
4
AUTHORS
4
AUTHORS
|
@ -354,6 +354,7 @@ Developers:
|
||||||
|
|
||||||
flamingo (flaming0)
|
flamingo (flaming0)
|
||||||
Null pointer check in order to prevent crashes.
|
Null pointer check in order to prevent crashes.
|
||||||
|
Updating spine-runtime to EsotericSoftware/spine-runtimes@5f90386.
|
||||||
|
|
||||||
rtissera (Romain TISSERAND)
|
rtissera (Romain TISSERAND)
|
||||||
Adding missing JNIEXPORT / JNICALL declarations.
|
Adding missing JNIEXPORT / JNICALL declarations.
|
||||||
|
@ -440,6 +441,9 @@ Developers:
|
||||||
Lee, Jae-Hong (pyrasis)
|
Lee, Jae-Hong (pyrasis)
|
||||||
Maintainer of tizen port.
|
Maintainer of tizen port.
|
||||||
|
|
||||||
|
lumendes
|
||||||
|
Updating spine-runtime to EsotericSoftware/spine-runtimes@5f90386.
|
||||||
|
|
||||||
Retired Core Developers:
|
Retired Core Developers:
|
||||||
WenSheng Yang
|
WenSheng Yang
|
||||||
Author of windows port, CCTextField,
|
Author of windows port, CCTextField,
|
||||||
|
|
|
@ -71,6 +71,8 @@ spine/Skin.cpp \
|
||||||
spine/Slot.cpp \
|
spine/Slot.cpp \
|
||||||
spine/SlotData.cpp \
|
spine/SlotData.cpp \
|
||||||
spine/extension.cpp \
|
spine/extension.cpp \
|
||||||
|
spine/CCSkeletonAnimation.cpp \
|
||||||
|
spine/CCSkeleton.cpp \
|
||||||
spine/spine-cocos2dx.cpp
|
spine/spine-cocos2dx.cpp
|
||||||
|
|
||||||
LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static
|
LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static
|
||||||
|
|
|
@ -74,7 +74,9 @@ SOURCES = ../CCBReader/CCBFileLoader.cpp \
|
||||||
../spine/Slot.cpp \
|
../spine/Slot.cpp \
|
||||||
../spine/SlotData.cpp \
|
../spine/SlotData.cpp \
|
||||||
../spine/extension.cpp \
|
../spine/extension.cpp \
|
||||||
../spine/spine-cocos2dx.cpp
|
../spine/spine-cocos2dx.cpp \
|
||||||
|
../spine/CCSkeleton.cpp \
|
||||||
|
../spine/CCSkeletonAnimation.cpp
|
||||||
|
|
||||||
include $(COCOS_ROOT)/cocos2dx/proj.linux/cocos2dx.mk
|
include $(COCOS_ROOT)/cocos2dx/proj.linux/cocos2dx.mk
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,8 @@ EXTENSIONS_SOURCES = ../CCBReader/CCBFileLoader.cpp \
|
||||||
../spine/Slot.cpp \
|
../spine/Slot.cpp \
|
||||||
../spine/SlotData.cpp \
|
../spine/SlotData.cpp \
|
||||||
../spine/extension.cpp \
|
../spine/extension.cpp \
|
||||||
|
../spine/CCSkeleton.cpp \
|
||||||
|
../spine/CCSkeletonAnimation.cpp \
|
||||||
../spine/spine-cocos2dx.cpp
|
../spine/spine-cocos2dx.cpp
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|
|
@ -148,6 +148,8 @@
|
||||||
<ClCompile Include="..\spine\AttachmentLoader.cpp" />
|
<ClCompile Include="..\spine\AttachmentLoader.cpp" />
|
||||||
<ClCompile Include="..\spine\Bone.cpp" />
|
<ClCompile Include="..\spine\Bone.cpp" />
|
||||||
<ClCompile Include="..\spine\BoneData.cpp" />
|
<ClCompile Include="..\spine\BoneData.cpp" />
|
||||||
|
<ClCompile Include="..\spine\CCSkeleton.cpp" />
|
||||||
|
<ClCompile Include="..\spine\CCSkeletonAnimation.cpp" />
|
||||||
<ClCompile Include="..\spine\extension.cpp" />
|
<ClCompile Include="..\spine\extension.cpp" />
|
||||||
<ClCompile Include="..\spine\Json.cpp" />
|
<ClCompile Include="..\spine\Json.cpp" />
|
||||||
<ClCompile Include="..\spine\RegionAttachment.cpp" />
|
<ClCompile Include="..\spine\RegionAttachment.cpp" />
|
||||||
|
@ -228,6 +230,8 @@
|
||||||
<ClInclude Include="..\spine\AttachmentLoader.h" />
|
<ClInclude Include="..\spine\AttachmentLoader.h" />
|
||||||
<ClInclude Include="..\spine\Bone.h" />
|
<ClInclude Include="..\spine\Bone.h" />
|
||||||
<ClInclude Include="..\spine\BoneData.h" />
|
<ClInclude Include="..\spine\BoneData.h" />
|
||||||
|
<ClInclude Include="..\spine\CCSkeleton.h" />
|
||||||
|
<ClInclude Include="..\spine\CCSkeletonAnimation.h" />
|
||||||
<ClInclude Include="..\spine\extension.h" />
|
<ClInclude Include="..\spine\extension.h" />
|
||||||
<ClInclude Include="..\spine\Json.h" />
|
<ClInclude Include="..\spine\Json.h" />
|
||||||
<ClInclude Include="..\spine\RegionAttachment.h" />
|
<ClInclude Include="..\spine\RegionAttachment.h" />
|
||||||
|
|
|
@ -234,6 +234,12 @@
|
||||||
<ClCompile Include="..\spine\spine-cocos2dx.cpp">
|
<ClCompile Include="..\spine\spine-cocos2dx.cpp">
|
||||||
<Filter>spine</Filter>
|
<Filter>spine</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\spine\CCSkeleton.cpp">
|
||||||
|
<Filter>spine</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\spine\CCSkeletonAnimation.cpp">
|
||||||
|
<Filter>spine</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\network\Websocket.cpp">
|
<ClCompile Include="..\network\Websocket.cpp">
|
||||||
<Filter>network</Filter>
|
<Filter>network</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -472,5 +478,11 @@
|
||||||
<ClInclude Include="..\network\Websocket.h">
|
<ClInclude Include="..\network\Websocket.h">
|
||||||
<Filter>network</Filter>
|
<Filter>network</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\spine\CCSkeleton.h">
|
||||||
|
<Filter>spine</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\spine\CCSkeletonAnimation.h">
|
||||||
|
<Filter>spine</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -42,21 +42,32 @@ void Animation_dispose (Animation* self) {
|
||||||
for (i = 0; i < self->timelineCount; ++i)
|
for (i = 0; i < self->timelineCount; ++i)
|
||||||
Timeline_dispose(self->timelines[i]);
|
Timeline_dispose(self->timelines[i]);
|
||||||
FREE(self->timelines);
|
FREE(self->timelines);
|
||||||
|
FREE(self->name);
|
||||||
FREE(self);
|
FREE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation_apply (const Animation* self, Skeleton* skeleton, float time, int/*bool*/loop) {
|
void Animation_apply (const Animation* self, Skeleton* skeleton, float time, int/*bool*/loop) {
|
||||||
if (loop && self->duration) time = fmodf(time, self->duration);
|
|
||||||
|
|
||||||
int i, n = self->timelineCount;
|
int i, n = self->timelineCount;
|
||||||
|
|
||||||
|
#ifdef __STDC_VERSION__
|
||||||
|
if (loop && self->duration) time = fmodf(time, self->duration);
|
||||||
|
#else
|
||||||
|
if (loop && self->duration) time = (float)fmod(time, self->duration);
|
||||||
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
Timeline_apply(self->timelines[i], skeleton, time, 1);
|
Timeline_apply(self->timelines[i], skeleton, time, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation_mix (const Animation* self, Skeleton* skeleton, float time, int/*bool*/loop, float alpha) {
|
void Animation_mix (const Animation* self, Skeleton* skeleton, float time, int/*bool*/loop, float alpha) {
|
||||||
if (loop && self->duration) time = fmodf(time, self->duration);
|
|
||||||
|
|
||||||
int i, n = self->timelineCount;
|
int i, n = self->timelineCount;
|
||||||
|
|
||||||
|
#ifdef __STDC_VERSION__
|
||||||
|
if (loop && self->duration) time = fmodf(time, self->duration);
|
||||||
|
#else
|
||||||
|
if (loop && self->duration) time = (float)fmod(time, self->duration);
|
||||||
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
Timeline_apply(self->timelines[i], skeleton, time, alpha);
|
Timeline_apply(self->timelines[i], skeleton, time, alpha);
|
||||||
}
|
}
|
||||||
|
@ -68,10 +79,10 @@ typedef struct _TimelineVtable {
|
||||||
void (*dispose) (Timeline* self);
|
void (*dispose) (Timeline* self);
|
||||||
} _TimelineVtable;
|
} _TimelineVtable;
|
||||||
|
|
||||||
void _Timeline_init (Timeline* self, //
|
void _Timeline_init (Timeline* self, /**/
|
||||||
void (*dispose) (Timeline* self), //
|
void (*dispose) (Timeline* self), /**/
|
||||||
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
|
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
|
||||||
CONST_CAST(void*, self->vtable) = NEW(_TimelineVtable);
|
CONST_CAST(_TimelineVtable*, self->vtable) = NEW(_TimelineVtable);
|
||||||
VTABLE(Timeline, self) ->dispose = dispose;
|
VTABLE(Timeline, self) ->dispose = dispose;
|
||||||
VTABLE(Timeline, self) ->apply = apply;
|
VTABLE(Timeline, self) ->apply = apply;
|
||||||
}
|
}
|
||||||
|
@ -94,8 +105,8 @@ static const float CURVE_LINEAR = 0;
|
||||||
static const float CURVE_STEPPED = -1;
|
static const float CURVE_STEPPED = -1;
|
||||||
static const int CURVE_SEGMENTS = 10;
|
static const int CURVE_SEGMENTS = 10;
|
||||||
|
|
||||||
void _CurveTimeline_init (CurveTimeline* self, int frameCount, //
|
void _CurveTimeline_init (CurveTimeline* self, int frameCount, /**/
|
||||||
void (*dispose) (Timeline* self), //
|
void (*dispose) (Timeline* self), /**/
|
||||||
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
|
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
|
||||||
_Timeline_init(SUPER(self), dispose, apply);
|
_Timeline_init(SUPER(self), dispose, apply);
|
||||||
self->curves = CALLOC(float, (frameCount - 1) * 6);
|
self->curves = CALLOC(float, (frameCount - 1) * 6);
|
||||||
|
@ -136,17 +147,24 @@ void CurveTimeline_setCurve (CurveTimeline* self, int frameIndex, float cx1, flo
|
||||||
}
|
}
|
||||||
|
|
||||||
float CurveTimeline_getCurvePercent (const CurveTimeline* self, int frameIndex, float percent) {
|
float CurveTimeline_getCurvePercent (const CurveTimeline* self, int frameIndex, float percent) {
|
||||||
|
float dfy;
|
||||||
|
float ddfx;
|
||||||
|
float ddfy;
|
||||||
|
float dddfx;
|
||||||
|
float dddfy;
|
||||||
|
float x, y;
|
||||||
|
int i;
|
||||||
int curveIndex = frameIndex * 6;
|
int curveIndex = frameIndex * 6;
|
||||||
float dfx = self->curves[curveIndex];
|
float dfx = self->curves[curveIndex];
|
||||||
if (dfx == CURVE_LINEAR) return percent;
|
if (dfx == CURVE_LINEAR) return percent;
|
||||||
if (dfx == CURVE_STEPPED) return 0;
|
if (dfx == CURVE_STEPPED) return 0;
|
||||||
float dfy = self->curves[curveIndex + 1];
|
dfy = self->curves[curveIndex + 1];
|
||||||
float ddfx = self->curves[curveIndex + 2];
|
ddfx = self->curves[curveIndex + 2];
|
||||||
float ddfy = self->curves[curveIndex + 3];
|
ddfy = self->curves[curveIndex + 3];
|
||||||
float dddfx = self->curves[curveIndex + 4];
|
dddfx = self->curves[curveIndex + 4];
|
||||||
float dddfy = self->curves[curveIndex + 5];
|
dddfy = self->curves[curveIndex + 5];
|
||||||
float x = dfx, y = dfy;
|
x = dfx, y = dfy;
|
||||||
int i = CURVE_SEGMENTS - 2;
|
i = CURVE_SEGMENTS - 2;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (x >= percent) {
|
if (x >= percent) {
|
||||||
float lastX = x - dfx;
|
float lastX = x - dfx;
|
||||||
|
@ -167,10 +185,10 @@ float CurveTimeline_getCurvePercent (const CurveTimeline* self, int frameIndex,
|
||||||
|
|
||||||
/* @param target After the first and before the last entry. */
|
/* @param target After the first and before the last entry. */
|
||||||
static int binarySearch (float *values, int valuesLength, float target, int step) {
|
static int binarySearch (float *values, int valuesLength, float target, int step) {
|
||||||
int low = 0;
|
int low = 0, current;
|
||||||
int high = valuesLength / step - 2;
|
int high = valuesLength / step - 2;
|
||||||
if (high == 0) return step;
|
if (high == 0) return step;
|
||||||
int current = high >> 1;
|
current = high >> 1;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (values[(current + 1) * step] <= target)
|
if (values[(current + 1) * step] <= target)
|
||||||
low = current + 1;
|
low = current + 1;
|
||||||
|
@ -201,7 +219,7 @@ void _BaseTimeline_dispose (Timeline* timeline) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Many timelines have structure identical to struct BaseTimeline and extend CurveTimeline. **/
|
/* Many timelines have structure identical to struct BaseTimeline and extend CurveTimeline. **/
|
||||||
struct BaseTimeline* _BaseTimeline_create (int frameCount, int frameSize, //
|
struct BaseTimeline* _BaseTimeline_create (int frameCount, int frameSize, /**/
|
||||||
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
|
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
|
||||||
|
|
||||||
struct BaseTimeline* self = NEW(struct BaseTimeline);
|
struct BaseTimeline* self = NEW(struct BaseTimeline);
|
||||||
|
@ -219,11 +237,15 @@ static const int ROTATE_LAST_FRAME_TIME = -2;
|
||||||
static const int ROTATE_FRAME_VALUE = 1;
|
static const int ROTATE_FRAME_VALUE = 1;
|
||||||
|
|
||||||
void _RotateTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
void _RotateTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
||||||
|
Bone *bone;
|
||||||
|
int frameIndex;
|
||||||
|
float lastFrameValue, frameTime, percent, amount;
|
||||||
|
|
||||||
RotateTimeline* self = SUB_CAST(RotateTimeline, timeline);
|
RotateTimeline* self = SUB_CAST(RotateTimeline, timeline);
|
||||||
|
|
||||||
if (time < self->frames[0]) return; /* Time is before first frame. */
|
if (time < self->frames[0]) return; /* Time is before first frame. */
|
||||||
|
|
||||||
Bone *bone = skeleton->bones[self->boneIndex];
|
bone = skeleton->bones[self->boneIndex];
|
||||||
|
|
||||||
if (time >= self->frames[self->framesLength - 2]) { /* Time is after last frame. */
|
if (time >= self->frames[self->framesLength - 2]) { /* Time is after last frame. */
|
||||||
float amount = bone->data->rotation + self->frames[self->framesLength - 1] - bone->rotation;
|
float amount = bone->data->rotation + self->frames[self->framesLength - 1] - bone->rotation;
|
||||||
|
@ -236,13 +258,13 @@ void _RotateTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interpolate between the last frame and the current frame. */
|
/* Interpolate between the last frame and the current frame. */
|
||||||
int frameIndex = binarySearch(self->frames, self->framesLength, time, 2);
|
frameIndex = binarySearch(self->frames, self->framesLength, time, 2);
|
||||||
float lastFrameValue = self->frames[frameIndex - 1];
|
lastFrameValue = self->frames[frameIndex - 1];
|
||||||
float frameTime = self->frames[frameIndex];
|
frameTime = self->frames[frameIndex];
|
||||||
float percent = 1 - (time - frameTime) / (self->frames[frameIndex + ROTATE_LAST_FRAME_TIME] - frameTime);
|
percent = 1 - (time - frameTime) / (self->frames[frameIndex + ROTATE_LAST_FRAME_TIME] - frameTime);
|
||||||
percent = CurveTimeline_getCurvePercent(SUPER(self), frameIndex / 2 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent));
|
percent = CurveTimeline_getCurvePercent(SUPER(self), frameIndex / 2 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent));
|
||||||
|
|
||||||
float amount = self->frames[frameIndex + ROTATE_FRAME_VALUE] - lastFrameValue;
|
amount = self->frames[frameIndex + ROTATE_FRAME_VALUE] - lastFrameValue;
|
||||||
while (amount > 180)
|
while (amount > 180)
|
||||||
amount -= 360;
|
amount -= 360;
|
||||||
while (amount < -180)
|
while (amount < -180)
|
||||||
|
@ -272,11 +294,15 @@ static const int TRANSLATE_FRAME_X = 1;
|
||||||
static const int TRANSLATE_FRAME_Y = 2;
|
static const int TRANSLATE_FRAME_Y = 2;
|
||||||
|
|
||||||
void _TranslateTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
void _TranslateTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
||||||
|
Bone *bone;
|
||||||
|
int frameIndex;
|
||||||
|
float lastFrameX, lastFrameY, frameTime, percent;
|
||||||
|
|
||||||
TranslateTimeline* self = SUB_CAST(TranslateTimeline, timeline);
|
TranslateTimeline* self = SUB_CAST(TranslateTimeline, timeline);
|
||||||
|
|
||||||
if (time < self->frames[0]) return; /* Time is before first frame. */
|
if (time < self->frames[0]) return; /* Time is before first frame. */
|
||||||
|
|
||||||
Bone *bone = skeleton->bones[self->boneIndex];
|
bone = skeleton->bones[self->boneIndex];
|
||||||
|
|
||||||
if (time >= self->frames[self->framesLength - 3]) { /* Time is after last frame. */
|
if (time >= self->frames[self->framesLength - 3]) { /* Time is after last frame. */
|
||||||
bone->x += (bone->data->x + self->frames[self->framesLength - 2] - bone->x) * alpha;
|
bone->x += (bone->data->x + self->frames[self->framesLength - 2] - bone->x) * alpha;
|
||||||
|
@ -285,11 +311,11 @@ void _TranslateTimeline_apply (const Timeline* timeline, Skeleton* skeleton, flo
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interpolate between the last frame and the current frame. */
|
/* Interpolate between the last frame and the current frame. */
|
||||||
int frameIndex = binarySearch(self->frames, self->framesLength, time, 3);
|
frameIndex = binarySearch(self->frames, self->framesLength, time, 3);
|
||||||
float lastFrameX = self->frames[frameIndex - 2];
|
lastFrameX = self->frames[frameIndex - 2];
|
||||||
float lastFrameY = self->frames[frameIndex - 1];
|
lastFrameY = self->frames[frameIndex - 1];
|
||||||
float frameTime = self->frames[frameIndex];
|
frameTime = self->frames[frameIndex];
|
||||||
float percent = 1 - (time - frameTime) / (self->frames[frameIndex + TRANSLATE_LAST_FRAME_TIME] - frameTime);
|
percent = 1 - (time - frameTime) / (self->frames[frameIndex + TRANSLATE_LAST_FRAME_TIME] - frameTime);
|
||||||
percent = CurveTimeline_getCurvePercent(SUPER(self), frameIndex / 3 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent));
|
percent = CurveTimeline_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 + lastFrameX + (self->frames[frameIndex + TRANSLATE_FRAME_X] - lastFrameX) * percent - bone->x)
|
||||||
|
@ -312,11 +338,15 @@ void TranslateTimeline_setFrame (TranslateTimeline* self, int frameIndex, float
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
void _ScaleTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
void _ScaleTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
||||||
|
Bone *bone;
|
||||||
|
int frameIndex;
|
||||||
|
float lastFrameX, lastFrameY, frameTime, percent;
|
||||||
|
|
||||||
ScaleTimeline* self = SUB_CAST(ScaleTimeline, timeline);
|
ScaleTimeline* self = SUB_CAST(ScaleTimeline, timeline);
|
||||||
|
|
||||||
if (time < self->frames[0]) return; /* Time is before first frame. */
|
if (time < self->frames[0]) return; /* Time is before first frame. */
|
||||||
|
|
||||||
Bone *bone = skeleton->bones[self->boneIndex];
|
bone = skeleton->bones[self->boneIndex];
|
||||||
if (time >= self->frames[self->framesLength - 3]) { /* Time is after last frame. */
|
if (time >= self->frames[self->framesLength - 3]) { /* Time is after last frame. */
|
||||||
bone->scaleX += (bone->data->scaleX - 1 + self->frames[self->framesLength - 2] - bone->scaleX) * alpha;
|
bone->scaleX += (bone->data->scaleX - 1 + self->frames[self->framesLength - 2] - bone->scaleX) * alpha;
|
||||||
bone->scaleY += (bone->data->scaleY - 1 + self->frames[self->framesLength - 1] - bone->scaleY) * alpha;
|
bone->scaleY += (bone->data->scaleY - 1 + self->frames[self->framesLength - 1] - bone->scaleY) * alpha;
|
||||||
|
@ -324,11 +354,11 @@ void _ScaleTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float t
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interpolate between the last frame and the current frame. */
|
/* Interpolate between the last frame and the current frame. */
|
||||||
int frameIndex = binarySearch(self->frames, self->framesLength, time, 3);
|
frameIndex = binarySearch(self->frames, self->framesLength, time, 3);
|
||||||
float lastFrameX = self->frames[frameIndex - 2];
|
lastFrameX = self->frames[frameIndex - 2];
|
||||||
float lastFrameY = self->frames[frameIndex - 1];
|
lastFrameY = self->frames[frameIndex - 1];
|
||||||
float frameTime = self->frames[frameIndex];
|
frameTime = self->frames[frameIndex];
|
||||||
float percent = 1 - (time - frameTime) / (self->frames[frameIndex + TRANSLATE_LAST_FRAME_TIME] - frameTime);
|
percent = 1 - (time - frameTime) / (self->frames[frameIndex + TRANSLATE_LAST_FRAME_TIME] - frameTime);
|
||||||
percent = CurveTimeline_getCurvePercent(SUPER(self), frameIndex / 3 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent));
|
percent = CurveTimeline_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 + lastFrameX + (self->frames[frameIndex + TRANSLATE_FRAME_X] - lastFrameX) * percent
|
||||||
|
@ -354,11 +384,15 @@ static const int COLOR_FRAME_B = 3;
|
||||||
static const int COLOR_FRAME_A = 4;
|
static const int COLOR_FRAME_A = 4;
|
||||||
|
|
||||||
void _ColorTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
void _ColorTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
||||||
|
Slot *slot;
|
||||||
|
int frameIndex;
|
||||||
|
float lastFrameR, lastFrameG, lastFrameB, lastFrameA, percent, frameTime;
|
||||||
|
float r, g, b, a;
|
||||||
ColorTimeline* self = (ColorTimeline*)timeline;
|
ColorTimeline* self = (ColorTimeline*)timeline;
|
||||||
|
|
||||||
if (time < self->frames[0]) return; /* Time is before first frame. */
|
if (time < self->frames[0]) return; /* Time is before first frame. */
|
||||||
|
|
||||||
Slot *slot = skeleton->slots[self->slotIndex];
|
slot = skeleton->slots[self->slotIndex];
|
||||||
|
|
||||||
if (time >= self->frames[self->framesLength - 5]) { /* Time is after last frame. */
|
if (time >= self->frames[self->framesLength - 5]) { /* Time is after last frame. */
|
||||||
int i = self->framesLength - 1;
|
int i = self->framesLength - 1;
|
||||||
|
@ -370,19 +404,19 @@ void _ColorTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float t
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interpolate between the last frame and the current frame. */
|
/* Interpolate between the last frame and the current frame. */
|
||||||
int frameIndex = binarySearch(self->frames, self->framesLength, time, 5);
|
frameIndex = binarySearch(self->frames, self->framesLength, time, 5);
|
||||||
float lastFrameR = self->frames[frameIndex - 4];
|
lastFrameR = self->frames[frameIndex - 4];
|
||||||
float lastFrameG = self->frames[frameIndex - 3];
|
lastFrameG = self->frames[frameIndex - 3];
|
||||||
float lastFrameB = self->frames[frameIndex - 2];
|
lastFrameB = self->frames[frameIndex - 2];
|
||||||
float lastFrameA = self->frames[frameIndex - 1];
|
lastFrameA = self->frames[frameIndex - 1];
|
||||||
float frameTime = self->frames[frameIndex];
|
frameTime = self->frames[frameIndex];
|
||||||
float percent = 1 - (time - frameTime) / (self->frames[frameIndex + COLOR_LAST_FRAME_TIME] - frameTime);
|
percent = 1 - (time - frameTime) / (self->frames[frameIndex + COLOR_LAST_FRAME_TIME] - frameTime);
|
||||||
percent = CurveTimeline_getCurvePercent(SUPER(self), frameIndex / 5 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent));
|
percent = CurveTimeline_getCurvePercent(SUPER(self), frameIndex / 5 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent));
|
||||||
|
|
||||||
float r = lastFrameR + (self->frames[frameIndex + COLOR_FRAME_R] - lastFrameR) * percent;
|
r = lastFrameR + (self->frames[frameIndex + COLOR_FRAME_R] - lastFrameR) * percent;
|
||||||
float g = lastFrameG + (self->frames[frameIndex + COLOR_FRAME_G] - lastFrameG) * percent;
|
g = lastFrameG + (self->frames[frameIndex + COLOR_FRAME_G] - lastFrameG) * percent;
|
||||||
float b = lastFrameB + (self->frames[frameIndex + COLOR_FRAME_B] - lastFrameB) * percent;
|
b = lastFrameB + (self->frames[frameIndex + COLOR_FRAME_B] - lastFrameB) * percent;
|
||||||
float a = lastFrameA + (self->frames[frameIndex + COLOR_FRAME_A] - lastFrameA) * percent;
|
a = lastFrameA + (self->frames[frameIndex + COLOR_FRAME_A] - lastFrameA) * percent;
|
||||||
if (alpha < 1) {
|
if (alpha < 1) {
|
||||||
slot->r += (r - slot->r) * alpha;
|
slot->r += (r - slot->r) * alpha;
|
||||||
slot->g += (g - slot->g) * alpha;
|
slot->g += (g - slot->g) * alpha;
|
||||||
|
@ -412,30 +446,33 @@ void ColorTimeline_setFrame (ColorTimeline* self, int frameIndex, float time, fl
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
void _AttachmentTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
void _AttachmentTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float time, float alpha) {
|
||||||
|
int frameIndex;
|
||||||
|
const char* attachmentName;
|
||||||
AttachmentTimeline* self = (AttachmentTimeline*)timeline;
|
AttachmentTimeline* self = (AttachmentTimeline*)timeline;
|
||||||
|
|
||||||
if (time < self->frames[0]) return; /* Time is before first frame. */
|
if (time < self->frames[0]) return; /* Time is before first frame. */
|
||||||
|
|
||||||
int frameIndex;
|
|
||||||
if (time >= self->frames[self->framesLength - 1]) /* Time is after last frame. */
|
if (time >= self->frames[self->framesLength - 1]) /* Time is after last frame. */
|
||||||
frameIndex = self->framesLength - 1;
|
frameIndex = self->framesLength - 1;
|
||||||
else
|
else
|
||||||
frameIndex = binarySearch(self->frames, self->framesLength, time, 1) - 1;
|
frameIndex = binarySearch(self->frames, self->framesLength, time, 1) - 1;
|
||||||
|
|
||||||
const char* attachmentName = self->attachmentNames[frameIndex];
|
attachmentName = self->attachmentNames[frameIndex];
|
||||||
Slot_setAttachment(skeleton->slots[self->slotIndex],
|
Slot_setAttachment(skeleton->slots[self->slotIndex],
|
||||||
attachmentName ? Skeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0);
|
attachmentName ? Skeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _AttachmentTimeline_dispose (Timeline* timeline) {
|
void _AttachmentTimeline_dispose (Timeline* timeline) {
|
||||||
_Timeline_deinit(timeline);
|
AttachmentTimeline* self;
|
||||||
AttachmentTimeline* self = (AttachmentTimeline*)timeline;
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
_Timeline_deinit(timeline);
|
||||||
|
self = (AttachmentTimeline*)timeline;
|
||||||
|
|
||||||
for (i = 0; i < self->framesLength; ++i)
|
for (i = 0; i < self->framesLength; ++i)
|
||||||
FREE(self->attachmentNames[i]);
|
FREE(self->attachmentNames[i]);
|
||||||
FREE(self->attachmentNames);
|
FREE(self->attachmentNames);
|
||||||
|
FREE(self->frames);
|
||||||
FREE(self);
|
FREE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,18 @@
|
||||||
|
|
||||||
#include <spine/AnimationState.h>
|
#include <spine/AnimationState.h>
|
||||||
#include <spine/extension.h>
|
#include <spine/extension.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace cocos2d { namespace extension {
|
namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
typedef struct _Entry _Entry;
|
||||||
|
struct _Entry {
|
||||||
|
Animation* animation;
|
||||||
|
int/*bool*/loop;
|
||||||
|
float delay;
|
||||||
|
_Entry* next;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
AnimationState super;
|
AnimationState super;
|
||||||
Animation *previous;
|
Animation *previous;
|
||||||
|
@ -35,6 +44,7 @@ typedef struct {
|
||||||
int/*bool*/previousLoop;
|
int/*bool*/previousLoop;
|
||||||
float mixTime;
|
float mixTime;
|
||||||
float mixDuration;
|
float mixDuration;
|
||||||
|
_Entry* queue;
|
||||||
} _Internal;
|
} _Internal;
|
||||||
|
|
||||||
AnimationState* AnimationState_create (AnimationStateData* data) {
|
AnimationState* AnimationState_create (AnimationStateData* data) {
|
||||||
|
@ -43,37 +53,57 @@ AnimationState* AnimationState_create (AnimationStateData* data) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _AnimationState_clearQueue (AnimationState* self) {
|
||||||
|
_Internal* internal = SUB_CAST(_Internal, self);
|
||||||
|
_Entry* entry = internal->queue;
|
||||||
|
while (entry) {
|
||||||
|
_Entry* nextEntry = entry->next;
|
||||||
|
FREE(entry);
|
||||||
|
entry = nextEntry;
|
||||||
|
}
|
||||||
|
internal->queue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationState_dispose (AnimationState* self) {
|
void AnimationState_dispose (AnimationState* self) {
|
||||||
|
_AnimationState_clearQueue(self);
|
||||||
FREE(self);
|
FREE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationState_update (AnimationState* self, float delta) {
|
void AnimationState_addAnimation (AnimationState* self, Animation* animation, int/*bool*/loop, float delay) {
|
||||||
self->time += delta;
|
_Entry* existingEntry;
|
||||||
SUB_CAST(_Internal, self) ->previousTime += delta;
|
Animation* previousAnimation;
|
||||||
SUB_CAST(_Internal, self) ->mixTime += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimationState_apply (AnimationState* self, Skeleton* skeleton) {
|
|
||||||
if (!self->animation) return;
|
|
||||||
_Internal* internal = SUB_CAST(_Internal, self);
|
_Internal* internal = SUB_CAST(_Internal, self);
|
||||||
if (internal->previous) {
|
_Entry* entry = NEW(_Entry);
|
||||||
Animation_apply(internal->previous, skeleton, internal->previousTime, internal->previousLoop);
|
entry->animation = animation;
|
||||||
float alpha = internal->mixTime / internal->mixDuration;
|
entry->loop = loop;
|
||||||
if (alpha >= 1) {
|
|
||||||
alpha = 1;
|
existingEntry = internal->queue;
|
||||||
internal->previous = 0;
|
if (existingEntry) {
|
||||||
|
while (existingEntry->next)
|
||||||
|
existingEntry = existingEntry->next;
|
||||||
|
existingEntry->next = entry;
|
||||||
|
previousAnimation = existingEntry->animation;
|
||||||
|
} else {
|
||||||
|
internal->queue = entry;
|
||||||
|
previousAnimation = self->animation;
|
||||||
}
|
}
|
||||||
Animation_mix(self->animation, skeleton, self->time, self->loop, alpha);
|
|
||||||
} else
|
if (delay <= 0) {
|
||||||
Animation_apply(self->animation, skeleton, self->time, self->loop);
|
if (previousAnimation)
|
||||||
|
delay = previousAnimation->duration - AnimationStateData_getMix(self->data, previousAnimation, animation) + delay;
|
||||||
|
else
|
||||||
|
delay = 0;
|
||||||
|
}
|
||||||
|
entry->delay = delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationState_setAnimationByName (AnimationState* self, const char* animationName, int/**/loop) {
|
void AnimationState_addAnimationByName (AnimationState* self, const char* animationName, int/*bool*/loop, float delay) {
|
||||||
Animation* animation = SkeletonData_findAnimation(self->data->skeletonData, animationName);
|
Animation* animation = animationName ? SkeletonData_findAnimation(self->data->skeletonData, animationName) : 0;
|
||||||
AnimationState_setAnimation(self, animation, loop);
|
AnimationState_addAnimation(self, animation, loop, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationState_setAnimation (AnimationState* self, Animation* newAnimation, int/**/loop) {
|
void _AnimationState_setAnimation (AnimationState* self, Animation* newAnimation, int/*bool*/loop) {
|
||||||
_Internal* internal = SUB_CAST(_Internal, self);
|
_Internal* internal = SUB_CAST(_Internal, self);
|
||||||
internal->previous = 0;
|
internal->previous = 0;
|
||||||
if (newAnimation && self->animation && self->data) {
|
if (newAnimation && self->animation && self->data) {
|
||||||
|
@ -90,9 +120,55 @@ void AnimationState_setAnimation (AnimationState* self, Animation* newAnimation,
|
||||||
self->time = 0;
|
self->time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimationState_setAnimation (AnimationState* self, Animation* newAnimation, int/*bool*/loop) {
|
||||||
|
_AnimationState_clearQueue(self);
|
||||||
|
_AnimationState_setAnimation(self, newAnimation, loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationState_setAnimationByName (AnimationState* self, const char* animationName, int/*bool*/loop) {
|
||||||
|
Animation* animation = animationName ? SkeletonData_findAnimation(self->data->skeletonData, animationName) : 0;
|
||||||
|
AnimationState_setAnimation(self, animation, loop);
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationState_clearAnimation (AnimationState* self) {
|
void AnimationState_clearAnimation (AnimationState* self) {
|
||||||
SUB_CAST(_Internal, self) ->previous = 0;
|
_Internal* internal = SUB_CAST(_Internal, self);
|
||||||
|
internal->previous = 0;
|
||||||
CONST_CAST(Animation*, self->animation) = 0;
|
CONST_CAST(Animation*, self->animation) = 0;
|
||||||
|
_AnimationState_clearQueue(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationState_update (AnimationState* self, float delta) {
|
||||||
|
_Entry* next;
|
||||||
|
_Internal* internal = SUB_CAST(_Internal, self);
|
||||||
|
|
||||||
|
self->time += delta;
|
||||||
|
internal->previousTime += delta;
|
||||||
|
internal->mixTime += delta;
|
||||||
|
|
||||||
|
if (internal->queue && self->time >= internal->queue->delay) {
|
||||||
|
_AnimationState_setAnimation(self, internal->queue->animation, internal->queue->loop);
|
||||||
|
next = internal->queue->next;
|
||||||
|
FREE(internal->queue);
|
||||||
|
internal->queue = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationState_apply (AnimationState* self, Skeleton* skeleton) {
|
||||||
|
_Internal* internal;
|
||||||
|
float alpha;
|
||||||
|
|
||||||
|
if (!self->animation) return;
|
||||||
|
internal = SUB_CAST(_Internal, self);
|
||||||
|
if (internal->previous) {
|
||||||
|
Animation_apply(internal->previous, skeleton, internal->previousTime, internal->previousLoop);
|
||||||
|
alpha = internal->mixTime / internal->mixDuration;
|
||||||
|
if (alpha >= 1) {
|
||||||
|
alpha = 1;
|
||||||
|
internal->previous = 0;
|
||||||
|
}
|
||||||
|
Animation_mix(self->animation, skeleton, self->time, self->loop, alpha);
|
||||||
|
} else
|
||||||
|
Animation_apply(self->animation, skeleton, self->time, self->loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
int/*bool*/AnimationState_isComplete (AnimationState* self) {
|
int/*bool*/AnimationState_isComplete (AnimationState* self) {
|
||||||
|
|
|
@ -46,9 +46,17 @@ void AnimationState_update (AnimationState* self, float delta);
|
||||||
void AnimationState_apply (AnimationState* self, struct Skeleton* skeleton);
|
void AnimationState_apply (AnimationState* self, struct Skeleton* skeleton);
|
||||||
|
|
||||||
/* @param animationName May be 0. */
|
/* @param animationName May be 0. */
|
||||||
void AnimationState_setAnimationByName (AnimationState* self, const char* animationName, int/**/loop);
|
void AnimationState_setAnimationByName (AnimationState* self, const char* animationName, int/*bool*/loop);
|
||||||
/* @param animation May be 0. */
|
/* @param animation May be 0. */
|
||||||
void AnimationState_setAnimation (AnimationState* self, Animation* animation, int/**/loop);
|
void AnimationState_setAnimation (AnimationState* self, Animation* animation, int/*bool*/loop);
|
||||||
|
|
||||||
|
/** @param animationName May be 0.
|
||||||
|
* @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */
|
||||||
|
void AnimationState_addAnimationByName (AnimationState* self, const char* animationName, int/*bool*/loop, float delay);
|
||||||
|
/** @param animation May be 0.
|
||||||
|
* @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */
|
||||||
|
void AnimationState_addAnimation (AnimationState* self, Animation* animation, int/*bool*/loop, float delay);
|
||||||
|
|
||||||
void AnimationState_clearAnimation (AnimationState* self);
|
void AnimationState_clearAnimation (AnimationState* self);
|
||||||
|
|
||||||
int/*bool*/AnimationState_isComplete (AnimationState* self);
|
int/*bool*/AnimationState_isComplete (AnimationState* self);
|
||||||
|
|
|
@ -74,37 +74,43 @@ AnimationStateData* AnimationStateData_create (SkeletonData* skeletonData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationStateData_dispose (AnimationStateData* self) {
|
void AnimationStateData_dispose (AnimationStateData* self) {
|
||||||
|
_ToEntry* toEntry;
|
||||||
|
_ToEntry* nextToEntry;
|
||||||
|
_FromEntry* nextFromEntry;
|
||||||
|
|
||||||
_FromEntry* fromEntry = (_FromEntry*)self->entries;
|
_FromEntry* fromEntry = (_FromEntry*)self->entries;
|
||||||
while (fromEntry) {
|
while (fromEntry) {
|
||||||
_ToEntry* toEntry = fromEntry->toEntries;
|
toEntry = fromEntry->toEntries;
|
||||||
while (toEntry) {
|
while (toEntry) {
|
||||||
_ToEntry* next = toEntry->next;
|
nextToEntry = toEntry->next;
|
||||||
_ToEntry_dispose(toEntry);
|
_ToEntry_dispose(toEntry);
|
||||||
toEntry = next;
|
toEntry = nextToEntry;
|
||||||
}
|
}
|
||||||
_FromEntry* next = fromEntry->next;
|
nextFromEntry = fromEntry->next;
|
||||||
_FromEntry_dispose(fromEntry);
|
_FromEntry_dispose(fromEntry);
|
||||||
fromEntry = next;
|
fromEntry = nextFromEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
FREE(self);
|
FREE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationStateData_setMixByName (AnimationStateData* self, const char* fromName, const char* toName, float duration) {
|
void AnimationStateData_setMixByName (AnimationStateData* self, const char* fromName, const char* toName, float duration) {
|
||||||
|
Animation* to;
|
||||||
Animation* from = SkeletonData_findAnimation(self->skeletonData, fromName);
|
Animation* from = SkeletonData_findAnimation(self->skeletonData, fromName);
|
||||||
if (!from) return;
|
if (!from) return;
|
||||||
Animation* to = SkeletonData_findAnimation(self->skeletonData, toName);
|
to = SkeletonData_findAnimation(self->skeletonData, toName);
|
||||||
if (!to) return;
|
if (!to) return;
|
||||||
AnimationStateData_setMix(self, from, to, duration);
|
AnimationStateData_setMix(self, from, to, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationStateData_setMix (AnimationStateData* self, Animation* from, Animation* to, float duration) {
|
void AnimationStateData_setMix (AnimationStateData* self, Animation* from, Animation* to, float duration) {
|
||||||
/* Find existing FromEntry. */
|
/* Find existing FromEntry. */
|
||||||
|
_ToEntry* toEntry;
|
||||||
_FromEntry* fromEntry = (_FromEntry*)self->entries;
|
_FromEntry* fromEntry = (_FromEntry*)self->entries;
|
||||||
while (fromEntry) {
|
while (fromEntry) {
|
||||||
if (fromEntry->animation == from) {
|
if (fromEntry->animation == from) {
|
||||||
/* Find existing ToEntry. */
|
/* Find existing ToEntry. */
|
||||||
_ToEntry* toEntry = fromEntry->toEntries;
|
toEntry = fromEntry->toEntries;
|
||||||
while (toEntry) {
|
while (toEntry) {
|
||||||
if (toEntry->animation == to) {
|
if (toEntry->animation == to) {
|
||||||
toEntry->duration = duration;
|
toEntry->duration = duration;
|
||||||
|
@ -119,9 +125,9 @@ void AnimationStateData_setMix (AnimationStateData* self, Animation* from, Anima
|
||||||
if (!fromEntry) {
|
if (!fromEntry) {
|
||||||
fromEntry = _FromEntry_create(from);
|
fromEntry = _FromEntry_create(from);
|
||||||
fromEntry->next = (_FromEntry*)self->entries;
|
fromEntry->next = (_FromEntry*)self->entries;
|
||||||
CONST_CAST(void*, self->entries) = fromEntry;
|
CONST_CAST(_FromEntry*, self->entries) = fromEntry;
|
||||||
}
|
}
|
||||||
_ToEntry* toEntry = _ToEntry_create(to, duration);
|
toEntry = _ToEntry_create(to, duration);
|
||||||
toEntry->next = fromEntry->toEntries;
|
toEntry->next = fromEntry->toEntries;
|
||||||
fromEntry->toEntries = toEntry;
|
fromEntry->toEntries = toEntry;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,9 @@ AtlasPage* AtlasPage_create (const char* name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtlasPage_dispose (AtlasPage* self) {
|
void AtlasPage_dispose (AtlasPage* self) {
|
||||||
FREE(self->name);
|
|
||||||
_AtlasPage_disposeTexture(self);
|
_AtlasPage_disposeTexture(self);
|
||||||
|
FREE(self->name);
|
||||||
|
FREE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -55,14 +56,9 @@ void AtlasRegion_dispose (AtlasRegion* self) {
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
typedef struct _struct_Str {
|
typedef struct {
|
||||||
const char* begin;
|
const char* begin;
|
||||||
const char* end;
|
const char* end;
|
||||||
|
|
||||||
_struct_Str()
|
|
||||||
: begin(NULL)
|
|
||||||
, end(NULL) {
|
|
||||||
}
|
|
||||||
} Str;
|
} Str;
|
||||||
|
|
||||||
static void trim (Str* str) {
|
static void trim (Str* str) {
|
||||||
|
@ -119,10 +115,11 @@ static int readValue (const char* end, Str* str) {
|
||||||
|
|
||||||
/* Returns the number of tuple values read (2, 4, or 0 for failure). */
|
/* Returns the number of tuple values read (2, 4, or 0 for failure). */
|
||||||
static int readTuple (const char* end, Str tuple[]) {
|
static int readTuple (const char* end, Str tuple[]) {
|
||||||
|
int i;
|
||||||
Str str;
|
Str str;
|
||||||
readLine(0, end, &str);
|
readLine(0, end, &str);
|
||||||
if (!beginPast(&str, ':')) return 0;
|
if (!beginPast(&str, ':')) return 0;
|
||||||
int i = 0;
|
|
||||||
for (i = 0; i < 3; ++i) {
|
for (i = 0; i < 3; ++i) {
|
||||||
tuple[i].begin = str.begin;
|
tuple[i].begin = str.begin;
|
||||||
if (!beginPast(&str, ',')) {
|
if (!beginPast(&str, ',')) {
|
||||||
|
@ -172,6 +169,7 @@ static const char* textureFilterNames[] = {"Nearest", "Linear", "MipMap", "MipMa
|
||||||
"MipMapNearestLinear", "MipMapLinearLinear"};
|
"MipMapNearestLinear", "MipMapLinearLinear"};
|
||||||
|
|
||||||
Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
|
Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
|
||||||
|
int count;
|
||||||
const char* end = begin + length;
|
const char* end = begin + length;
|
||||||
int dirLength = strlen(dir);
|
int dirLength = strlen(dir);
|
||||||
int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
|
int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
|
||||||
|
@ -241,10 +239,14 @@ Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
|
||||||
|
|
||||||
region->u = region->x / (float)page->width;
|
region->u = region->x / (float)page->width;
|
||||||
region->v = region->y / (float)page->height;
|
region->v = region->y / (float)page->height;
|
||||||
|
if (region->rotate) {
|
||||||
|
region->u2 = (region->x + region->height) / (float)page->width;
|
||||||
|
region->v2 = (region->y + region->width) / (float)page->height;
|
||||||
|
} else {
|
||||||
region->u2 = (region->x + region->width) / (float)page->width;
|
region->u2 = (region->x + region->width) / (float)page->width;
|
||||||
region->v2 = (region->y + region->height) / (float)page->height;
|
region->v2 = (region->y + region->height) / (float)page->height;
|
||||||
|
}
|
||||||
|
|
||||||
int count;
|
|
||||||
if (!(count = readTuple(end, tuple))) return abortAtlas(self);
|
if (!(count = readTuple(end, tuple))) return abortAtlas(self);
|
||||||
if (count == 4) { /* split is optional */
|
if (count == 4) { /* split is optional */
|
||||||
region->splits = MALLOC(int, 4);
|
region->splits = MALLOC(int, 4);
|
||||||
|
@ -269,8 +271,8 @@ Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
|
||||||
region->originalHeight = toInt(tuple + 1);
|
region->originalHeight = toInt(tuple + 1);
|
||||||
|
|
||||||
readTuple(end, tuple);
|
readTuple(end, tuple);
|
||||||
region->offsetX = (float)toInt(tuple);
|
region->offsetX = toInt(tuple);
|
||||||
region->offsetY = (float)toInt(tuple + 1);
|
region->offsetY = toInt(tuple + 1);
|
||||||
|
|
||||||
if (!readValue(end, &str)) return abortAtlas(self);
|
if (!readValue(end, &str)) return abortAtlas(self);
|
||||||
region->index = toInt(&str);
|
region->index = toInt(&str);
|
||||||
|
@ -281,6 +283,11 @@ Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Atlas* Atlas_readAtlasFile (const char* path) {
|
Atlas* Atlas_readAtlasFile (const char* path) {
|
||||||
|
int dirLength;
|
||||||
|
char *dir;
|
||||||
|
int length;
|
||||||
|
const char* data;
|
||||||
|
|
||||||
Atlas* atlas = 0;
|
Atlas* atlas = 0;
|
||||||
|
|
||||||
/* Get directory from atlas path. */
|
/* Get directory from atlas path. */
|
||||||
|
@ -288,13 +295,12 @@ Atlas* Atlas_readAtlasFile (const char* path) {
|
||||||
const char* lastBackwardSlash = strrchr(path, '\\');
|
const char* lastBackwardSlash = strrchr(path, '\\');
|
||||||
const char* lastSlash = lastForwardSlash > lastBackwardSlash ? lastForwardSlash : lastBackwardSlash;
|
const char* lastSlash = lastForwardSlash > lastBackwardSlash ? lastForwardSlash : lastBackwardSlash;
|
||||||
if (lastSlash == path) lastSlash++; /* Never drop starting slash. */
|
if (lastSlash == path) lastSlash++; /* Never drop starting slash. */
|
||||||
int dirLength = lastSlash ? lastSlash - path : 0;
|
dirLength = lastSlash ? lastSlash - path : 0;
|
||||||
char* dir = MALLOC(char, dirLength + 1);
|
dir = MALLOC(char, dirLength + 1);
|
||||||
memcpy(dir, path, dirLength);
|
memcpy(dir, path, dirLength);
|
||||||
dir[dirLength] = '\0';
|
dir[dirLength] = '\0';
|
||||||
|
|
||||||
int length;
|
data = _Util_readFile(path, &length);
|
||||||
const char* data = _Util_readFile(path, &length);
|
|
||||||
if (data) atlas = Atlas_readAtlas(data, length, dir);
|
if (data) atlas = Atlas_readAtlas(data, length, dir);
|
||||||
|
|
||||||
FREE(data);
|
FREE(data);
|
||||||
|
@ -303,6 +309,7 @@ Atlas* Atlas_readAtlasFile (const char* path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Atlas_dispose (Atlas* self) {
|
void Atlas_dispose (Atlas* self) {
|
||||||
|
AtlasRegion* region, *nextRegion;
|
||||||
AtlasPage* page = self->pages;
|
AtlasPage* page = self->pages;
|
||||||
while (page) {
|
while (page) {
|
||||||
AtlasPage* nextPage = page->next;
|
AtlasPage* nextPage = page->next;
|
||||||
|
@ -310,9 +317,9 @@ void Atlas_dispose (Atlas* self) {
|
||||||
page = nextPage;
|
page = nextPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
AtlasRegion* region = self->regions;
|
region = self->regions;
|
||||||
while (region) {
|
while (region) {
|
||||||
AtlasRegion* nextRegion = region->next;
|
nextRegion = region->next;
|
||||||
AtlasRegion_dispose(region);
|
AtlasRegion_dispose(region);
|
||||||
region = nextRegion;
|
region = nextRegion;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ struct AtlasPage {
|
||||||
AtlasFilter minFilter, magFilter;
|
AtlasFilter minFilter, magFilter;
|
||||||
AtlasWrap uWrap, vWrap;
|
AtlasWrap uWrap, vWrap;
|
||||||
|
|
||||||
void* texture;
|
void* rendererObject;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
AtlasPage* next;
|
AtlasPage* next;
|
||||||
|
@ -69,7 +69,7 @@ struct AtlasRegion {
|
||||||
const char* name;
|
const char* name;
|
||||||
int x, y, width, height;
|
int x, y, width, height;
|
||||||
float u, v, u2, v2;
|
float u, v, u2, v2;
|
||||||
float offsetX, offsetY;
|
int offsetX, offsetY;
|
||||||
int originalWidth, originalHeight;
|
int originalWidth, originalHeight;
|
||||||
int index;
|
int index;
|
||||||
int/*bool*/rotate;
|
int/*bool*/rotate;
|
||||||
|
|
|
@ -32,13 +32,21 @@ Attachment* _AtlasAttachmentLoader_newAttachment (AttachmentLoader* loader, Skin
|
||||||
AtlasAttachmentLoader* self = SUB_CAST(AtlasAttachmentLoader, loader);
|
AtlasAttachmentLoader* self = SUB_CAST(AtlasAttachmentLoader, loader);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ATTACHMENT_REGION: {
|
case ATTACHMENT_REGION: {
|
||||||
|
RegionAttachment* attachment;
|
||||||
AtlasRegion* region = Atlas_findRegion(self->atlas, name);
|
AtlasRegion* region = Atlas_findRegion(self->atlas, name);
|
||||||
if (!region) {
|
if (!region) {
|
||||||
_AttachmentLoader_setError(loader, "Region not found: ", name);
|
_AttachmentLoader_setError(loader, "Region not found: ", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
RegionAttachment* attachment = RegionAttachment_create(name);
|
attachment = RegionAttachment_create(name);
|
||||||
attachment->region = region;
|
attachment->rendererObject = region;
|
||||||
|
RegionAttachment_setUVs(attachment, region->u, region->v, region->u2, region->v2, region->rotate);
|
||||||
|
attachment->regionOffsetX = region->offsetX;
|
||||||
|
attachment->regionOffsetY = region->offsetY;
|
||||||
|
attachment->regionWidth = region->width;
|
||||||
|
attachment->regionHeight = region->height;
|
||||||
|
attachment->regionOriginalWidth = region->originalWidth;
|
||||||
|
attachment->regionOriginalHeight = region->originalHeight;
|
||||||
return SUPER(attachment);
|
return SUPER(attachment);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -33,10 +33,10 @@ typedef struct _AttachmentVtable {
|
||||||
void (*dispose) (Attachment* self);
|
void (*dispose) (Attachment* self);
|
||||||
} _AttachmentVtable;
|
} _AttachmentVtable;
|
||||||
|
|
||||||
void _Attachment_init (Attachment* self, const char* name, AttachmentType type, //
|
void _Attachment_init (Attachment* self, const char* name, AttachmentType type, /**/
|
||||||
void (*dispose) (Attachment* self)) {
|
void (*dispose) (Attachment* self)) {
|
||||||
|
|
||||||
CONST_CAST(void*, self->vtable) = NEW(_AttachmentVtable);
|
CONST_CAST(_AttachmentVtable*, self->vtable) = NEW(_AttachmentVtable);
|
||||||
VTABLE(Attachment, self) ->dispose = dispose;
|
VTABLE(Attachment, self) ->dispose = dispose;
|
||||||
|
|
||||||
MALLOC_STR(self->name, name);
|
MALLOC_STR(self->name, name);
|
||||||
|
@ -50,6 +50,7 @@ void _Attachment_deinit (Attachment* self) {
|
||||||
|
|
||||||
void Attachment_dispose (Attachment* self) {
|
void Attachment_dispose (Attachment* self) {
|
||||||
VTABLE(Attachment, self) ->dispose(self);
|
VTABLE(Attachment, self) ->dispose(self);
|
||||||
|
FREE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace cocos2d { namespace extension {
|
}} // namespace cocos2d { namespace extension {
|
|
@ -34,10 +34,10 @@ typedef struct _AttachmentLoaderVtable {
|
||||||
void (*dispose) (AttachmentLoader* self);
|
void (*dispose) (AttachmentLoader* self);
|
||||||
} _AttachmentLoaderVtable;
|
} _AttachmentLoaderVtable;
|
||||||
|
|
||||||
void _AttachmentLoader_init (AttachmentLoader* self, //
|
void _AttachmentLoader_init (AttachmentLoader* self, /**/
|
||||||
void (*dispose) (AttachmentLoader* self), //
|
void (*dispose) (AttachmentLoader* self), /**/
|
||||||
Attachment* (*newAttachment) (AttachmentLoader* self, Skin* skin, AttachmentType type, const char* name)) {
|
Attachment* (*newAttachment) (AttachmentLoader* self, Skin* skin, AttachmentType type, const char* name)) {
|
||||||
CONST_CAST(void*, self->vtable) = NEW(_AttachmentLoaderVtable);
|
CONST_CAST(_AttachmentLoaderVtable*, self->vtable) = NEW(_AttachmentLoaderVtable);
|
||||||
VTABLE(AttachmentLoader, self) ->dispose = dispose;
|
VTABLE(AttachmentLoader, self) ->dispose = dispose;
|
||||||
VTABLE(AttachmentLoader, self) ->newAttachment = newAttachment;
|
VTABLE(AttachmentLoader, self) ->newAttachment = newAttachment;
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ void _AttachmentLoader_deinit (AttachmentLoader* self) {
|
||||||
|
|
||||||
void AttachmentLoader_dispose (AttachmentLoader* self) {
|
void AttachmentLoader_dispose (AttachmentLoader* self) {
|
||||||
VTABLE(AttachmentLoader, self) ->dispose(self);
|
VTABLE(AttachmentLoader, self) ->dispose(self);
|
||||||
|
FREE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
Attachment* AttachmentLoader_newAttachment (AttachmentLoader* self, Skin* skin, AttachmentType type, const char* name) {
|
Attachment* AttachmentLoader_newAttachment (AttachmentLoader* self, Skin* skin, AttachmentType type, const char* name) {
|
||||||
|
|
|
@ -37,6 +37,9 @@ struct AttachmentLoader {
|
||||||
const char* error2;
|
const char* error2;
|
||||||
|
|
||||||
const void* const vtable;
|
const void* const vtable;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
AttachmentLoader () : error1(0), error2(0), vtable(0) {}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void AttachmentLoader_dispose (AttachmentLoader* self);
|
void AttachmentLoader_dispose (AttachmentLoader* self);
|
||||||
|
|
|
@ -39,7 +39,7 @@ Bone* Bone_create (BoneData* data, Bone* parent) {
|
||||||
Bone* self = NEW(Bone);
|
Bone* self = NEW(Bone);
|
||||||
CONST_CAST(BoneData*, self->data) = data;
|
CONST_CAST(BoneData*, self->data) = data;
|
||||||
CONST_CAST(Bone*, self->parent) = parent;
|
CONST_CAST(Bone*, self->parent) = parent;
|
||||||
Bone_setToBindPose(self);
|
Bone_setToSetupPose(self);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ void Bone_dispose (Bone* self) {
|
||||||
FREE(self);
|
FREE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bone_setToBindPose (Bone* self) {
|
void Bone_setToSetupPose (Bone* self) {
|
||||||
self->x = self->data->x;
|
self->x = self->data->x;
|
||||||
self->y = self->data->y;
|
self->y = self->data->y;
|
||||||
self->rotation = self->data->rotation;
|
self->rotation = self->data->rotation;
|
||||||
|
@ -56,6 +56,7 @@ void Bone_setToBindPose (Bone* self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bone_updateWorldTransform (Bone* self, int flipX, int flipY) {
|
void Bone_updateWorldTransform (Bone* self, int flipX, int flipY) {
|
||||||
|
float radians, cosine, sine;
|
||||||
if (self->parent) {
|
if (self->parent) {
|
||||||
CONST_CAST(float, self->worldX) = self->x * self->parent->m00 + self->y * self->parent->m01 + self->parent->worldX;
|
CONST_CAST(float, self->worldX) = self->x * self->parent->m00 + self->y * self->parent->m01 + self->parent->worldX;
|
||||||
CONST_CAST(float, self->worldY) = self->x * self->parent->m10 + self->y * self->parent->m11 + self->parent->worldY;
|
CONST_CAST(float, self->worldY) = self->x * self->parent->m10 + self->y * self->parent->m11 + self->parent->worldY;
|
||||||
|
@ -63,15 +64,20 @@ void Bone_updateWorldTransform (Bone* self, int flipX, int flipY) {
|
||||||
CONST_CAST(float, self->worldScaleY) = self->parent->worldScaleY * self->scaleY;
|
CONST_CAST(float, self->worldScaleY) = self->parent->worldScaleY * self->scaleY;
|
||||||
CONST_CAST(float, self->worldRotation) = self->parent->worldRotation + self->rotation;
|
CONST_CAST(float, self->worldRotation) = self->parent->worldRotation + self->rotation;
|
||||||
} else {
|
} else {
|
||||||
CONST_CAST(float, self->worldX) = self->x;
|
CONST_CAST(float, self->worldX) = flipX ? -self->x : self->x;
|
||||||
CONST_CAST(float, self->worldY) = self->y;
|
CONST_CAST(float, self->worldY) = flipX ? -self->y : self->y;
|
||||||
CONST_CAST(float, self->worldScaleX) = self->scaleX;
|
CONST_CAST(float, self->worldScaleX) = self->scaleX;
|
||||||
CONST_CAST(float, self->worldScaleY) = self->scaleY;
|
CONST_CAST(float, self->worldScaleY) = self->scaleY;
|
||||||
CONST_CAST(float, self->worldRotation) = self->rotation;
|
CONST_CAST(float, self->worldRotation) = self->rotation;
|
||||||
}
|
}
|
||||||
float radians = (float)(self->worldRotation * 3.1415926535897932385 / 180);
|
radians = (float)(self->worldRotation * 3.1415926535897932385 / 180);
|
||||||
float cosine = cosf(radians);
|
#ifdef __STDC_VERSION__
|
||||||
float sine = sinf(radians);
|
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->m00) = cosine * self->worldScaleX;
|
||||||
CONST_CAST(float, self->m10) = sine * self->worldScaleX;
|
CONST_CAST(float, self->m10) = sine * self->worldScaleX;
|
||||||
CONST_CAST(float, self->m01) = -sine * self->worldScaleY;
|
CONST_CAST(float, self->m01) = -sine * self->worldScaleY;
|
||||||
|
|
|
@ -50,7 +50,7 @@ void Bone_setYDown (int/*bool*/yDown);
|
||||||
Bone* Bone_create (BoneData* data, Bone* parent);
|
Bone* Bone_create (BoneData* data, Bone* parent);
|
||||||
void Bone_dispose (Bone* self);
|
void Bone_dispose (Bone* self);
|
||||||
|
|
||||||
void Bone_setToBindPose (Bone* self);
|
void Bone_setToSetupPose (Bone* self);
|
||||||
|
|
||||||
void Bone_updateWorldTransform (Bone* self, int/*bool*/flipX, int/*bool*/flipY);
|
void Bone_updateWorldTransform (Bone* self, int/*bool*/flipX, int/*bool*/flipY);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,290 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <spine/CCSkeleton.h>
|
||||||
|
#include <spine/spine-cocos2dx.h>
|
||||||
|
|
||||||
|
USING_NS_CC;
|
||||||
|
using std::min;
|
||||||
|
using std::max;
|
||||||
|
|
||||||
|
namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
CCSkeleton* CCSkeleton::createWithData (SkeletonData* skeletonData, bool ownsSkeletonData) {
|
||||||
|
CCSkeleton* node = new CCSkeleton(skeletonData, ownsSkeletonData);
|
||||||
|
node->autorelease();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeleton* CCSkeleton::createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale) {
|
||||||
|
CCSkeleton* node = new CCSkeleton(skeletonDataFile, atlas, scale);
|
||||||
|
node->autorelease();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeleton* CCSkeleton::createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale) {
|
||||||
|
CCSkeleton* node = new CCSkeleton(skeletonDataFile, atlasFile, scale);
|
||||||
|
node->autorelease();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeleton::initialize () {
|
||||||
|
atlas = 0;
|
||||||
|
debugSlots = false;
|
||||||
|
debugBones = false;
|
||||||
|
timeScale = 1;
|
||||||
|
|
||||||
|
blendFunc.src = GL_ONE;
|
||||||
|
blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||||
|
setOpacityModifyRGB(true);
|
||||||
|
|
||||||
|
setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor));
|
||||||
|
scheduleUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeleton::setSkeletonData (SkeletonData *skeletonData, bool ownsSkeletonData) {
|
||||||
|
skeleton = Skeleton_create(skeletonData);
|
||||||
|
rootBone = skeleton->bones[0];
|
||||||
|
this->ownsSkeletonData = ownsSkeletonData;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeleton::CCSkeleton () {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeleton::CCSkeleton (SkeletonData *skeletonData, bool ownsSkeletonData) {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
setSkeletonData(skeletonData, ownsSkeletonData);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeleton::CCSkeleton (const char* skeletonDataFile, Atlas* atlas, float scale) {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
SkeletonJson* json = SkeletonJson_create(atlas);
|
||||||
|
json->scale = scale;
|
||||||
|
SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, skeletonDataFile);
|
||||||
|
CCAssert(skeletonData, json->error ? json->error : "Error reading skeleton data.");
|
||||||
|
SkeletonJson_dispose(json);
|
||||||
|
|
||||||
|
setSkeletonData(skeletonData, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeleton::CCSkeleton (const char* skeletonDataFile, const char* atlasFile, float scale) {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
atlas = Atlas_readAtlasFile(atlasFile);
|
||||||
|
CCAssert(atlas, "Error reading atlas file.");
|
||||||
|
|
||||||
|
SkeletonJson* json = SkeletonJson_create(atlas);
|
||||||
|
json->scale = scale;
|
||||||
|
SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, skeletonDataFile);
|
||||||
|
CCAssert(skeletonData, json->error ? json->error : "Error reading skeleton data file.");
|
||||||
|
SkeletonJson_dispose(json);
|
||||||
|
|
||||||
|
setSkeletonData(skeletonData, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeleton::~CCSkeleton () {
|
||||||
|
if (ownsSkeletonData) SkeletonData_dispose(skeleton->data);
|
||||||
|
if (atlas) Atlas_dispose(atlas);
|
||||||
|
Skeleton_dispose(skeleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeleton::update (float deltaTime) {
|
||||||
|
Skeleton_update(skeleton, deltaTime * timeScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeleton::draw () {
|
||||||
|
CC_NODE_DRAW_SETUP();
|
||||||
|
|
||||||
|
ccGLBlendFunc(blendFunc.src, blendFunc.dst);
|
||||||
|
ccColor3B color = getColor();
|
||||||
|
skeleton->r = color.r / (float)255;
|
||||||
|
skeleton->g = color.g / (float)255;
|
||||||
|
skeleton->b = color.b / (float)255;
|
||||||
|
skeleton->a = getOpacity() / (float)255;
|
||||||
|
if (premultipliedAlpha) {
|
||||||
|
skeleton->r *= skeleton->a;
|
||||||
|
skeleton->g *= skeleton->a;
|
||||||
|
skeleton->b *= skeleton->a;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCTextureAtlas* textureAtlas = 0;
|
||||||
|
ccV3F_C4B_T2F_Quad quad;
|
||||||
|
quad.tl.vertices.z = 0;
|
||||||
|
quad.tr.vertices.z = 0;
|
||||||
|
quad.bl.vertices.z = 0;
|
||||||
|
quad.br.vertices.z = 0;
|
||||||
|
for (int i = 0, n = skeleton->slotCount; i < n; i++) {
|
||||||
|
Slot* slot = skeleton->slots[i];
|
||||||
|
if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
|
||||||
|
RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
|
||||||
|
CCTextureAtlas* regionTextureAtlas = getTextureAtlas(attachment);
|
||||||
|
if (regionTextureAtlas != textureAtlas) {
|
||||||
|
if (textureAtlas) {
|
||||||
|
textureAtlas->drawQuads();
|
||||||
|
textureAtlas->removeAllQuads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textureAtlas = regionTextureAtlas;
|
||||||
|
if (textureAtlas->getCapacity() == textureAtlas->getTotalQuads() &&
|
||||||
|
!textureAtlas->resizeCapacity(textureAtlas->getCapacity() * 2)) return;
|
||||||
|
RegionAttachment_updateQuad(attachment, slot, &quad, premultipliedAlpha);
|
||||||
|
textureAtlas->updateQuad(&quad, textureAtlas->getTotalQuads());
|
||||||
|
}
|
||||||
|
if (textureAtlas) {
|
||||||
|
textureAtlas->drawQuads();
|
||||||
|
textureAtlas->removeAllQuads();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugSlots) {
|
||||||
|
// Slots.
|
||||||
|
ccDrawColor4B(0, 0, 255, 255);
|
||||||
|
glLineWidth(1);
|
||||||
|
CCPoint points[4];
|
||||||
|
ccV3F_C4B_T2F_Quad quad;
|
||||||
|
for (int i = 0, n = skeleton->slotCount; i < n; i++) {
|
||||||
|
Slot* slot = skeleton->slots[i];
|
||||||
|
if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
|
||||||
|
RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
|
||||||
|
RegionAttachment_updateQuad(attachment, slot, &quad);
|
||||||
|
points[0] = ccp(quad.bl.vertices.x, quad.bl.vertices.y);
|
||||||
|
points[1] = ccp(quad.br.vertices.x, quad.br.vertices.y);
|
||||||
|
points[2] = ccp(quad.tr.vertices.x, quad.tr.vertices.y);
|
||||||
|
points[3] = ccp(quad.tl.vertices.x, quad.tl.vertices.y);
|
||||||
|
ccDrawPoly(points, 4, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (debugBones) {
|
||||||
|
// Bone lengths.
|
||||||
|
glLineWidth(2);
|
||||||
|
ccDrawColor4B(255, 0, 0, 255);
|
||||||
|
for (int i = 0, n = skeleton->boneCount; i < n; i++) {
|
||||||
|
Bone *bone = skeleton->bones[i];
|
||||||
|
float x = bone->data->length * bone->m00 + bone->worldX;
|
||||||
|
float y = bone->data->length * bone->m10 + bone->worldY;
|
||||||
|
ccDrawLine(ccp(bone->worldX, bone->worldY), ccp(x, y));
|
||||||
|
}
|
||||||
|
// Bone origins.
|
||||||
|
ccPointSize(4);
|
||||||
|
ccDrawColor4B(0, 0, 255, 255); // Root bone is blue.
|
||||||
|
for (int i = 0, n = skeleton->boneCount; i < n; i++) {
|
||||||
|
Bone *bone = skeleton->bones[i];
|
||||||
|
ccDrawPoint(ccp(bone->worldX, bone->worldY));
|
||||||
|
if (i == 0) ccDrawColor4B(0, 255, 0, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CCTextureAtlas* CCSkeleton::getTextureAtlas (RegionAttachment* regionAttachment) const {
|
||||||
|
return (CCTextureAtlas*)((AtlasRegion*)regionAttachment->rendererObject)->page->rendererObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCRect CCSkeleton::boundingBox () {
|
||||||
|
float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN;
|
||||||
|
float scaleX = getScaleX();
|
||||||
|
float scaleY = getScaleY();
|
||||||
|
float vertices[8];
|
||||||
|
for (int i = 0; i < skeleton->slotCount; ++i) {
|
||||||
|
Slot* slot = skeleton->slots[i];
|
||||||
|
if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
|
||||||
|
RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
|
||||||
|
RegionAttachment_computeVertices(attachment, slot->skeleton->x, slot->skeleton->y, slot->bone, vertices);
|
||||||
|
minX = min(minX, vertices[VERTEX_X1] * scaleX);
|
||||||
|
minY = min(minY, vertices[VERTEX_Y1] * scaleY);
|
||||||
|
maxX = max(maxX, vertices[VERTEX_X1] * scaleX);
|
||||||
|
maxY = max(maxY, vertices[VERTEX_Y1] * scaleY);
|
||||||
|
minX = min(minX, vertices[VERTEX_X4] * scaleX);
|
||||||
|
minY = min(minY, vertices[VERTEX_Y4] * scaleY);
|
||||||
|
maxX = max(maxX, vertices[VERTEX_X4] * scaleX);
|
||||||
|
maxY = max(maxY, vertices[VERTEX_Y4] * scaleY);
|
||||||
|
minX = min(minX, vertices[VERTEX_X2] * scaleX);
|
||||||
|
minY = min(minY, vertices[VERTEX_Y2] * scaleY);
|
||||||
|
maxX = max(maxX, vertices[VERTEX_X2] * scaleX);
|
||||||
|
maxY = max(maxY, vertices[VERTEX_Y2] * scaleY);
|
||||||
|
minX = min(minX, vertices[VERTEX_X3] * scaleX);
|
||||||
|
minY = min(minY, vertices[VERTEX_Y3] * scaleY);
|
||||||
|
maxX = max(maxX, vertices[VERTEX_X3] * scaleX);
|
||||||
|
maxY = max(maxY, vertices[VERTEX_Y3] * scaleY);
|
||||||
|
}
|
||||||
|
CCPoint position = getPosition();
|
||||||
|
return CCRectMake(position.x + minX, position.y + minY, maxX - minX, maxY - minY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Convenience methods for Skeleton_* functions.
|
||||||
|
|
||||||
|
void CCSkeleton::updateWorldTransform () {
|
||||||
|
Skeleton_updateWorldTransform(skeleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeleton::setToSetupPose () {
|
||||||
|
Skeleton_setToSetupPose(skeleton);
|
||||||
|
}
|
||||||
|
void CCSkeleton::setBonesToSetupPose () {
|
||||||
|
Skeleton_setBonesToSetupPose(skeleton);
|
||||||
|
}
|
||||||
|
void CCSkeleton::setSlotsToSetupPose () {
|
||||||
|
Skeleton_setSlotsToSetupPose(skeleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bone* CCSkeleton::findBone (const char* boneName) const {
|
||||||
|
return Skeleton_findBone(skeleton, boneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
Slot* CCSkeleton::findSlot (const char* slotName) const {
|
||||||
|
return Skeleton_findSlot(skeleton, slotName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCSkeleton::setSkin (const char* skinName) {
|
||||||
|
return Skeleton_setSkinByName(skeleton, skinName) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attachment* CCSkeleton::getAttachment (const char* slotName, const char* attachmentName) const {
|
||||||
|
return Skeleton_getAttachmentForSlotName(skeleton, slotName, attachmentName);
|
||||||
|
}
|
||||||
|
bool CCSkeleton::setAttachment (const char* slotName, const char* attachmentName) {
|
||||||
|
return Skeleton_setAttachment(skeleton, slotName, attachmentName) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- CCBlendProtocol
|
||||||
|
|
||||||
|
ccBlendFunc CCSkeleton::getBlendFunc () {
|
||||||
|
return blendFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeleton::setBlendFunc (ccBlendFunc blendFunc) {
|
||||||
|
this->blendFunc = blendFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeleton::setOpacityModifyRGB (bool value) {
|
||||||
|
premultipliedAlpha = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCSkeleton::isOpacityModifyRGB () {
|
||||||
|
return premultipliedAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace cocos2d { namespace extension {
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SPINE_CCSKELETON_H_
|
||||||
|
#define SPINE_CCSKELETON_H_
|
||||||
|
|
||||||
|
#include <spine/spine.h>
|
||||||
|
#include "cocos2d.h"
|
||||||
|
|
||||||
|
namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Draws a skeleton.
|
||||||
|
*/
|
||||||
|
class CCSkeleton: public cocos2d::CCNodeRGBA, public cocos2d::CCBlendProtocol {
|
||||||
|
public:
|
||||||
|
Skeleton* skeleton;
|
||||||
|
Bone* rootBone;
|
||||||
|
float timeScale;
|
||||||
|
bool debugSlots;
|
||||||
|
bool debugBones;
|
||||||
|
bool premultipliedAlpha;
|
||||||
|
|
||||||
|
static CCSkeleton* createWithData (SkeletonData* skeletonData, bool ownsSkeletonData = false);
|
||||||
|
static CCSkeleton* createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||||
|
static CCSkeleton* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale = 1);
|
||||||
|
|
||||||
|
CCSkeleton (SkeletonData* skeletonData, bool ownsSkeletonData = false);
|
||||||
|
CCSkeleton (const char* skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||||
|
CCSkeleton (const char* skeletonDataFile, const char* atlasFile, float scale = 1);
|
||||||
|
|
||||||
|
virtual ~CCSkeleton ();
|
||||||
|
|
||||||
|
virtual void update (float deltaTime);
|
||||||
|
virtual void draw ();
|
||||||
|
virtual cocos2d::CCRect boundingBox ();
|
||||||
|
|
||||||
|
// --- Convenience methods for common Skeleton_* functions.
|
||||||
|
void updateWorldTransform ();
|
||||||
|
|
||||||
|
void setToSetupPose ();
|
||||||
|
void setBonesToSetupPose ();
|
||||||
|
void setSlotsToSetupPose ();
|
||||||
|
|
||||||
|
/* Returns 0 if the bone was not found. */
|
||||||
|
Bone* findBone (const char* boneName) const;
|
||||||
|
/* Returns 0 if the slot was not found. */
|
||||||
|
Slot* findSlot (const char* slotName) const;
|
||||||
|
|
||||||
|
/* Sets the skin used to look up attachments not found in the SkeletonData defaultSkin. Attachments from the new skin are
|
||||||
|
* attached if the corresponding attachment from the old skin was attached. Returns false if the skin was not found.
|
||||||
|
* @param skin May be 0.*/
|
||||||
|
bool setSkin (const char* skinName);
|
||||||
|
|
||||||
|
/* Returns 0 if the slot or attachment was not found. */
|
||||||
|
Attachment* getAttachment (const char* slotName, const char* attachmentName) const;
|
||||||
|
/* Returns false if the slot or attachment was not found. */
|
||||||
|
bool setAttachment (const char* slotName, const char* attachmentName);
|
||||||
|
|
||||||
|
// --- CCBlendProtocol
|
||||||
|
CC_PROPERTY(cocos2d::ccBlendFunc, blendFunc, BlendFunc);
|
||||||
|
virtual void setOpacityModifyRGB (bool value);
|
||||||
|
virtual bool isOpacityModifyRGB ();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CCSkeleton ();
|
||||||
|
void setSkeletonData (SkeletonData* skeletonData, bool ownsSkeletonData);
|
||||||
|
cocos2d::CCTextureAtlas* getTextureAtlas (RegionAttachment* regionAttachment) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool ownsSkeletonData;
|
||||||
|
Atlas* atlas;
|
||||||
|
void initialize ();
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
#endif /* SPINE_CCSKELETON_H_ */
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <spine/CCSkeletonAnimation.h>
|
||||||
|
#include <spine/extension.h>
|
||||||
|
#include <spine/spine-cocos2dx.h>
|
||||||
|
|
||||||
|
USING_NS_CC;
|
||||||
|
using std::min;
|
||||||
|
using std::max;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
CCSkeletonAnimation* CCSkeletonAnimation::createWithData (SkeletonData* skeletonData) {
|
||||||
|
CCSkeletonAnimation* node = new CCSkeletonAnimation(skeletonData);
|
||||||
|
node->autorelease();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeletonAnimation* CCSkeletonAnimation::createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale) {
|
||||||
|
CCSkeletonAnimation* node = new CCSkeletonAnimation(skeletonDataFile, atlas, scale);
|
||||||
|
node->autorelease();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeletonAnimation* CCSkeletonAnimation::createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale) {
|
||||||
|
CCSkeletonAnimation* node = new CCSkeletonAnimation(skeletonDataFile, atlasFile, scale);
|
||||||
|
node->autorelease();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeletonAnimation::CCSkeletonAnimation (SkeletonData *skeletonData)
|
||||||
|
: CCSkeleton(skeletonData) {
|
||||||
|
addAnimationState();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeletonAnimation::CCSkeletonAnimation (const char* skeletonDataFile, Atlas* atlas, float scale)
|
||||||
|
: CCSkeleton(skeletonDataFile, atlas, scale) {
|
||||||
|
addAnimationState();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeletonAnimation::CCSkeletonAnimation (const char* skeletonDataFile, const char* atlasFile, float scale)
|
||||||
|
: CCSkeleton(skeletonDataFile, atlasFile, scale) {
|
||||||
|
addAnimationState();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSkeletonAnimation::~CCSkeletonAnimation () {
|
||||||
|
for (std::vector<AnimationStateData*>::iterator iter = stateDatas.begin(); iter != stateDatas.end(); ++iter)
|
||||||
|
AnimationStateData_dispose(*iter);
|
||||||
|
|
||||||
|
for (std::vector<AnimationState*>::iterator iter = states.begin(); iter != states.end(); ++iter)
|
||||||
|
AnimationState_dispose(*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeletonAnimation::update (float deltaTime) {
|
||||||
|
super::update(deltaTime);
|
||||||
|
|
||||||
|
deltaTime *= timeScale;
|
||||||
|
for (std::vector<AnimationState*>::iterator iter = states.begin(); iter != states.end(); ++iter) {
|
||||||
|
AnimationState_update(*iter, deltaTime);
|
||||||
|
AnimationState_apply(*iter, skeleton);
|
||||||
|
}
|
||||||
|
Skeleton_updateWorldTransform(skeleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeletonAnimation::addAnimationState (AnimationStateData* stateData) {
|
||||||
|
if (!stateData) {
|
||||||
|
stateData = AnimationStateData_create(skeleton->data);
|
||||||
|
stateDatas.push_back(stateData);
|
||||||
|
}
|
||||||
|
AnimationState* state = AnimationState_create(stateData);
|
||||||
|
states.push_back(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeletonAnimation::setAnimationStateData (AnimationStateData* stateData, int stateIndex) {
|
||||||
|
CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range.");
|
||||||
|
CCAssert(stateData, "stateData cannot be null.");
|
||||||
|
|
||||||
|
AnimationState* state = states[stateIndex];
|
||||||
|
for (std::vector<AnimationStateData*>::iterator iter = stateDatas.begin(); iter != stateDatas.end(); ++iter) {
|
||||||
|
if (state->data == *iter) {
|
||||||
|
AnimationStateData_dispose(state->data);
|
||||||
|
stateDatas.erase(iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (std::vector<AnimationState*>::iterator iter = states.begin(); iter != states.end(); ++iter) {
|
||||||
|
if (state == *iter) {
|
||||||
|
states.erase(iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnimationState_dispose(state);
|
||||||
|
|
||||||
|
state = AnimationState_create(stateData);
|
||||||
|
states[stateIndex] = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeletonAnimation::setMix (const char* fromAnimation, const char* toAnimation, float duration, int stateIndex) {
|
||||||
|
CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range.");
|
||||||
|
AnimationStateData_setMixByName(states[stateIndex]->data, fromAnimation, toAnimation, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeletonAnimation::setAnimation (const char* name, bool loop, int stateIndex) {
|
||||||
|
CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range.");
|
||||||
|
AnimationState_setAnimationByName(states[stateIndex], name, loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeletonAnimation::addAnimation (const char* name, bool loop, float delay, int stateIndex) {
|
||||||
|
CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range.");
|
||||||
|
AnimationState_addAnimationByName(states[stateIndex], name, loop, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCSkeletonAnimation::clearAnimation (int stateIndex) {
|
||||||
|
CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range.");
|
||||||
|
AnimationState_clearAnimation(states[stateIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace cocos2d { namespace extension {
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SPINE_CCSKELETONANIMATION_H_
|
||||||
|
#define SPINE_CCSKELETONANIMATION_H_
|
||||||
|
|
||||||
|
#include <spine/spine.h>
|
||||||
|
#include <spine/CCSkeleton.h>
|
||||||
|
#include "cocos2d.h"
|
||||||
|
|
||||||
|
namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Draws an animated skeleton, providing a simple API for applying one or more animations and queuing animations to be played later.
|
||||||
|
*/
|
||||||
|
class CCSkeletonAnimation: public CCSkeleton {
|
||||||
|
public:
|
||||||
|
std::vector<AnimationState*> states;
|
||||||
|
|
||||||
|
static CCSkeletonAnimation* createWithData (SkeletonData* skeletonData);
|
||||||
|
static CCSkeletonAnimation* createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||||
|
static CCSkeletonAnimation* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale = 1);
|
||||||
|
|
||||||
|
CCSkeletonAnimation (SkeletonData* skeletonData);
|
||||||
|
CCSkeletonAnimation (const char* skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||||
|
CCSkeletonAnimation (const char* skeletonDataFile, const char* atlasFile, float scale = 1);
|
||||||
|
|
||||||
|
virtual ~CCSkeletonAnimation ();
|
||||||
|
|
||||||
|
virtual void update (float deltaTime);
|
||||||
|
|
||||||
|
void addAnimationState (AnimationStateData* stateData = 0);
|
||||||
|
void setAnimationStateData (AnimationStateData* stateData, int stateIndex = 0);
|
||||||
|
void setMix (const char* fromAnimation, const char* toAnimation, float duration, int stateIndex = 0);
|
||||||
|
void setAnimation (const char* name, bool loop, int stateIndex = 0);
|
||||||
|
void addAnimation (const char* name, bool loop, float delay = 0, int stateIndex = 0);
|
||||||
|
void clearAnimation (int stateIndex = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CCSkeletonAnimation ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef CCSkeleton super;
|
||||||
|
std::vector<AnimationStateData*> stateDatas;
|
||||||
|
|
||||||
|
void initialize ();
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
#endif /* SPINE_CCSKELETONANIMATION_H_ */
|
|
@ -90,7 +90,7 @@ static const char* parse_number (Json *item, const char* num) {
|
||||||
subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
|
subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
|
||||||
}
|
}
|
||||||
|
|
||||||
n = sign * n * pow(10.0f, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
|
n = sign * n * (float)pow(10.0f, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
|
||||||
|
|
||||||
item->valuefloat = n;
|
item->valuefloat = n;
|
||||||
item->valueint = (int)n;
|
item->valueint = (int)n;
|
||||||
|
|
|
@ -37,29 +37,43 @@ RegionAttachment* RegionAttachment_create (const char* name) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionAttachment_updateOffset (RegionAttachment* self) {
|
void RegionAttachment_setUVs (RegionAttachment* self, float u, float v, float u2, float v2, int/*bool*/rotate) {
|
||||||
float localX2 = self->width / 2;
|
if (rotate) {
|
||||||
float localY2 = self->height / 2;
|
self->uvs[VERTEX_X2] = u;
|
||||||
float localX = -localX2;
|
self->uvs[VERTEX_Y2] = v2;
|
||||||
float localY = -localY2;
|
self->uvs[VERTEX_X3] = u;
|
||||||
if (self->region->rotate) {
|
self->uvs[VERTEX_Y3] = v;
|
||||||
localX += self->region->offsetX / self->region->originalWidth * self->height;
|
self->uvs[VERTEX_X4] = u2;
|
||||||
localY += self->region->offsetY / self->region->originalHeight * self->width;
|
self->uvs[VERTEX_Y4] = v;
|
||||||
localX2 -= (self->region->originalWidth - self->region->offsetX - self->region->height) / self->region->originalWidth * self->width;
|
self->uvs[VERTEX_X1] = u2;
|
||||||
localY2 -= (self->region->originalHeight - self->region->offsetY - self->region->width) / self->region->originalHeight * self->height;
|
self->uvs[VERTEX_Y1] = v2;
|
||||||
} else {
|
} else {
|
||||||
localX += self->region->offsetX / self->region->originalWidth * self->width;
|
self->uvs[VERTEX_X1] = u;
|
||||||
localY += self->region->offsetY / self->region->originalHeight * self->height;
|
self->uvs[VERTEX_Y1] = v2;
|
||||||
localX2 -= (self->region->originalWidth - self->region->offsetX - self->region->width) / self->region->originalWidth * self->width;
|
self->uvs[VERTEX_X2] = u;
|
||||||
localY2 -= (self->region->originalHeight - self->region->offsetY - self->region->height) / self->region->originalHeight * self->height;
|
self->uvs[VERTEX_Y2] = v;
|
||||||
|
self->uvs[VERTEX_X3] = u2;
|
||||||
|
self->uvs[VERTEX_Y3] = v;
|
||||||
|
self->uvs[VERTEX_X4] = u2;
|
||||||
|
self->uvs[VERTEX_Y4] = v2;
|
||||||
}
|
}
|
||||||
localX *= self->scaleX;
|
}
|
||||||
localY *= self->scaleY;
|
|
||||||
localX2 *= self->scaleX;
|
void RegionAttachment_updateOffset (RegionAttachment* self) {
|
||||||
localY2 *= self->scaleY;
|
float regionScaleX = self->width / self->regionOriginalWidth * self->scaleX;
|
||||||
|
float regionScaleY = self->height / self->regionOriginalHeight * self->scaleY;
|
||||||
|
float localX = -self->width / 2 * self->scaleX + self->regionOffsetX * regionScaleX;
|
||||||
|
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);
|
float radians = (float)(self->rotation * 3.1415926535897932385 / 180);
|
||||||
|
#ifdef __STDC_VERSION__
|
||||||
float cosine = cosf(radians);
|
float cosine = cosf(radians);
|
||||||
float sine = sinf(radians);
|
float sine = sinf(radians);
|
||||||
|
#else
|
||||||
|
float cosine = (float)cos(radians);
|
||||||
|
float sine = (float)sin(radians);
|
||||||
|
#endif
|
||||||
float localXCos = localX * cosine + self->x;
|
float localXCos = localX * cosine + self->x;
|
||||||
float localXSin = localX * sine;
|
float localXSin = localX * sine;
|
||||||
float localYCos = localY * cosine + self->y;
|
float localYCos = localY * cosine + self->y;
|
||||||
|
@ -78,17 +92,18 @@ void RegionAttachment_updateOffset (RegionAttachment* self) {
|
||||||
self->offset[VERTEX_Y4] = localYCos + localX2Sin;
|
self->offset[VERTEX_Y4] = localYCos + localX2Sin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionAttachment_updateVertices (RegionAttachment* self, Slot* slot) {
|
void RegionAttachment_computeVertices (RegionAttachment* self, float x, float y, Bone* bone, float* vertices) {
|
||||||
float* offset = self->offset;
|
float* offset = self->offset;
|
||||||
Bone* bone = slot->bone;
|
x += bone->worldX;
|
||||||
self->vertices[VERTEX_X1] = offset[VERTEX_X1] * bone->m00 + offset[VERTEX_Y1] * bone->m01 + bone->worldX;
|
y += bone->worldY;
|
||||||
self->vertices[VERTEX_Y1] = offset[VERTEX_X1] * bone->m10 + offset[VERTEX_Y1] * bone->m11 + bone->worldY;
|
vertices[VERTEX_X1] = offset[VERTEX_X1] * bone->m00 + offset[VERTEX_Y1] * bone->m01 + x;
|
||||||
self->vertices[VERTEX_X2] = offset[VERTEX_X2] * bone->m00 + offset[VERTEX_Y2] * bone->m01 + bone->worldX;
|
vertices[VERTEX_Y1] = offset[VERTEX_X1] * bone->m10 + offset[VERTEX_Y1] * bone->m11 + y;
|
||||||
self->vertices[VERTEX_Y2] = offset[VERTEX_X2] * bone->m10 + offset[VERTEX_Y2] * bone->m11 + bone->worldY;
|
vertices[VERTEX_X2] = offset[VERTEX_X2] * bone->m00 + offset[VERTEX_Y2] * bone->m01 + x;
|
||||||
self->vertices[VERTEX_X3] = offset[VERTEX_X3] * bone->m00 + offset[VERTEX_Y3] * bone->m01 + bone->worldX;
|
vertices[VERTEX_Y2] = offset[VERTEX_X2] * bone->m10 + offset[VERTEX_Y2] * bone->m11 + y;
|
||||||
self->vertices[VERTEX_Y3] = offset[VERTEX_X3] * bone->m10 + offset[VERTEX_Y3] * bone->m11 + bone->worldY;
|
vertices[VERTEX_X3] = offset[VERTEX_X3] * bone->m00 + offset[VERTEX_Y3] * bone->m01 + x;
|
||||||
self->vertices[VERTEX_X4] = offset[VERTEX_X4] * bone->m00 + offset[VERTEX_Y4] * bone->m01 + bone->worldX;
|
vertices[VERTEX_Y3] = offset[VERTEX_X3] * bone->m10 + offset[VERTEX_Y3] * bone->m11 + y;
|
||||||
self->vertices[VERTEX_Y4] = offset[VERTEX_X4] * bone->m10 + offset[VERTEX_Y4] * bone->m11 + bone->worldY;
|
vertices[VERTEX_X4] = offset[VERTEX_X4] * bone->m00 + offset[VERTEX_Y4] * bone->m01 + x;
|
||||||
|
vertices[VERTEX_Y4] = offset[VERTEX_X4] * bone->m10 + offset[VERTEX_Y4] * bone->m11 + y;
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace cocos2d { namespace extension {
|
}} // namespace cocos2d { namespace extension {
|
|
@ -40,16 +40,20 @@ typedef struct RegionAttachment RegionAttachment;
|
||||||
struct RegionAttachment {
|
struct RegionAttachment {
|
||||||
Attachment super;
|
Attachment super;
|
||||||
float x, y, scaleX, scaleY, rotation, width, height;
|
float x, y, scaleX, scaleY, rotation, width, height;
|
||||||
AtlasRegion* region;
|
|
||||||
|
void* rendererObject;
|
||||||
|
int regionOffsetX, regionOffsetY; /* Pixels stripped from the bottom left, unrotated. */
|
||||||
|
int regionWidth, regionHeight; /* Unrotated, stripped pixel size. */
|
||||||
|
int regionOriginalWidth, regionOriginalHeight; /* Unrotated, unstripped pixel size. */
|
||||||
|
|
||||||
float offset[8];
|
float offset[8];
|
||||||
float vertices[8];
|
|
||||||
float uvs[8];
|
float uvs[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
RegionAttachment* RegionAttachment_create (const char* name);
|
RegionAttachment* RegionAttachment_create (const char* name);
|
||||||
|
void RegionAttachment_setUVs (RegionAttachment* self, float u, float v, float u2, float v2, int/*bool*/rotate);
|
||||||
void RegionAttachment_updateOffset (RegionAttachment* self);
|
void RegionAttachment_updateOffset (RegionAttachment* self);
|
||||||
void RegionAttachment_updateVertices (RegionAttachment* self, Slot* slot);
|
void RegionAttachment_computeVertices (RegionAttachment* self, float x, float y, Bone* bone, float* vertices);
|
||||||
|
|
||||||
}} // namespace cocos2d { namespace extension {
|
}} // namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
|
|
@ -30,12 +30,14 @@
|
||||||
namespace cocos2d { namespace extension {
|
namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
Skeleton* Skeleton_create (SkeletonData* data) {
|
Skeleton* Skeleton_create (SkeletonData* data) {
|
||||||
|
int i, ii;
|
||||||
|
|
||||||
Skeleton* self = NEW(Skeleton);
|
Skeleton* self = NEW(Skeleton);
|
||||||
CONST_CAST(SkeletonData*, self->data) = data;
|
CONST_CAST(SkeletonData*, self->data) = data;
|
||||||
|
|
||||||
self->boneCount = self->data->boneCount;
|
self->boneCount = self->data->boneCount;
|
||||||
self->bones = MALLOC(Bone*, self->boneCount);
|
self->bones = MALLOC(Bone*, self->boneCount);
|
||||||
int i, ii;
|
|
||||||
for (i = 0; i < self->boneCount; ++i) {
|
for (i = 0; i < self->boneCount; ++i) {
|
||||||
BoneData* boneData = self->data->bones[i];
|
BoneData* boneData = self->data->bones[i];
|
||||||
Bone* parent = 0;
|
Bone* parent = 0;
|
||||||
|
@ -58,14 +60,13 @@ Skeleton* Skeleton_create (SkeletonData* data) {
|
||||||
SlotData *slotData = data->slots[i];
|
SlotData *slotData = data->slots[i];
|
||||||
|
|
||||||
/* Find bone for the slotData's boneData. */
|
/* Find bone for the slotData's boneData. */
|
||||||
Bone *bone = NULL;
|
Bone* bone = 0;
|
||||||
for (ii = 0; ii < self->boneCount; ++ii) {
|
for (ii = 0; ii < self->boneCount; ++ii) {
|
||||||
if (data->bones[ii] == slotData->boneData) {
|
if (data->bones[ii] == slotData->boneData) {
|
||||||
bone = self->bones[ii];
|
bone = self->bones[ii];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self->slots[i] = Slot_create(slotData, self, bone);
|
self->slots[i] = Slot_create(slotData, self, bone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ void Skeleton_dispose (Skeleton* self) {
|
||||||
FREE(self->slots);
|
FREE(self->slots);
|
||||||
|
|
||||||
FREE(self->drawOrder);
|
FREE(self->drawOrder);
|
||||||
|
FREE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skeleton_updateWorldTransform (const Skeleton* self) {
|
void Skeleton_updateWorldTransform (const Skeleton* self) {
|
||||||
|
@ -99,21 +101,21 @@ void Skeleton_updateWorldTransform (const Skeleton* self) {
|
||||||
Bone_updateWorldTransform(self->bones[i], self->flipX, self->flipY);
|
Bone_updateWorldTransform(self->bones[i], self->flipX, self->flipY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skeleton_setToBindPose (const Skeleton* self) {
|
void Skeleton_setToSetupPose (const Skeleton* self) {
|
||||||
Skeleton_setBonesToBindPose(self);
|
Skeleton_setBonesToSetupPose(self);
|
||||||
Skeleton_setSlotsToBindPose(self);
|
Skeleton_setSlotsToSetupPose(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skeleton_setBonesToBindPose (const Skeleton* self) {
|
void Skeleton_setBonesToSetupPose (const Skeleton* self) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < self->boneCount; ++i)
|
for (i = 0; i < self->boneCount; ++i)
|
||||||
Bone_setToBindPose(self->bones[i]);
|
Bone_setToSetupPose(self->bones[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skeleton_setSlotsToBindPose (const Skeleton* self) {
|
void Skeleton_setSlotsToSetupPose (const Skeleton* self) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < self->slotCount; ++i)
|
for (i = 0; i < self->slotCount; ++i)
|
||||||
Slot_setToBindPose(self->slots[i]);
|
Slot_setToSetupPose(self->slots[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bone* Skeleton_findBone (const Skeleton* self, const char* boneName) {
|
Bone* Skeleton_findBone (const Skeleton* self, const char* boneName) {
|
||||||
|
@ -145,11 +147,12 @@ int Skeleton_findSlotIndex (const Skeleton* self, const char* slotName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Skeleton_setSkinByName (Skeleton* self, const char* skinName) {
|
int Skeleton_setSkinByName (Skeleton* self, const char* skinName) {
|
||||||
|
Skin *skin;
|
||||||
if (!skinName) {
|
if (!skinName) {
|
||||||
Skeleton_setSkin(self, 0);
|
Skeleton_setSkin(self, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Skin *skin = SkeletonData_findSkin(self->data, skinName);
|
skin = SkeletonData_findSkin(self->data, skinName);
|
||||||
if (!skin) return 0;
|
if (!skin) return 0;
|
||||||
Skeleton_setSkin(self, skin);
|
Skeleton_setSkin(self, skin);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct Skeleton {
|
||||||
float r, g, b, a;
|
float r, g, b, a;
|
||||||
float time;
|
float time;
|
||||||
int/*bool*/flipX, flipY;
|
int/*bool*/flipX, flipY;
|
||||||
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
Skeleton* Skeleton_create (SkeletonData* data);
|
Skeleton* Skeleton_create (SkeletonData* data);
|
||||||
|
@ -55,9 +56,9 @@ void Skeleton_dispose (Skeleton* self);
|
||||||
|
|
||||||
void Skeleton_updateWorldTransform (const Skeleton* self);
|
void Skeleton_updateWorldTransform (const Skeleton* self);
|
||||||
|
|
||||||
void Skeleton_setToBindPose (const Skeleton* self);
|
void Skeleton_setToSetupPose (const Skeleton* self);
|
||||||
void Skeleton_setBonesToBindPose (const Skeleton* self);
|
void Skeleton_setBonesToSetupPose (const Skeleton* self);
|
||||||
void Skeleton_setSlotsToBindPose (const Skeleton* self);
|
void Skeleton_setSlotsToSetupPose (const Skeleton* self);
|
||||||
|
|
||||||
/* Returns 0 if the bone was not found. */
|
/* Returns 0 if the bone was not found. */
|
||||||
Bone* Skeleton_findBone (const Skeleton* self, const char* boneName);
|
Bone* Skeleton_findBone (const Skeleton* self, const char* boneName);
|
||||||
|
|
|
@ -60,24 +60,28 @@ void SkeletonJson_dispose (SkeletonJson* self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _SkeletonJson_setError (SkeletonJson* self, Json* root, const char* value1, const char* value2) {
|
void _SkeletonJson_setError (SkeletonJson* self, Json* root, const char* value1, const char* value2) {
|
||||||
FREE(self->error);
|
|
||||||
char message[256];
|
char message[256];
|
||||||
|
int length;
|
||||||
|
FREE(self->error);
|
||||||
strcpy(message, value1);
|
strcpy(message, value1);
|
||||||
int length = strlen(value1);
|
length = strlen(value1);
|
||||||
if (value2) strncat(message + length, value2, 256 - length);
|
if (value2) strncat(message + length, value2, 256 - length);
|
||||||
MALLOC_STR(self->error, message);
|
MALLOC_STR(self->error, message);
|
||||||
if (root) Json_dispose(root);
|
if (root) Json_dispose(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float toColor (const char* value, int index) {
|
static float toColor (const char* value, int index) {
|
||||||
|
char digits[3];
|
||||||
|
char *error;
|
||||||
|
int color;
|
||||||
|
|
||||||
if (strlen(value) != 8) return -1;
|
if (strlen(value) != 8) return -1;
|
||||||
value += index * 2;
|
value += index * 2;
|
||||||
char digits[3];
|
|
||||||
digits[0] = *value;
|
digits[0] = *value;
|
||||||
digits[1] = *(value + 1);
|
digits[1] = *(value + 1);
|
||||||
digits[2] = '\0';
|
digits[2] = '\0';
|
||||||
char* error;
|
color = strtoul(digits, &error, 16);
|
||||||
int color = strtoul(digits, &error, 16);
|
|
||||||
if (*error != 0) return -1;
|
if (*error != 0) return -1;
|
||||||
return color / (float)255;
|
return color / (float)255;
|
||||||
}
|
}
|
||||||
|
@ -94,6 +98,8 @@ static void readCurve (CurveTimeline* timeline, int frameIndex, Json* frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, SkeletonData *skeletonData) {
|
static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, SkeletonData *skeletonData) {
|
||||||
|
Animation* animation;
|
||||||
|
|
||||||
Json* bones = Json_getItem(root, "bones");
|
Json* bones = Json_getItem(root, "bones");
|
||||||
int boneCount = bones ? Json_getSize(bones) : 0;
|
int boneCount = bones ? Json_getSize(bones) : 0;
|
||||||
|
|
||||||
|
@ -106,12 +112,13 @@ static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, S
|
||||||
timelineCount += Json_getSize(Json_getItemAt(bones, i));
|
timelineCount += Json_getSize(Json_getItemAt(bones, i));
|
||||||
for (i = 0; i < slotCount; ++i)
|
for (i = 0; i < slotCount; ++i)
|
||||||
timelineCount += Json_getSize(Json_getItemAt(slots, i));
|
timelineCount += Json_getSize(Json_getItemAt(slots, i));
|
||||||
Animation* animation = Animation_create(root->name, timelineCount);
|
animation = Animation_create(root->name, timelineCount);
|
||||||
animation->timelineCount = 0;
|
animation->timelineCount = 0;
|
||||||
skeletonData->animations[skeletonData->animationCount] = animation;
|
skeletonData->animations[skeletonData->animationCount] = animation;
|
||||||
skeletonData->animationCount++;
|
skeletonData->animationCount++;
|
||||||
|
|
||||||
for (i = 0; i < boneCount; ++i) {
|
for (i = 0; i < boneCount; ++i) {
|
||||||
|
int timelineCount;
|
||||||
Json* boneMap = Json_getItemAt(bones, i);
|
Json* boneMap = Json_getItemAt(bones, i);
|
||||||
|
|
||||||
const char* boneName = boneMap->name;
|
const char* boneName = boneMap->name;
|
||||||
|
@ -123,13 +130,15 @@ static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, S
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int timelineCount = Json_getSize(boneMap);
|
timelineCount = Json_getSize(boneMap);
|
||||||
for (ii = 0; ii < timelineCount; ++ii) {
|
for (ii = 0; ii < timelineCount; ++ii) {
|
||||||
|
float duration;
|
||||||
Json* timelineArray = Json_getItemAt(boneMap, ii);
|
Json* timelineArray = Json_getItemAt(boneMap, ii);
|
||||||
int frameCount = Json_getSize(timelineArray);
|
int frameCount = Json_getSize(timelineArray);
|
||||||
const char* timelineType = timelineArray->name;
|
const char* timelineType = timelineArray->name;
|
||||||
|
|
||||||
if (strcmp(timelineType, "rotate") == 0) {
|
if (strcmp(timelineType, "rotate") == 0) {
|
||||||
|
|
||||||
RotateTimeline *timeline = RotateTimeline_create(frameCount);
|
RotateTimeline *timeline = RotateTimeline_create(frameCount);
|
||||||
timeline->boneIndex = boneIndex;
|
timeline->boneIndex = boneIndex;
|
||||||
for (iii = 0; iii < frameCount; ++iii) {
|
for (iii = 0; iii < frameCount; ++iii) {
|
||||||
|
@ -138,14 +147,14 @@ static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, S
|
||||||
readCurve(SUPER(timeline), iii, frame);
|
readCurve(SUPER(timeline), iii, frame);
|
||||||
}
|
}
|
||||||
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
|
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
|
||||||
float duration = timeline->frames[frameCount * 2 - 2];
|
duration = timeline->frames[frameCount * 2 - 2];
|
||||||
if (duration > animation->duration) animation->duration = duration;
|
if (duration > animation->duration) animation->duration = duration;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int isScale = strcmp(timelineType, "scale") == 0;
|
int isScale = strcmp(timelineType, "scale") == 0;
|
||||||
if (isScale || strcmp(timelineType, "translate") == 0) {
|
if (isScale || strcmp(timelineType, "translate") == 0) {
|
||||||
TranslateTimeline *timeline = isScale ? ScaleTimeline_create(frameCount) : TranslateTimeline_create(frameCount);
|
|
||||||
float scale = isScale ? 1 : self->scale;
|
float scale = isScale ? 1 : self->scale;
|
||||||
|
TranslateTimeline *timeline = isScale ? ScaleTimeline_create(frameCount) : TranslateTimeline_create(frameCount);
|
||||||
timeline->boneIndex = boneIndex;
|
timeline->boneIndex = boneIndex;
|
||||||
for (iii = 0; iii < frameCount; ++iii) {
|
for (iii = 0; iii < frameCount; ++iii) {
|
||||||
Json* frame = Json_getItemAt(timelineArray, iii);
|
Json* frame = Json_getItemAt(timelineArray, iii);
|
||||||
|
@ -154,7 +163,7 @@ static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, S
|
||||||
readCurve(SUPER(timeline), iii, frame);
|
readCurve(SUPER(timeline), iii, frame);
|
||||||
}
|
}
|
||||||
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
|
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
|
||||||
float duration = timeline->frames[frameCount * 3 - 3];
|
duration = timeline->frames[frameCount * 3 - 3];
|
||||||
if (duration > animation->duration) animation->duration = duration;
|
if (duration > animation->duration) animation->duration = duration;
|
||||||
} else {
|
} else {
|
||||||
Animation_dispose(animation);
|
Animation_dispose(animation);
|
||||||
|
@ -166,6 +175,7 @@ static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, S
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < slotCount; ++i) {
|
for (i = 0; i < slotCount; ++i) {
|
||||||
|
int timelineCount;
|
||||||
Json* slotMap = Json_getItemAt(slots, i);
|
Json* slotMap = Json_getItemAt(slots, i);
|
||||||
const char* slotName = slotMap->name;
|
const char* slotName = slotMap->name;
|
||||||
|
|
||||||
|
@ -176,8 +186,9 @@ static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, S
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int timelineCount = Json_getSize(slotMap);
|
timelineCount = Json_getSize(slotMap);
|
||||||
for (ii = 0; ii < timelineCount; ++ii) {
|
for (ii = 0; ii < timelineCount; ++ii) {
|
||||||
|
float duration;
|
||||||
Json* timelineArray = Json_getItemAt(slotMap, ii);
|
Json* timelineArray = Json_getItemAt(slotMap, ii);
|
||||||
int frameCount = Json_getSize(timelineArray);
|
int frameCount = Json_getSize(timelineArray);
|
||||||
const char* timelineType = timelineArray->name;
|
const char* timelineType = timelineArray->name;
|
||||||
|
@ -193,7 +204,7 @@ static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, S
|
||||||
readCurve(SUPER(timeline), iii, frame);
|
readCurve(SUPER(timeline), iii, frame);
|
||||||
}
|
}
|
||||||
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
|
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
|
||||||
float duration = timeline->frames[frameCount * 5 - 5];
|
duration = timeline->frames[frameCount * 5 - 5];
|
||||||
if (duration > animation->duration) animation->duration = duration;
|
if (duration > animation->duration) animation->duration = duration;
|
||||||
|
|
||||||
} else if (strcmp(timelineType, "attachment") == 0) {
|
} else if (strcmp(timelineType, "attachment") == 0) {
|
||||||
|
@ -206,7 +217,7 @@ static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, S
|
||||||
name->type == Json_NULL ? 0 : name->valuestring);
|
name->type == Json_NULL ? 0 : name->valuestring);
|
||||||
}
|
}
|
||||||
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
|
animation->timelines[animation->timelineCount++] = (Timeline*)timeline;
|
||||||
float duration = timeline->frames[frameCount - 1];
|
duration = timeline->frames[frameCount - 1];
|
||||||
if (duration > animation->duration) animation->duration = duration;
|
if (duration > animation->duration) animation->duration = duration;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -222,34 +233,42 @@ static Animation* _SkeletonJson_readAnimation (SkeletonJson* self, Json* root, S
|
||||||
|
|
||||||
SkeletonData* SkeletonJson_readSkeletonDataFile (SkeletonJson* self, const char* path) {
|
SkeletonData* SkeletonJson_readSkeletonDataFile (SkeletonJson* self, const char* path) {
|
||||||
int length;
|
int length;
|
||||||
|
SkeletonData* skeletonData;
|
||||||
const char* json = _Util_readFile(path, &length);
|
const char* json = _Util_readFile(path, &length);
|
||||||
if (!json) {
|
if (!json) {
|
||||||
_SkeletonJson_setError(self, 0, "Unable to read skeleton file: ", path);
|
_SkeletonJson_setError(self, 0, "Unable to read skeleton file: ", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
SkeletonData* skeletonData = SkeletonJson_readSkeletonData(self, json);
|
skeletonData = SkeletonJson_readSkeletonData(self, json);
|
||||||
FREE(json);
|
FREE(json);
|
||||||
return skeletonData;
|
return skeletonData;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* json) {
|
SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* json) {
|
||||||
|
SkeletonData* skeletonData;
|
||||||
|
Json *root, *bones;
|
||||||
|
int i, ii, iii, boneCount;
|
||||||
|
Json* slots;
|
||||||
|
Json* skinsMap;
|
||||||
|
Json* animations;
|
||||||
|
|
||||||
FREE(self->error);
|
FREE(self->error);
|
||||||
CONST_CAST(char*, self->error) = 0;
|
CONST_CAST(char*, self->error) = 0;
|
||||||
|
|
||||||
Json* root = Json_create(json);
|
root = Json_create(json);
|
||||||
if (!root) {
|
if (!root) {
|
||||||
_SkeletonJson_setError(self, 0, "Invalid skeleton JSON: ", Json_getError());
|
_SkeletonJson_setError(self, 0, "Invalid skeleton JSON: ", Json_getError());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkeletonData* skeletonData = SkeletonData_create();
|
skeletonData = SkeletonData_create();
|
||||||
int i, ii, iii;
|
|
||||||
|
|
||||||
Json* bones = Json_getItem(root, "bones");
|
bones = Json_getItem(root, "bones");
|
||||||
int boneCount = Json_getSize(bones);
|
boneCount = Json_getSize(bones);
|
||||||
skeletonData->bones = MALLOC(BoneData*, boneCount);
|
skeletonData->bones = MALLOC(BoneData*, boneCount);
|
||||||
for (i = 0; i < boneCount; ++i) {
|
for (i = 0; i < boneCount; ++i) {
|
||||||
Json* boneMap = Json_getItemAt(bones, i);
|
Json* boneMap = Json_getItemAt(bones, i);
|
||||||
|
BoneData* boneData;
|
||||||
|
|
||||||
const char* boneName = Json_getString(boneMap, "name", 0);
|
const char* boneName = Json_getString(boneMap, "name", 0);
|
||||||
|
|
||||||
|
@ -264,7 +283,7 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoneData* boneData = BoneData_create(boneName, parent);
|
boneData = BoneData_create(boneName, parent);
|
||||||
boneData->length = Json_getFloat(boneMap, "length", 0) * self->scale;
|
boneData->length = Json_getFloat(boneMap, "length", 0) * self->scale;
|
||||||
boneData->x = Json_getFloat(boneMap, "x", 0) * self->scale;
|
boneData->x = Json_getFloat(boneMap, "x", 0) * self->scale;
|
||||||
boneData->y = Json_getFloat(boneMap, "y", 0) * self->scale;
|
boneData->y = Json_getFloat(boneMap, "y", 0) * self->scale;
|
||||||
|
@ -276,11 +295,14 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
|
||||||
skeletonData->boneCount++;
|
skeletonData->boneCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Json* slots = Json_getItem(root, "slots");
|
slots = Json_getItem(root, "slots");
|
||||||
if (slots) {
|
if (slots) {
|
||||||
int slotCount = Json_getSize(slots);
|
int slotCount = Json_getSize(slots);
|
||||||
skeletonData->slots = MALLOC(SlotData*, slotCount);
|
skeletonData->slots = MALLOC(SlotData*, slotCount);
|
||||||
for (i = 0; i < slotCount; ++i) {
|
for (i = 0; i < slotCount; ++i) {
|
||||||
|
SlotData* slotData;
|
||||||
|
const char* color;
|
||||||
|
Json *attachmentItem;
|
||||||
Json* slotMap = Json_getItemAt(slots, i);
|
Json* slotMap = Json_getItemAt(slots, i);
|
||||||
|
|
||||||
const char* slotName = Json_getString(slotMap, "name", 0);
|
const char* slotName = Json_getString(slotMap, "name", 0);
|
||||||
|
@ -293,9 +315,9 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SlotData* slotData = SlotData_create(slotName, boneData);
|
slotData = SlotData_create(slotName, boneData);
|
||||||
|
|
||||||
const char* color = Json_getString(slotMap, "color", 0);
|
color = Json_getString(slotMap, "color", 0);
|
||||||
if (color) {
|
if (color) {
|
||||||
slotData->r = toColor(color, 0);
|
slotData->r = toColor(color, 0);
|
||||||
slotData->g = toColor(color, 1);
|
slotData->g = toColor(color, 1);
|
||||||
|
@ -303,7 +325,7 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
|
||||||
slotData->a = toColor(color, 3);
|
slotData->a = toColor(color, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
Json *attachmentItem = Json_getItem(slotMap, "attachment");
|
attachmentItem = Json_getItem(slotMap, "attachment");
|
||||||
if (attachmentItem) SlotData_setAttachmentName(slotData, attachmentItem->valuestring);
|
if (attachmentItem) SlotData_setAttachmentName(slotData, attachmentItem->valuestring);
|
||||||
|
|
||||||
skeletonData->slots[i] = slotData;
|
skeletonData->slots[i] = slotData;
|
||||||
|
@ -311,7 +333,7 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Json* skinsMap = Json_getItem(root, "skins");
|
skinsMap = Json_getItem(root, "skins");
|
||||||
if (skinsMap) {
|
if (skinsMap) {
|
||||||
int skinCount = Json_getSize(skinsMap);
|
int skinCount = Json_getSize(skinsMap);
|
||||||
skeletonData->skins = MALLOC(Skin*, skinCount);
|
skeletonData->skins = MALLOC(Skin*, skinCount);
|
||||||
|
@ -319,11 +341,13 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
|
||||||
Json* slotMap = Json_getItemAt(skinsMap, i);
|
Json* slotMap = Json_getItemAt(skinsMap, i);
|
||||||
const char* skinName = slotMap->name;
|
const char* skinName = slotMap->name;
|
||||||
Skin *skin = Skin_create(skinName);
|
Skin *skin = Skin_create(skinName);
|
||||||
|
int slotNameCount;
|
||||||
|
|
||||||
skeletonData->skins[i] = skin;
|
skeletonData->skins[i] = skin;
|
||||||
skeletonData->skinCount++;
|
skeletonData->skinCount++;
|
||||||
if (strcmp(skinName, "default") == 0) skeletonData->defaultSkin = skin;
|
if (strcmp(skinName, "default") == 0) skeletonData->defaultSkin = skin;
|
||||||
|
|
||||||
int slotNameCount = Json_getSize(slotMap);
|
slotNameCount = Json_getSize(slotMap);
|
||||||
for (ii = 0; ii < slotNameCount; ++ii) {
|
for (ii = 0; ii < slotNameCount; ++ii) {
|
||||||
Json* attachmentsMap = Json_getItemAt(slotMap, ii);
|
Json* attachmentsMap = Json_getItemAt(slotMap, ii);
|
||||||
const char* slotName = attachmentsMap->name;
|
const char* slotName = attachmentsMap->name;
|
||||||
|
@ -331,6 +355,7 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
|
||||||
|
|
||||||
int attachmentCount = Json_getSize(attachmentsMap);
|
int attachmentCount = Json_getSize(attachmentsMap);
|
||||||
for (iii = 0; iii < attachmentCount; ++iii) {
|
for (iii = 0; iii < attachmentCount; ++iii) {
|
||||||
|
Attachment* attachment;
|
||||||
Json* attachmentMap = Json_getItemAt(attachmentsMap, iii);
|
Json* attachmentMap = Json_getItemAt(attachmentsMap, iii);
|
||||||
const char* skinAttachmentName = attachmentMap->name;
|
const char* skinAttachmentName = attachmentMap->name;
|
||||||
const char* attachmentName = Json_getString(attachmentMap, "name", skinAttachmentName);
|
const char* attachmentName = Json_getString(attachmentMap, "name", skinAttachmentName);
|
||||||
|
@ -347,7 +372,7 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Attachment* attachment = AttachmentLoader_newAttachment(self->attachmentLoader, skin, type, attachmentName);
|
attachment = AttachmentLoader_newAttachment(self->attachmentLoader, skin, type, attachmentName);
|
||||||
if (!attachment) {
|
if (!attachment) {
|
||||||
if (self->attachmentLoader->error1) {
|
if (self->attachmentLoader->error1) {
|
||||||
SkeletonData_dispose(skeletonData);
|
SkeletonData_dispose(skeletonData);
|
||||||
|
@ -375,7 +400,7 @@ SkeletonData* SkeletonJson_readSkeletonData (SkeletonJson* self, const char* jso
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Json* animations = Json_getItem(root, "animations");
|
animations = Json_getItem(root, "animations");
|
||||||
if (animations) {
|
if (animations) {
|
||||||
int animationCount = Json_getSize(animations);
|
int animationCount = Json_getSize(animations);
|
||||||
skeletonData->animations = MALLOC(Animation*, animationCount);
|
skeletonData->animations = MALLOC(Animation*, animationCount);
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
|
|
||||||
#include <spine/Skin.h>
|
#include <spine/Skin.h>
|
||||||
#include <spine/extension.h>
|
#include <spine/extension.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
namespace cocos2d { namespace extension {
|
namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
@ -65,11 +64,11 @@ Skin* Skin_create (const char* name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skin_dispose (Skin* self) {
|
void Skin_dispose (Skin* self) {
|
||||||
_Entry* entry = SUB_CAST(_Internal, self)->entries;
|
_Entry* entry = SUB_CAST(_Internal, self) ->entries;
|
||||||
while (entry) {
|
while (entry) {
|
||||||
_Entry* nextEtry = entry->next;
|
_Entry* nextEntry = entry->next;
|
||||||
_Entry_dispose(entry);
|
_Entry_dispose(entry);
|
||||||
entry = nextEtry;
|
entry = nextEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
FREE(self->name);
|
FREE(self->name);
|
||||||
|
@ -78,8 +77,8 @@ void Skin_dispose (Skin* self) {
|
||||||
|
|
||||||
void Skin_addAttachment (Skin* self, int slotIndex, const char* name, Attachment* attachment) {
|
void Skin_addAttachment (Skin* self, int slotIndex, const char* name, Attachment* attachment) {
|
||||||
_Entry* newEntry = _Entry_create(slotIndex, name, attachment);
|
_Entry* newEntry = _Entry_create(slotIndex, name, attachment);
|
||||||
newEntry->next = SUB_CAST(_Internal, self)->entries;
|
newEntry->next = SUB_CAST(_Internal, self) ->entries;
|
||||||
SUB_CAST(_Internal, self)->entries = newEntry;
|
SUB_CAST(_Internal, self) ->entries = newEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
Attachment* Skin_getAttachment (const Skin* self, int slotIndex, const char* name) {
|
Attachment* Skin_getAttachment (const Skin* self, int slotIndex, const char* name) {
|
||||||
|
@ -91,6 +90,19 @@ Attachment* Skin_getAttachment (const Skin* self, int slotIndex, const char* nam
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* Skin_getAttachmentName (const Skin* self, int slotIndex, int attachmentIndex) {
|
||||||
|
const _Entry* entry = SUB_CAST(_Internal, self) ->entries;
|
||||||
|
int i = 0;
|
||||||
|
while (entry) {
|
||||||
|
if (entry->slotIndex == slotIndex) {
|
||||||
|
if (i == attachmentIndex) return entry->name;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Skin_attachAll (const Skin* self, Skeleton* skeleton, const Skin* oldSkin) {
|
void Skin_attachAll (const Skin* self, Skeleton* skeleton, const Skin* oldSkin) {
|
||||||
const _Entry *entry = SUB_CAST(_Internal, oldSkin) ->entries;
|
const _Entry *entry = SUB_CAST(_Internal, oldSkin) ->entries;
|
||||||
while (entry) {
|
while (entry) {
|
||||||
|
|
|
@ -44,6 +44,9 @@ void Skin_addAttachment (Skin* self, int slotIndex, const char* name, Attachment
|
||||||
/* Returns 0 if the attachment was not found. */
|
/* Returns 0 if the attachment was not found. */
|
||||||
Attachment* Skin_getAttachment (const Skin* self, int slotIndex, const char* name);
|
Attachment* Skin_getAttachment (const Skin* self, int slotIndex, const char* name);
|
||||||
|
|
||||||
|
/* Returns 0 if the slot or attachment was not found. */
|
||||||
|
const char* Skin_getAttachmentName (const Skin* self, int slotIndex, int attachmentIndex);
|
||||||
|
|
||||||
/** Attach each attachment in this skin if the corresponding attachment in oldSkin is currently attached. */
|
/** Attach each attachment in this skin if the corresponding attachment in oldSkin is currently attached. */
|
||||||
void Skin_attachAll (const Skin* self, struct Skeleton* skeleton, const Skin* oldSkin);
|
void Skin_attachAll (const Skin* self, struct Skeleton* skeleton, const Skin* oldSkin);
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ Slot* Slot_create (SlotData* data, Skeleton* skeleton, Bone* bone) {
|
||||||
CONST_CAST(SlotData*, self->data) = data;
|
CONST_CAST(SlotData*, self->data) = data;
|
||||||
CONST_CAST(Skeleton*, self->skeleton) = skeleton;
|
CONST_CAST(Skeleton*, self->skeleton) = skeleton;
|
||||||
CONST_CAST(Bone*, self->bone) = bone;
|
CONST_CAST(Bone*, self->bone) = bone;
|
||||||
Slot_setToBindPose(self);
|
Slot_setToSetupPose(self);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,13 +60,13 @@ float Slot_getAttachmentTime (const Slot* self) {
|
||||||
return self->skeleton->time - SUB_CAST(_Internal, self) ->attachmentTime;
|
return self->skeleton->time - SUB_CAST(_Internal, self) ->attachmentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Slot_setToBindPose (Slot* self) {
|
void Slot_setToSetupPose (Slot* self) {
|
||||||
|
Attachment* attachment = 0;
|
||||||
self->r = self->data->r;
|
self->r = self->data->r;
|
||||||
self->g = self->data->g;
|
self->g = self->data->g;
|
||||||
self->b = self->data->b;
|
self->b = self->data->b;
|
||||||
self->a = self->data->a;
|
self->a = self->data->a;
|
||||||
|
|
||||||
Attachment* attachment = 0;
|
|
||||||
if (self->data->attachmentName) {
|
if (self->data->attachmentName) {
|
||||||
/* Find slot index. */
|
/* Find slot index. */
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -51,7 +51,7 @@ void Slot_setAttachment (Slot* self, Attachment* attachment);
|
||||||
void Slot_setAttachmentTime (Slot* self, float time);
|
void Slot_setAttachmentTime (Slot* self, float time);
|
||||||
float Slot_getAttachmentTime (const Slot* self);
|
float Slot_getAttachmentTime (const Slot* self);
|
||||||
|
|
||||||
void Slot_setToBindPose (Slot* self);
|
void Slot_setToSetupPose (Slot* self);
|
||||||
|
|
||||||
}} // namespace cocos2d { namespace extension {
|
}} // namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ typedef struct {
|
||||||
SlotData* SlotData_create (const char* name, BoneData* boneData);
|
SlotData* SlotData_create (const char* name, BoneData* boneData);
|
||||||
void SlotData_dispose (SlotData* self);
|
void SlotData_dispose (SlotData* self);
|
||||||
|
|
||||||
/* @param attachmentName May be 0 for no bind pose attachment. */
|
/* @param attachmentName May be 0 for no setup pose attachment. */
|
||||||
void SlotData_setAttachmentName (SlotData* self, const char* attachmentName);
|
void SlotData_setAttachmentName (SlotData* self, const char* attachmentName);
|
||||||
|
|
||||||
}} // namespace cocos2d { namespace extension {
|
}} // namespace cocos2d { namespace extension {
|
||||||
|
|
|
@ -51,6 +51,7 @@ void _setFree (void (*free) (void* ptr)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char* _readFile (const char* path, int* length) {
|
char* _readFile (const char* path, int* length) {
|
||||||
|
char *data;
|
||||||
FILE *file = fopen(path, "rb");
|
FILE *file = fopen(path, "rb");
|
||||||
if (!file) return 0;
|
if (!file) return 0;
|
||||||
|
|
||||||
|
@ -58,10 +59,9 @@ char* _readFile (const char* path, int* length) {
|
||||||
*length = ftell(file);
|
*length = ftell(file);
|
||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
char* data = MALLOC(char, *length);
|
data = MALLOC(char, *length);
|
||||||
int rtn = fread(data, 1, *length, file);
|
fread(data, 1, *length, file);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
if (rtn != *length) return 0;
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,8 +113,8 @@ char* _readFile (const char* path, int* length);
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
void _AttachmentLoader_init (AttachmentLoader* self, //
|
void _AttachmentLoader_init (AttachmentLoader* self, /**/
|
||||||
void (*dispose) (AttachmentLoader* self), //
|
void (*dispose) (AttachmentLoader* self), /**/
|
||||||
Attachment* (*newAttachment) (AttachmentLoader* self, Skin* skin, AttachmentType type, const char* name));
|
Attachment* (*newAttachment) (AttachmentLoader* self, Skin* skin, AttachmentType type, const char* name));
|
||||||
void _AttachmentLoader_deinit (AttachmentLoader* self);
|
void _AttachmentLoader_deinit (AttachmentLoader* self);
|
||||||
void _AttachmentLoader_setError (AttachmentLoader* self, const char* error1, const char* error2);
|
void _AttachmentLoader_setError (AttachmentLoader* self, const char* error1, const char* error2);
|
||||||
|
@ -122,21 +122,21 @@ void _AttachmentLoader_setUnknownTypeError (AttachmentLoader* self, AttachmentTy
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
void _Attachment_init (Attachment* self, const char* name, AttachmentType type, //
|
void _Attachment_init (Attachment* self, const char* name, AttachmentType type, /**/
|
||||||
void (*dispose) (Attachment* self));
|
void (*dispose) (Attachment* self));
|
||||||
void _Attachment_deinit (Attachment* self);
|
void _Attachment_deinit (Attachment* self);
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
void _Timeline_init (Timeline* self, //
|
void _Timeline_init (Timeline* self, /**/
|
||||||
void (*dispose) (Timeline* self), //
|
void (*dispose) (Timeline* self), /**/
|
||||||
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha));
|
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha));
|
||||||
void _Timeline_deinit (Timeline* self);
|
void _Timeline_deinit (Timeline* self);
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
void _CurveTimeline_init (CurveTimeline* self, int frameCount, //
|
void _CurveTimeline_init (CurveTimeline* self, int frameCount, /**/
|
||||||
void (*dispose) (Timeline* self), //
|
void (*dispose) (Timeline* self), /**/
|
||||||
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha));
|
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha));
|
||||||
void _CurveTimeline_deinit (CurveTimeline* self);
|
void _CurveTimeline_deinit (CurveTimeline* self);
|
||||||
|
|
||||||
|
|
|
@ -27,45 +27,46 @@
|
||||||
#include <spine/extension.h>
|
#include <spine/extension.h>
|
||||||
|
|
||||||
USING_NS_CC;
|
USING_NS_CC;
|
||||||
using std::min;
|
|
||||||
using std::max;
|
|
||||||
namespace cocos2d { namespace extension {
|
namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
|
void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
|
||||||
CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage(path);
|
CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage(path);
|
||||||
CCTextureAtlas* textureAtlas = CCTextureAtlas::createWithTexture(texture, 4);
|
CCTextureAtlas* textureAtlas = CCTextureAtlas::createWithTexture(texture, 4);
|
||||||
textureAtlas->retain();
|
textureAtlas->retain();
|
||||||
self->texture = textureAtlas;
|
self->rendererObject = textureAtlas;
|
||||||
|
self->width = texture->getPixelsWide();
|
||||||
// Using getContentSize to make it supports the strategy of loading resources in cocos2d-x.
|
self->height = texture->getPixelsHigh();
|
||||||
|
|
||||||
// self->width = texture->getPixelsWide();
|
|
||||||
// self->height = texture->getPixelsHigh();
|
|
||||||
|
|
||||||
self->width = texture->getContentSize().width;
|
|
||||||
self->height = texture->getContentSize().height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _AtlasPage_disposeTexture (AtlasPage* self) {
|
void _AtlasPage_disposeTexture (AtlasPage* self) {
|
||||||
((CCTextureAtlas*)self->texture)->release();
|
((CCTextureAtlas*)self->rendererObject)->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
char* _Util_readFile (const char* path, int* length) {
|
char* _Util_readFile (const char* path, int* length) {
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
char* data = reinterpret_cast<char*>(CCFileUtils::sharedFileUtils()->getFileData(path, "r", &size));
|
char* data = reinterpret_cast<char*>(CCFileUtils::sharedFileUtils()->getFileData(
|
||||||
|
CCFileUtils::sharedFileUtils()->fullPathForFilename(path).c_str(), "r", &size));
|
||||||
*length = size;
|
*length = size;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_T2F_Quad* quad) {
|
void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_T2F_Quad* quad, bool premultipliedAlpha) {
|
||||||
RegionAttachment_updateVertices(self, slot);
|
float vertices[8];
|
||||||
|
RegionAttachment_computeVertices(self, slot->skeleton->x, slot->skeleton->y, slot->bone, vertices);
|
||||||
|
|
||||||
GLubyte r = slot->skeleton->r * slot->r * 255;
|
GLubyte r = slot->skeleton->r * slot->r * 255;
|
||||||
GLubyte g = slot->skeleton->g * slot->g * 255;
|
GLubyte g = slot->skeleton->g * slot->g * 255;
|
||||||
GLubyte b = slot->skeleton->b * slot->b * 255;
|
GLubyte b = slot->skeleton->b * slot->b * 255;
|
||||||
GLubyte a = slot->skeleton->a * slot->a * 255;
|
float normalizedAlpha = slot->skeleton->a * slot->a;
|
||||||
|
if (premultipliedAlpha) {
|
||||||
|
r *= normalizedAlpha;
|
||||||
|
g *= normalizedAlpha;
|
||||||
|
b *= normalizedAlpha;
|
||||||
|
}
|
||||||
|
GLubyte a = normalizedAlpha * 255;
|
||||||
quad->bl.colors.r = r;
|
quad->bl.colors.r = r;
|
||||||
quad->bl.colors.g = g;
|
quad->bl.colors.g = g;
|
||||||
quad->bl.colors.b = b;
|
quad->bl.colors.b = b;
|
||||||
|
@ -83,225 +84,23 @@ void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_
|
||||||
quad->br.colors.b = b;
|
quad->br.colors.b = b;
|
||||||
quad->br.colors.a = a;
|
quad->br.colors.a = a;
|
||||||
|
|
||||||
quad->bl.vertices.x = self->vertices[VERTEX_X1];
|
quad->bl.vertices.x = vertices[VERTEX_X1];
|
||||||
quad->bl.vertices.y = self->vertices[VERTEX_Y1];
|
quad->bl.vertices.y = vertices[VERTEX_Y1];
|
||||||
quad->tl.vertices.x = self->vertices[VERTEX_X2];
|
quad->tl.vertices.x = vertices[VERTEX_X2];
|
||||||
quad->tl.vertices.y = self->vertices[VERTEX_Y2];
|
quad->tl.vertices.y = vertices[VERTEX_Y2];
|
||||||
quad->tr.vertices.x = self->vertices[VERTEX_X3];
|
quad->tr.vertices.x = vertices[VERTEX_X3];
|
||||||
quad->tr.vertices.y = self->vertices[VERTEX_Y3];
|
quad->tr.vertices.y = vertices[VERTEX_Y3];
|
||||||
quad->br.vertices.x = self->vertices[VERTEX_X4];
|
quad->br.vertices.x = vertices[VERTEX_X4];
|
||||||
quad->br.vertices.y = self->vertices[VERTEX_Y4];
|
quad->br.vertices.y = vertices[VERTEX_Y4];
|
||||||
|
|
||||||
if (self->region->rotate) {
|
quad->bl.texCoords.u = self->uvs[VERTEX_X1];
|
||||||
quad->tl.texCoords.u = self->region->u;
|
quad->bl.texCoords.v = self->uvs[VERTEX_Y1];
|
||||||
quad->tl.texCoords.v = self->region->v2;
|
quad->tl.texCoords.u = self->uvs[VERTEX_X2];
|
||||||
quad->tr.texCoords.u = self->region->u;
|
quad->tl.texCoords.v = self->uvs[VERTEX_Y2];
|
||||||
quad->tr.texCoords.v = self->region->v;
|
quad->tr.texCoords.u = self->uvs[VERTEX_X3];
|
||||||
quad->br.texCoords.u = self->region->u2;
|
quad->tr.texCoords.v = self->uvs[VERTEX_Y3];
|
||||||
quad->br.texCoords.v = self->region->v;
|
quad->br.texCoords.u = self->uvs[VERTEX_X4];
|
||||||
quad->bl.texCoords.u = self->region->u2;
|
quad->br.texCoords.v = self->uvs[VERTEX_Y4];
|
||||||
quad->bl.texCoords.v = self->region->v2;
|
|
||||||
} else {
|
|
||||||
quad->bl.texCoords.u = self->region->u;
|
|
||||||
quad->bl.texCoords.v = self->region->v2;
|
|
||||||
quad->tl.texCoords.u = self->region->u;
|
|
||||||
quad->tl.texCoords.v = self->region->v;
|
|
||||||
quad->tr.texCoords.u = self->region->u2;
|
|
||||||
quad->tr.texCoords.v = self->region->v;
|
|
||||||
quad->br.texCoords.u = self->region->u2;
|
|
||||||
quad->br.texCoords.v = self->region->v2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**/
|
|
||||||
|
|
||||||
CCSkeleton* CCSkeleton::createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale) {
|
|
||||||
SkeletonJson* json = SkeletonJson_create(atlas);
|
|
||||||
json->scale = scale;
|
|
||||||
SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, skeletonDataFile);
|
|
||||||
SkeletonJson_dispose(json);
|
|
||||||
CCSkeleton* node = skeletonData ? createWithData(skeletonData) : 0;
|
|
||||||
node->ownsSkeleton = true;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
CCSkeleton* CCSkeleton::createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale) {
|
|
||||||
Atlas* atlas = Atlas_readAtlasFile(atlasFile);
|
|
||||||
if (!atlas) return 0;
|
|
||||||
SkeletonJson* json = SkeletonJson_create(atlas);
|
|
||||||
json->scale = scale;
|
|
||||||
SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, skeletonDataFile);
|
|
||||||
SkeletonJson_dispose(json);
|
|
||||||
if (!skeletonData) {
|
|
||||||
Atlas_dispose(atlas);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
CCSkeleton* node = createWithData(skeletonData);
|
|
||||||
node->ownsSkeleton = true;
|
|
||||||
node->atlas = atlas;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
CCSkeleton* CCSkeleton::createWithData (SkeletonData* skeletonData, AnimationStateData* stateData) {
|
|
||||||
CCSkeleton* node = new CCSkeleton(skeletonData, stateData);
|
|
||||||
node->autorelease();
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
CCSkeleton::CCSkeleton (SkeletonData *skeletonData, AnimationStateData *stateData) :
|
|
||||||
ownsSkeleton(false), ownsStateData(false), atlas(0),
|
|
||||||
skeleton(0), state(0), debugSlots(false), debugBones(false) {
|
|
||||||
CONST_CAST(Skeleton*, skeleton) = Skeleton_create(skeletonData);
|
|
||||||
|
|
||||||
if (!stateData) {
|
|
||||||
stateData = AnimationStateData_create(skeletonData);
|
|
||||||
ownsStateData = true;
|
|
||||||
}
|
|
||||||
CONST_CAST(AnimationState*, state) = AnimationState_create(stateData);
|
|
||||||
|
|
||||||
blendFunc.src = GL_ONE;
|
|
||||||
blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
|
|
||||||
|
|
||||||
timeScale = 1;
|
|
||||||
|
|
||||||
setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor));
|
|
||||||
scheduleUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
CCSkeleton::~CCSkeleton () {
|
|
||||||
if (ownsSkeleton) Skeleton_dispose(skeleton);
|
|
||||||
if (ownsStateData) AnimationStateData_dispose(state->data);
|
|
||||||
if (atlas) Atlas_dispose(atlas);
|
|
||||||
AnimationState_dispose(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCSkeleton::update (float deltaTime) {
|
|
||||||
Skeleton_update(skeleton, deltaTime);
|
|
||||||
AnimationState_update(state, deltaTime * timeScale);
|
|
||||||
AnimationState_apply(state, skeleton);
|
|
||||||
Skeleton_updateWorldTransform(skeleton);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCSkeleton::draw () {
|
|
||||||
CC_NODE_DRAW_SETUP();
|
|
||||||
|
|
||||||
ccGLBlendFunc(blendFunc.src, blendFunc.dst);
|
|
||||||
ccColor3B color = getColor();
|
|
||||||
skeleton->r = color.r / (float)255;
|
|
||||||
skeleton->g = color.g / (float)255;
|
|
||||||
skeleton->b = color.b / (float)255;
|
|
||||||
skeleton->a = getOpacity() / (float)255;
|
|
||||||
|
|
||||||
CCTextureAtlas* textureAtlas = 0;
|
|
||||||
ccV3F_C4B_T2F_Quad quad;
|
|
||||||
quad.tl.vertices.z = 0;
|
|
||||||
quad.tr.vertices.z = 0;
|
|
||||||
quad.bl.vertices.z = 0;
|
|
||||||
quad.br.vertices.z = 0;
|
|
||||||
for (int i = 0, n = skeleton->slotCount; i < n; i++) {
|
|
||||||
Slot* slot = skeleton->slots[i];
|
|
||||||
if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
|
|
||||||
RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
|
|
||||||
CCTextureAtlas* regionTextureAtlas = (CCTextureAtlas*)attachment->region->page->texture;
|
|
||||||
if (regionTextureAtlas != textureAtlas) {
|
|
||||||
if (textureAtlas) {
|
|
||||||
textureAtlas->drawQuads();
|
|
||||||
textureAtlas->removeAllQuads();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
textureAtlas = regionTextureAtlas;
|
|
||||||
if (textureAtlas->getCapacity() == textureAtlas->getTotalQuads() &&
|
|
||||||
!textureAtlas->resizeCapacity(textureAtlas->getCapacity() * 2)) return;
|
|
||||||
RegionAttachment_updateQuad(attachment, slot, &quad);
|
|
||||||
textureAtlas->updateQuad(&quad, textureAtlas->getTotalQuads());
|
|
||||||
}
|
|
||||||
if (textureAtlas) {
|
|
||||||
textureAtlas->drawQuads();
|
|
||||||
textureAtlas->removeAllQuads();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debugSlots) {
|
|
||||||
// Slots.
|
|
||||||
ccDrawColor4B(0, 0, 255, 255);
|
|
||||||
glLineWidth(1);
|
|
||||||
CCPoint points[4];
|
|
||||||
ccV3F_C4B_T2F_Quad quad;
|
|
||||||
for (int i = 0, n = skeleton->slotCount; i < n; i++) {
|
|
||||||
Slot* slot = skeleton->slots[i];
|
|
||||||
if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
|
|
||||||
RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
|
|
||||||
RegionAttachment_updateQuad(attachment, slot, &quad);
|
|
||||||
points[0] = ccp(quad.bl.vertices.x, quad.bl.vertices.y);
|
|
||||||
points[1] = ccp(quad.br.vertices.x, quad.br.vertices.y);
|
|
||||||
points[2] = ccp(quad.tr.vertices.x, quad.tr.vertices.y);
|
|
||||||
points[3] = ccp(quad.tl.vertices.x, quad.tl.vertices.y);
|
|
||||||
ccDrawPoly(points, 4, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debugBones) {
|
|
||||||
// Bone lengths.
|
|
||||||
glLineWidth(2);
|
|
||||||
ccDrawColor4B(255, 0, 0, 255);
|
|
||||||
for (int i = 0, n = skeleton->boneCount; i < n; i++) {
|
|
||||||
Bone *bone = skeleton->bones[i];
|
|
||||||
float x = bone->data->length * bone->m00 + bone->worldX;
|
|
||||||
float y = bone->data->length * bone->m10 + bone->worldY;
|
|
||||||
ccDrawLine(ccp(bone->worldX, bone->worldY), ccp(x, y));
|
|
||||||
}
|
|
||||||
// Bone origins.
|
|
||||||
ccPointSize(4);
|
|
||||||
ccDrawColor4B(0, 0, 255, 255); // Root bone is blue.
|
|
||||||
for (int i = 0, n = skeleton->boneCount; i < n; i++) {
|
|
||||||
Bone *bone = skeleton->bones[i];
|
|
||||||
ccDrawPoint(ccp(bone->worldX, bone->worldY));
|
|
||||||
if (i == 0) ccDrawColor4B(0, 255, 0, 255);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CCRect CCSkeleton::boundingBox () {
|
|
||||||
float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN;
|
|
||||||
float scaleX = getScaleX();
|
|
||||||
float scaleY = getScaleY();
|
|
||||||
ccV3F_C4B_T2F_Quad quad;
|
|
||||||
for (int i = 0; i < skeleton->slotCount; ++i) {
|
|
||||||
Slot* slot = skeleton->slots[i];
|
|
||||||
if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
|
|
||||||
RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
|
|
||||||
RegionAttachment_updateQuad(attachment, slot, &quad);
|
|
||||||
minX = min(minX, quad.bl.vertices.x * scaleX);
|
|
||||||
minY = min(minY, quad.bl.vertices.y * scaleY);
|
|
||||||
maxX = max(maxX, quad.bl.vertices.x * scaleX);
|
|
||||||
maxY = max(maxY, quad.bl.vertices.y * scaleY);
|
|
||||||
minX = min(minX, quad.br.vertices.x * scaleX);
|
|
||||||
minY = min(minY, quad.br.vertices.y * scaleY);
|
|
||||||
maxX = max(maxX, quad.br.vertices.x * scaleX);
|
|
||||||
maxY = max(maxY, quad.br.vertices.y * scaleY);
|
|
||||||
minX = min(minX, quad.tl.vertices.x * scaleX);
|
|
||||||
minY = min(minY, quad.tl.vertices.y * scaleY);
|
|
||||||
maxX = max(maxX, quad.tl.vertices.x * scaleX);
|
|
||||||
maxY = max(maxY, quad.tl.vertices.y * scaleY);
|
|
||||||
minX = min(minX, quad.tr.vertices.x * scaleX);
|
|
||||||
minY = min(minY, quad.tr.vertices.y * scaleY);
|
|
||||||
maxX = max(maxX, quad.tr.vertices.x * scaleX);
|
|
||||||
maxY = max(maxY, quad.tr.vertices.y * scaleY);
|
|
||||||
}
|
|
||||||
CCPoint position = getPosition();
|
|
||||||
minX = position.x + minX;
|
|
||||||
minY = position.y + minY;
|
|
||||||
maxX = position.x + maxX;
|
|
||||||
maxY = position.y + maxY;
|
|
||||||
return CCRectMake(minX, minY, maxX - minX, maxY - minY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CCBlendProtocol
|
|
||||||
|
|
||||||
ccBlendFunc CCSkeleton::getBlendFunc () {
|
|
||||||
return blendFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCSkeleton::setBlendFunc (ccBlendFunc blendFunc) {
|
|
||||||
this->blendFunc = blendFunc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace cocos2d { namespace extension {
|
}} // namespace cocos2d { namespace extension {
|
|
@ -28,40 +28,12 @@
|
||||||
|
|
||||||
#include <spine/spine.h>
|
#include <spine/spine.h>
|
||||||
#include "cocos2d.h"
|
#include "cocos2d.h"
|
||||||
|
#include <spine/CCSkeleton.h>
|
||||||
|
#include <spine/CCSkeletonAnimation.h>
|
||||||
|
|
||||||
namespace cocos2d { namespace extension {
|
namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
class CCSkeleton: public cocos2d::CCNodeRGBA, public cocos2d::CCBlendProtocol {
|
void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, cocos2d::ccV3F_C4B_T2F_Quad* quad, bool premultiplied = false);
|
||||||
private:
|
|
||||||
bool ownsSkeleton;
|
|
||||||
bool ownsStateData;
|
|
||||||
Atlas* atlas;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Skeleton* const skeleton;
|
|
||||||
AnimationState* const state;
|
|
||||||
float timeScale;
|
|
||||||
bool debugSlots;
|
|
||||||
bool debugBones;
|
|
||||||
|
|
||||||
static CCSkeleton* createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale = 1);
|
|
||||||
static CCSkeleton* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale = 1);
|
|
||||||
static CCSkeleton* createWithData (SkeletonData* skeletonData, AnimationStateData* stateData = 0);
|
|
||||||
|
|
||||||
CCSkeleton (SkeletonData* skeletonData, AnimationStateData* stateData = 0);
|
|
||||||
virtual ~CCSkeleton ();
|
|
||||||
|
|
||||||
virtual void update (float deltaTime);
|
|
||||||
virtual void draw ();
|
|
||||||
virtual cocos2d::CCRect boundingBox ();
|
|
||||||
|
|
||||||
// CCBlendProtocol
|
|
||||||
CC_PROPERTY(cocos2d::ccBlendFunc, blendFunc, BlendFunc);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**/
|
|
||||||
|
|
||||||
void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, cocos2d::ccV3F_C4B_T2F_Quad* quad);
|
|
||||||
|
|
||||||
}} // namespace cocos2d { namespace extension {
|
}} // namespace cocos2d { namespace extension {
|
||||||
|
|
||||||
|
|
|
@ -48,10 +48,11 @@ void SpineTestScene::runThisTest()
|
||||||
bool SpineTestLayer::init () {
|
bool SpineTestLayer::init () {
|
||||||
if (!CCLayer::init()) return false;
|
if (!CCLayer::init()) return false;
|
||||||
|
|
||||||
skeletonNode = CCSkeleton::createWithFile("spine/spineboy.json", "spine/spineboy.atlas");
|
skeletonNode = CCSkeletonAnimation::createWithFile("spine/spineboy.json", "spine/spineboy.atlas");
|
||||||
AnimationStateData_setMixByName(skeletonNode->state->data, "walk", "jump", 0.4f);
|
skeletonNode->setMix("walk", "jump", 0.4f);
|
||||||
AnimationStateData_setMixByName(skeletonNode->state->data, "jump", "walk", 0.4f);
|
skeletonNode->setMix("jump", "walk", 0.4f);
|
||||||
AnimationState_setAnimationByName(skeletonNode->state, "walk", true);
|
skeletonNode->setAnimation("walk", true);
|
||||||
|
|
||||||
skeletonNode->timeScale = 0.3f;
|
skeletonNode->timeScale = 0.3f;
|
||||||
skeletonNode->debugBones = true;
|
skeletonNode->debugBones = true;
|
||||||
|
|
||||||
|
@ -70,9 +71,11 @@ bool SpineTestLayer::init () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpineTestLayer::update (float deltaTime) {
|
void SpineTestLayer::update (float deltaTime) {
|
||||||
if (skeletonNode->state->loop) {
|
if (skeletonNode->states[0]->loop) {
|
||||||
if (skeletonNode->state->time > 2) AnimationState_setAnimationByName(skeletonNode->state, "jump", false);
|
if (skeletonNode->states[0]->time > 2)
|
||||||
|
skeletonNode->setAnimation("jump", false);
|
||||||
} else {
|
} else {
|
||||||
if (skeletonNode->state->time > 1) AnimationState_setAnimationByName(skeletonNode->state, "walk", true);
|
if (skeletonNode->states[0]->time > 1)
|
||||||
|
skeletonNode->setAnimation("walk", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
|
|
||||||
class SpineTestLayer: public cocos2d::CCLayer {
|
class SpineTestLayer: public cocos2d::CCLayer {
|
||||||
private:
|
private:
|
||||||
cocos2d::extension::CCSkeleton* skeletonNode;
|
cocos2d::extension::CCSkeletonAnimation* skeletonNode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
b95526a387e924fd628b7408ad3b7da4814a1f11
|
a236c647a983eee2393f9d63d67c7ae1817a3ed8
|
|
@ -1 +1 @@
|
||||||
5bf596dcac34b37a7ba44a2063590fb43de53efb
|
267a49c99f5d0f31e0b8d65f8d4df421a06de76f
|
Loading…
Reference in New Issue