[cpp] More 4.0 porting, SkeletonJson.

This commit is contained in:
badlogic 2021-03-05 13:47:50 +01:00
parent 5ef75959b9
commit 4375342576
7 changed files with 444 additions and 282 deletions

View File

@ -54,6 +54,8 @@ public:
/* Get item "string" from object. Case insensitive. */
static Json *getItem(Json *object, const char *string);
static Json *getItem(Json *object, int childIndex);
static const char *getString(Json *object, const char *name, const char *defaultValue);
static float getFloat(Json *object, const char *name, float defaultValue);

View File

@ -35,8 +35,14 @@
#include <spine/SpineString.h>
namespace spine {
class Timeline;
class CurveTimeline;
class CurveTimeline1;
class CurveTimeline2;
class VertexAttachment;
class Animation;
@ -76,9 +82,15 @@ private:
const bool _ownsLoader;
String _error;
static float toColor(const char *value, size_t index);
static void setBezier (CurveTimeline *timeline, int frame, int value, int bezier, float time1, float value1, float cx1, float cy1,
float cx2, float cy2, float time2, float value2);
static void readCurve(Json *frame, CurveTimeline *timeline, size_t frameIndex);
static int readCurve(Json *curve, CurveTimeline *timeline, int bezier, int frame, int value, float time1, float time2,
float value1, float value2, float scale);
static Timeline *readTimeline (Json *keyMap, CurveTimeline1 *timeline, float defaultValue, float scale);
static Timeline *readTimeline (Json *keyMap, CurveTimeline2 *timeline, const char* name1, const char *name2, float defaultValue, float scale);
Animation *readAnimation(Json *root, SkeletonData *skeletonData);

View File

@ -102,7 +102,6 @@
#include <spine/TransformMode.h>
#include <spine/TranslateTimeline.h>
#include <spine/Triangulator.h>
#include <spine/TwoColorTimeline.h>
#include <spine/Updatable.h>
#include <spine/Vector.h>
#include <spine/VertexAttachment.h>

View File

@ -56,6 +56,8 @@ AttachmentTimeline::AttachmentTimeline(size_t frameCount, int slotIndex) : Timel
}
}
AttachmentTimeline::~AttachmentTimeline() {}
void AttachmentTimeline::setAttachment(Skeleton& skeleton, Slot& slot, String* attachmentName) {
slot.setAttachment(attachmentName == NULL || attachmentName->isEmpty() ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName));
}

View File

@ -65,6 +65,15 @@ Json *Json::getItem(Json *object, const char *string) {
return c;
}
Json *Json::getItem(Json *object, int childIndex) {
Json *current = object->_child;
while (current != NULL && childIndex > 0) {
childIndex--;
current = current->_next;
}
return current;
}
const char *Json::getString(Json *object, const char *name, const char *defaultValue) {
object = getItem(object, name);
if (object) {

View File

@ -51,6 +51,8 @@ ScaleTimeline::ScaleTimeline(size_t frameCount, size_t bezierCount, int boneInde
setPropertyIds(ids, 2);
}
ScaleTimeline::~ScaleTimeline() {}
void ScaleTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction
) {
@ -164,6 +166,8 @@ ScaleXTimeline::ScaleXTimeline(size_t frameCount, size_t bezierCount, int boneIn
setPropertyIds(ids, 1);
}
ScaleXTimeline::~ScaleXTimeline() {}
void ScaleXTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction
) {
@ -235,6 +239,8 @@ ScaleYTimeline::ScaleYTimeline(size_t frameCount, size_t bezierCount, int boneIn
setPropertyIds(ids, 1);
}
ScaleYTimeline::~ScaleYTimeline() {}
void ScaleYTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction
) {

View File

@ -79,6 +79,31 @@
using namespace spine;
static float toColor(const char *value, size_t index) {
char digits[3];
char *error;
int color;
if (index >= strlen(value) / 2) return -1;
value += index * 2;
digits[0] = *value;
digits[1] = *(value + 1);
digits[2] = '\0';
color = (int) strtoul(digits, &error, 16);
if (*error != 0) return -1;
return color / (float) 255;
}
static void toColor(Color &color, const char *value, bool hasAlpha) {
color.r = toColor(value, 0);
color.g = toColor(value, 1);
color.g = toColor(value, 2);
if (hasAlpha) color.a = toColor(value, 3);
}
SkeletonJson::SkeletonJson(Atlas *atlas) : _attachmentLoader(new(__FILE__, __LINE__) AtlasAttachmentLoader(atlas)),
_scale(1), _ownsLoader(true)
{}
@ -132,11 +157,6 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
if (skeleton) {
skeletonData->_hash = Json::getString(skeleton, "hash", 0);
skeletonData->_version = Json::getString(skeleton, "spine", 0);
if ("3.8.75" == skeletonData->_version) {
delete skeletonData;
setError(root, "Unsupported skeleton data, please export with a newer version of Spine.", "");
return NULL;
}
skeletonData->_x = Json::getFloat(skeleton, "x", 0);
skeletonData->_y = Json::getFloat(skeleton, "y", 0);
skeletonData->_width = Json::getFloat(skeleton, "width", 0);
@ -329,10 +349,12 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
data->_offsetScaleY = Json::getFloat(constraintMap, "scaleY", 0);
data->_offsetShearY = Json::getFloat(constraintMap, "shearY", 0);
data->_rotateMix = Json::getFloat(constraintMap, "rotateMix", 1);
data->_translateMix = Json::getFloat(constraintMap, "translateMix", 1);
data->_scaleMix = Json::getFloat(constraintMap, "scaleMix", 1);
data->_shearMix = Json::getFloat(constraintMap, "shearMix", 1);
data->_mixRotate = Json::getFloat(constraintMap, "mixRotate", 1);
data->_mixX = Json::getFloat(constraintMap, "mixX", 1);
data->_mixY = Json::getFloat(constraintMap, "mixY", data->_mixX);
data->_mixScaleX = Json::getFloat(constraintMap, "mixScaleX", 1);
data->_mixScaleY = Json::getFloat(constraintMap, "mixScaleY", data->_mixScaleX);
data->_mixShearY = Json::getFloat(constraintMap, "mixShearY", 1);
skeletonData->_transformConstraints[i] = data;
}
@ -394,8 +416,9 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
if (data->_positionMode == PositionMode_Fixed) data->_position *= _scale;
data->_spacing = Json::getFloat(constraintMap, "spacing", 0);
if (data->_spacingMode == SpacingMode_Length || data->_spacingMode == SpacingMode_Fixed) data->_spacing *= _scale;
data->_rotateMix = Json::getFloat(constraintMap, "rotateMix", 1);
data->_translateMix = Json::getFloat(constraintMap, "translateMix", 1);
data->_mixRotate = Json::getFloat(constraintMap, "mixRotate", 1);
data->_mixX = Json::getFloat(constraintMap, "mixX", 1);
data->_mixY = Json::getFloat(constraintMap, "mixY", 1);
skeletonData->_pathConstraints[i] = data;
}
@ -725,46 +748,75 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
return skeletonData;
}
float SkeletonJson::toColor(const char *value, size_t index) {
char digits[3];
char *error;
int color;
if (index >= strlen(value) / 2) return -1;
value += index * 2;
digits[0] = *value;
digits[1] = *(value + 1);
digits[2] = '\0';
color = (int) strtoul(digits, &error, 16);
if (*error != 0) return -1;
return color / (float) 255;
void SkeletonJson::setBezier (CurveTimeline *timeline, int frame, int value, int bezier, float time1, float value1, float cx1, float cy1,
float cx2, float cy2, float time2, float value2) {
timeline->setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2);
}
void SkeletonJson::readCurve(Json *frame, CurveTimeline *timeline, size_t frameIndex) {
Json *curve = Json::getItem(frame, "curve");
if (!curve) return;
if (curve->_type == Json::JSON_STRING && strcmp(curve->_valueString, "stepped") == 0)
timeline->setStepped(frameIndex);
else {
float c1 = Json::getFloat(frame, "curve", 0);
float c2 = Json::getFloat(frame, "c2", 0);
float c3 = Json::getFloat(frame, "c3", 1);
float c4 = Json::getFloat(frame, "c4", 1);
timeline->setCurve(frameIndex, c1, c2, c3, c4);
}
int SkeletonJson::readCurve (Json *curve, CurveTimeline *timeline, int bezier, int frame, int value, float time1, float time2,
float value1, float value2, float scale) {
if (curve->_type == Json::JSON_STRING && strcmp(curve->_valueString, "stepped") == 0) {
timeline->setStepped(frame);
} else {
curve = Json::getItem(curve, value << 2);
float cx1 = curve->_valueFloat;
curve = curve->_next;
float cy1 = curve->_valueFloat * scale;
curve = curve->_next;
float cx2 = curve->_valueFloat;
curve = curve->_next;
float cy2 = curve->_valueFloat * scale;
setBezier(timeline, frame, value, bezier++, time1, value1, cx1, cy1, cx2, cy2, time2, value2);
}
return bezier;
}
Timeline *SkeletonJson::readTimeline (Json *keyMap, CurveTimeline1 *timeline, float defaultValue, float scale) {
float time = Json::getFloat(keyMap, "time", 0);
float value = Json::getFloat(keyMap, "value", defaultValue) * scale;
int bezier = 0;
for (int frame = 0;; frame++) {
timeline->setFrame(frame, time, value);
Json* nextMap = keyMap->_next;
if (nextMap == NULL) break;
float time2 = Json::getFloat(nextMap, "time", 0);
float value2 = Json::getFloat(nextMap, "value", defaultValue) * scale;
Json* curve = Json::getItem(keyMap, "curve");
if (curve != NULL) bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, value, value2, scale);
time = time2;
value = value2;
keyMap = nextMap;
}
return timeline;
}
Timeline *SkeletonJson::readTimeline (Json *keyMap, CurveTimeline2 *timeline, const char *name1, const char *name2, float defaultValue, float scale) {
float time = Json::getFloat(keyMap, "time", 0);
float value1 = Json::getFloat(keyMap, name1, defaultValue) * scale;
float value2 = Json::getFloat(keyMap, name2, defaultValue) * scale;
int bezier = 0;
for (int frame = 0;; frame++) {
timeline->setFrame(frame, time, value1, value2);
Json *nextMap = keyMap->_next;
if (nextMap == NULL) break;
float time2 = Json::getFloat(nextMap, "time", 0);
float nvalue1 = Json::getFloat(nextMap, name1, defaultValue) * scale;
float nvalue2 = Json::getFloat(nextMap, name2, defaultValue) * scale;
Json *curve = Json::getItem(keyMap, "curve");
if (curve != NULL) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, value1, nvalue1, scale);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, value2, nvalue2, scale);
}
time = time2;
value1 = nvalue1;
value2 = nvalue2;
keyMap = nextMap;
}
return timeline;
}
Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
Vector<Timeline *> timelines;
float duration = 0;
size_t frameIndex;
Json *valueMap;
int timelinesCount = 0;
Json *bones = Json::getItem(root, "bones");
Json *slots = Json::getItem(root, "slots");
Json *ik = Json::getItem(root, "ik");
@ -773,33 +825,12 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
Json *deform = Json::getItem(root, "deform");
Json *drawOrder = Json::getItem(root, "drawOrder");
Json *events = Json::getItem(root, "events");
Json *boneMap, *slotMap, *constraintMap;
if (!drawOrder) drawOrder = Json::getItem(root, "draworder");
for (boneMap = bones ? bones->_child : NULL; boneMap; boneMap = boneMap->_next)
timelinesCount += boneMap->_size;
for (slotMap = slots ? slots->_child : NULL; slotMap; slotMap = slotMap->_next)
timelinesCount += slotMap->_size;
timelinesCount += ik ? ik->_size : 0;
timelinesCount += transform ? transform->_size : 0;
for (constraintMap = paths ? paths->_child : NULL; constraintMap; constraintMap = constraintMap->_next)
timelinesCount += constraintMap->_size;
for (constraintMap = deform ? deform->_child : NULL; constraintMap; constraintMap = constraintMap->_next)
for (slotMap = constraintMap->_child; slotMap; slotMap = slotMap->_next)
timelinesCount += slotMap->_size;
if (drawOrder) ++timelinesCount;
if (events) ++timelinesCount;
Json *boneMap, *slotMap, *constraintMap, *keyMap, *nextMap, *curve;
int frame, bezier;
Color color, color2, newColor, newColor2;
/** Slot timelines. */
for (slotMap = slots ? slots->_child : 0; slotMap; slotMap = slotMap->_next) {
Json *timelineMap;
int slotIndex = skeletonData->findSlotIndex(slotMap->_name);
if (slotIndex == -1) {
ContainerUtil::cleanUpVectorOfPointers(timelines);
@ -807,52 +838,131 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
return NULL;
}
for (timelineMap = slotMap->_child; timelineMap; timelineMap = timelineMap->_next) {
for (Json *timelineMap = slotMap->_child; timelineMap; timelineMap = timelineMap->_next) {
if (strcmp(timelineMap->_name, "attachment") == 0) {
AttachmentTimeline *timeline = new(__FILE__, __LINE__) AttachmentTimeline(timelineMap->_size);
timeline->_slotIndex = slotIndex;
for (valueMap = timelineMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
Json *name = Json::getItem(valueMap, "name");
String attachmentName = name->_type == Json::JSON_NULL ? "" : name->_valueString;
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0), attachmentName);
int frameCount = timelineMap->_size;
AttachmentTimeline *timeline = new(__FILE__, __LINE__) AttachmentTimeline(frameCount, slotIndex);
for (keyMap = timelineMap->_child, frame = 0; keyMap; keyMap = keyMap->_next, ++frame) {
timeline->setFrame(frame, Json::getFloat(keyMap, "time", 0), Json::getItem(keyMap, "name")->_valueString);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[timelineMap->_size - 1]);
} else if (strcmp(timelineMap->_name, "color") == 0) {
ColorTimeline *timeline = new(__FILE__, __LINE__) ColorTimeline(timelineMap->_size);
} else if (strcmp(timelineMap->_name, "rgba") == 0) {
int frameCount = timelineMap->_size;
int bezierCount = frameCount << 2;
RGBATimeline *timeline = new(__FILE__, __LINE__) RGBATimeline(frameCount, bezierCount, slotIndex);
keyMap = timelineMap->_child;
float time = Json::getFloat(keyMap, "time", 0);
toColor(color, Json::getString(keyMap, "color", 0), true);
timeline->_slotIndex = slotIndex;
for (valueMap = timelineMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
const char *s = Json::getString(valueMap, "color", 0);
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0), toColor(s, 0), toColor(s, 1),
toColor(s, 2), toColor(s, 3));
readCurve(valueMap, timeline, frameIndex);
for (frame = 0, bezier = 0;;++frame) {
timeline->setFrame(frame, time, color.r, color.g, color.b, color.a);
nextMap = keyMap->_next;
if (!keyMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
toColor(newColor, Json::getString(nextMap, "color", 0), true);
curve = Json::getItem(keyMap, "curve");
if (curve) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1);
bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color.a, newColor.a, 1);
}
time = time2;
color = newColor;
keyMap = nextMap;
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[(timelineMap->_size - 1) * ColorTimeline::ENTRIES]);
} else if (strcmp(timelineMap->_name, "rgb") == 0) {
int frameCount = timelineMap->_size;
int bezierCount = frameCount * 3;
RGBTimeline *timeline = new(__FILE__, __LINE__) RGBTimeline(frameCount, bezierCount, slotIndex);
keyMap = timelineMap->_child;
float time = Json::getFloat(keyMap, "time", 0);
toColor(color, Json::getString(keyMap, "color", 0), false);
} else if (strcmp(timelineMap->_name, "twoColor") == 0) {
TwoColorTimeline *timeline = new(__FILE__, __LINE__) TwoColorTimeline(timelineMap->_size);
for (frame = 0, bezier = 0;;++frame) {
timeline->setFrame(frame, time, color.r, color.g, color.b);
nextMap = keyMap->_next;
if (!keyMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
toColor(newColor, Json::getString(nextMap, "color", 0), false);
curve = Json::getItem(keyMap, "curve");
if (curve) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1);
}
time = time2;
color = newColor;
keyMap = nextMap;
}
timelines.add(timeline);
} else if (strcmp(timelineMap->_name, "alpha") == 0) {
timelines.add(readTimeline(timelineMap, new (__FILE__, __LINE__) AlphaTimeline(timelineMap->_size, timelineMap->_size, slotIndex), 0, 1));
} else if (strcmp(timelineMap->_name, "rgba2") == 0) {
int frameCount = timelineMap->_size;
int bezierCount = frameCount * 7;
RGBA2Timeline *timeline = new(__FILE__, __LINE__) RGBA2Timeline(frameCount, bezierCount, slotIndex);
keyMap = timelineMap->_child;
float time = Json::getFloat(keyMap, "time", 0);
toColor(color, Json::getString(keyMap, "light", 0), true);
toColor(color2, Json::getString(keyMap, "dark", 0), false);
timeline->_slotIndex = slotIndex;
for (frame = 0, bezier = 0;;++frame) {
timeline->setFrame(frame, time, color.r, color.g, color.b, color.a, color2.g, color2.g, color2.b);
nextMap = keyMap->_next;
if (!keyMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
toColor(newColor, Json::getString(nextMap, "light", 0), true);
toColor(newColor2, Json::getString(nextMap, "dark", 0), false);
curve = Json::getItem(keyMap, "curve");
if (curve) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1);
bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color.a, newColor.a, 1);
bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color2.r, newColor2.r, 1);
bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color2.g, newColor2.g, 1);
bezier = readCurve(curve, timeline, bezier, frame, 6, time, time2, color2.b, newColor2.b, 1);
}
time = time2;
color = newColor;
color2 = newColor2;
keyMap = nextMap;
}
timelines.add(timeline);
} else if (strcmp(timelineMap->_name, "rgb2") == 0) {
int frameCount = timelineMap->_size;
int bezierCount = frameCount * 7;
RGBA2Timeline *timeline = new(__FILE__, __LINE__) RGBA2Timeline(frameCount, bezierCount, slotIndex);
keyMap = timelineMap->_child;
float time = Json::getFloat(keyMap, "time", 0);
toColor(color, Json::getString(keyMap, "light", 0), false);
toColor(color2, Json::getString(keyMap, "dark", 0), false);
for (valueMap = timelineMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
const char *s = Json::getString(valueMap, "light", 0);
const char *ds = Json::getString(valueMap, "dark", 0);
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0), toColor(s, 0), toColor(s, 1),
toColor(s, 2), toColor(s, 3), toColor(ds, 0), toColor(ds, 1), toColor(ds, 2));
readCurve(valueMap, timeline, frameIndex);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration,
timeline->_frames[(timelineMap->_size - 1) * TwoColorTimeline::ENTRIES]);
for (frame = 0, bezier = 0;;++frame) {
timeline->setFrame(frame, time, color.r, color.g, color.b, color.a, color2.r, color2.g, color2.b);
nextMap = keyMap->_next;
if (!keyMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
toColor(newColor, Json::getString(nextMap, "light", 0), false);
toColor(newColor2, Json::getString(nextMap, "dark", 0), false);
curve = Json::getItem(keyMap, "curve");
if (curve) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1);
bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color2.r, newColor2.r, 1);
bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color2.g, newColor2.g, 1);
bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color2.b, newColor2.b, 1);
}
time = time2;
color = newColor;
color2 = newColor2;
keyMap = nextMap;
}
timelines.add(timeline);
} else {
ContainerUtil::cleanUpVectorOfPointers(timelines);
setError(NULL, "Invalid timeline type for a slot: ", timelineMap->_name);
@ -873,161 +983,184 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
}
for (timelineMap = boneMap->_child; timelineMap; timelineMap = timelineMap->_next) {
if (strcmp(timelineMap->_name, "rotate") == 0) {
RotateTimeline *timeline = new(__FILE__, __LINE__) RotateTimeline(timelineMap->_size);
if (timelineMap->_size == 0) continue;
timeline->_boneIndex = boneIndex;
for (valueMap = timelineMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0), Json::getFloat(valueMap, "angle", 0));
readCurve(valueMap, timeline, frameIndex);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[(timelineMap->_size - 1) * RotateTimeline::ENTRIES]);
} else {
int isScale = strcmp(timelineMap->_name, "scale") == 0;
int isTranslate = strcmp(timelineMap->_name, "translate") == 0;
int isShear = strcmp(timelineMap->_name, "shear") == 0;
if (isScale || isTranslate || isShear) {
float timelineScale = isTranslate ? _scale : 1;
float defaultValue = 0;
TranslateTimeline *timeline = 0;
if (isScale) {
timeline = new(__FILE__, __LINE__) ScaleTimeline(timelineMap->_size);
defaultValue = 1;
} else if (isTranslate) {
timeline = new(__FILE__, __LINE__) TranslateTimeline(timelineMap->_size);
} else if (isShear) {
timeline = new(__FILE__, __LINE__) ShearTimeline(timelineMap->_size);
}
timeline->_boneIndex = boneIndex;
for (valueMap = timelineMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0),
Json::getFloat(valueMap, "x", defaultValue) * timelineScale,
Json::getFloat(valueMap, "y", defaultValue) * timelineScale);
readCurve(valueMap, timeline, frameIndex);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[(timelineMap->_size - 1) * TranslateTimeline::ENTRIES]);
} else {
ContainerUtil::cleanUpVectorOfPointers(timelines);
setError(NULL, "Invalid timeline type for a bone: ", timelineMap->_name);
return NULL;
}
}
if (strcmp(timelineMap->_name, "rotate") == 0) {
timelines.add(readTimeline(timelineMap, new RotateTimeline(timelineMap->_size, timelineMap->_size, boneIndex), 0, 1));
} else if (strcmp(timelineMap->_name, "translate") == 0) {
TranslateTimeline *timeline = new TranslateTimeline(timelineMap->_size, timelineMap->_size << 1, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, "x", "y", 0, _scale));
} else if (strcmp(timelineMap->_name, "translatex") == 0) {
TranslateXTimeline *timeline = new TranslateXTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 0, _scale));
} else if (strcmp(timelineMap->_name, "translatey") == 0) {
TranslateYTimeline *timeline = new TranslateYTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 0, _scale));
} else if (strcmp(timelineMap->_name, "scale") == 0) {
ScaleTimeline *timeline = new (__FILE__, __LINE__) ScaleTimeline(timelineMap->_size, timelineMap->_size << 1, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, "x", "y", 1, 1));
} else if (strcmp(timelineMap->_name, "scalex") == 0) {
ScaleXTimeline *timeline = new (__FILE__, __LINE__) ScaleXTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 1, 1));
} else if (strcmp(timelineMap->_name, "scaley") == 0) {
ScaleYTimeline *timeline = new (__FILE__, __LINE__) ScaleYTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 1, 1));
} else if (strcmp(timelineMap->_name, "shear") == 0) {
ShearTimeline *timeline = new (__FILE__, __LINE__) ShearTimeline(timelineMap->_size, timelineMap->_size << 1, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, "x", "y", 0, 1));
} else if (strcmp(timelineMap->_name, "shearx") == 0) {
ShearXTimeline *timeline = new (__FILE__, __LINE__) ShearXTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 0, 1));
} else if (strcmp(timelineMap->_name, "sheary") == 0) {
ShearYTimeline *timeline = new (__FILE__, __LINE__) ShearYTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 0, 1));
} else {
ContainerUtil::cleanUpVectorOfPointers(timelines);
setError(NULL, "Invalid timeline type for a bone: ", timelineMap->_name);
return NULL;
}
}
}
/** IK constraint timelines. */
for (constraintMap = ik ? ik->_child : 0; constraintMap; constraintMap = constraintMap->_next) {
IkConstraintData *constraint = skeletonData->findIkConstraint(constraintMap->_name);
IkConstraintTimeline *timeline = new(__FILE__, __LINE__) IkConstraintTimeline(constraintMap->_size);
keyMap = constraintMap->_child;
if (keyMap == NULL) continue;
IkConstraintData *constraint = skeletonData->findIkConstraint(constraintMap->_name);
int constraintIndex = skeletonData->_ikConstraints.indexOf(constraint);
IkConstraintTimeline *timeline = new(__FILE__, __LINE__) IkConstraintTimeline(constraintMap->_size, constraintMap->_size << 1, constraintIndex);
float time = Json::getFloat(keyMap, "time", 0);
float mix = Json::getFloat(keyMap, "mix", 1);
float softness = Json::getFloat(keyMap, "softness", 0) * _scale;
for (frame = 0, bezier = 0;; frame++) {
timeline->setFrame(frame, time, mix, softness, Json::getBoolean(keyMap, "bendPositive", true) ? 1 : -1, Json::getBoolean(keyMap, "compress", false), Json::getBoolean(keyMap, "stretch", false));
nextMap = keyMap->_next;
if (!nextMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
float mix2 = Json::getFloat(nextMap, "mix", 1);
float softness2 = Json::getFloat(nextMap, "softness", 0) * _scale;
curve = Json::getItem(keyMap, "curve");
if (curve) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mix, mix2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, softness, softness2, _scale);
}
time = time2;
mix = mix2;
softness = softness2;
keyMap = nextMap;
}
for (frameIndex = 0; frameIndex < skeletonData->_ikConstraints.size(); ++frameIndex) {
if (constraint == skeletonData->_ikConstraints[frameIndex]) {
timeline->_ikConstraintIndex = frameIndex;
break;
}
}
for (valueMap = constraintMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0), Json::getFloat(valueMap, "mix", 1),
Json::getFloat(valueMap, "softness", 0) * _scale, Json::getInt(valueMap, "bendPositive", 1) ? 1 : -1,
Json::getInt(valueMap, "compress", 0) ? true : false, Json::getInt(valueMap, "stretch", 0) ? true : false);
readCurve(valueMap, timeline, frameIndex);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[(constraintMap->_size - 1) * IkConstraintTimeline::ENTRIES]);
}
/** Transform constraint timelines. */
for (constraintMap = transform ? transform->_child : 0; constraintMap; constraintMap = constraintMap->_next) {
TransformConstraintData *constraint = skeletonData->findTransformConstraint(constraintMap->_name);
TransformConstraintTimeline *timeline = new(__FILE__, __LINE__) TransformConstraintTimeline(constraintMap->_size);
keyMap = constraintMap->_child;
if (keyMap == NULL) continue;
for (frameIndex = 0; frameIndex < skeletonData->_transformConstraints.size(); ++frameIndex) {
if (constraint == skeletonData->_transformConstraints[frameIndex]) {
timeline->_transformConstraintIndex = frameIndex;
break;
}
}
for (valueMap = constraintMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0),
Json::getFloat(valueMap, "rotateMix", 1), Json::getFloat(valueMap, "translateMix", 1),
Json::getFloat(valueMap, "scaleMix", 1), Json::getFloat(valueMap, "shearMix", 1));
readCurve(valueMap, timeline, frameIndex);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[(constraintMap->_size - 1) * TransformConstraintTimeline::ENTRIES]);
TransformConstraintData *constraint = skeletonData->findTransformConstraint(constraintMap->_name);
int constraintIndex = skeletonData->_transformConstraints.indexOf(constraint);
TransformConstraintTimeline *timeline = new(__FILE__, __LINE__) TransformConstraintTimeline(constraintMap->_size, constraintMap->_size << 2, constraintIndex);
float time = Json::getFloat(keyMap, "time", 0);
float mixRotate = Json::getFloat(keyMap, "mixRotate", 1);
float mixShearY = Json::getFloat(keyMap, "mixShearY", 1);
float mixX = Json::getFloat(keyMap, "mixX", 1);
float mixY = Json::getFloat(keyMap, "mixY", mixX);
float mixScaleX = Json::getFloat(keyMap, "mixScaleX", 1);
float mixScaleY = Json::getFloat(keyMap, "mixScaleY", mixScaleX);
for (frame = 0, bezier = 0;; frame++) {
timeline->setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY);
nextMap = keyMap->_next;
if (!nextMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
float mixRotate2 = Json::getFloat(nextMap, "mixRotate", 1);
float mixShearY2 = Json::getFloat(nextMap, "mixShearY", 1);
float mixX2 = Json::getFloat(nextMap, "mixX", 1);
float mixY2 = Json::getFloat(nextMap, "mixY", mixX2);
float mixScaleX2 = Json::getFloat(nextMap, "mixScaleX", 1);
float mixScaleY2 = Json::getFloat(nextMap, "mixScaleY", mixScaleX2);
curve = Json::getItem(keyMap, "curve");
if (curve) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, mixScaleX, mixScaleX2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, mixScaleY, mixScaleY2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, mixShearY, mixShearY2, 1);
}
time = time2;
mixRotate = mixRotate2;
mixX = mixX2;
mixY = mixY2;
mixScaleX = mixScaleX2;
mixScaleY = mixScaleY2;
mixScaleX = mixScaleX2;
keyMap = nextMap;
}
timelines.add(timeline);
}
/** Path constraint timelines. */
for (constraintMap = paths ? paths->_child : 0; constraintMap; constraintMap = constraintMap->_next) {
size_t constraintIndex = 0, i;
Json *timelineMap;
PathConstraintData *data = skeletonData->findPathConstraint(constraintMap->_name);
if (!data) {
ContainerUtil::cleanUpVectorOfPointers(timelines);
setError(NULL, "Path constraint not found: ", constraintMap->_name);
return NULL;
}
for (i = 0; i < skeletonData->_pathConstraints.size(); i++) {
if (skeletonData->_pathConstraints[i] == data) {
constraintIndex = i;
break;
}
}
for (timelineMap = constraintMap->_child; timelineMap; timelineMap = timelineMap->_next) {
const char *timelineName = timelineMap->_name;
if (strcmp(timelineName, "position") == 0 || strcmp(timelineName, "spacing") == 0) {
PathConstraintPositionTimeline *timeline;
float timelineScale = 1;
if (strcmp(timelineName, "spacing") == 0) {
timeline = new(__FILE__, __LINE__) PathConstraintSpacingTimeline(timelineMap->_size);
if (data->_spacingMode == SpacingMode_Length || data->_spacingMode == SpacingMode_Fixed) {
timelineScale = _scale;
}
} else {
timeline = new(__FILE__, __LINE__) PathConstraintPositionTimeline(timelineMap->_size);
if (data->_positionMode == PositionMode_Fixed) {
timelineScale = _scale;
}
}
timeline->_pathConstraintIndex = constraintIndex;
for (valueMap = timelineMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0),
Json::getFloat(valueMap, timelineName, 0) * timelineScale);
readCurve(valueMap, timeline, frameIndex);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[(timelineMap->_size - 1) *
PathConstraintPositionTimeline::ENTRIES]);
} else if (strcmp(timelineName, "mix") == 0) {
PathConstraintMixTimeline *timeline = new(__FILE__, __LINE__) PathConstraintMixTimeline(timelineMap->_size);
timeline->_pathConstraintIndex = constraintIndex;
for (valueMap = timelineMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0),
Json::getFloat(valueMap, "rotateMix", 1),
Json::getFloat(valueMap, "translateMix", 1));
readCurve(valueMap, timeline, frameIndex);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[(timelineMap->_size - 1) * PathConstraintMixTimeline::ENTRIES]);
}
}
PathConstraintData *data = skeletonData->findPathConstraint(constraintMap->_name);
if (!data) {
ContainerUtil::cleanUpVectorOfPointers(timelines);
setError(NULL, "Path constraint not found: ", constraintMap->_name);
return NULL;
}
int index = skeletonData->_pathConstraints.indexOf(data);
for (Json *timelineMap = constraintMap->_child; timelineMap; timelineMap = timelineMap->_next) {
keyMap = timelineMap->_child;
if (keyMap == NULL) continue;
const char *timelineName = timelineMap->_name;
if (strcmp(timelineName, "position") == 0 ) {
PathConstraintPositionTimeline *timeline = new (__FILE__, __LINE__) PathConstraintPositionTimeline(timelineMap->_size, timelineMap->_size, index);
timelines.add(readTimeline(keyMap, timeline, 0, data->_positionMode == PositionMode_Fixed ? _scale : 1));
} else if (strcmp(timelineName, "spacing") == 0) {
CurveTimeline1 *timeline = new PathConstraintSpacingTimeline(timelineMap->_size, timelineMap->_size, index);
timelines.add(readTimeline(keyMap, timeline, 0,
data->_spacingMode == SpacingMode_Length || data->_spacingMode == SpacingMode_Fixed ? _scale : 1));
} else if (strcmp(timelineName, "mix") == 0) {
PathConstraintMixTimeline *timeline = new PathConstraintMixTimeline(timelineMap->_size, timelineMap->_size * 3, index);
float time = Json::getFloat(keyMap, "time", 0);
float mixRotate = Json::getFloat(keyMap, "mixRotate", 1);
float mixX = Json::getFloat(keyMap, "mixX", 1);
float mixY = Json::getFloat(keyMap, "mixY", mixX);
for (frame = 0, bezier = 0;; frame++) {
timeline->setFrame(frame, time, mixRotate, mixX, mixY);
nextMap = keyMap->_next;
if (nextMap == NULL) {
break;
}
float time2 = Json::getFloat(nextMap, "time", 0);
float mixRotate2 = Json::getFloat(nextMap, "mixRotate", 1);
float mixX2 = Json::getFloat(nextMap, "mixX", 1);
float mixY2 = Json::getFloat(nextMap, "mixY", mixX2);
curve = Json::getItem(keyMap, "curve");
if (curve != NULL) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1);
}
time = time2;
mixRotate = mixRotate2;
mixX = mixX2;
mixY = mixY2;
keyMap = nextMap;
}
timelines.add(timeline);
}
}
}
/** Deform timelines. */
@ -1037,30 +1170,25 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
int slotIndex = skeletonData->findSlotIndex(slotMap->_name);
Json *timelineMap;
for (timelineMap = slotMap->_child; timelineMap; timelineMap = timelineMap->_next) {
DeformTimeline *timeline;
int weighted, deformLength;
keyMap = timelineMap->_child;
if (keyMap == NULL) continue;
Attachment *baseAttachment = skin->getAttachment(slotIndex, timelineMap->_name);
if (!baseAttachment) {
ContainerUtil::cleanUpVectorOfPointers(timelines);
setError(NULL, "Attachment not found: ", timelineMap->_name);
return NULL;
}
VertexAttachment *attachment = static_cast<VertexAttachment *>(baseAttachment);
weighted = attachment->_bones.size() != 0;
bool weighted = attachment->_bones.size() != 0;
Vector<float> &verts = attachment->_vertices;
deformLength = weighted ? verts.size() / 3 * 2 : verts.size();
int deformLength = weighted ? verts.size() / 3 * 2 : verts.size();
timeline = new(__FILE__, __LINE__) DeformTimeline(timelineMap->_size);
timeline->_slotIndex = slotIndex;
timeline->_attachment = attachment;
for (valueMap = timelineMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
Json *vertices = Json::getItem(valueMap, "vertices");
DeformTimeline *timeline = new(__FILE__, __LINE__) DeformTimeline(timelineMap->_size, timelineMap->_size, slotIndex, attachment);
float time = Json::getFloat(keyMap, "time", 0);
for (frame = 0, bezier = 0;; frame++) {
Json *vertices = Json::getItem(keyMap, "vertices");
Vector<float> deformed;
if (!vertices) {
if (weighted) {
@ -1069,7 +1197,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
deformed.clearAndAddAll(attachment->_vertices);
}
} else {
int v, start = Json::getInt(valueMap, "offset", 0);
int v, start = Json::getInt(keyMap, "offset", 0);
Json *vertex;
deformed.setSize(deformLength, 0);
if (_scale == 1) {
@ -1088,13 +1216,18 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
}
}
}
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0), deformed);
readCurve(valueMap, timeline, frameIndex);
timeline->setFrame(frame, time, deformed);
nextMap = keyMap->_next;
if (!nextMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
curve = Json::getItem(keyMap, "curve");
if (curve) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1);
}
time = time2;
keyMap = nextMap;
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[timelineMap->_size - 1]);
}
}
}
@ -1103,10 +1236,10 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
if (drawOrder) {
DrawOrderTimeline *timeline = new(__FILE__, __LINE__) DrawOrderTimeline(drawOrder->_size);
for (valueMap = drawOrder->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
for (keyMap = drawOrder->_child, frame = 0; keyMap; keyMap = keyMap->_next, ++frame) {
int ii;
Vector<int> drawOrder2;
Json *offsets = Json::getItem(valueMap, "offsets");
Json *offsets = Json::getItem(keyMap, "offsets");
if (offsets) {
Json *offsetMap;
Vector<int> unchanged;
@ -1140,41 +1273,40 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
for (ii = (int)skeletonData->_slots.size() - 1; ii >= 0; ii--)
if (drawOrder2[ii] == -1) drawOrder2[ii] = unchanged[--unchangedIndex];
}
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0), drawOrder2);
timeline->setFrame(frame, Json::getFloat(keyMap, "time", 0), drawOrder2);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[drawOrder->_size - 1]);
}
/** Event timeline. */
if (events) {
EventTimeline *timeline = new(__FILE__, __LINE__) EventTimeline(events->_size);
for (valueMap = events->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
for (keyMap = events->_child, frame = 0; keyMap; keyMap = keyMap->_next, ++frame) {
Event *event;
EventData *eventData = skeletonData->findEvent(Json::getString(valueMap, "name", 0));
EventData *eventData = skeletonData->findEvent(Json::getString(keyMap, "name", 0));
if (!eventData) {
ContainerUtil::cleanUpVectorOfPointers(timelines);
setError(NULL, "Event not found: ", Json::getString(valueMap, "name", 0));
setError(NULL, "Event not found: ", Json::getString(keyMap, "name", 0));
return NULL;
}
event = new(__FILE__, __LINE__) Event(Json::getFloat(valueMap, "time", 0), *eventData);
event->_intValue = Json::getInt(valueMap, "int", eventData->_intValue);
event->_floatValue = Json::getFloat(valueMap, "float", eventData->_floatValue);
event->_stringValue = Json::getString(valueMap, "string", eventData->_stringValue.buffer());
event = new(__FILE__, __LINE__) Event(Json::getFloat(keyMap, "time", 0), *eventData);
event->_intValue = Json::getInt(keyMap, "int", eventData->_intValue);
event->_floatValue = Json::getFloat(keyMap, "float", eventData->_floatValue);
event->_stringValue = Json::getString(keyMap, "string", eventData->_stringValue.buffer());
if (!eventData->_audioPath.isEmpty()) {
event->_volume = Json::getFloat(valueMap, "volume", 1);
event->_balance = Json::getFloat(valueMap, "balance", 0);
event->_volume = Json::getFloat(keyMap, "volume", 1);
event->_balance = Json::getFloat(keyMap, "balance", 0);
}
timeline->setFrame(frameIndex, event);
timeline->setFrame(frame, event);
}
timelines.add(timeline);
timelinesCount++;
duration = MathUtil::max(duration, timeline->_frames[events->_size - 1]);
}
float duration = 0;
for (size_t i = 0; i < timelines.size(); i++)
duration = MathUtil::max(duration, timelines[i]->getDuration());
return new(__FILE__, __LINE__) Animation(String(root->_name), timelines, duration);
}