cocos2d-x rendering now uses TrianglesCommand for batching across scene graph nodes.

This commit is contained in:
NathanSweet 2016-04-01 18:37:54 +02:00
parent 3da9f83501
commit 55851f7699
19 changed files with 624 additions and 242 deletions

View File

@ -35,6 +35,7 @@
#include <string>
#include "RaptorExample.h"
#include "BatchingExample.h"
#include "AppMacros.h"
USING_NS_CC;
@ -98,6 +99,7 @@ bool AppDelegate::applicationDidFinishLaunching () {
// create a scene. it's an autorelease object
auto scene = RaptorExample::scene();
//auto scene = BatchingExample::scene();
// run
director->runWithScene(scene);

View File

@ -0,0 +1,92 @@
/******************************************************************************
* 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 "BatchingExample.h"
#include "SpineboyExample.h"
USING_NS_CC;
using namespace spine;
Scene* BatchingExample::scene () {
Scene *scene = Scene::create();
scene->addChild(BatchingExample::create());
return scene;
}
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.");
// 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_dispose(json);
// Setup mix times.
spAnimationStateData* 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);
skeletonNode->setAnimation(0, "walk", true);
skeletonNode->addAnimation(0, "jump", false, 3);
skeletonNode->addAnimation(0, "run", true);
skeletonNode->setPosition(Vec2(
RandomHelper::random_int(xMin, xMax),
RandomHelper::random_int(yMin, yMax)
));
addChild(skeletonNode);
}
scheduleUpdate();
EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool {
Director::getInstance()->replaceScene(SpineboyExample::scene());
return true;
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
return true;
}

View File

@ -0,0 +1,47 @@
/******************************************************************************
* 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 _BATCHINGEXAMPLE_H_
#define _BATCHINGEXAMPLE_H_
#include "cocos2d.h"
#include <spine/spine-cocos2dx.h>
class BatchingExample : public cocos2d::LayerColor {
public:
static cocos2d::Scene* scene ();
CREATE_FUNC(BatchingExample);
virtual bool init ();
};
#endif // _BATCHINGEXAMPLE_H_

View File

@ -31,13 +31,9 @@
#include "GoblinsExample.h"
#include "RaptorExample.h"
#include <iostream>
#include <fstream>
#include <string.h>
USING_NS_CC;
using namespace spine;
using namespace std;
Scene* GoblinsExample::scene () {
Scene *scene = Scene::create();

View File

@ -39,9 +39,10 @@ class GoblinsExample : public cocos2d::LayerColor {
public:
static cocos2d::Scene* scene ();
CREATE_FUNC(GoblinsExample);
virtual bool init ();
CREATE_FUNC (GoblinsExample);
private:
spine::SkeletonAnimation* skeletonNode;
};

View File

@ -30,14 +30,10 @@
*****************************************************************************/
#include "RaptorExample.h"
#include "SpineboyExample.h"
#include <iostream>
#include <fstream>
#include <string.h>
#include "BatchingExample.h"
USING_NS_CC;
using namespace spine;
using namespace std;
Scene* RaptorExample::scene () {
Scene *scene = Scene::create();
@ -66,7 +62,7 @@ bool RaptorExample::init () {
else if (skeletonNode->getTimeScale() == 1)
skeletonNode->setTimeScale(0.3f);
else
Director::getInstance()->replaceScene(SpineboyExample::scene());
Director::getInstance()->replaceScene(BatchingExample::scene());
return true;
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

View File

@ -39,9 +39,10 @@ class RaptorExample : public cocos2d::LayerColor {
public:
static cocos2d::Scene* scene ();
CREATE_FUNC(RaptorExample);
virtual bool init ();
CREATE_FUNC (RaptorExample);
private:
spine::SkeletonAnimation* skeletonNode;
};

View File

@ -0,0 +1,103 @@
/******************************************************************************
* 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 "SimpleCommand.h"
USING_NS_CC;
using namespace std;
Scene* SimpleCommand::scene () {
Scene *scene = Scene::create();
scene->addChild(SimpleCommand::create());
return scene;
}
bool SimpleCommand::init () {
if (!Node::init()) return false;
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));
_texture = _director->getTextureCache()->addImage("sprite.png");
setPosition(100, 100);
return true;
}
void SimpleCommand::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) {
TrianglesCommand::Triangles* triangles = new TrianglesCommand::Triangles();
float x = 0, y = 0;
float w = 80, h = 80;
triangles->vertCount = 4;
triangles->verts = new V3F_C4B_T2F[4];
triangles->verts[0].colors = Color4B::WHITE;
triangles->verts[0].texCoords.u = 0;
triangles->verts[0].texCoords.v = 1;
triangles->verts[0].vertices.x = 0;
triangles->verts[0].vertices.y = 0;
triangles->verts[0].vertices.z = 0;
triangles->verts[1].colors = Color4B::WHITE;
triangles->verts[1].texCoords.u = 0;
triangles->verts[1].texCoords.v = 0;
triangles->verts[1].vertices.x = 0;
triangles->verts[1].vertices.y = h;
triangles->verts[1].vertices.z = 0;
triangles->verts[2].colors = Color4B::WHITE;
triangles->verts[2].texCoords.u = 1;
triangles->verts[2].texCoords.v = 1;
triangles->verts[2].vertices.x = w;
triangles->verts[2].vertices.y = 0;
triangles->verts[2].vertices.z = 0;
triangles->verts[3].colors = Color4B::WHITE;
triangles->verts[3].texCoords.u = 1;
triangles->verts[3].texCoords.v = 0;
triangles->verts[3].vertices.x = w;
triangles->verts[3].vertices.y = h;
triangles->verts[3].vertices.z = 0;
triangles->indexCount = 6;
triangles->indices = new GLushort[6];
triangles->indices[0] = 0;
triangles->indices[1] = 1;
triangles->indices[2] = 2;
triangles->indices[3] = 3;
triangles->indices[4] = 2;
triangles->indices[5] = 1;
TrianglesCommand* trianglesCommand = new TrianglesCommand();
trianglesCommand->init(_globalZOrder, _texture->getName(), getGLProgramState(), BlendFunc::ALPHA_PREMULTIPLIED, *triangles, transform, transformFlags);
renderer->addCommand(trianglesCommand);
}

View File

@ -29,36 +29,23 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#ifndef SPINE_POLYGONBATCH_H_
#define SPINE_POLYGONBATCH_H_
#ifndef _SIMPLECOMMAND_H_
#define _SIMPLECOMMAND_H_
#include "cocos2d.h"
namespace spine {
class PolygonBatch : public cocos2d::Ref {
class SimpleCommand : public cocos2d::Node {
public:
static PolygonBatch* createWithCapacity (ssize_t capacity);
static cocos2d::Scene* scene ();
void add (const cocos2d::Texture2D* texture,
const float* vertices, const float* uvs, int verticesCount,
const int* triangles, int trianglesCount,
cocos2d::Color4B* color);
void flush ();
virtual bool init ();
virtual void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override;
CREATE_FUNC (SimpleCommand);
protected:
PolygonBatch();
virtual ~PolygonBatch();
bool initWithCapacity (ssize_t capacity);
ssize_t _capacity;
cocos2d::V2F_C4B_T2F* _vertices;
int _verticesCount;
GLushort* _triangles;
int _trianglesCount;
const cocos2d::Texture2D* _texture;
cocos2d::Texture2D* _texture;
};
}
#endif // SPINE_POLYGONBATCH_H_
#endif // _SIMPLECOMMAND_H_

View File

@ -31,13 +31,9 @@
#include "SpineboyExample.h"
#include "GoblinsExample.h"
#include <iostream>
#include <fstream>
#include <string.h>
USING_NS_CC;
using namespace spine;
using namespace std;
Scene* SpineboyExample::scene () {
Scene *scene = Scene::create();

View File

@ -39,10 +39,12 @@ class SpineboyExample : public cocos2d::LayerColor {
public:
static cocos2d::Scene* scene ();
CREATE_FUNC (SpineboyExample);
virtual bool init ();
virtual void update (float deltaTime);
CREATE_FUNC (SpineboyExample);
private:
spine::SkeletonAnimation* skeletonNode;
};

View File

@ -129,23 +129,25 @@
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\src\spine\PolygonBatch.h" />
<ClInclude Include="..\..\src\spine\SkeletonBatch.h" />
<ClInclude Include="..\..\src\spine\SkeletonAnimation.h" />
<ClInclude Include="..\..\src\spine\SkeletonRenderer.h" />
<ClInclude Include="..\..\src\spine\spine-cocos2dx.h" />
<ClInclude Include="..\Classes\AppDelegate.h" />
<ClInclude Include="..\Classes\AppMacros.h" />
<ClInclude Include="..\Classes\BatchingExample.h" />
<ClInclude Include="..\Classes\GoblinsExample.h" />
<ClInclude Include="..\Classes\RaptorExample.h" />
<ClInclude Include="..\Classes\SpineboyExample.h" />
<ClInclude Include="main.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\spine\PolygonBatch.cpp" />
<ClCompile Include="..\..\src\spine\SkeletonBatch.cpp" />
<ClCompile Include="..\..\src\spine\SkeletonAnimation.cpp" />
<ClCompile Include="..\..\src\spine\SkeletonRenderer.cpp" />
<ClCompile Include="..\..\src\spine\spine-cocos2dx.cpp" />
<ClCompile Include="..\Classes\AppDelegate.cpp" />
<ClCompile Include="..\Classes\BatchingExample.cpp" />
<ClCompile Include="..\Classes\GoblinsExample.cpp" />
<ClCompile Include="..\Classes\RaptorExample.cpp" />
<ClCompile Include="..\Classes\SpineboyExample.cpp" />

View File

@ -30,9 +30,6 @@
<ClInclude Include="..\Classes\RaptorExample.h">
<Filter>Classes</Filter>
</ClInclude>
<ClInclude Include="..\..\src\spine\PolygonBatch.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="..\..\src\spine\SkeletonAnimation.h">
<Filter>src</Filter>
</ClInclude>
@ -42,6 +39,12 @@
<ClInclude Include="..\..\src\spine\spine-cocos2dx.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="..\Classes\BatchingExample.h">
<Filter>Classes</Filter>
</ClInclude>
<ClInclude Include="..\..\src\spine\SkeletonBatch.h">
<Filter>src</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
@ -59,9 +62,6 @@
<ClCompile Include="..\Classes\RaptorExample.cpp">
<Filter>Classes</Filter>
</ClCompile>
<ClCompile Include="..\..\src\spine\PolygonBatch.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\spine\SkeletonAnimation.cpp">
<Filter>src</Filter>
</ClCompile>
@ -71,5 +71,11 @@
<ClCompile Include="..\..\src\spine\spine-cocos2dx.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\Classes\BatchingExample.cpp">
<Filter>Classes</Filter>
</ClCompile>
<ClCompile Include="..\..\src\spine\SkeletonBatch.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,116 +0,0 @@
/******************************************************************************
* 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 <spine/PolygonBatch.h>
#include <spine/extension.h>
USING_NS_CC;
namespace spine {
PolygonBatch* PolygonBatch::createWithCapacity (ssize_t capacity) {
PolygonBatch* batch = new PolygonBatch();
batch->initWithCapacity(capacity);
batch->autorelease();
return batch;
}
PolygonBatch::PolygonBatch () :
_capacity(0),
_vertices(nullptr), _verticesCount(0),
_triangles(nullptr), _trianglesCount(0),
_texture(nullptr)
{}
bool PolygonBatch::initWithCapacity (ssize_t capacity) {
// 32767 is max index, so 32767 / 3 - (32767 / 3 % 3) = 10920.
CCASSERT(capacity <= 10920, "capacity cannot be > 10920");
CCASSERT(capacity >= 0, "capacity cannot be < 0");
_capacity = capacity;
_vertices = MALLOC(V2F_C4B_T2F, capacity);
_triangles = MALLOC(GLushort, capacity * 3);
return true;
}
PolygonBatch::~PolygonBatch () {
FREE(_vertices);
FREE(_triangles);
}
void PolygonBatch::add (const Texture2D* addTexture,
const float* addVertices, const float* uvs, int addVerticesCount,
const int* addTriangles, int addTrianglesCount,
Color4B* color) {
if (
addTexture != _texture
|| _verticesCount + (addVerticesCount >> 1) > _capacity
|| _trianglesCount + addTrianglesCount > _capacity * 3) {
this->flush();
_texture = addTexture;
}
for (int i = 0; i < addTrianglesCount; ++i, ++_trianglesCount)
_triangles[_trianglesCount] = addTriangles[i] + _verticesCount;
for (int i = 0; i < addVerticesCount; i += 2, ++_verticesCount) {
V2F_C4B_T2F* vertex = _vertices + _verticesCount;
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];
}
}
void PolygonBatch::flush () {
if (!_verticesCount) return;
GL::bindTexture2D(_texture->getName());
GL::bindVAO(0);
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR);
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_TEX_COORDS);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), &_vertices[0].vertices);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V2F_C4B_T2F), &_vertices[0].colors);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORDS, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), &_vertices[0].texCoords);
glDrawElements(GL_TRIANGLES, _trianglesCount, GL_UNSIGNED_SHORT, _triangles);
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, _verticesCount);
_verticesCount = 0;
_trianglesCount = 0;
CHECK_GL_ERROR_DEBUG();
}
}

View File

@ -47,6 +47,7 @@ typedef std::function<void(int trackIndex, spEvent* event)> EventListener;
* played later. */
class SkeletonAnimation: public SkeletonRenderer {
public:
CREATE_FUNC(SkeletonAnimation);
static SkeletonAnimation* createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData = false);
static SkeletonAnimation* createWithFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1);
static SkeletonAnimation* createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);

View File

@ -0,0 +1,182 @@
/******************************************************************************
* 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 <spine/SkeletonBatch.h>
#include <spine/extension.h>
#include <algorithm>
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");
if (instance) delete instance;
instance = new SkeletonBatch(maxVertices, maxTriangles);
}
SkeletonBatch* SkeletonBatch::getInstance () {
if (!instance) instance = new SkeletonBatch(64, 64 * 3);
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)
{
_firstCommand = new Command(maxVertices, maxTriangles);
_command = _firstCommand;
Director::getInstance()->getScheduler()->scheduleUpdate(this, -1, false);
}
SkeletonBatch::~SkeletonBatch () {
Director::getInstance()->getScheduler()->unscheduleUpdate(this);
Command* command = _firstCommand;
while (command) {
Command* next = command->_next;
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;
}
void SkeletonBatch::update (float delta) {
// Reuse commands at the beginning of each frame.
_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
) {
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;
}
TrianglesCommand::Triangles* triangles = _command->_triangles;
for (int i = 0; i < addTrianglesCount; ++i, ++triangles->indexCount)
triangles->indices[triangles->indexCount] = addTriangles[i] + 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];
}
}
void SkeletonBatch::flush (int maxVertices, int maxTriangles) {
if (!_command->_triangles->vertCount) return;
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);
_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)
{
_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;
}
}

View File

@ -0,0 +1,101 @@
/******************************************************************************
* 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_SKELETONBATCH_H_
#define SPINE_SKELETONBATCH_H_
#include <spine/spine.h>
#include "cocos2d.h"
namespace spine {
/* Batches attachment geometry and issues one or more TrianglesCommands per skeleton. */
class SkeletonBatch : public cocos2d::Ref {
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);
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);
}
protected:
SkeletonBatch (int maxVertices, int maxTriangles);
virtual ~SkeletonBatch ();
void flush (int maxVertices, int maxTriangles);
class Command {
public:
Command (int maxVertices, int maxTriangles);
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;
};
}
#endif // SPINE_SKELETONBATCH_H_

View File

@ -32,7 +32,7 @@
#include <spine/SkeletonRenderer.h>
#include <spine/spine-cocos2dx.h>
#include <spine/extension.h>
#include <spine/PolygonBatch.h>
#include <spine/SkeletonBatch.h>
#include <algorithm>
USING_NS_CC;
@ -64,13 +64,10 @@ SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonD
void SkeletonRenderer::initialize () {
_worldVertices = MALLOC(float, 1000); // Max number of vertices per mesh.
_batch = PolygonBatch::createWithCapacity(2000); // Max number of vertices and triangles per batch.
_batch->retain();
_blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
setOpacityModifyRGB(true);
setGLProgram(ShaderCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR));
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));
}
void SkeletonRenderer::setSkeletonData (spSkeletonData *skeletonData, bool ownsSkeletonData) {
@ -101,7 +98,6 @@ SkeletonRenderer::~SkeletonRenderer () {
if (_ownsSkeletonData) spSkeletonData_dispose(_skeleton->data);
if (_atlas) spAtlas_dispose(_atlas);
spSkeleton_dispose(_skeleton);
_batch->release();
FREE(_worldVertices);
}
@ -144,13 +140,8 @@ void SkeletonRenderer::update (float deltaTime) {
}
void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) {
_drawCommand.init(_globalZOrder);
_drawCommand.func = CC_CALLBACK_0(SkeletonRenderer::drawSkeleton, this, transform, transformFlags);
renderer->addCommand(&_drawCommand);
}
void SkeletonRenderer::drawSkeleton (const Mat4 &transform, uint32_t transformFlags) {
getGLProgramState()->apply(transform);
SkeletonBatch* batch = SkeletonBatch::getInstance();
batch->setRendererState(renderer, &transform, transformFlags, _globalZOrder, getGLProgramState(), _premultipliedAlpha);
Color3B nodeColor = getColor();
_skeleton->r = nodeColor.r / (float)255;
@ -215,34 +206,26 @@ void SkeletonRenderer::drawSkeleton (const Mat4 &transform, uint32_t transformFl
default: ;
}
if (texture) {
if (slot->data->blendMode != blendMode) {
_batch->flush();
blendMode = slot->data->blendMode;
switch (slot->data->blendMode) {
case SP_BLEND_MODE_ADDITIVE:
GL::blendFunc(_premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE);
break;
case SP_BLEND_MODE_MULTIPLY:
GL::blendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
break;
case SP_BLEND_MODE_SCREEN:
GL::blendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
break;
default:
GL::blendFunc(_blendFunc.src, _blendFunc.dst);
}
}
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);
batch->add(texture, _worldVertices, uvs, verticesCount, triangles, trianglesCount, color, slot->data->blendMode);
}
}
_batch->flush();
batch->flush();
if (_debugSlots || _debugBones) {
_debugCommand.init(_globalZOrder);
_debugCommand.func = CC_CALLBACK_0(SkeletonRenderer::drawDebug, this, transform, transformFlags);
renderer->addCommand(&_debugCommand);
}
}
void SkeletonRenderer::drawDebug (const Mat4 &transform, uint32_t transformFlags) {
getGLProgramState()->apply(transform);
Director* director = Director::getInstance();
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform);
@ -285,7 +268,6 @@ void SkeletonRenderer::drawSkeleton (const Mat4 &transform, uint32_t transformFl
}
}
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
}
Texture2D* SkeletonRenderer::getTexture (spRegionAttachment* attachment) const {

View File

@ -39,16 +39,17 @@ namespace spine {
class PolygonBatch;
/** Draws a skeleton. */
/* Draws a skeleton. */
class SkeletonRenderer: public cocos2d::Node, public cocos2d::BlendProtocol {
public:
CREATE_FUNC(SkeletonRenderer);
static SkeletonRenderer* createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData = false);
static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1);
static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
virtual void update (float deltaTime) override;
virtual void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override;
virtual void drawSkeleton (const cocos2d::Mat4& transform, uint32_t transformFlags);
virtual void drawDebug (const cocos2d::Mat4& transform, uint32_t transformFlags);
virtual cocos2d::Rect getBoundingBox () const override;
virtual void onEnter () override;
virtual void onExit () override;
@ -58,6 +59,7 @@ public:
void setTimeScale(float scale);
float getTimeScale() const;
/* */
void setDebugSlotsEnabled(bool enabled);
bool getDebugSlotsEnabled() const;
@ -119,9 +121,8 @@ protected:
bool _ownsSkeletonData;
spAtlas* _atlas;
cocos2d::CustomCommand _drawCommand;
cocos2d::CustomCommand _debugCommand;
cocos2d::BlendFunc _blendFunc;
PolygonBatch* _batch;
float* _worldVertices;
bool _premultipliedAlpha;
spSkeleton* _skeleton;