diff --git a/spine-c/spine-c/src/spine/Json.c b/spine-c/spine-c/src/spine/Json.c index 6225ff00c..c260bb39f 100644 --- a/spine-c/spine-c/src/spine/Json.c +++ b/spine-c/spine-c/src/spine/Json.c @@ -92,29 +92,65 @@ void Json_dispose (Json *c) { /* Parse the input text to generate a number, and populate the result into item. */ static const char* parse_number (Json *item, const char* num) { - char * endptr; - float n; + double result = 0.0; + int negative = 0; + char* ptr = (char*)num; - /* Using strtod and strtof is slightly more permissive than RFC4627, - * accepting for example hex-encoded floating point, but either - * is often leagues faster than any manual implementation. - * - * We also already know that this starts with [-0-9] from parse_value. - */ -#if __STDC_VERSION__ >= 199901L - n = strtof(num, &endptr); -#else - n = (float)strtod( num, &endptr ); -#endif - /* ignore errno's ERANGE, which returns +/-HUGE_VAL */ - /* n is 0 on any other error */ + if (*ptr == '-') { + negative = -1; + ++ptr; + } - if (endptr != num) { + 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 = n; - item->valueInt = (int)n; + item->valueFloat = result; + item->valueInt = (int)result; item->type = Json_Number; - return endptr; + return ptr; } else { /* Parse failure, ep is set. */ ep = num; diff --git a/spine-c/spine-c/src/spine/SkeletonJson.c b/spine-c/spine-c/src/spine/SkeletonJson.c index c6136c66c..48322bad5 100644 --- a/spine-c/spine-c/src/spine/SkeletonJson.c +++ b/spine-c/spine-c/src/spine/SkeletonJson.c @@ -30,7 +30,6 @@ #include #include -#include #include "Json.h" #include #include @@ -579,25 +578,14 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha int i, ii; spSkeletonData* skeletonData; Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *path, *slots, *skins, *animations, *events; - char* oldLocale; _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self); FREE(self->error); CONST_CAST(char*, self->error) = 0; internal->linkedMeshCount = 0; -#ifndef __ANDROID__ - oldLocale = strdup(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); -#endif - root = Json_create(json); -#ifndef __ANDROID__ - setlocale(LC_NUMERIC, oldLocale); - free(oldLocale); -#endif - if (!root) { _spSkeletonJson_setError(self, 0, "Invalid skeleton JSON: ", Json_getError()); return 0; diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp index cde7ce45e..df80160a1 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp @@ -36,12 +36,35 @@ #include #include +#define INITIAL_WORLD_VERTICES_LENGTH 1000 +// Used for transforming attachments for bounding boxes & debug rendering +static float* worldVertices = nullptr; +static size_t worldVerticesLength = 0; + +void ensureWorldVerticesCapacity(size_t capacity) { + if (worldVerticesLength < capacity) { + float* newWorldVertices = new float[capacity]; + memcpy(newWorldVertices, worldVertices, capacity * sizeof(float)); + delete[] worldVertices; + worldVertices = newWorldVertices; + worldVerticesLength = capacity; + } +} + USING_NS_CC; using std::min; using std::max; namespace spine { +void SkeletonRenderer::destroyScratchBuffers() { + if (worldVertices) { + delete[] worldVertices; + worldVertices = nullptr; + worldVerticesLength = 0; + } +} + SkeletonRenderer* SkeletonRenderer::createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) { SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData); node->autorelease(); @@ -61,7 +84,10 @@ SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonD } void SkeletonRenderer::initialize () { - _worldVertices = new float[1000]; // Max number of vertices per mesh. + if (!worldVertices) { + worldVertices = new float[INITIAL_WORLD_VERTICES_LENGTH]; + worldVerticesLength = INITIAL_WORLD_VERTICES_LENGTH; + } _clipper = spSkeletonClipping_create(); @@ -131,8 +157,7 @@ SkeletonRenderer::~SkeletonRenderer () { if (_ownsSkeletonData) spSkeletonData_dispose(_skeleton->data); spSkeleton_dispose(_skeleton); if (_atlas) spAtlas_dispose(_atlas); - if (_attachmentLoader) spAttachmentLoader_dispose(_attachmentLoader); - delete [] _worldVertices; + if (_attachmentLoader) spAttachmentLoader_dispose(_attachmentLoader); spSkeletonClipping_dispose(_clipper); } @@ -613,11 +638,11 @@ void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uin spSlot* slot = _skeleton->drawOrder[i]; if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue; spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; - spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices, 0, 2); - points[0] = Vec2(_worldVertices[0], _worldVertices[1]); - points[1] = Vec2(_worldVertices[2], _worldVertices[3]); - points[2] = Vec2(_worldVertices[4], _worldVertices[5]); - points[3] = Vec2(_worldVertices[6], _worldVertices[7]); + spRegionAttachment_computeWorldVertices(attachment, slot->bone, worldVertices, 0, 2); + points[0] = Vec2(worldVertices[0], worldVertices[1]); + points[1] = Vec2(worldVertices[2], worldVertices[3]); + points[2] = Vec2(worldVertices[4], worldVertices[5]); + points[3] = Vec2(worldVertices[6], worldVertices[7]); drawNode->drawPoly(points, 4, true, Color4F::BLUE); } } @@ -645,12 +670,13 @@ void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uin for (int i = 0, n = _skeleton->slotsCount; i < n; ++i) { spSlot* slot = _skeleton->drawOrder[i]; if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_MESH) continue; - spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment; - spVertexAttachment_computeWorldVertices(SUPER(attachment), slot, 0, attachment->super.worldVerticesLength, _worldVertices, 0, 2); + spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment; + ensureWorldVerticesCapacity(attachment->super.worldVerticesLength); + spVertexAttachment_computeWorldVertices(SUPER(attachment), slot, 0, attachment->super.worldVerticesLength, worldVertices, 0, 2); for (int ii = 0; ii < attachment->trianglesCount;) { - Vec2 v1(_worldVertices + (attachment->triangles[ii++] * 2)); - Vec2 v2(_worldVertices + (attachment->triangles[ii++] * 2)); - Vec2 v3(_worldVertices + (attachment->triangles[ii++] * 2)); + Vec2 v1(worldVertices + (attachment->triangles[ii++] * 2)); + Vec2 v2(worldVertices + (attachment->triangles[ii++] * 2)); + Vec2 v3(worldVertices + (attachment->triangles[ii++] * 2)); drawNode->drawLine(v1, v2, Color4F::YELLOW); drawNode->drawLine(v2, v3, Color4F::YELLOW); drawNode->drawLine(v3, v1, Color4F::YELLOW); @@ -680,16 +706,17 @@ Rect SkeletonRenderer::getBoundingBox () const { int verticesCount; if (slot->attachment->type == SP_ATTACHMENT_REGION) { spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; - spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices, 0, 2); + spRegionAttachment_computeWorldVertices(attachment, slot->bone, worldVertices, 0, 2); verticesCount = 8; } else if (slot->attachment->type == SP_ATTACHMENT_MESH) { spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment; - spVertexAttachment_computeWorldVertices(SUPER(mesh), slot, 0, mesh->super.worldVerticesLength, _worldVertices, 0, 2); + ensureWorldVerticesCapacity(mesh->super.worldVerticesLength); + spVertexAttachment_computeWorldVertices(SUPER(mesh), slot, 0, mesh->super.worldVerticesLength, worldVertices, 0, 2); verticesCount = mesh->super.worldVerticesLength; } else continue; for (int ii = 0; ii < verticesCount; ii += 2) { - float x = _worldVertices[ii] * scaleX, y = _worldVertices[ii + 1] * scaleY; + float x = worldVertices[ii] * scaleX, y = worldVertices[ii + 1] * scaleY; minX = min(minX, x); minY = min(minY, y); maxX = max(maxX, x); diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.h b/spine-cocos2dx/src/spine/SkeletonRenderer.h index 8ac8f9a62..426cba1aa 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.h +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.h @@ -108,6 +108,9 @@ public: virtual const cocos2d::BlendFunc& getBlendFunc () const override; virtual void setOpacityModifyRGB (bool value) override; virtual bool isOpacityModifyRGB () const override; + + // Frees global memory used for temporay vertex transformations. + static void destroyScratchBuffers(); CC_CONSTRUCTOR_ACCESS: SkeletonRenderer (); @@ -136,7 +139,6 @@ protected: spAttachmentLoader* _attachmentLoader; cocos2d::CustomCommand _debugCommand; cocos2d::BlendFunc _blendFunc; - float* _worldVertices; bool _premultipliedAlpha; spSkeleton* _skeleton; float _timeScale;