diff --git a/spine-cocos2dx/3/example/Classes/AppDelegate.cpp b/spine-cocos2dx/3/example/Classes/AppDelegate.cpp
index a4e47ed64..252e465d3 100644
--- a/spine-cocos2dx/3/example/Classes/AppDelegate.cpp
+++ b/spine-cocos2dx/3/example/Classes/AppDelegate.cpp
@@ -98,8 +98,8 @@ bool AppDelegate::applicationDidFinishLaunching () {
director->setAnimationInterval(1.0f / 60);
// create a scene. it's an autorelease object
- auto scene = RaptorExample::scene();
- //auto scene = BatchingExample::scene();
+ //auto scene = RaptorExample::scene();
+ auto scene = BatchingExample::scene();
// run
director->runWithScene(scene);
diff --git a/spine-cocos2dx/3/example/Classes/BatchingExample.cpp b/spine-cocos2dx/3/example/Classes/BatchingExample.cpp
index ec569d58e..15f936d62 100644
--- a/spine-cocos2dx/3/example/Classes/BatchingExample.cpp
+++ b/spine-cocos2dx/3/example/Classes/BatchingExample.cpp
@@ -45,28 +45,32 @@ bool BatchingExample::init () {
if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false;
// Load the texture atlas.
- spAtlas* atlas = spAtlas_createFromFile("spineboy.atlas", 0);
- CCASSERT(atlas, "Error reading atlas file.");
+ _atlas = spAtlas_createFromFile("spineboy.atlas", 0);
+ CCASSERT(_atlas, "Error reading atlas file.");
+
+ // This attachment loader configures attachments with data needed for cocos2d-x rendering.
+ // Do not dispose the attachment loader until the skeleton data is disposed!
+ _attachmentLoader = (spAttachmentLoader*)Cocos2dAttachmentLoader_create(_atlas);
// Load the skeleton data.
- spSkeletonJson* json = spSkeletonJson_create(atlas);
- json->scale = 0.6f;
- spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, "spineboy.json");
- CCASSERT(skeletonData, json->error ? json->error : "Error reading skeleton data file.");
+ spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader);
+ json->scale = 0.6f; // Resizes skeleton data to 60% of the size it was in Spine.
+ _skeletonData = spSkeletonJson_readSkeletonDataFile(json, "spineboy.json");
+ CCASSERT(_skeletonData, json->error ? json->error : "Error reading skeleton data file.");
spSkeletonJson_dispose(json);
// Setup mix times.
- spAnimationStateData* stateData = spAnimationStateData_create(skeletonData);
- spAnimationStateData_setMixByName(stateData, "walk", "jump", 0.2f);
- spAnimationStateData_setMixByName(stateData, "jump", "run", 0.2f);
+ _stateData = spAnimationStateData_create(_skeletonData);
+ spAnimationStateData_setMixByName(_stateData, "walk", "jump", 0.2f);
+ spAnimationStateData_setMixByName(_stateData, "jump", "run", 0.2f);
Size windowSize = Director::getInstance()->getWinSize();
int xMin = (int)(windowSize.width * 0.10f), xMax = (int)windowSize.width - xMin;
int yMin = 20, yMax = windowSize.height - 350;
for (int i = 0; i < 50; i++) {
// Each skeleton node shares the same atlas, skeleton data, and mix times.
- SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(skeletonData, false);
- skeletonNode->setAnimationStateData(stateData);
+ SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(_skeletonData, false);
+ skeletonNode->setAnimationStateData(_stateData);
skeletonNode->setAnimation(0, "walk", true);
skeletonNode->addAnimation(0, "jump", false, 3);
@@ -90,3 +94,12 @@ bool BatchingExample::init () {
return true;
}
+
+BatchingExample::~BatchingExample () {
+ // SkeletonAnimation instances are cocos2d-x nodes and are disposed of automatically as normal, but the data created
+ // manually to be shared across multiple SkeletonAnimations needs to be disposed of manually.
+ spSkeletonData_dispose(_skeletonData);
+ spAnimationStateData_dispose(_stateData);
+ spAttachmentLoader_dispose(_attachmentLoader);
+ spAtlas_dispose(_atlas);
+}
diff --git a/spine-cocos2dx/3/example/Classes/BatchingExample.h b/spine-cocos2dx/3/example/Classes/BatchingExample.h
index 499df60e8..763e786a8 100644
--- a/spine-cocos2dx/3/example/Classes/BatchingExample.h
+++ b/spine-cocos2dx/3/example/Classes/BatchingExample.h
@@ -40,8 +40,15 @@ public:
static cocos2d::Scene* scene ();
CREATE_FUNC(BatchingExample);
+ ~BatchingExample ();
virtual bool init ();
+
+protected:
+ spAtlas* _atlas;
+ spAttachmentLoader* _attachmentLoader;
+ spSkeletonData* _skeletonData;
+ spAnimationStateData* _stateData;
};
#endif // _BATCHINGEXAMPLE_H_
diff --git a/spine-cocos2dx/3/example/proj.win32/spine-cocos2dx.vcxproj b/spine-cocos2dx/3/example/proj.win32/spine-cocos2dx.vcxproj
index 2ff10fdda..dd41be986 100644
--- a/spine-cocos2dx/3/example/proj.win32/spine-cocos2dx.vcxproj
+++ b/spine-cocos2dx/3/example/proj.win32/spine-cocos2dx.vcxproj
@@ -129,6 +129,8 @@
+
+
@@ -142,6 +144,8 @@
+
+
diff --git a/spine-cocos2dx/3/example/proj.win32/spine-cocos2dx.vcxproj.filters b/spine-cocos2dx/3/example/proj.win32/spine-cocos2dx.vcxproj.filters
index 4851d364d..e0653582d 100644
--- a/spine-cocos2dx/3/example/proj.win32/spine-cocos2dx.vcxproj.filters
+++ b/spine-cocos2dx/3/example/proj.win32/spine-cocos2dx.vcxproj.filters
@@ -45,6 +45,12 @@
src
+
+ src
+
+
+ src
+
@@ -77,5 +83,11 @@
src
+
+ src
+
+
+ src
+
\ No newline at end of file
diff --git a/spine-cocos2dx/3/src/spine/AttachmentVertices.cpp b/spine-cocos2dx/3/src/spine/AttachmentVertices.cpp
new file mode 100644
index 000000000..b45320f34
--- /dev/null
+++ b/spine-cocos2dx/3/src/spine/AttachmentVertices.cpp
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ *
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include
+
+USING_NS_CC;
+
+namespace spine {
+
+AttachmentVertices::AttachmentVertices (Texture2D* texture, int verticesCount, unsigned short* triangles, int trianglesCount) {
+ _texture = texture;
+
+ _triangles = new TrianglesCommand::Triangles();
+ _triangles->verts = new V3F_C4B_T2F[verticesCount];
+ _triangles->vertCount = verticesCount;
+ _triangles->indices = triangles;
+ _triangles->indexCount = trianglesCount;
+}
+
+AttachmentVertices::~AttachmentVertices () {
+ delete [] _triangles->verts;
+ delete _triangles;
+}
+
+}
diff --git a/spine-cocos2dx/3/src/spine/AttachmentVertices.h b/spine-cocos2dx/3/src/spine/AttachmentVertices.h
new file mode 100644
index 000000000..72ff827e9
--- /dev/null
+++ b/spine-cocos2dx/3/src/spine/AttachmentVertices.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ *
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef SPINE_ATTACHMENTVERTICES_H_
+#define SPINE_ATTACHMENTVERTICES_H_
+
+#include "cocos2d.h"
+
+namespace spine {
+
+class AttachmentVertices {
+public:
+ AttachmentVertices (cocos2d::Texture2D* texture, int verticesCount, unsigned short* triangles, int trianglesCount);
+ virtual ~AttachmentVertices ();
+
+ cocos2d::Texture2D* _texture;
+ cocos2d::TrianglesCommand::Triangles* _triangles;
+};
+
+}
+
+#endif /* SPINE_ATTACHMENTVERTICES_H_ */
diff --git a/spine-cocos2dx/3/src/spine/Cocos2dAttachmentLoader.c b/spine-cocos2dx/3/src/spine/Cocos2dAttachmentLoader.c
new file mode 100644
index 000000000..880614c85
--- /dev/null
+++ b/spine-cocos2dx/3/src/spine/Cocos2dAttachmentLoader.c
@@ -0,0 +1,118 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ *
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include
+#include
+#include
+
+USING_NS_CC;
+using namespace spine;
+
+static unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};
+
+spAttachment* _Cocos2dAttachmentLoader_createAttachment (spAttachmentLoader* loader, spSkin* skin, spAttachmentType type,
+ const char* name, const char* path) {
+ Cocos2dAttachmentLoader* self = SUB_CAST(Cocos2dAttachmentLoader, loader);
+ return spAttachmentLoader_createAttachment(SUPER(self->atlasAttachmentLoader), skin, type, name, path);
+}
+
+void _Cocos2dAttachmentLoader_configureAttachment (spAttachmentLoader* loader, spAttachment* attachment) {
+ switch (attachment->type) {
+ case SP_ATTACHMENT_REGION: {
+ spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment);
+ spAtlasRegion* region = (spAtlasRegion*)regionAttachment->rendererObject;
+ AttachmentVertices* attachmentVertices = new AttachmentVertices((Texture2D*)region->page->rendererObject, 4, quadTriangles, 6);
+ V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts;
+ for (int i = 0, ii = 0; i < 4; ++i, ii += 2) {
+ vertices[i].texCoords.u = regionAttachment->uvs[ii];
+ vertices[i].texCoords.v = regionAttachment->uvs[ii + 1];
+ }
+ regionAttachment->rendererObject = attachmentVertices;
+ break;
+ }
+ case SP_ATTACHMENT_MESH: {
+ spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment);
+ spAtlasRegion* region = (spAtlasRegion*)meshAttachment->rendererObject;
+ AttachmentVertices* attachmentVertices = new AttachmentVertices((Texture2D*)region->page->rendererObject,
+ meshAttachment->verticesCount >> 1, meshAttachment->triangles, meshAttachment->trianglesCount);
+ V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts;
+ for (int i = 0, ii = 0, nn = meshAttachment->verticesCount; ii < nn; ++i, ii += 2) {
+ vertices[i].texCoords.u = meshAttachment->uvs[ii];
+ vertices[i].texCoords.v = meshAttachment->uvs[ii + 1];
+ }
+ meshAttachment->rendererObject = attachmentVertices;
+ break;
+ }
+ case SP_ATTACHMENT_WEIGHTED_MESH: {
+ spWeightedMeshAttachment* meshAttachment = SUB_CAST(spWeightedMeshAttachment, attachment);
+ spAtlasRegion* region = (spAtlasRegion*)meshAttachment->rendererObject;
+ AttachmentVertices* attachmentVertices = new AttachmentVertices((Texture2D*)region->page->rendererObject,
+ meshAttachment->uvsCount >> 1, meshAttachment->triangles, meshAttachment->trianglesCount);
+ V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts;
+ for (int i = 0, ii = 0, nn = meshAttachment->uvsCount; ii < nn; ++i, ii += 2) {
+ vertices[i].texCoords.u = meshAttachment->uvs[ii];
+ vertices[i].texCoords.v = meshAttachment->uvs[ii + 1];
+ }
+ meshAttachment->rendererObject = attachmentVertices;
+ break;
+ }
+ default: ;
+ }
+}
+
+void _Cocos2dAttachmentLoader_disposeAttachment (spAttachmentLoader* loader, spAttachment* attachment) {
+ switch (attachment->type) {
+ case SP_ATTACHMENT_REGION: {
+ spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment);
+ delete (AttachmentVertices*)regionAttachment->rendererObject;
+ break;
+ }
+ case SP_ATTACHMENT_MESH: {
+ spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment);
+ delete (AttachmentVertices*)meshAttachment->rendererObject;
+ break;
+ }
+ case SP_ATTACHMENT_WEIGHTED_MESH: {
+ spWeightedMeshAttachment* meshAttachment = SUB_CAST(spWeightedMeshAttachment, attachment);
+ delete (AttachmentVertices*)meshAttachment->rendererObject;
+ break;
+ }
+ default: ;
+ }
+}
+
+Cocos2dAttachmentLoader* Cocos2dAttachmentLoader_create (spAtlas* atlas) {
+ Cocos2dAttachmentLoader* self = NEW(Cocos2dAttachmentLoader);
+ _spAttachmentLoader_init(SUPER(self), _spAttachmentLoader_deinit, _Cocos2dAttachmentLoader_createAttachment,
+ _Cocos2dAttachmentLoader_configureAttachment, _Cocos2dAttachmentLoader_disposeAttachment);
+ self->atlasAttachmentLoader = spAtlasAttachmentLoader_create(atlas);
+ return self;
+}
diff --git a/spine-cocos2dx/3/src/spine/Cocos2dAttachmentLoader.h b/spine-cocos2dx/3/src/spine/Cocos2dAttachmentLoader.h
new file mode 100644
index 000000000..34816348e
--- /dev/null
+++ b/spine-cocos2dx/3/src/spine/Cocos2dAttachmentLoader.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ *
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef SPINE_COCOS2DATTACHMENTLOADER_H_
+#define SPINE_COCOS2DATTACHMENTLOADER_H_
+
+#include
+
+extern "C" {
+
+typedef struct Cocos2dAttachmentLoader {
+ spAttachmentLoader super;
+ spAtlasAttachmentLoader* atlasAttachmentLoader;
+} Cocos2dAttachmentLoader;
+
+Cocos2dAttachmentLoader* Cocos2dAttachmentLoader_create (spAtlas* atlas);
+
+}
+
+#endif /* SPINE_COCOS2DATTACHMENTLOADER_H_ */
diff --git a/spine-cocos2dx/3/src/spine/SkeletonBatch.cpp b/spine-cocos2dx/3/src/spine/SkeletonBatch.cpp
index 6462ad31a..e0428f508 100644
--- a/spine-cocos2dx/3/src/spine/SkeletonBatch.cpp
+++ b/spine-cocos2dx/3/src/spine/SkeletonBatch.cpp
@@ -34,31 +34,26 @@
#include
USING_NS_CC;
-using namespace std;
namespace spine {
static SkeletonBatch* instance = nullptr;
-void SkeletonBatch::setCommandSize (int maxVertices, int maxTriangles) {
- // 32767 is max index, so 32767 / 3 - (32767 / 3 % 3) = 10920.
- CCASSERT(maxTriangles <= 10920, "maxTriangles cannot be > 10920");
- CCASSERT(maxTriangles >= 0, "maxTriangles cannot be < 0");
+void SkeletonBatch::setBufferSize (int vertexCount) {
if (instance) delete instance;
- instance = new SkeletonBatch(maxVertices, maxTriangles);
+ instance = new SkeletonBatch(vertexCount);
}
SkeletonBatch* SkeletonBatch::getInstance () {
- if (!instance) instance = new SkeletonBatch(64, 64 * 3);
+ if (!instance) instance = new SkeletonBatch(8192);
return instance;
}
-SkeletonBatch::SkeletonBatch (int maxVertices, int maxTriangles) :
- _maxVertices(maxVertices), _maxTriangles(maxTriangles),
- _renderer(nullptr), _transform(nullptr), _transformFlags(0), _globalZOrder(0), _glProgramState(nullptr),
- _texture(nullptr), _blendMode(SP_BLEND_MODE_NORMAL)
+SkeletonBatch::SkeletonBatch (int capacity) :
+ _capacity(capacity), _position(0)
{
- _firstCommand = new Command(maxVertices, maxTriangles);
+ _buffer = new V3F_C4B_T2F[capacity];
+ _firstCommand = new Command();
_command = _firstCommand;
Director::getInstance()->getScheduler()->scheduleUpdate(this, -1, false);
@@ -73,109 +68,44 @@ SkeletonBatch::~SkeletonBatch () {
delete command;
command = next;
}
-}
-void SkeletonBatch::setRendererState (Renderer* renderer, const Mat4* transform, uint32_t transformFlags,
- float globalZOrder, GLProgramState* glProgramState, bool premultipliedAlpha) {
- _renderer = renderer;
- _transform = transform;
- _transformFlags = transformFlags;
- _globalZOrder = globalZOrder;
- _glProgramState = glProgramState;
- _premultipliedAlpha = premultipliedAlpha;
+ delete [] _buffer;
}
void SkeletonBatch::update (float delta) {
- // Reuse commands at the beginning of each frame.
+ _position = 0;
_command = _firstCommand;
- _command->_triangles->vertCount = 0;
- _command->_triangles->indexCount = 0;
}
-void SkeletonBatch::add (const Texture2D* addTexture,
- const float* addVertices, const float* uvs, int addVerticesCount,
- const int* addTriangles, int addTrianglesCount,
- const Color4B& color, spBlendMode blendMode
+void SkeletonBatch::addCommand (cocos2d::Renderer* renderer, float globalZOrder, GLuint textureID, GLProgramState* glProgramState,
+ BlendFunc blendFunc, const TrianglesCommand::Triangles& triangles, const Mat4& transform, uint32_t transformFlags
) {
- if (addTexture != _texture
- || blendMode != _blendMode
- || _command->_triangles->vertCount + (addVerticesCount >> 1) > _maxVertices
- || _command->_triangles->indexCount + addTrianglesCount > _maxTriangles
- ) {
- this->flush(max(addVerticesCount >> 1, _maxVertices), max(addTrianglesCount, _maxTriangles));
- _texture = addTexture;
- _blendMode = blendMode;
- }
+ CCASSERT(_position + triangles.vertCount < _capacity, "SkeletonBatch capacity is too small");
- TrianglesCommand::Triangles* triangles = _command->_triangles;
- for (int i = 0; i < addTrianglesCount; ++i, ++triangles->indexCount)
- triangles->indices[triangles->indexCount] = addTriangles[i] + triangles->vertCount;
+ memcpy(_buffer + _position, triangles.verts, sizeof(V3F_C4B_T2F) * triangles.vertCount);
+ _command->_triangles->verts = _buffer + _position;
+ _position += triangles.vertCount;
- for (int i = 0; i < addVerticesCount; i += 2, ++triangles->vertCount) {
- V3F_C4B_T2F* vertex = triangles->verts + triangles->vertCount;
- vertex->vertices.x = addVertices[i];
- vertex->vertices.y = addVertices[i + 1];
- vertex->colors = color;
- vertex->texCoords.u = uvs[i];
- vertex->texCoords.v = uvs[i + 1];
- }
-}
+ _command->_triangles->vertCount = triangles.vertCount;
+ _command->_triangles->indexCount = triangles.indexCount;
+ _command->_triangles->indices = triangles.indices;
-void SkeletonBatch::flush (int maxVertices, int maxTriangles) {
- if (!_command->_triangles->vertCount) return;
+ _command->_trianglesCommand->init(globalZOrder, textureID, glProgramState, blendFunc, *_command->_triangles, transform, transformFlags);
+ renderer->addCommand(_command->_trianglesCommand);
- BlendFunc blendFunc;
- switch (_blendMode) {
- case SP_BLEND_MODE_ADDITIVE:
- blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
- blendFunc.dst = GL_ONE;
- break;
- case SP_BLEND_MODE_MULTIPLY:
- blendFunc.src = GL_DST_COLOR;
- blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
- break;
- case SP_BLEND_MODE_SCREEN:
- blendFunc.src = GL_ONE;
- blendFunc.dst = GL_ONE_MINUS_SRC_COLOR;
- break;
- default:
- blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
- blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
- }
-
- _command->_trianglesCommand->init(_globalZOrder, _texture->getName(), _glProgramState, blendFunc, *_command->_triangles,
- *_transform, _transformFlags);
- _renderer->addCommand(_command->_trianglesCommand);
-
- if (!_command->_next) _command->_next = new Command(maxVertices, maxTriangles);
+ if (!_command->_next) _command->_next = new Command();
_command = _command->_next;
-
- // If not as large as required, insert new command.
- if (_command->_maxVertices < maxVertices || _command->_maxTriangles < maxTriangles) {
- Command* next = _command->_next;
- _command = new Command(maxVertices, maxTriangles);
- _command->_next = next;
- }
-
- _command->_triangles->vertCount = 0;
- _command->_triangles->indexCount = 0;
}
-SkeletonBatch::Command::Command (int maxVertices, int maxTriangles) :
- _maxVertices(maxVertices), _maxTriangles(maxTriangles), _next(nullptr)
+SkeletonBatch::Command::Command () :
+ _next(nullptr)
{
_trianglesCommand = new TrianglesCommand();
-
_triangles = new TrianglesCommand::Triangles();
- _triangles->verts = new V3F_C4B_T2F[maxVertices];
- _triangles->indices = new GLushort[maxTriangles];
}
SkeletonBatch::Command::~Command () {
- delete [] _triangles->indices;
- delete [] _triangles->verts;
delete _triangles;
-
delete _trianglesCommand;
}
diff --git a/spine-cocos2dx/3/src/spine/SkeletonBatch.h b/spine-cocos2dx/3/src/spine/SkeletonBatch.h
index 19904db87..2c7ae9454 100644
--- a/spine-cocos2dx/3/src/spine/SkeletonBatch.h
+++ b/spine-cocos2dx/3/src/spine/SkeletonBatch.h
@@ -37,63 +37,39 @@
namespace spine {
-/* Batches attachment geometry and issues one or more TrianglesCommands per skeleton. */
-class SkeletonBatch : public cocos2d::Ref {
+class SkeletonBatch {
public:
- /* Sets the default size of each TrianglesCommand. Best to call before getInstance is called for the first time. Default is 64, 192.
- * TrianglesCommands may be larger than the specified sizes if required to hold the geometry for a single attachment. */
- static void setCommandSize (int maxVertices, int maxTriangles);
+ /* Sets the max number of vertices that can be drawn in a single frame. Best to call before getInstance is called for the
+ * first time. Default is 8192. */
+ static void SkeletonBatch::setBufferSize (int vertexCount);
static SkeletonBatch* getInstance ();
void update (float delta);
- void setRendererState (cocos2d::Renderer* renderer, const cocos2d::Mat4* transform, uint32_t transformFlags,
- float globalZOrder, cocos2d::GLProgramState* glProgramState, bool premultipliedAlpha);
-
- void add (const cocos2d::Texture2D* texture,
- const float* vertices, const float* uvs, int verticesCount,
- const int* triangles, int trianglesCount,
- const cocos2d::Color4B& color, spBlendMode blendMode);
-
- void flush () {
- flush(_maxVertices, _maxTriangles);
- }
+ void addCommand (cocos2d::Renderer* renderer, float globalOrder, GLuint textureID, cocos2d::GLProgramState* glProgramState,
+ cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand:: Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags);
protected:
- SkeletonBatch (int maxVertices, int maxTriangles);
+ SkeletonBatch (int capacity);
virtual ~SkeletonBatch ();
- void flush (int maxVertices, int maxTriangles);
+ cocos2d::V3F_C4B_T2F* _buffer;
+ int _capacity;
+ int _position;
class Command {
public:
- Command (int maxVertices, int maxTriangles);
+ Command ();
virtual ~Command ();
- int _maxVertices;
- int _maxTriangles;
cocos2d::TrianglesCommand* _trianglesCommand;
cocos2d::TrianglesCommand::Triangles* _triangles;
Command* _next;
};
- int _maxVertices;
- int _maxTriangles;
Command* _firstCommand;
Command* _command;
-
- // Renderer state.
- cocos2d::Renderer* _renderer;
- const cocos2d::Mat4* _transform;
- uint32_t _transformFlags;
- float _globalZOrder;
- cocos2d::GLProgramState* _glProgramState;
- bool _premultipliedAlpha;
-
- // Batch state.
- const cocos2d::Texture2D* _texture;
- spBlendMode _blendMode;
};
}
diff --git a/spine-cocos2dx/3/src/spine/SkeletonRenderer.cpp b/spine-cocos2dx/3/src/spine/SkeletonRenderer.cpp
index 97a1e0814..572b200ea 100644
--- a/spine-cocos2dx/3/src/spine/SkeletonRenderer.cpp
+++ b/spine-cocos2dx/3/src/spine/SkeletonRenderer.cpp
@@ -30,9 +30,10 @@
*****************************************************************************/
#include
-#include
#include
#include
+#include
+#include
#include
USING_NS_CC;
@@ -41,8 +42,6 @@ using std::max;
namespace spine {
-static const int quadTriangles[6] = {0, 1, 2, 2, 3, 0};
-
SkeletonRenderer* SkeletonRenderer::createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) {
SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData);
node->autorelease();
@@ -62,7 +61,7 @@ SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonD
}
void SkeletonRenderer::initialize () {
- _worldVertices = MALLOC(float, 1000); // Max number of vertices per mesh.
+ _worldVertices = new float[1000]; // Max number of vertices per mesh.
_blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
setOpacityModifyRGB(true);
@@ -76,29 +75,30 @@ void SkeletonRenderer::setSkeletonData (spSkeletonData *skeletonData, bool ownsS
}
SkeletonRenderer::SkeletonRenderer ()
- : _atlas(0), _debugSlots(false), _debugBones(false), _timeScale(1) {
+ : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) {
}
SkeletonRenderer::SkeletonRenderer (spSkeletonData *skeletonData, bool ownsSkeletonData)
- : _atlas(0), _debugSlots(false), _debugBones(false), _timeScale(1) {
+ : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) {
initWithData(skeletonData, ownsSkeletonData);
}
SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, spAtlas* atlas, float scale)
- : _atlas(0), _debugSlots(false), _debugBones(false), _timeScale(1) {
+ : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) {
initWithFile(skeletonDataFile, atlas, scale);
}
SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale)
- : _atlas(0), _debugSlots(false), _debugBones(false), _timeScale(1) {
+ : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) {
initWithFile(skeletonDataFile, atlasFile, scale);
}
SkeletonRenderer::~SkeletonRenderer () {
if (_ownsSkeletonData) spSkeletonData_dispose(_skeleton->data);
- if (_atlas) spAtlas_dispose(_atlas);
spSkeleton_dispose(_skeleton);
- FREE(_worldVertices);
+ if (_atlas) spAtlas_dispose(_atlas);
+ if (_attachmentLoader) spAttachmentLoader_dispose(_attachmentLoader);
+ delete _worldVertices;
}
void SkeletonRenderer::initWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) {
@@ -108,7 +108,9 @@ void SkeletonRenderer::initWithData (spSkeletonData* skeletonData, bool ownsSkel
}
void SkeletonRenderer::initWithFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale) {
- spSkeletonJson* json = spSkeletonJson_create(atlas);
+ _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas));
+
+ spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader);
json->scale = scale;
spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile.c_str());
CCASSERT(skeletonData, json->error ? json->error : "Error reading skeleton data.");
@@ -123,7 +125,9 @@ void SkeletonRenderer::initWithFile (const std::string& skeletonDataFile, const
_atlas = spAtlas_createFromFile(atlasFile.c_str(), 0);
CCASSERT(_atlas, "Error reading atlas file.");
- spSkeletonJson* json = spSkeletonJson_create(_atlas);
+ _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas));
+
+ spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader);
json->scale = scale;
spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile.c_str());
CCASSERT(skeletonData, json->error ? json->error : "Error reading skeleton data file.");
@@ -141,7 +145,6 @@ void SkeletonRenderer::update (float deltaTime) {
void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) {
SkeletonBatch* batch = SkeletonBatch::getInstance();
- batch->setRendererState(renderer, &transform, transformFlags, _globalZOrder, getGLProgramState(), _premultipliedAlpha);
Color3B nodeColor = getColor();
_skeleton->r = nodeColor.r / (float)255;
@@ -149,72 +152,83 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
_skeleton->b = nodeColor.b / (float)255;
_skeleton->a = getDisplayedOpacity() / (float)255;
- int blendMode = -1;
Color4B color;
- const float* uvs = nullptr;
- int verticesCount = 0;
- const int* triangles = nullptr;
- int trianglesCount = 0;
- float r = 0, g = 0, b = 0, a = 0;
- for (int i = 0, n = _skeleton->slotsCount; i < n; i++) {
+ int vertexCount = 0;
+ AttachmentVertices* attachmentVertices = nullptr;
+ for (int i = 0, n = _skeleton->slotsCount; i < n; ++i) {
spSlot* slot = _skeleton->drawOrder[i];
if (!slot->attachment) continue;
- Texture2D *texture = nullptr;
+
switch (slot->attachment->type) {
case SP_ATTACHMENT_REGION: {
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices);
- texture = getTexture(attachment);
- uvs = attachment->uvs;
- verticesCount = 8;
- triangles = quadTriangles;
- trianglesCount = 6;
- r = attachment->r;
- g = attachment->g;
- b = attachment->b;
- a = attachment->a;
+ attachmentVertices = getAttachmentVertices(attachment);
+ color.r = attachment->r;
+ color.g = attachment->g;
+ color.b = attachment->b;
+ color.a = attachment->a;
break;
}
case SP_ATTACHMENT_MESH: {
spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment;
spMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices);
- texture = getTexture(attachment);
- uvs = attachment->uvs;
- verticesCount = attachment->verticesCount;
- triangles = attachment->triangles;
- trianglesCount = attachment->trianglesCount;
- r = attachment->r;
- g = attachment->g;
- b = attachment->b;
- a = attachment->a;
+ attachmentVertices = getAttachmentVertices(attachment);
+ color.r = attachment->r;
+ color.g = attachment->g;
+ color.b = attachment->b;
+ color.a = attachment->a;
break;
}
case SP_ATTACHMENT_WEIGHTED_MESH: {
spWeightedMeshAttachment* attachment = (spWeightedMeshAttachment*)slot->attachment;
spWeightedMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices);
- texture = getTexture(attachment);
- uvs = attachment->uvs;
- verticesCount = attachment->uvsCount;
- triangles = attachment->triangles;
- trianglesCount = attachment->trianglesCount;
- r = attachment->r;
- g = attachment->g;
- b = attachment->b;
- a = attachment->a;
+ attachmentVertices = getAttachmentVertices(attachment);
+ color.r = attachment->r;
+ color.g = attachment->g;
+ color.b = attachment->b;
+ color.a = attachment->a;
break;
}
- default: ;
- }
- if (texture) {
- color.a = _skeleton->a * slot->a * a * 255;
- float multiplier = _premultipliedAlpha ? color.a : 255;
- color.r = _skeleton->r * slot->r * r * multiplier;
- color.g = _skeleton->g * slot->g * g * multiplier;
- color.b = _skeleton->b * slot->b * b * multiplier;
- batch->add(texture, _worldVertices, uvs, verticesCount, triangles, trianglesCount, color, slot->data->blendMode);
+ default:
+ continue;
}
+
+ color.a *= _skeleton->a * slot->a * 255;
+ float multiplier = _premultipliedAlpha ? color.a : 255;
+ color.r *= _skeleton->r * slot->r * multiplier;
+ color.g *= _skeleton->g * slot->g * multiplier;
+ color.b *= _skeleton->b * slot->b * multiplier;
+
+ for (int v = 0, w = 0, vn = attachmentVertices->_triangles->vertCount; v < vn; ++v, w += 2) {
+ V3F_C4B_T2F* vertex = attachmentVertices->_triangles->verts + v;
+ vertex->vertices.x = _worldVertices[w];
+ vertex->vertices.y = _worldVertices[w + 1];
+ vertex->colors = color;
+ }
+
+ BlendFunc blendFunc;
+ switch (slot->data->blendMode) {
+ case SP_BLEND_MODE_ADDITIVE:
+ blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ blendFunc.dst = GL_ONE;
+ break;
+ case SP_BLEND_MODE_MULTIPLY:
+ blendFunc.src = GL_DST_COLOR;
+ blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case SP_BLEND_MODE_SCREEN:
+ blendFunc.src = GL_ONE;
+ blendFunc.dst = GL_ONE_MINUS_SRC_COLOR;
+ break;
+ default:
+ blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
+ }
+
+ batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc,
+ *attachmentVertices->_triangles, transform, transformFlags);
}
- batch->flush();
if (_debugSlots || _debugBones) {
_debugCommand.init(_globalZOrder);
@@ -236,7 +250,7 @@ void SkeletonRenderer::drawDebug (const Mat4 &transform, uint32_t transformFlags
glLineWidth(1);
Vec2 points[4];
V3F_C4B_T2F_Quad quad;
- for (int i = 0, n = _skeleton->slotsCount; i < n; i++) {
+ for (int i = 0, n = _skeleton->slotsCount; i < n; ++i) {
spSlot* slot = _skeleton->drawOrder[i];
if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue;
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
@@ -252,7 +266,7 @@ void SkeletonRenderer::drawDebug (const Mat4 &transform, uint32_t transformFlags
// Bone lengths.
glLineWidth(2);
DrawPrimitives::setDrawColor4B(255, 0, 0, 255);
- for (int i = 0, n = _skeleton->bonesCount; i < n; i++) {
+ for (int i = 0, n = _skeleton->bonesCount; i < n; ++i) {
spBone *bone = _skeleton->bones[i];
float x = bone->data->length * bone->a + bone->worldX;
float y = bone->data->length * bone->c + bone->worldY;
@@ -261,7 +275,7 @@ void SkeletonRenderer::drawDebug (const Mat4 &transform, uint32_t transformFlags
// Bone origins.
DrawPrimitives::setPointSize(4);
DrawPrimitives::setDrawColor4B(0, 0, 255, 255); // Root bone is blue.
- for (int i = 0, n = _skeleton->bonesCount; i < n; i++) {
+ for (int i = 0, n = _skeleton->bonesCount; i < n; ++i) {
spBone *bone = _skeleton->bones[i];
DrawPrimitives::drawPoint(Vec2(bone->worldX, bone->worldY));
if (i == 0) DrawPrimitives::setDrawColor4B(0, 255, 0, 255);
@@ -270,16 +284,16 @@ void SkeletonRenderer::drawDebug (const Mat4 &transform, uint32_t transformFlags
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
-Texture2D* SkeletonRenderer::getTexture (spRegionAttachment* attachment) const {
- return (Texture2D*)((spAtlasRegion*)attachment->rendererObject)->page->rendererObject;
+AttachmentVertices* SkeletonRenderer::getAttachmentVertices (spRegionAttachment* attachment) const {
+ return (AttachmentVertices*)attachment->rendererObject;
}
-Texture2D* SkeletonRenderer::getTexture (spMeshAttachment* attachment) const {
- return (Texture2D*)((spAtlasRegion*)attachment->rendererObject)->page->rendererObject;
+AttachmentVertices* SkeletonRenderer::getAttachmentVertices (spMeshAttachment* attachment) const {
+ return (AttachmentVertices*)attachment->rendererObject;
}
-Texture2D* SkeletonRenderer::getTexture (spWeightedMeshAttachment* attachment) const {
- return (Texture2D*)((spAtlasRegion*)attachment->rendererObject)->page->rendererObject;
+AttachmentVertices* SkeletonRenderer::getAttachmentVertices (spWeightedMeshAttachment* attachment) const {
+ return (AttachmentVertices*)attachment->rendererObject;
}
Rect SkeletonRenderer::getBoundingBox () const {
diff --git a/spine-cocos2dx/3/src/spine/SkeletonRenderer.h b/spine-cocos2dx/3/src/spine/SkeletonRenderer.h
index e22bbedf2..05f0b5534 100644
--- a/spine-cocos2dx/3/src/spine/SkeletonRenderer.h
+++ b/spine-cocos2dx/3/src/spine/SkeletonRenderer.h
@@ -37,7 +37,7 @@
namespace spine {
-class PolygonBatch;
+class AttachmentVertices;
/* Draws a skeleton. */
class SkeletonRenderer: public cocos2d::Node, public cocos2d::BlendProtocol {
@@ -115,12 +115,13 @@ CC_CONSTRUCTOR_ACCESS:
protected:
void setSkeletonData (spSkeletonData* skeletonData, bool ownsSkeletonData);
- virtual cocos2d::Texture2D* getTexture (spRegionAttachment* attachment) const;
- virtual cocos2d::Texture2D* getTexture (spMeshAttachment* attachment) const;
- virtual cocos2d::Texture2D* getTexture (spWeightedMeshAttachment* attachment) const;
+ virtual AttachmentVertices* getAttachmentVertices (spRegionAttachment* attachment) const;
+ virtual AttachmentVertices* getAttachmentVertices (spMeshAttachment* attachment) const;
+ virtual AttachmentVertices* getAttachmentVertices (spWeightedMeshAttachment* attachment) const;
bool _ownsSkeletonData;
spAtlas* _atlas;
+ spAttachmentLoader* _attachmentLoader;
cocos2d::CustomCommand _debugCommand;
cocos2d::BlendFunc _blendFunc;
float* _worldVertices;
diff --git a/spine-cocos2dx/3/src/spine/spine-cocos2dx.h b/spine-cocos2dx/3/src/spine/spine-cocos2dx.h
index f96eba024..31f56ed40 100644
--- a/spine-cocos2dx/3/src/spine/spine-cocos2dx.h
+++ b/spine-cocos2dx/3/src/spine/spine-cocos2dx.h
@@ -34,6 +34,7 @@
#include
#include "cocos2d.h"
+#include
#include
#include