From be2dfc7ff4709e35975081e57d46aafdd49661e6 Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Sun, 3 Dec 2017 21:32:44 -0500 Subject: [PATCH] wip --- spine-cpp/spine-cpp/include/spine/Json.h | 73 +- .../spine-cpp/include/spine/SkeletonJson.h | 24 +- spine-cpp/spine-cpp/src/spine/Json.cpp | 616 ++++++++- .../spine-cpp/src/spine/SkeletonJson.cpp | 1185 ++++++++++++++++- 4 files changed, 1893 insertions(+), 5 deletions(-) diff --git a/spine-cpp/spine-cpp/include/spine/Json.h b/spine-cpp/spine-cpp/include/spine/Json.h index 0e8b64a41..e64a7e72a 100644 --- a/spine-cpp/spine-cpp/include/spine/Json.h +++ b/spine-cpp/spine-cpp/include/spine/Json.h @@ -31,9 +31,80 @@ #ifndef Spine_Json_h #define Spine_Json_h +#ifndef SPINE_JSON_HAVE_PREV +/* Spine doesn't use the "prev" link in the Json sibling lists. */ +#define SPINE_JSON_HAVE_PREV 0 +#endif + namespace Spine { - // TODO + class Json + { + public: + /* Json Types: */ + static const int JSON_FALSE; + static const int JSON_TRUE; + static const int JSON_NULL; + static const int JSON_NUMBER; + static const int JSON_STRING; + static const int JSON_ARRAY; + static const int JSON_OBJECT; + + /* Get item "string" from object. Case insensitive. */ + static Json* getItem(Json *object, const char* string); + + static const char* getString(Json *object, const char* name, const char* defaultValue); + + static float getFloat(Json *object, const char* name, float defaultValue); + + static int getInt(Json *object, const char* name, int defaultValue); + + /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when Json_create() returns 0. 0 when Json_create() succeeds. */ + static const char* getError(); + + /* Supply a block of JSON, and this returns a Json object you can interrogate. Call Json_dispose when finished. */ + Json(const char* value); + + ~Json(); + + private: + static const char* JSON_ERROR; + + Json* _next; +#if SPINE_JSON_HAVE_PREV + Json* _prev; /* next/prev allow you to walk array/object chains. Alternatively, use getSize/getItem */ +#endif + Json* _child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + + int _type; /* The type of the item, as above. */ + int _size; /* The number of children. */ + + const char* _valueString; /* The item's string, if type==JSON_STRING */ + int _valueInt; /* The item's number, if type==JSON_NUMBER */ + float _valueFloat; /* The item's number, if type==JSON_NUMBER */ + + const char* _name; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + + /* Utility to jump whitespace and cr/lf */ + static const char* skip(const char* inValue); + + /* Parser core - when encountering text, process appropriately. */ + static const char* parseValue(Json *item, const char* value); + + /* Parse the input text into an unescaped cstring, and populate item. */ + static const char* parseString(Json *item, const char* str); + + /* Parse the input text to generate a number, and populate the result into item. */ + static const char* parseNumber(Json *item, const char* num); + + /* Build an array from input text. */ + static const char* parseArray(Json *item, const char* value); + + /* Build an object from the text. */ + static const char* parseObject(Json *item, const char* value); + + static int strcasecmp(const char* s1, const char* s2); + }; } #endif /* Spine_Json_h */ diff --git a/spine-cpp/spine-cpp/include/spine/SkeletonJson.h b/spine-cpp/spine-cpp/include/spine/SkeletonJson.h index 87139437d..cc0c6d7a7 100644 --- a/spine-cpp/spine-cpp/include/spine/SkeletonJson.h +++ b/spine-cpp/spine-cpp/include/spine/SkeletonJson.h @@ -33,8 +33,15 @@ #include +#include + namespace Spine { + class MeshAttachment; + class CurveTimeline; + class VertexAttachment; + class Animation; + class Json; class SkeletonData; class Atlas; class AttachmentLoader; @@ -49,15 +56,28 @@ namespace Spine ~SkeletonJson(); - SkeletonData* readSkeletonData(const char* json); - SkeletonData* readSkeletonDataFile(const char* path); + SkeletonData* readSkeletonData(const char* json); + private: AttachmentLoader* _attachmentLoader; Vector _linkedMeshes; float _scale; const bool _ownsLoader; + std::string _error; + + static float toColor(const char* value, int index); + + static void readCurve(Json* frame, CurveTimeline* timeline, int frameIndex); + + void addLinkedMesh(MeshAttachment* mesh, const char* skin, int slotIndex, const char* parent); + + Animation* readAnimation(Json* root, SkeletonData *skeletonData); + + void readVertices(Json* attachmentMap, VertexAttachment* attachment, int verticesLength); + + void setError(Json* root, const char* value1, const char* value2); }; } diff --git a/spine-cpp/spine-cpp/src/spine/Json.cpp b/spine-cpp/spine-cpp/src/spine/Json.cpp index bb4d2ccfe..80dd36047 100644 --- a/spine-cpp/spine-cpp/src/spine/Json.cpp +++ b/spine-cpp/spine-cpp/src/spine/Json.cpp @@ -28,7 +28,621 @@ * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +/* Json */ +/* JSON parser in CPP, shamelessly ripped from json.c in the spine-c runtime */ + +#ifndef _DEFAULT_SOURCE +/* Bring strings.h definitions into string.h, where appropriate */ +#define _DEFAULT_SOURCE +#endif + +#ifndef _BSD_SOURCE +/* Bring strings.h definitions into string.h, where appropriate */ +#define _BSD_SOURCE +#endif + +#include + +#include +#include +#include +#include +#include /* strtod (C89), strtof (C99) */ +#include /* strcasecmp (4.4BSD - compatibility), _stricmp (_WIN32) */ +#include +#include + namespace Spine { - // TODO + const int Json::JSON_FALSE = 0; + const int Json::JSON_TRUE = 1; + const int Json::JSON_NULL = 2; + const int Json::JSON_NUMBER = 3; + const int Json::JSON_STRING = 4; + const int Json::JSON_ARRAY = 5; + const int Json::JSON_OBJECT = 6; + + const char* Json::JSON_ERROR = NULL; + + Json* Json::getItem(Json *object, const char* string) + { + Json *c = object->_child; + while (c && strcasecmp(c->_name, string)) + { + c = c->_next; + } + return c; + } + + const char* Json::getString(Json *object, const char* name, const char* defaultValue) + { + object = getItem(object, name); + if (object) + { + return object->_valueString; + } + + return defaultValue; + } + + float Json::getFloat(Json *value, const char* name, float defaultValue) + { + value = getItem(value, name); + return value ? value->_valueFloat : defaultValue; + } + + int Json::getInt(Json *value, const char* name, int defaultValue) + { + value = getItem(value, name); + return value ? value->_valueInt : defaultValue; + } + + const char* Json::getError() + { + return JSON_ERROR; + } + + Json::Json(const char* value) : + _next(NULL), +#if SPINE_JSON_HAVE_PREV + _prev(NULL), +#endif + _child(NULL), + _type(0), + _size(0), + _valueString(NULL), + _valueInt(0), + _valueFloat(0), + _name(NULL) + { + if (value) + { + value = parseValue(this, skip(value)); + + assert(value); + } + } + + Json::~Json() + { + if (_child) + { + DESTROY(Json, _child); + } + + if (_valueString) + { + FREE(_valueString); + } + + if (_name) + { + FREE(_name); + } + + if (_next) + { + DESTROY(Json, _next); + } + } + + const char* Json::skip(const char* inValue) + { + if (!inValue) + { + /* must propagate NULL since it's often called in skip(f(...)) form */ + return NULL; + } + + while (*inValue && (unsigned char)*inValue <= 32) + { + inValue++; + } + + return inValue; + } + + const char* Json::parseValue(Json *item, const char* value) + { + /* Referenced by constructor, parseArray(), and parseObject(). */ + /* Always called with the result of skip(). */ +#if SPINE_JSON_DEBUG /* Checked at entry to graph, constructor, and after every parse call. */ + if (!value) + { + /* Fail on null. */ + return NULL; + } +#endif + + switch (*value) + { + case 'n': + { + if (!strncmp(value + 1, "ull", 3)) + { + item->_type = JSON_NULL; + return value + 4; + } + break; + } + case 'f': + { + if (!strncmp(value + 1, "alse", 4)) + { + item->_type = JSON_FALSE; + /* calloc prevents us needing item->_type = JSON_FALSE or valueInt = 0 here */ + return value + 5; + } + break; + } + case 't': + { + if (!strncmp(value + 1, "rue", 3)) + { + item->_type = JSON_TRUE; + item->_valueInt = 1; + return value + 4; + } + break; + } + case '\"': + return parseString(item, value); + case '[': + return parseArray(item, value); + case '{': + return parseObject(item, value); + case '-': /* fallthrough */ + case '0': /* fallthrough */ + case '1': /* fallthrough */ + case '2': /* fallthrough */ + case '3': /* fallthrough */ + case '4': /* fallthrough */ + case '5': /* fallthrough */ + case '6': /* fallthrough */ + case '7': /* fallthrough */ + case '8': /* fallthrough */ + case '9': + return parseNumber(item, value); + default: + break; + } + + JSON_ERROR = value; + return NULL; /* failure. */ + } + + static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; + const char* Json::parseString(Json *item, const char* str) + { + const char* ptr = str + 1; + char* ptr2; + char* out; + int len = 0; + unsigned uc, uc2; + if (*str != '\"') + { + /* TODO: don't need this check when called from parseValue, but do need from parseObject */ + JSON_ERROR = str; + return 0; + } /* not a string! */ + + while (*ptr != '\"' && *ptr && ++len) + { + if (*ptr++ == '\\') + { + ptr++; /* Skip escaped quotes. */ + } + } + + out = MALLOC(char, len + 1); /* The length needed for the string, roughly. */ + if (!out) + { + return 0; + } + + ptr = str + 1; + ptr2 = out; + while (*ptr != '\"' && *ptr) + { + if (*ptr != '\\') + { + *ptr2++ = *ptr++; + } + else + { + ptr++; + switch (*ptr) + { + case 'b': + *ptr2++ = '\b'; + break; + case 'f': + *ptr2++ = '\f'; + break; + case 'n': + *ptr2++ = '\n'; + break; + case 'r': + *ptr2++ = '\r'; + break; + case 't': + *ptr2++ = '\t'; + break; + case 'u': + { + /* transcode utf16 to utf8. */ + sscanf(ptr + 1, "%4x", &uc); + ptr += 4; /* get the unicode char. */ + + if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) + { + break; /* check for invalid. */ + } + + /* TODO provide an option to ignore surrogates, use unicode replacement character? */ + if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */ + { + if (ptr[1] != '\\' || ptr[2] != 'u') + { + break; /* missing second-half of surrogate. */ + } + sscanf(ptr + 3, "%4x", &uc2); + ptr += 6; + if (uc2 < 0xDC00 || uc2 > 0xDFFF) + { + break; /* invalid second-half of surrogate. */ + } + uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF)); + } + + len = 4; + if (uc < 0x80) + { + len = 1; + } + else if (uc < 0x800) + { + len = 2; + } + else if (uc < 0x10000) + { + len = 3; + } + ptr2 += len; + + switch (len) + { + case 4: + *--ptr2 = ((uc | 0x80) & 0xBF); + uc >>= 6; + /* fallthrough */ + case 3: + *--ptr2 = ((uc | 0x80) & 0xBF); + uc >>= 6; + /* fallthrough */ + case 2: + *--ptr2 = ((uc | 0x80) & 0xBF); + uc >>= 6; + /* fallthrough */ + case 1: + *--ptr2 = (uc | firstByteMark[len]); + } + ptr2 += len; + break; + } + default: + *ptr2++ = *ptr; + break; + } + ptr++; + } + } + + *ptr2 = NULL; + + if (*ptr == '\"') + { + ptr++; /* TODO error handling if not \" or \0 ? */ + } + + item->_valueString = out; + item->_type = JSON_STRING; + + return ptr; + } + + const char* Json::parseNumber(Json *item, const char* num) + { + double result = 0.0; + int negative = 0; + char* ptr = (char*)num; + + if (*ptr == '-') + { + negative = -1; + ++ptr; + } + + while (*ptr >= '0' && *ptr <= '9') + { + result = result * 10.0 + (*ptr - '0'); + ++ptr; + } + + if (*ptr == '.') + { + double fraction = 0.0; + int n = 0; + ++ptr; + + while (*ptr >= '0' && *ptr <= '9') + { + fraction = (fraction * 10.0) + (*ptr - '0'); + ++ptr; + ++n; + } + result += fraction / pow(10.0, n); + } + + if (negative) + { + result = -result; + } + + if (*ptr == 'e' || *ptr == 'E') + { + double exponent = 0; + int expNegative = 0; + int n = 0; + ++ptr; + + if (*ptr == '-') + { + expNegative = -1; + ++ptr; + } + else if (*ptr == '+') + { + ++ptr; + } + + while (*ptr >= '0' && *ptr <= '9') + { + exponent = (exponent * 10.0) + (*ptr - '0'); + ++ptr; + ++n; + } + + if (expNegative) + { + result = result / pow(10, exponent); + } + else + { + result = result * pow(10, exponent); + } + } + + if (ptr != num) + { + /* Parse success, number found. */ + item->_valueFloat = result; + item->_valueInt = static_cast(result); + item->_type = JSON_NUMBER; + return ptr; + } + else + { + /* Parse failure, JSON_ERROR is set. */ + JSON_ERROR = num; + return NULL; + } + } + + const char* Json::parseArray(Json *item, const char* value) + { + Json *child; + +#if SPINE_JSON_DEBUG /* unnecessary, only callsite (parse_value) verifies this */ + if (*value != '[') + { + ep = value; + return 0; + } /* not an array! */ +#endif + + item->_type = JSON_ARRAY; + value = skip(value + 1); + if (*value == ']') + { + return value + 1; /* empty array. */ + } + + item->_child = child = NEW(Json); + new (item->_child) Json(NULL); + if (!item->_child) + { + return NULL; /* memory fail */ + } + + value = skip(parseValue(child, skip(value))); /* skip any spacing, get the value. */ + + if (!value) + { + return NULL; + } + + item->_size = 1; + + while (*value == ',') + { + Json *new_item = NEW(Json); + new (new_item) Json(NULL); + if (!new_item) + { + return NULL; /* memory fail */ + } + child->_next = new_item; +#if SPINE_JSON_HAVE_PREV + new_item->prev = child; +#endif + child = new_item; + value = skip(parseValue(child, skip(value + 1))); + if (!value) + { + return NULL; /* parse fail */ + } + item->_size++; + } + + if (*value == ']') + { + return value + 1; /* end of array */ + } + + JSON_ERROR = value; + + return NULL; /* malformed. */ + } + + /* Build an object from the text. */ + const char* Json::parseObject(Json *item, const char* value) + { + Json *child; + +#if SPINE_JSON_DEBUG /* unnecessary, only callsite (parse_value) verifies this */ + if (*value != '{') + { + ep = value; + return 0; + } /* not an object! */ +#endif + + item->_type = JSON_OBJECT; + value = skip(value + 1); + if (*value == '}') + { + return value + 1; /* empty array. */ + } + + item->_child = child = NEW(Json); + new (item->_child) Json(NULL); + if (!item->_child) + { + return NULL; + } + value = skip(parseString(child, skip(value))); + if (!value) + { + return NULL; + } + child->_name = child->_valueString; + child->_valueString = 0; + if (*value != ':') + { + JSON_ERROR = value; + return NULL; + } /* fail! */ + + value = skip(parseValue(child, skip(value + 1))); /* skip any spacing, get the value. */ + if (!value) + { + return NULL; + } + + item->_size = 1; + + while (*value == ',') + { + Json *new_item = NEW(Json); + new (new_item) Json(NULL); + if (!new_item) + { + return NULL; /* memory fail */ + } + child->_next = new_item; +#if SPINE_JSON_HAVE_PREV + new_item->prev = child; +#endif + child = new_item; + value = skip(parseString(child, skip(value + 1))); + if (!value) + { + return NULL; + } + child->_name = child->_valueString; + child->_valueString = 0; + if (*value != ':') + { + JSON_ERROR = value; + return NULL; + } /* fail! */ + + value = skip(parseValue(child, skip(value + 1))); /* skip any spacing, get the value. */ + if (!value) + { + return NULL; + } + item->_size++; + } + + if (*value == '}') + { + return value + 1; /* end of array */ + } + + JSON_ERROR = value; + + return NULL; /* malformed. */ + } + + int Json::strcasecmp(const char* s1, const char* s2) + { + /* TODO we may be able to elide these NULL checks if we can prove + * the graph and input (only callsite is Json_getItem) should not have NULLs + */ + if (s1 && s2) + { +#if defined(_WIN32) + return _stricmp(s1, s2); +#else + return strcasecmp( s1, s2 ); +#endif + } + else + { + if (s1 < s2) + { + return -1; /* s1 is null, s2 is not */ + } + else if (s1 == s2) + { + return 0; /* both are null */ + } + else + { + return 1; /* s2 is nul s1 is not */ + } + } + } } diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp index 482b7cbb5..dd3b04abd 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp @@ -30,6 +30,10 @@ #include +#include + +#include +#include #include #include #include @@ -37,6 +41,10 @@ #include #include +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) +#define strdup _strdup +#endif + namespace Spine { SkeletonJson::SkeletonJson(Vector& atlasArray) : _attachmentLoader(NEW(AtlasAttachmentLoader)), _scale(1), _ownsLoader(true) @@ -59,13 +67,1188 @@ namespace Spine } } + SkeletonData* SkeletonJson::readSkeletonDataFile(const char* path) + { + int length; + SkeletonData* skeletonData; + const char* json = SPINE_EXTENSION->spineReadFile(path, &length); + if (length == 0 || !json) + { + setError(NULL, "Unable to read skeleton file: ", path); + return NULL; + } + + skeletonData = readSkeletonData(json); + + FREE(json); + + return skeletonData; + } + SkeletonData* SkeletonJson::readSkeletonData(const char* json) { +// int i, ii; +// SkeletonData* skeletonData; +// Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *path, *slots, *skins, *animations, *events; +// _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self); +// +// FREE(self->error); +// CONST_CAST(char*, self->error) = 0; +// internal->linkedMeshCount = 0; +// +// root = Json_create(json); +// +// if (!root) { +// _spSkeletonJson_setError(self, 0, "Invalid skeleton JSON: ", Json_getError()); +// return 0; +// } +// +// skeletonData = spSkeletonData_create(); +// +// skeleton = Json_getItem(root, "skeleton"); +// if (skeleton) { +// MALLOC_STR(skeletonData->hash, Json_getString(skeleton, "hash", 0)); +// MALLOC_STR(skeletonData->version, Json_getString(skeleton, "spine", 0)); +// skeletonData->width = Json_getFloat(skeleton, "width", 0); +// skeletonData->height = Json_getFloat(skeleton, "height", 0); +// } +// +// /* Bones. */ +// bones = Json_getItem(root, "bones"); +// skeletonData->bones = MALLOC(spBoneData*, bones->size); +// for (boneMap = bones->child, i = 0; boneMap; boneMap = boneMap->next, ++i) { +// spBoneData* data; +// const char* transformMode; +// +// spBoneData* parent = 0; +// const char* parentName = Json_getString(boneMap, "parent", 0); +// if (parentName) { +// parent = spSkeletonData_findBone(skeletonData, parentName); +// if (!parent) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, "Parent bone not found: ", parentName); +// return 0; +// } +// } +// +// data = spBoneData_create(skeletonData->bonesCount, Json_getString(boneMap, "name", 0), parent); +// data->length = Json_getFloat(boneMap, "length", 0) * self->scale; +// data->x = Json_getFloat(boneMap, "x", 0) * self->scale; +// data->y = Json_getFloat(boneMap, "y", 0) * self->scale; +// data->rotation = Json_getFloat(boneMap, "rotation", 0); +// data->scaleX = Json_getFloat(boneMap, "scaleX", 1); +// data->scaleY = Json_getFloat(boneMap, "scaleY", 1); +// data->shearX = Json_getFloat(boneMap, "shearX", 0); +// data->shearY = Json_getFloat(boneMap, "shearY", 0); +// transformMode = Json_getString(boneMap, "transform", "normal"); +// data->transformMode = SP_TRANSFORMMODE_NORMAL; +// if (strcmp(transformMode, "normal") == 0) +// data->transformMode = SP_TRANSFORMMODE_NORMAL; +// if (strcmp(transformMode, "onlyTranslation") == 0) +// data->transformMode = SP_TRANSFORMMODE_ONLYTRANSLATION; +// if (strcmp(transformMode, "noRotationOrReflection") == 0) +// data->transformMode = SP_TRANSFORMMODE_NOROTATIONORREFLECTION; +// if (strcmp(transformMode, "noScale") == 0) +// data->transformMode = SP_TRANSFORMMODE_NOSCALE; +// if (strcmp(transformMode, "noScaleOrReflection") == 0) +// data->transformMode = SP_TRANSFORMMODE_NOSCALEORREFLECTION; +// +// skeletonData->bones[i] = data; +// skeletonData->bonesCount++; +// } +// +// /* Slots. */ +// slots = Json_getItem(root, "slots"); +// if (slots) { +// Json *slotMap; +// skeletonData->slotsCount = slots->size; +// skeletonData->slots = MALLOC(spSlotData*, slots->size); +// for (slotMap = slots->child, i = 0; slotMap; slotMap = slotMap->next, ++i) { +// spSlotData* data; +// const char* color; +// const char* dark; +// Json *item; +// +// const char* boneName = Json_getString(slotMap, "bone", 0); +// spBoneData* boneData = spSkeletonData_findBone(skeletonData, boneName); +// if (!boneData) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, "Slot bone not found: ", boneName); +// return 0; +// } +// +// data = spSlotData_create(i, Json_getString(slotMap, "name", 0), boneData); +// +// color = Json_getString(slotMap, "color", 0); +// if (color) { +// spColor_setFromFloats(&data->color, +// toColor(color, 0), +// toColor(color, 1), +// toColor(color, 2), +// toColor(color, 3)); +// } +// +// dark = Json_getString(slotMap, "dark", 0); +// if (dark) { +// data->darkColor = spColor_create(); +// spColor_setFromFloats(data->darkColor, +// toColor(dark, 0), +// toColor(dark, 1), +// toColor(dark, 2), +// toColor(dark, 3)); +// } +// +// item = Json_getItem(slotMap, "attachment"); +// if (item) spSlotData_setAttachmentName(data, item->valueString); +// +// item = Json_getItem(slotMap, "blend"); +// if (item) { +// if (strcmp(item->valueString, "additive") == 0) +// data->blendMode = SP_BLEND_MODE_ADDITIVE; +// else if (strcmp(item->valueString, "multiply") == 0) +// data->blendMode = SP_BLEND_MODE_MULTIPLY; +// else if (strcmp(item->valueString, "screen") == 0) +// data->blendMode = SP_BLEND_MODE_SCREEN; +// } +// +// skeletonData->slots[i] = data; +// } +// } +// +// /* IK constraints. */ +// ik = Json_getItem(root, "ik"); +// if (ik) { +// Json *constraintMap; +// skeletonData->ikConstraintsCount = ik->size; +// skeletonData->ikConstraints = MALLOC(spIkConstraintData*, ik->size); +// for (constraintMap = ik->child, i = 0; constraintMap; constraintMap = constraintMap->next, ++i) { +// const char* targetName; +// +// spIkConstraintData* data = spIkConstraintData_create(Json_getString(constraintMap, "name", 0)); +// data->order = Json_getInt(constraintMap, "order", 0); +// +// boneMap = Json_getItem(constraintMap, "bones"); +// data->bonesCount = boneMap->size; +// data->bones = MALLOC(spBoneData*, boneMap->size); +// for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { +// data->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); +// if (!data->bones[ii]) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, "IK bone not found: ", boneMap->valueString); +// return 0; +// } +// } +// +// targetName = Json_getString(constraintMap, "target", 0); +// data->target = spSkeletonData_findBone(skeletonData, targetName); +// if (!data->target) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, "Target bone not found: ", boneMap->name); +// return 0; +// } +// +// data->bendDirection = Json_getInt(constraintMap, "bendPositive", 1) ? 1 : -1; +// data->mix = Json_getFloat(constraintMap, "mix", 1); +// +// skeletonData->ikConstraints[i] = data; +// } +// } +// +// /* Transform constraints. */ +// transform = Json_getItem(root, "transform"); +// if (transform) { +// Json *constraintMap; +// skeletonData->transformConstraintsCount = transform->size; +// skeletonData->transformConstraints = MALLOC(spTransformConstraintData*, transform->size); +// for (constraintMap = transform->child, i = 0; constraintMap; constraintMap = constraintMap->next, ++i) { +// const char* name; +// +// spTransformConstraintData* data = spTransformConstraintData_create(Json_getString(constraintMap, "name", 0)); +// data->order = Json_getInt(constraintMap, "order", 0); +// +// boneMap = Json_getItem(constraintMap, "bones"); +// data->bonesCount = boneMap->size; +// CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, boneMap->size); +// for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { +// data->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); +// if (!data->bones[ii]) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, "Transform bone not found: ", boneMap->valueString); +// return 0; +// } +// } +// +// name = Json_getString(constraintMap, "target", 0); +// data->target = spSkeletonData_findBone(skeletonData, name); +// if (!data->target) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, "Target bone not found: ", boneMap->name); +// return 0; +// } +// +// data->local = Json_getInt(constraintMap, "local", 0); +// data->relative = Json_getInt(constraintMap, "relative", 0); +// data->offsetRotation = Json_getFloat(constraintMap, "rotation", 0); +// data->offsetX = Json_getFloat(constraintMap, "x", 0) * self->scale; +// data->offsetY = Json_getFloat(constraintMap, "y", 0) * self->scale; +// data->offsetScaleX = Json_getFloat(constraintMap, "scaleX", 0); +// 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); +// +// skeletonData->transformConstraints[i] = data; +// } +// } +// +// /* Path constraints */ +// path = Json_getItem(root, "path"); +// if (path) { +// Json *constraintMap; +// skeletonData->pathConstraintsCount = path->size; +// skeletonData->pathConstraints = MALLOC(spPathConstraintData*, path->size); +// for (constraintMap = path->child, i = 0; constraintMap; constraintMap = constraintMap->next, ++i) { +// const char* name; +// const char* item; +// +// spPathConstraintData* data = spPathConstraintData_create(Json_getString(constraintMap, "name", 0)); +// data->order = Json_getInt(constraintMap, "order", 0); +// +// boneMap = Json_getItem(constraintMap, "bones"); +// data->bonesCount = boneMap->size; +// CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, boneMap->size); +// for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { +// data->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); +// if (!data->bones[ii]) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, "Path bone not found: ", boneMap->valueString); +// return 0; +// } +// } +// +// name = Json_getString(constraintMap, "target", 0); +// data->target = spSkeletonData_findSlot(skeletonData, name); +// if (!data->target) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, "Target slot not found: ", boneMap->name); +// return 0; +// } +// +// item = Json_getString(constraintMap, "positionMode", "percent"); +// if (strcmp(item, "fixed") == 0) data->positionMode = SP_POSITION_MODE_FIXED; +// else if (strcmp(item, "percent") == 0) data->positionMode = SP_POSITION_MODE_PERCENT; +// +// item = Json_getString(constraintMap, "spacingMode", "length"); +// if (strcmp(item, "length") == 0) data->spacingMode = SP_SPACING_MODE_LENGTH; +// else if (strcmp(item, "fixed") == 0) data->spacingMode = SP_SPACING_MODE_FIXED; +// else if (strcmp(item, "percent") == 0) data->spacingMode = SP_SPACING_MODE_PERCENT; +// +// item = Json_getString(constraintMap, "rotateMode", "tangent"); +// if (strcmp(item, "tangent") == 0) data->rotateMode = SP_ROTATE_MODE_TANGENT; +// else if (strcmp(item, "chain") == 0) data->rotateMode = SP_ROTATE_MODE_CHAIN; +// else if (strcmp(item, "chainScale") == 0) data->rotateMode = SP_ROTATE_MODE_CHAIN_SCALE; +// +// data->offsetRotation = Json_getFloat(constraintMap, "rotation", 0); +// data->position = Json_getFloat(constraintMap, "position", 0); +// if (data->positionMode == SP_POSITION_MODE_FIXED) data->position *= self->scale; +// data->spacing = Json_getFloat(constraintMap, "spacing", 0); +// if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) data->spacing *= self->scale; +// data->rotateMix = Json_getFloat(constraintMap, "rotateMix", 1); +// data->translateMix = Json_getFloat(constraintMap, "translateMix", 1); +// +// skeletonData->pathConstraints[i] = data; +// } +// } +// +// /* Skins. */ +// skins = Json_getItem(root, "skins"); +// if (skins) { +// Json *skinMap; +// skeletonData->skins = MALLOC(spSkin*, skins->size); +// for (skinMap = skins->child, i = 0; skinMap; skinMap = skinMap->next, ++i) { +// Json *attachmentsMap; +// Json *curves; +// spSkin *skin = spSkin_create(skinMap->name); +// +// skeletonData->skins[skeletonData->skinsCount++] = skin; +// if (strcmp(skinMap->name, "default") == 0) skeletonData->defaultSkin = skin; +// +// for (attachmentsMap = skinMap->child; attachmentsMap; attachmentsMap = attachmentsMap->next) { +// int slotIndex = spSkeletonData_findSlotIndex(skeletonData, attachmentsMap->name); +// Json *attachmentMap; +// +// for (attachmentMap = attachmentsMap->child; attachmentMap; attachmentMap = attachmentMap->next) { +// spAttachment* attachment; +// const char* skinAttachmentName = attachmentMap->name; +// const char* attachmentName = Json_getString(attachmentMap, "name", skinAttachmentName); +// const char* attachmentPath = Json_getString(attachmentMap, "path", attachmentName); +// const char* color; +// Json* entry; +// +// const char* typeString = Json_getString(attachmentMap, "type", "region"); +// spAttachmentType type; +// if (strcmp(typeString, "region") == 0) +// type = SP_ATTACHMENT_REGION; +// else if (strcmp(typeString, "mesh") == 0) +// type = SP_ATTACHMENT_MESH; +// else if (strcmp(typeString, "linkedmesh") == 0) +// type = SP_ATTACHMENT_LINKED_MESH; +// else if (strcmp(typeString, "boundingbox") == 0) +// type = SP_ATTACHMENT_BOUNDING_BOX; +// else if (strcmp(typeString, "path") == 0) +// type = SP_ATTACHMENT_PATH; +// else if (strcmp(typeString, "clipping") == 0) +// type = SP_ATTACHMENT_CLIPPING; +// else { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, "Unknown attachment type: ", typeString); +// return 0; +// } +// +// attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, attachmentName, attachmentPath); +// if (!attachment) { +// if (self->attachmentLoader->error1) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, root, self->attachmentLoader->error1, self->attachmentLoader->error2); +// return 0; +// } +// continue; +// } +// +// switch (attachment->type) { +// case SP_ATTACHMENT_REGION: { +// spRegionAttachment* region = SUB_CAST(spRegionAttachment, attachment); +// if (path) MALLOC_STR(region->path, attachmentPath); +// region->x = Json_getFloat(attachmentMap, "x", 0) * self->scale; +// region->y = Json_getFloat(attachmentMap, "y", 0) * self->scale; +// region->scaleX = Json_getFloat(attachmentMap, "scaleX", 1); +// region->scaleY = Json_getFloat(attachmentMap, "scaleY", 1); +// region->rotation = Json_getFloat(attachmentMap, "rotation", 0); +// region->width = Json_getFloat(attachmentMap, "width", 32) * self->scale; +// region->height = Json_getFloat(attachmentMap, "height", 32) * self->scale; +// +// color = Json_getString(attachmentMap, "color", 0); +// if (color) { +// spColor_setFromFloats(®ion->color, +// toColor(color, 0), +// toColor(color, 1), +// toColor(color, 2), +// toColor(color, 3)); +// } +// +// spRegionAttachment_updateOffset(region); +// +// spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); +// break; +// } +// case SP_ATTACHMENT_MESH: +// case SP_ATTACHMENT_LINKED_MESH: { +// spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, attachment); +// +// MALLOC_STR(mesh->path, attachmentPath); +// +// color = Json_getString(attachmentMap, "color", 0); +// if (color) { +// spColor_setFromFloats(&mesh->color, +// toColor(color, 0), +// toColor(color, 1), +// toColor(color, 2), +// toColor(color, 3)); +// } +// +// mesh->width = Json_getFloat(attachmentMap, "width", 32) * self->scale; +// mesh->height = Json_getFloat(attachmentMap, "height", 32) * self->scale; +// +// entry = Json_getItem(attachmentMap, "parent"); +// if (!entry) { +// int verticesLength; +// entry = Json_getItem(attachmentMap, "triangles"); +// mesh->trianglesCount = entry->size; +// mesh->triangles = MALLOC(unsigned short, entry->size); +// for (entry = entry->child, ii = 0; entry; entry = entry->next, ++ii) +// mesh->triangles[ii] = (unsigned short)entry->valueInt; +// +// entry = Json_getItem(attachmentMap, "uvs"); +// verticesLength = entry->size; +// mesh->regionUVs = MALLOC(float, verticesLength); +// for (entry = entry->child, ii = 0; entry; entry = entry->next, ++ii) +// mesh->regionUVs[ii] = entry->valueFloat; +// +// _readVertices(self, attachmentMap, SUPER(mesh), verticesLength); +// +// spMeshAttachment_updateUVs(mesh); +// +// mesh->hullLength = Json_getInt(attachmentMap, "hull", 0); +// +// entry = Json_getItem(attachmentMap, "edges"); +// if (entry) { +// mesh->edgesCount = entry->size; +// mesh->edges = MALLOC(int, entry->size); +// for (entry = entry->child, ii = 0; entry; entry = entry->next, ++ii) +// mesh->edges[ii] = entry->valueInt; +// } +// +// spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); +// } else { +// mesh->inheritDeform = Json_getInt(attachmentMap, "deform", 1); +// _spSkeletonJson_addLinkedMesh(self, SUB_CAST(spMeshAttachment, attachment), Json_getString(attachmentMap, "skin", 0), slotIndex, +// entry->valueString); +// } +// break; +// } +// case SP_ATTACHMENT_BOUNDING_BOX: { +// spBoundingBoxAttachment* box = SUB_CAST(spBoundingBoxAttachment, attachment); +// int vertexCount = Json_getInt(attachmentMap, "vertexCount", 0) << 1; +// _readVertices(self, attachmentMap, SUPER(box), vertexCount); +// box->super.verticesCount = vertexCount; +// spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); +// break; +// } +// case SP_ATTACHMENT_PATH: { +// spPathAttachment* pathAttatchment = SUB_CAST(spPathAttachment, attachment); +// int vertexCount = 0; +// pathAttatchment->closed = Json_getInt(attachmentMap, "closed", 0); +// pathAttatchment->constantSpeed = Json_getInt(attachmentMap, "constantSpeed", 1); +// vertexCount = Json_getInt(attachmentMap, "vertexCount", 0); +// _readVertices(self, attachmentMap, SUPER(pathAttatchment), vertexCount << 1); +// +// pathAttatchment->lengthsLength = vertexCount / 3; +// pathAttatchment->lengths = MALLOC(float, pathAttatchment->lengthsLength); +// +// curves = Json_getItem(attachmentMap, "lengths"); +// for (curves = curves->child, ii = 0; curves; curves = curves->next, ++ii) { +// pathAttatchment->lengths[ii] = curves->valueFloat * self->scale; +// } +// break; +// } +// case SP_ATTACHMENT_POINT: { +// spPointAttachment* point = SUB_CAST(spPointAttachment, attachment); +// point->x = Json_getFloat(attachmentMap, "x", 0) * self->scale; +// point->y = Json_getFloat(attachmentMap, "y", 0) * self->scale; +// point->rotation = Json_getFloat(attachmentMap, "rotation", 0); +// +// color = Json_getString(attachmentMap, "color", 0); +// if (color) { +// spColor_setFromFloats(&point->color, +// toColor(color, 0), +// toColor(color, 1), +// toColor(color, 2), +// toColor(color, 3)); +// } +// break; +// } +// case SP_ATTACHMENT_CLIPPING: { +// spClippingAttachment* clip = SUB_CAST(spClippingAttachment, attachment); +// int vertexCount = 0; +// const char* end = Json_getString(attachmentMap, "end", 0); +// if (end) { +// spSlotData* slot = spSkeletonData_findSlot(skeletonData, end); +// clip->endSlot = slot; +// } +// vertexCount = Json_getInt(attachmentMap, "vertexCount", 0) << 1; +// _readVertices(self, attachmentMap, SUPER(clip), vertexCount); +// spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); +// break; +// } +// } +// +// spSkin_addAttachment(skin, slotIndex, skinAttachmentName, attachment); +// } +// } +// } +// } +// +// /* Linked meshes. */ +// for (i = 0; i < internal->linkedMeshCount; i++) { +// spAttachment* parent; +// _spLinkedMesh* linkedMesh = internal->linkedMeshes + i; +// spSkin* skin = !linkedMesh->skin ? skeletonData->defaultSkin : spSkeletonData_findSkin(skeletonData, linkedMesh->skin); +// if (!skin) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, 0, "Skin not found: ", linkedMesh->skin); +// return 0; +// } +// parent = spSkin_getAttachment(skin, linkedMesh->slotIndex, linkedMesh->parent); +// if (!parent) { +// spSkeletonData_dispose(skeletonData); +// _spSkeletonJson_setError(self, 0, "Parent mesh not found: ", linkedMesh->parent); +// return 0; +// } +// spMeshAttachment_setParentMesh(linkedMesh->mesh, SUB_CAST(spMeshAttachment, parent)); +// spMeshAttachment_updateUVs(linkedMesh->mesh); +// spAttachmentLoader_configureAttachment(self->attachmentLoader, SUPER(SUPER(linkedMesh->mesh))); +// } +// +// /* Events. */ +// events = Json_getItem(root, "events"); +// if (events) { +// Json *eventMap; +// const char* stringValue; +// skeletonData->eventsCount = events->size; +// skeletonData->events = MALLOC(spEventData*, events->size); +// for (eventMap = events->child, i = 0; eventMap; eventMap = eventMap->next, ++i) { +// spEventData* eventData = spEventData_create(eventMap->name); +// eventData->intValue = Json_getInt(eventMap, "int", 0); +// eventData->floatValue = Json_getFloat(eventMap, "float", 0); +// stringValue = Json_getString(eventMap, "string", 0); +// if (stringValue) MALLOC_STR(eventData->stringValue, stringValue); +// skeletonData->events[i] = eventData; +// } +// } +// +// /* Animations. */ +// animations = Json_getItem(root, "animations"); +// if (animations) { +// Json *animationMap; +// skeletonData->animations = MALLOC(spAnimation*, animations->size); +// for (animationMap = animations->child; animationMap; animationMap = animationMap->next) { +// spAnimation* animation = _spSkeletonJson_readAnimation(self, animationMap, skeletonData); +// if (!animation) { +// spSkeletonData_dispose(skeletonData); +// return 0; +// } +// skeletonData->animations[skeletonData->animationsCount++] = animation; +// } +// } +// +// Json_dispose(root); +// return skeletonData; return NULL; } - SkeletonData* SkeletonJson::readSkeletonDataFile(const char* path) + float SkeletonJson::toColor(const char* value, int 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; + return 0; + } + + void SkeletonJson::readCurve(Json* frame, CurveTimeline* timeline, int frameIndex) + { +// Json* curve = Json_getItem(frame, "curve"); +// if (!curve) +// { +// return; +// } +// if (curve->type == JSON_STRING && strcmp(curve->valueString, "stepped") == 0) +// { +// spCurveTimeline_setStepped(timeline, frameIndex); +// } +// else if (curve->type == JSON_ARRAY) +// { +// Json* child0 = curve->child; +// Json* child1 = child0->next; +// Json* child2 = child1->next; +// Json* child3 = child2->next; +// spCurveTimeline_setCurve(timeline, frameIndex, child0->valueFloat, child1->valueFloat, child2->valueFloat, child3->valueFloat); +// } + } + + void SkeletonJson::addLinkedMesh(MeshAttachment* mesh, const char* skin, int slotIndex, const char* parent) + { +// _spLinkedMesh* linkedMesh; +// _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self); +// +// if (internal->linkedMeshCount == internal->linkedMeshCapacity) +// { +// _spLinkedMesh* linkedMeshes; +// internal->linkedMeshCapacity *= 2; +// if (internal->linkedMeshCapacity < 8) internal->linkedMeshCapacity = 8; +// linkedMeshes = MALLOC(_spLinkedMesh, internal->linkedMeshCapacity); +// memcpy(linkedMeshes, internal->linkedMeshes, sizeof(_spLinkedMesh) * internal->linkedMeshCount); +// FREE(internal->linkedMeshes); +// internal->linkedMeshes = linkedMeshes; +// } +// +// linkedMesh = internal->linkedMeshes + internal->linkedMeshCount++; +// linkedMesh->mesh = mesh; +// linkedMesh->skin = skin; +// linkedMesh->slotIndex = slotIndex; +// linkedMesh->parent = parent; + } + + Animation* SkeletonJson::readAnimation(Json* root, SkeletonData *skeletonData) + { +// int frameIndex; +// spAnimation* animation; +// Json* valueMap; +// int timelinesCount = 0; +// +// Json* bones = Json_getItem(root, "bones"); +// Json* slots = Json_getItem(root, "slots"); +// Json* ik = Json_getItem(root, "ik"); +// Json* transform = Json_getItem(root, "transform"); +// Json* paths = Json_getItem(root, "paths"); +// 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 : 0; boneMap; boneMap = boneMap->next) +// { +// timelinesCount += boneMap->size; +// } +// for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) +// { +// timelinesCount += slotMap->size; +// } +// timelinesCount += ik ? ik->size : 0; +// timelinesCount += transform ? transform->size : 0; +// for (constraintMap = paths ? paths->child : 0; constraintMap; constraintMap = constraintMap->next) +// { +// timelinesCount += constraintMap->size; +// } +// for (constraintMap = deform ? deform->child : 0; constraintMap; constraintMap = constraintMap->next) +// { +// for (slotMap = constraintMap->child; slotMap; slotMap = slotMap->next) +// { +// timelinesCount += slotMap->size; +// } +// } +// if (drawOrder) +// { +// ++timelinesCount; +// } +// if (events) +// { +// ++timelinesCount; +// } +// +// animation = spAnimation_create(root->name, timelinesCount); +// animation->timelinesCount = 0; +// +// /* Slot timelines. */ +// for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) +// { +// Json *timelineMap; +// +// int slotIndex = spSkeletonData_findSlotIndex(skeletonData, slotMap->name); +// if (slotIndex == -1) +// { +// spAnimation_dispose(animation); +// _spSkeletonJson_setError(self, root, "Slot not found: ", slotMap->name); +// return 0; +// } +// +// for (timelineMap = slotMap->child; timelineMap; timelineMap = timelineMap->next) +// { +// if (strcmp(timelineMap->name, "attachment") == 0) +// { +// spAttachmentTimeline *timeline = spAttachmentTimeline_create(timelineMap->size); +// timeline->slotIndex = slotIndex; +// +// for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// Json* name = Json_getItem(valueMap, "name"); +// spAttachmentTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), name->type == Json_NULL ? 0 : name->valueString); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[timelineMap->size - 1]); +// +// } +// else if (strcmp(timelineMap->name, "color") == 0) +// { +// spColorTimeline *timeline = spColorTimeline_create(timelineMap->size); +// timeline->slotIndex = slotIndex; +// +// for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// const char* s = Json_getString(valueMap, "color", 0); +// spColorTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), toColor(s, 0), toColor(s, 1), toColor(s, 2), toColor(s, 3)); +// readCurve(valueMap, SUPER(timeline), frameIndex); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * COLOR_ENTRIES]); +// +// } +// else if (strcmp(timelineMap->name, "twoColor") == 0) +// { +// spTwoColorTimeline *timeline = spTwoColorTimeline_create(timelineMap->size); +// timeline->slotIndex = slotIndex; +// +// 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); +// spTwoColorTimeline_setFrame(timeline, 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, SUPER(timeline), frameIndex); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * TWOCOLOR_ENTRIES]); +// } +// else +// { +// spAnimation_dispose(animation); +// _spSkeletonJson_setError(self, 0, "Invalid timeline type for a slot: ", timelineMap->name); +// return 0; +// } +// } +// } +// +// /* Bone timelines. */ +// for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next) +// { +// Json *timelineMap; +// +// int boneIndex = spSkeletonData_findBoneIndex(skeletonData, boneMap->name); +// if (boneIndex == -1) +// { +// spAnimation_dispose(animation); +// _spSkeletonJson_setError(self, root, "Bone not found: ", boneMap->name); +// return 0; +// } +// +// for (timelineMap = boneMap->child; timelineMap; timelineMap = timelineMap->next) +// { +// if (strcmp(timelineMap->name, "rotate") == 0) +// { +// spRotateTimeline *timeline = spRotateTimeline_create(timelineMap->size); +// timeline->boneIndex = boneIndex; +// +// for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// spRotateTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "angle", 0)); +// readCurve(valueMap, SUPER(timeline), frameIndex); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * ROTATE_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 ? self->scale: 1; +// spTranslateTimeline *timeline = 0; +// if (isScale) +// { +// timeline = spScaleTimeline_create(timelineMap->size); +// } +// else if (isTranslate) +// { +// timeline = spTranslateTimeline_create(timelineMap->size); +// } +// else if (isShear) +// { +// timeline = spShearTimeline_create(timelineMap->size); +// } +// timeline->boneIndex = boneIndex; +// +// for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// spTranslateTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "x", 0) * timelineScale, Json_getFloat(valueMap, "y", 0) * timelineScale); +// readCurve(valueMap, SUPER(timeline), frameIndex); +// } +// +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * TRANSLATE_ENTRIES]); +// } +// else +// { +// spAnimation_dispose(animation); +// _spSkeletonJson_setError(self, 0, "Invalid timeline type for a bone: ", timelineMap->name); +// return 0; +// } +// } +// } +// } +// +// /* IK constraint timelines. */ +// for (constraintMap = ik ? ik->child : 0; constraintMap; constraintMap = constraintMap->next) +// { +// spIkConstraintData* constraint = spSkeletonData_findIkConstraint(skeletonData, constraintMap->name); +// spIkConstraintTimeline* timeline = spIkConstraintTimeline_create(constraintMap->size); +// for (frameIndex = 0; frameIndex < skeletonData->ikConstraintsCount; ++frameIndex) +// { +// if (constraint == skeletonData->ikConstraints[frameIndex]) +// { +// timeline->ikConstraintIndex = frameIndex; +// break; +// } +// } +// for (valueMap = constraintMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// spIkConstraintTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "mix", 1), Json_getInt(valueMap, "bendPositive", 1) ? 1 : -1); +// readCurve(valueMap, SUPER(timeline), frameIndex); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[(constraintMap->size - 1) * IKCONSTRAINT_ENTRIES]); +// } +// +// /* Transform constraint timelines. */ +// for (constraintMap = transform ? transform->child : 0; constraintMap; constraintMap = constraintMap->next) +// { +// spTransformConstraintData* constraint = spSkeletonData_findTransformConstraint(skeletonData, constraintMap->name); +// spTransformConstraintTimeline* timeline = spTransformConstraintTimeline_create(constraintMap->size); +// for (frameIndex = 0; frameIndex < skeletonData->transformConstraintsCount; ++frameIndex) +// { +// if (constraint == skeletonData->transformConstraints[frameIndex]) +// { +// timeline->transformConstraintIndex = frameIndex; +// break; +// } +// } +// for (valueMap = constraintMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// spTransformConstraintTimeline_setFrame(timeline, 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, SUPER(timeline), frameIndex); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[(constraintMap->size - 1) * TRANSFORMCONSTRAINT_ENTRIES]); +// } +// +// /** Path constraint timelines. */ +// for (constraintMap = paths ? paths->child : 0; constraintMap; constraintMap = constraintMap->next) +// { +// int constraintIndex, i; +// Json* timelineMap; +// +// spPathConstraintData* data = spSkeletonData_findPathConstraint(skeletonData, constraintMap->name); +// if (!data) +// { +// spAnimation_dispose(animation); +// _spSkeletonJson_setError(self, root, "Path constraint not found: ", constraintMap->name); +// return 0; +// } +// +// for (i = 0; i < skeletonData->pathConstraintsCount; 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) +// { +// spPathConstraintPositionTimeline* timeline; +// float timelineScale = 1; +// if (strcmp(timelineName, "spacing") == 0) +// { +// timeline = (spPathConstraintPositionTimeline*)spPathConstraintSpacingTimeline_create(timelineMap->size); +// if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) +// { +// timelineScale = self->scale; +// } +// } +// else +// { +// timeline = spPathConstraintPositionTimeline_create(timelineMap->size); +// if (data->positionMode == SP_POSITION_MODE_FIXED) +// { +// timelineScale = self->scale; +// } +// } +// +// timeline->pathConstraintIndex = constraintIndex; +// for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// spPathConstraintPositionTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, timelineName, 0) * timelineScale); +// readCurve(valueMap, SUPER(timeline), frameIndex); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * PATHCONSTRAINTPOSITION_ENTRIES]); +// } +// else if (strcmp(timelineName, "mix") == 0) +// { +// spPathConstraintMixTimeline* timeline = spPathConstraintMixTimeline_create(timelineMap->size); +// timeline->pathConstraintIndex = constraintIndex; +// for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// spPathConstraintMixTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "rotateMix", 1), Json_getFloat(valueMap, "translateMix", 1)); +// readCurve(valueMap, SUPER(timeline), frameIndex); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * PATHCONSTRAINTMIX_ENTRIES]); +// } +// } +// } +// +// /* Deform timelines. */ +// for (constraintMap = deform ? deform->child : 0; constraintMap; constraintMap = constraintMap->next) +// { +// spSkin* skin = spSkeletonData_findSkin(skeletonData, constraintMap->name); +// for (slotMap = constraintMap->child; slotMap; slotMap = slotMap->next) +// { +// int slotIndex = spSkeletonData_findSlotIndex(skeletonData, slotMap->name); +// Json* timelineMap; +// for (timelineMap = slotMap->child; timelineMap; timelineMap = timelineMap->next) +// { +// float* tempDeform; +// spDeformTimeline *timeline; +// int weighted, deformLength; +// +// spVertexAttachment* attachment = SUB_CAST(spVertexAttachment, spSkin_getAttachment(skin, slotIndex, timelineMap->name)); +// if (!attachment) +// { +// spAnimation_dispose(animation); +// _spSkeletonJson_setError(self, 0, "Attachment not found: ", timelineMap->name); +// return 0; +// } +// weighted = attachment->bones != 0; +// deformLength = weighted ? attachment->verticesCount / 3 * 2 : attachment->verticesCount; +// tempDeform = MALLOC(float, deformLength); +// +// timeline = spDeformTimeline_create(timelineMap->size, deformLength); +// timeline->slotIndex = slotIndex; +// timeline->attachment = SUPER(attachment); +// +// for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// Json* vertices = Json_getItem(valueMap, "vertices"); +// float* deform2; +// if (!vertices) +// { +// if (weighted) +// { +// deform2 = tempDeform; +// memset(deform, 0, sizeof(float) * deformLength); +// } +// else +// { +// deform2 = attachment->vertices; +// } +// } +// else +// { +// int v, start = Json_getInt(valueMap, "offset", 0); +// Json* vertex; +// deform2 = tempDeform; +// memset(deform, 0, sizeof(float) * start); +// if (self->scale == 1) +// { +// for (vertex = vertices->child, v = start; vertex; vertex = vertex->next, ++v) +// { +// deform2[v] = vertex->valueFloat; +// } +// } +// else +// { +// for (vertex = vertices->child, v = start; vertex; vertex = vertex->next, ++v) +// { +// deform2[v] = vertex->valueFloat * self->scale; +// } +// } +// memset(deform + v, 0, sizeof(float) * (deformLength - v)); +// if (!weighted) +// { +// float* verticesAttachment = attachment->vertices; +// for (v = 0; v < deformLength; ++v) +// { +// deform2[v] += verticesAttachment[v]; +// } +// } +// } +// spDeformTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), deform2); +// readCurve(valueMap, SUPER(timeline), frameIndex); +// } +// FREE(tempDeform); +// +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[timelineMap->size - 1]); +// } +// } +// } +// +// /* Draw order timeline. */ +// if (drawOrder) +// { +// spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrder->size, skeletonData->slotsCount); +// for (valueMap = drawOrder->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// int ii; +// int* drawOrder2 = 0; +// Json* offsets = Json_getItem(valueMap, "offsets"); +// if (offsets) +// { +// Json* offsetMap; +// int* unchanged = MALLOC(int, skeletonData->slotsCount - offsets->size); +// int originalIndex = 0, unchangedIndex = 0; +// +// drawOrder2 = MALLOC(int, skeletonData->slotsCount); +// for (ii = skeletonData->slotsCount - 1; ii >= 0; --ii) +// { +// drawOrder2[ii] = -1; +// } +// +// for (offsetMap = offsets->child; offsetMap; offsetMap = offsetMap->next) +// { +// int slotIndex = spSkeletonData_findSlotIndex(skeletonData, Json_getString(offsetMap, "slot", 0)); +// if (slotIndex == -1) +// { +// spAnimation_dispose(animation); +// _spSkeletonJson_setError(self, 0, "Slot not found: ", Json_getString(offsetMap, "slot", 0)); +// return 0; +// } +// /* Collect unchanged items. */ +// while (originalIndex != slotIndex) +// { +// unchanged[unchangedIndex++] = originalIndex++; +// } +// /* Set changed items. */ +// drawOrder2[originalIndex + Json_getInt(offsetMap, "offset", 0)] = originalIndex; +// originalIndex++; +// } +// /* Collect remaining unchanged items. */ +// while (originalIndex < skeletonData->slotsCount) +// { +// unchanged[unchangedIndex++] = originalIndex++; +// } +// /* Fill in unchanged items. */ +// for (ii = skeletonData->slotsCount - 1; ii >= 0; ii--) +// { +// if (drawOrder2[ii] == -1) +// { +// drawOrder2[ii] = unchanged[--unchangedIndex]; +// } +// } +// FREE(unchanged); +// } +// spDrawOrderTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), drawOrder2); +// FREE(drawOrder2); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[drawOrder->size - 1]); +// } +// +// /* Event timeline. */ +// if (events) +// { +// spEventTimeline* timeline = spEventTimeline_create(events->size); +// for (valueMap = events->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) +// { +// spEvent* event; +// const char* stringValue; +// spEventData* eventData = spSkeletonData_findEvent(skeletonData, Json_getString(valueMap, "name", 0)); +// if (!eventData) +// { +// spAnimation_dispose(animation); +// _spSkeletonJson_setError(self, 0, "Event not found: ", Json_getString(valueMap, "name", 0)); +// return 0; +// } +// event = spEvent_create(Json_getFloat(valueMap, "time", 0), eventData); +// event->intValue = Json_getInt(valueMap, "int", eventData->intValue); +// event->floatValue = Json_getFloat(valueMap, "float", eventData->floatValue); +// stringValue = Json_getString(valueMap, "string", eventData->stringValue); +// if (stringValue) +// { +// MALLOC_STR(event->stringValue, stringValue); +// } +// spEventTimeline_setFrame(timeline, frameIndex, event); +// } +// animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); +// animation->duration = MAX(animation->duration, timeline->frames[events->size - 1]); +// } +// +// return animation; return NULL; } + + void SkeletonJson::readVertices(Json* attachmentMap, VertexAttachment* attachment, int verticesLength) + { +// Json* entry; +// float* vertices; +// int i, n, nn, entrySize; +// spFloatArray* weights; +// spIntArray* bones; +// +// attachment->worldVerticesLength = verticesLength; +// +// entry = Json_getItem(attachmentMap, "vertices"); +// entrySize = entry->size; +// vertices = MALLOC(float, entrySize); +// for (entry = entry->child, i = 0; entry; entry = entry->next, ++i) +// { +// vertices[i] = entry->valueFloat; +// } +// +// if (verticesLength == entrySize) +// { +// if (self->scale != 1) +// { +// for (i = 0; i < entrySize; ++i) +// { +// vertices[i] *= self->scale; +// } +// } +// attachment->verticesCount = verticesLength; +// attachment->vertices = vertices; +// +// attachment->bonesCount = 0; +// attachment->bones = 0; +// return; +// } +// +// weights = spFloatArray_create(verticesLength * 3 * 3); +// bones = spIntArray_create(verticesLength * 3); +// +// for (i = 0, n = entrySize; i < n;) +// { +// int boneCount = (int)vertices[i++]; +// spIntArray_add(bones, boneCount); +// for (nn = i + boneCount * 4; i < nn; i += 4) +// { +// spIntArray_add(bones, (int)vertices[i]); +// spFloatArray_add(weights, vertices[i + 1] * self->scale); +// spFloatArray_add(weights, vertices[i + 2] * self->scale); +// spFloatArray_add(weights, vertices[i + 3]); +// } +// } +// +// attachment->verticesCount = weights->size; +// attachment->vertices = weights->items; +// FREE(weights); +// attachment->bonesCount = bones->size; +// attachment->bones = bones->items; +// FREE(bones); +// +// FREE(vertices); + } + + void SkeletonJson::setError(Json* root, const char* value1, const char* value2) + { +// char message[256]; +// int length; +// strcpy(message, value1); +// length = (int)strlen(value1); +// if (value2) +// { +// strncat(message + length, value2, 255 - length); +// } +// +// _error = std::string(message); +// if (root) +// { +// DESTROY(Json, root); +// } + } }