diff --git a/spine-cocos2dx/CMakeLists.txt b/spine-cocos2dx/CMakeLists.txt
index 50d304d22..096e8eedc 100644
--- a/spine-cocos2dx/CMakeLists.txt
+++ b/spine-cocos2dx/CMakeLists.txt
@@ -2,14 +2,14 @@ cmake_minimum_required(VERSION 2.8)
set(EXAMPLE_DIR "${CMAKE_CURRENT_LIST_DIR}/example")
if (NOT EXISTS ${EXAMPLE_DIR}/cocos2d)
message("Downloading cocos2dx, this may take some time!")
- file(DOWNLOAD "https://digitalocean.cocos2d-x.org/Cocos2D-X/cocos2d-x-3.17.1.zip" "${EXAMPLE_DIR}/cocos2dx.zip")
+ file(DOWNLOAD "https://digitalocean.cocos2d-x.org/Cocos2D-X/cocos2d-x-3.17.2.zip" "${EXAMPLE_DIR}/cocos2dx.zip")
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar x ${EXAMPLE_DIR}/cocos2dx.zip
WORKING_DIRECTORY ${EXAMPLE_DIR}
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E rename
- "${EXAMPLE_DIR}/cocos2d-x-3.17.1" "${EXAMPLE_DIR}/cocos2d"
+ "${EXAMPLE_DIR}/cocos2d-x-3.17.2" "${EXAMPLE_DIR}/cocos2d"
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E remove_directory "${EXAMPLE_DIR}/cocos2d/cocos/editor-support/spine"
diff --git a/spine-cocos2dx/example/Classes/BatchingExample.cpp b/spine-cocos2dx/example/Classes/BatchingExample.cpp
index b2f09a78d..c85940888 100644
--- a/spine-cocos2dx/example/Classes/BatchingExample.cpp
+++ b/spine-cocos2dx/example/Classes/BatchingExample.cpp
@@ -48,7 +48,7 @@ bool BatchingExample::init () {
// Load the texture atlas. Note that the texture loader has to live
// as long as the Atlas, as the Atlas destructor will call TextureLoader::unload.
- _atlas = new (__FILE__, __LINE__) Atlas("spineboy.atlas", &textureLoader);
+ _atlas = new (__FILE__, __LINE__) Atlas("spineboy.atlas", &textureLoader, true);
CCASSERT(_atlas, "Error reading atlas file.");
// This attachment loader configures attachments with data needed for cocos2d-x rendering.
diff --git a/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.sln b/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.sln
index df46c3507..54d77b2c3 100644
--- a/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.sln
+++ b/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25420.1
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spine-cocos2d-x", "spine-cocos2d-x.vcxproj", "{76A39BB2-9B84-4C65-98A5-654D86B86F2A}"
ProjectSection(ProjectDependencies) = postProject
@@ -10,8 +10,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spine-cocos2d-x", "spine-co
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcocos2d", "..\cocos2d\cocos\2d\libcocos2d.vcxproj", "{98A51BA8-FC3A-415B-AC8F-8C7BD464E93E}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbox2d", "..\cocos2d\external\Box2D\proj.win32\libbox2d.vcxproj", "{929480E7-23C0-4DF6-8456-096D71547116}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "librecast", "..\cocos2d\external\recast\proj.win32\librecast.vcxproj", "{41E34993-647E-4282-8384-4AB1AE31A452}"
EndProject
Global
@@ -28,10 +26,6 @@ Global
{98A51BA8-FC3A-415B-AC8F-8C7BD464E93E}.Debug|Win32.Build.0 = Debug|Win32
{98A51BA8-FC3A-415B-AC8F-8C7BD464E93E}.Release|Win32.ActiveCfg = Release|Win32
{98A51BA8-FC3A-415B-AC8F-8C7BD464E93E}.Release|Win32.Build.0 = Release|Win32
- {929480E7-23C0-4DF6-8456-096D71547116}.Debug|Win32.ActiveCfg = Debug|Win32
- {929480E7-23C0-4DF6-8456-096D71547116}.Debug|Win32.Build.0 = Debug|Win32
- {929480E7-23C0-4DF6-8456-096D71547116}.Release|Win32.ActiveCfg = Release|Win32
- {929480E7-23C0-4DF6-8456-096D71547116}.Release|Win32.Build.0 = Release|Win32
{41E34993-647E-4282-8384-4AB1AE31A452}.Debug|Win32.ActiveCfg = Debug|Win32
{41E34993-647E-4282-8384-4AB1AE31A452}.Debug|Win32.Build.0 = Debug|Win32
{41E34993-647E-4282-8384-4AB1AE31A452}.Release|Win32.ActiveCfg = Release|Win32
@@ -40,4 +34,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {E20D34B0-B32B-44B5-B42D-0028D1ED286F}
+ EndGlobalSection
EndGlobal
diff --git a/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj b/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj
index b0532496a..84a8d56b8 100644
--- a/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj
+++ b/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj
@@ -19,11 +19,12 @@
Application
Unicode
- true
+ false
v120
v120_xp
v140
v140_xp
+ v142
Application
@@ -32,6 +33,7 @@
v120_xp
v140
v140_xp
+ v142
@@ -62,13 +64,6 @@
-
- $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath)
- $(VC_IncludePath);$(WindowsSdk_71A_IncludePath);
-
-
- $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath)
-
Disabled
@@ -114,7 +109,7 @@ xcopy "$(ProjectDir)..\Resources" "$(OutDir)" /D /E /I /F /Y
MaxSpeed
true
- $(EngineRoot)external;$(EngineRoot)cocos\audio\include;$(EngineRoot)external\chipmunk\include\chipmunk;$(EngineRoot)extensions;..\Classes;..;%(AdditionalIncludeDirectories);$(_COCOS_HEADER_WIN32_BEGIN);$(_COCOS_HEADER_WIN32_END)
+ $(EngineRoot)external;$(EngineRoot)cocos\audio\include;$(EngineRoot)external\chipmunk\include\chipmunk;$(EngineRoot)extensions;..\Classes;..;%(AdditionalIncludeDirectories);$(_COCOS_HEADER_WIN32_BEGIN);$(_COCOS_HEADER_WIN32_END);$(SolutionDir)..\..\..\spine-cpp\spine-cpp\include;$(SolutionDir)..\..\src;$(IncludePath)
WIN32;NDEBUG;_WINDOWS;_USE_MATH_DEFINES;GL_GLEXT_PROTOTYPES;CC_ENABLE_CHIPMUNK_INTEGRATION=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
MultiThreadedDLL
true
@@ -126,7 +121,7 @@ xcopy "$(ProjectDir)..\Resources" "$(OutDir)" /D /E /I /F /Y
true
- libcurl_imp.lib;websockets.lib;%(AdditionalDependencies);$(_COCOS_LIB_WIN32_BEGIN);$(_COCOS_LIB_WIN32_END)
+ %(AdditionalDependencies);$(_COCOS_LIB_WIN32_BEGIN);$(_COCOS_LIB_WIN32_END)
$(OutDir)$(ProjectName).exe
$(OutDir);%(AdditionalLibraryDirectories);$(_COCOS_LIB_PATH_WIN32_BEGIN);$(_COCOS_LIB_PATH_WIN32_END)
true
@@ -325,9 +320,6 @@ xcopy "$(ProjectDir)..\Resources" "$(OutDir)" /D /E /I /F /Y
{98a51ba8-fc3a-415b-ac8f-8c7bd464e93e}
false
-
- {929480e7-23c0-4df6-8456-096d71547116}
-
diff --git a/spine-cocos2dx/src/spine/SkeletonAnimation.cpp b/spine-cocos2dx/src/spine/SkeletonAnimation.cpp
index 9b0444eaf..78f0a4958 100644
--- a/spine-cocos2dx/src/spine/SkeletonAnimation.cpp
+++ b/spine-cocos2dx/src/spine/SkeletonAnimation.cpp
@@ -111,6 +111,7 @@ void SkeletonAnimation::initialize () {
super::initialize();
_ownsAnimationStateData = true;
+ _updateOnlyIfVisible = false;
_state = new (__FILE__, __LINE__) AnimationState(new (__FILE__, __LINE__) AnimationStateData(_skeleton->getData()));
_state->setRendererObject(this);
_state->setListener(animationCallback);
@@ -128,6 +129,8 @@ SkeletonAnimation::~SkeletonAnimation () {
}
void SkeletonAnimation::update (float deltaTime) {
+ if (_updateOnlyIfVisible && !isVisible()) return;
+
super::update(deltaTime);
deltaTime *= _timeScale;
@@ -306,4 +309,8 @@ AnimationState* SkeletonAnimation::getState() const {
return _state;
}
+void SkeletonAnimation::setUpdateOnlyIfVisible(bool status) {
+ _updateOnlyIfVisible = status;
+}
+
}
diff --git a/spine-cocos2dx/src/spine/SkeletonAnimation.h b/spine-cocos2dx/src/spine/SkeletonAnimation.h
index b0d47fec7..7db3dfba1 100644
--- a/spine-cocos2dx/src/spine/SkeletonAnimation.h
+++ b/spine-cocos2dx/src/spine/SkeletonAnimation.h
@@ -99,6 +99,7 @@ public:
virtual void onTrackEntryEvent (TrackEntry* entry, EventType type, Event* event);
AnimationState* getState() const;
+ void setUpdateOnlyIfVisible(bool status);
CC_CONSTRUCTOR_ACCESS:
SkeletonAnimation ();
@@ -109,6 +110,7 @@ protected:
AnimationState* _state;
bool _ownsAnimationStateData;
+ bool _updateOnlyIfVisible;
bool _firstDraw;
StartListener _startListener;
diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp
index 818a70682..64bf98a1e 100644
--- a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp
+++ b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp
@@ -35,37 +35,37 @@
#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, worldVerticesLength * sizeof(float));
- delete[] worldVertices;
- worldVertices = newWorldVertices;
- worldVerticesLength = capacity;
- }
-}
-
USING_NS_CC;
-using std::min;
-using std::max;
+
namespace spine {
-
- static Cocos2dTextureLoader textureLoader;
-
- void SkeletonRenderer::destroyScratchBuffers() {
- if (worldVertices) {
- delete[] worldVertices;
- worldVertices = nullptr;
- worldVerticesLength = 0;
- }
+
+ namespace {
+ Cocos2dTextureLoader textureLoader;
+
+ int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex);
+ cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount);
+ void interleaveCoordinates(float* dst, const float* src, int vertexCount, int dstStride);
+ BlendFunc makeBlendFunc(int blendMode, bool premultipliedAlpha);
+ void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex);
+ bool cullRectangle(const Mat4& transform, const cocos2d::Rect& rect, const Camera& camera);
+ Color4B ColorToColor4B(const Color& color);
+ bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex);
}
-
+
+// C Variable length array
+#ifdef _MSC_VER
+ // VLA not supported, use _malloca
+ #define VLA(type, arr, count) \
+ type* arr = static_cast( _malloca(sizeof(type) * count) )
+ #define VLA_FREE(arr) do { _freea(arr); } while(false)
+#else
+ #define VLA(type, arr, count) \
+ type arr[count]
+ #define VLA_FREE(arr)
+#endif
+
+
SkeletonRenderer* SkeletonRenderer::createWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData) {
SkeletonRenderer* node = new SkeletonRenderer(skeleton, ownsSkeleton, ownsSkeletonData);
node->autorelease();
@@ -77,32 +77,27 @@ namespace spine {
node->autorelease();
return node;
}
-
+
SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) {
SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlas, scale);
node->autorelease();
return node;
}
-
+
SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) {
SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlasFile, scale);
node->autorelease();
return node;
}
-
+
void SkeletonRenderer::initialize () {
- if (!worldVertices) {
- worldVertices = new float[INITIAL_WORLD_VERTICES_LENGTH];
- worldVerticesLength = INITIAL_WORLD_VERTICES_LENGTH;
- }
-
_clipper = new (__FILE__, __LINE__) SkeletonClipping();
-
+
_blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
setOpacityModifyRGB(true);
-
+
setupGLProgramState(false);
-
+
_skeleton->setToSetupPose();
_skeleton->updateWorldTransform();
}
@@ -112,71 +107,72 @@ namespace spine {
setGLProgramState(SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState());
return;
}
-
+
Texture2D *texture = nullptr;
for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) {
Slot* slot = _skeleton->getDrawOrder()[i];
- if (!slot->getAttachment()) continue;
- if (slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) {
- RegionAttachment* attachment = (RegionAttachment*)slot->getAttachment();
- texture = static_cast(attachment->getRendererObject())->_texture;
- } else if (slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) {
- MeshAttachment* attachment = (MeshAttachment*)slot->getAttachment();
- texture = static_cast(attachment->getRendererObject())->_texture;
- } else {
+ Attachment* const attachment = slot->getAttachment();
+ if (!attachment) continue;
+ if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
+ RegionAttachment* regionAttachment = static_cast(attachment);
+ texture = static_cast(regionAttachment->getRendererObject())->_texture;
+ } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
+ MeshAttachment* meshAttachment = static_cast(attachment);
+ texture = static_cast(meshAttachment->getRendererObject())->_texture;
+ }
+ else {
continue;
}
-
+
if (texture != nullptr) {
break;
}
}
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture));
}
-
+
void SkeletonRenderer::setSkeletonData (SkeletonData *skeletonData, bool ownsSkeletonData) {
_skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData);
_ownsSkeletonData = ownsSkeletonData;
}
-
+
SkeletonRenderer::SkeletonRenderer ()
- : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr), _startSlotIndex(-1), _endSlotIndex(-1) {
+ : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _timeScale(1), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) {
}
SkeletonRenderer::SkeletonRenderer(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas)
- : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr), _startSlotIndex(-1), _endSlotIndex(-1) {
+ : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _timeScale(1), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) {
initWithSkeleton(skeleton, ownsSkeleton, ownsSkeletonData, ownsAtlas);
}
-
+
SkeletonRenderer::SkeletonRenderer (SkeletonData *skeletonData, bool ownsSkeletonData)
- : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr), _startSlotIndex(-1), _endSlotIndex(-1) {
+ : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _timeScale(1), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) {
initWithData(skeletonData, ownsSkeletonData);
}
-
+
SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, Atlas* atlas, float scale)
- : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr), _startSlotIndex(-1), _endSlotIndex(-1) {
+ : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _timeScale(1), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) {
initWithJsonFile(skeletonDataFile, atlas, scale);
}
-
+
SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale)
- : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr), _startSlotIndex(-1), _endSlotIndex(-1) {
+ : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _timeScale(1), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) {
initWithJsonFile(skeletonDataFile, atlasFile, scale);
}
-
+
SkeletonRenderer::~SkeletonRenderer () {
if (_ownsSkeletonData) delete _skeleton->getData();
if (_ownsSkeleton) delete _skeleton;
- if (_ownsAtlas && _atlas) delete _atlas;
- if (_attachmentLoader) delete _attachmentLoader;
+ if (_ownsAtlas) delete _atlas;
+ delete _attachmentLoader;
delete _clipper;
}
-
+
void SkeletonRenderer::initWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) {
_skeleton = skeleton;
_ownsSkeleton = ownsSkeleton;
_ownsSkeletonData = ownsSkeletonData;
_ownsAtlas = ownsAtlas;
-
initialize();
}
@@ -185,199 +181,222 @@ namespace spine {
setSkeletonData(skeletonData, ownsSkeletonData);
initialize();
}
-
+
void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) {
_atlas = atlas;
_attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas);
-
- SkeletonJson* json = new (__FILE__, __LINE__) SkeletonJson(_attachmentLoader);
- json->setScale(scale);
- SkeletonData* skeletonData = json->readSkeletonDataFile(skeletonDataFile.c_str());
- CCASSERT(skeletonData, !json->getError().isEmpty() ? json->getError().buffer() : "Error reading skeleton data.");
- delete json;
-
+
+ SkeletonJson json(_attachmentLoader);
+ json.setScale(scale);
+ SkeletonData* skeletonData = json.readSkeletonDataFile(skeletonDataFile.c_str());
+ CCASSERT(skeletonData, !json.getError().isEmpty() ? json.getError().buffer() : "Error reading skeleton data.");
+
_ownsSkeleton = true;
setSkeletonData(skeletonData, true);
-
+
initialize();
}
-
+
void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) {
- _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader);
+ _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader, true);
CCASSERT(_atlas, "Error reading atlas file.");
-
+
_attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas);
-
- SkeletonJson* json = new (__FILE__, __LINE__) SkeletonJson(_attachmentLoader);
- json->setScale(scale);
- SkeletonData* skeletonData = json->readSkeletonDataFile(skeletonDataFile.c_str());
- CCASSERT(skeletonData, !json->getError().isEmpty() ? json->getError().buffer() : "Error reading skeleton data.");
- delete json;
-
+
+ SkeletonJson json(_attachmentLoader);
+ json.setScale(scale);
+ SkeletonData* skeletonData = json.readSkeletonDataFile(skeletonDataFile.c_str());
+ CCASSERT(skeletonData, !json.getError().isEmpty() ? json.getError().buffer() : "Error reading skeleton data.");
+
_ownsSkeleton = true;
_ownsAtlas = true;
setSkeletonData(skeletonData, true);
-
+
initialize();
}
void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) {
_atlas = atlas;
_attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas);
-
- SkeletonBinary* binary = new (__FILE__, __LINE__) SkeletonBinary(_attachmentLoader);
- binary->setScale(scale);
- SkeletonData* skeletonData = binary->readSkeletonDataFile(skeletonDataFile.c_str());
- CCASSERT(skeletonData, !binary->getError().isEmpty() ? binary->getError().buffer() : "Error reading skeleton data.");
- delete binary;
+
+ SkeletonBinary binary(_attachmentLoader);
+ binary.setScale(scale);
+ SkeletonData* skeletonData = binary.readSkeletonDataFile(skeletonDataFile.c_str());
+ CCASSERT(skeletonData, !binary.getError().isEmpty() ? binary.getError().buffer() : "Error reading skeleton data.");
_ownsSkeleton = true;
setSkeletonData(skeletonData, true);
-
+
initialize();
}
-
+
void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) {
- _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader);
+ _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader, true);
CCASSERT(_atlas, "Error reading atlas file.");
-
+
_attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas);
-
- SkeletonBinary* binary = new (__FILE__, __LINE__) SkeletonBinary(_attachmentLoader);
- binary->setScale(scale);
- SkeletonData* skeletonData = binary->readSkeletonDataFile(skeletonDataFile.c_str());
- CCASSERT(skeletonData, !binary->getError().isEmpty() ? binary->getError().buffer() : "Error reading skeleton data.");
- delete binary;
+
+ SkeletonBinary binary(_attachmentLoader);
+ binary.setScale(scale);
+ SkeletonData* skeletonData = binary.readSkeletonDataFile(skeletonDataFile.c_str());
+ CCASSERT(skeletonData, !binary.getError().isEmpty() ? binary.getError().buffer() : "Error reading skeleton data.");
_ownsSkeleton = true;
_ownsAtlas = true;
setSkeletonData(skeletonData, true);
-
+
initialize();
}
-
+
+
void SkeletonRenderer::update (float deltaTime) {
Node::update(deltaTime);
if (_ownsSkeleton) _skeleton->update(deltaTime * _timeScale);
}
-
+
void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) {
- SkeletonBatch* batch = SkeletonBatch::getInstance();
- SkeletonTwoColorBatch* twoColorBatch = SkeletonTwoColorBatch::getInstance();
- bool isTwoColorTint = this->isTwoColorTint();
-
// Early exit if the skeleton is invisible
if (getDisplayedOpacity() == 0 || _skeleton->getColor().a == 0){
return;
}
-
- if (_effect) _effect->begin(*_skeleton);
-
- Color4F nodeColor;
- nodeColor.r = getDisplayedColor().r / (float)255;
- nodeColor.g = getDisplayedColor().g / (float)255;
- nodeColor.b = getDisplayedColor().b / (float)255;
- nodeColor.a = getDisplayedOpacity() / (float)255;
-
- Color4F color;
- Color4F darkColor;
- float darkPremultipliedAlpha = _premultipliedAlpha ? 255 : 0;
+
+ const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex);
+ if (coordCount == 0)
+ {
+ return;
+ }
+ assert(coordCount % 2 == 0);
+
+ VLA(float, worldCoords, coordCount);
+ transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex);
+
+ #if CC_USE_CULLING
+ const Camera* camera = Camera::getVisitingCamera();
+ const cocos2d::Rect brect = computeBoundingRect(worldCoords, coordCount / 2);
+ _boundingRect = brect;
+
+ if (camera && cullRectangle(transform, brect, *camera))
+ {
+ VLA_FREE(worldCoords);
+ return;
+ }
+ #endif
+
+ const float* worldCoordPtr = worldCoords;
+ SkeletonBatch* batch = SkeletonBatch::getInstance();
+ SkeletonTwoColorBatch* twoColorBatch = SkeletonTwoColorBatch::getInstance();
+ const bool hasSingleTint = (isTwoColorTint() == false);
+
+ if (_effect) {
+ _effect->begin(*_skeleton);
+ }
+
+ const Color3B displayedColor = getDisplayedColor();
+ Color nodeColor;
+ nodeColor.r = displayedColor.r / 255.f;
+ nodeColor.g = displayedColor.g / 255.f;
+ nodeColor.b = displayedColor.b / 255.f;
+ nodeColor.a = getDisplayedOpacity() / 255.f;
+
+ Color color;
+ Color darkColor;
+ const float darkPremultipliedAlpha = _premultipliedAlpha ? 1.f : 0;
AttachmentVertices* attachmentVertices = nullptr;
TwoColorTrianglesCommand* lastTwoColorTrianglesCommand = nullptr;
- bool inRange = _startSlotIndex != -1 || _endSlotIndex != -1 ? false : true;
for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) {
- Slot* slot = _skeleton->getDrawOrder()[i];
-
- if (_startSlotIndex >= 0 && _startSlotIndex == slot->getData().getIndex()) {
- inRange = true;
- }
-
- if (!inRange) {
+ Slot* slot = _skeleton->getDrawOrder()[i];;
+
+ if (slotIsOutRange(*slot, _startSlotIndex, _endSlotIndex)) {
_clipper->clipEnd(*slot);
continue;
}
-
- if (_endSlotIndex >= 0 && _endSlotIndex == slot->getData().getIndex()) {
- inRange = false;
- }
-
+
if (!slot->getAttachment()) {
_clipper->clipEnd(*slot);
continue;
}
-
+
// Early exit if slot is invisible
if (slot->getColor().a == 0 || !slot->getBone().isActive()) {
_clipper->clipEnd(*slot);
continue;
}
-
+
cocos2d::TrianglesCommand::Triangles triangles;
TwoColorTriangles trianglesTwoColor;
-
+
if (slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) {
- RegionAttachment* attachment = (RegionAttachment*)slot->getAttachment();
- attachmentVertices = (AttachmentVertices*)attachment->getRendererObject();
+ RegionAttachment* attachment = static_cast(slot->getAttachment());
+ attachmentVertices = static_cast(attachment->getRendererObject());
// Early exit if attachment is invisible
if (attachment->getColor().a == 0) {
_clipper->clipEnd(*slot);
continue;
}
-
- if (!isTwoColorTint) {
+
+ float* dstTriangleVertices = nullptr;
+ int dstStride = 0; // in floats
+ if (hasSingleTint) {
triangles.indices = attachmentVertices->_triangles->indices;
triangles.indexCount = attachmentVertices->_triangles->indexCount;
triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount);
triangles.vertCount = attachmentVertices->_triangles->vertCount;
+ assert(triangles.vertCount == 4);
memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount);
- attachment->computeWorldVertices(slot->getBone(), (float*)triangles.verts, 0, 6);
+ dstStride = sizeof(V3F_C4B_T2F) / sizeof(float);
+ dstTriangleVertices = reinterpret_cast(triangles.verts);
} else {
trianglesTwoColor.indices = attachmentVertices->_triangles->indices;
trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount;
trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount);
trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount;
- for (int i = 0; i < trianglesTwoColor.vertCount; i++) {
- trianglesTwoColor.verts[i].texCoords = attachmentVertices->_triangles->verts[i].texCoords;
+ assert(trianglesTwoColor.vertCount == 4);
+ for (int v = 0; v < trianglesTwoColor.vertCount; v++) {
+ trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords;
}
- attachment->computeWorldVertices(slot->getBone(), (float*)trianglesTwoColor.verts, 0, 7);
+ dstTriangleVertices = reinterpret_cast(trianglesTwoColor.verts);
+ dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float);
}
-
- color.r = attachment->getColor().r;
- color.g = attachment->getColor().g;
- color.b = attachment->getColor().b;
- color.a = attachment->getColor().a;
+ // Copy world vertices to triangle vertices
+ interleaveCoordinates(dstTriangleVertices, worldCoordPtr, 4, dstStride);
+ worldCoordPtr += 8;
+
+ color = attachment->getColor();
}
else if (slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) {
MeshAttachment* attachment = (MeshAttachment*)slot->getAttachment();
attachmentVertices = (AttachmentVertices*)attachment->getRendererObject();
- // Early exit if attachment is invisible
- if (attachment->getColor().a == 0) {
- _clipper->clipEnd(*slot);
- continue;
- }
-
- if (!isTwoColorTint) {
+ float* dstTriangleVertices = nullptr;
+ int dstStride = 0; // in floats
+ int dstVertexCount = 0;
+ if (hasSingleTint) {
triangles.indices = attachmentVertices->_triangles->indices;
triangles.indexCount = attachmentVertices->_triangles->indexCount;
triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount);
triangles.vertCount = attachmentVertices->_triangles->vertCount;
memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount);
- attachment->computeWorldVertices(*slot, 0, attachment->getWorldVerticesLength(), (float*)triangles.verts, 0, 6);
+ dstTriangleVertices = (float*)triangles.verts;
+ dstStride = sizeof(V3F_C4B_T2F) / sizeof(float);
+ dstVertexCount = triangles.vertCount;
} else {
trianglesTwoColor.indices = attachmentVertices->_triangles->indices;
trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount;
trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount);
trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount;
- for (int i = 0; i < trianglesTwoColor.vertCount; i++) {
- trianglesTwoColor.verts[i].texCoords = attachmentVertices->_triangles->verts[i].texCoords;
+ for (int v = 0; v < trianglesTwoColor.vertCount; v++) {
+ trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords;
}
- attachment->computeWorldVertices(*slot, 0, attachment->getWorldVerticesLength(), (float*)trianglesTwoColor.verts, 0, 7);
+ dstTriangleVertices = (float*)trianglesTwoColor.verts;
+ dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float);
+ dstVertexCount = trianglesTwoColor.vertCount;
}
- color.r = attachment->getColor().r;
- color.g = attachment->getColor().g;
- color.b = attachment->getColor().b;
- color.a = attachment->getColor().a;
+ // Copy world vertices to triangle vertices
+ //assert(dstVertexCount * 2 == attachment->super.worldVerticesLength);
+ interleaveCoordinates(dstTriangleVertices, worldCoordPtr, dstVertexCount, dstStride);
+ worldCoordPtr += dstVertexCount * 2;
+
+ color = attachment->getColor();
}
else if (slot->getAttachment()->getRTTI().isExactly(ClippingAttachment::rtti)) {
ClippingAttachment* clip = (ClippingAttachment*)slot->getAttachment();
@@ -387,257 +406,174 @@ namespace spine {
_clipper->clipEnd(*slot);
continue;
}
-
- float alpha = nodeColor.a * _skeleton->getColor().a * slot->getColor().a * color.a * 255;
- // skip rendering if the color of this attachment is 0
- if (alpha == 0){
- _clipper->clipEnd(*slot);
- continue;
- }
- float multiplier = _premultipliedAlpha ? alpha : 255;
- float red = nodeColor.r * _skeleton->getColor().r * color.r * multiplier;
- float green = nodeColor.g * _skeleton->getColor().g * color.g * multiplier;
- float blue = nodeColor.b * _skeleton->getColor().b * color.b * multiplier;
-
- color.r = red * slot->getColor().r;
- color.g = green * slot->getColor().g;
- color.b = blue * slot->getColor().b;
- color.a = alpha;
-
+
if (slot->hasDarkColor()) {
- darkColor.r = red * slot->getDarkColor().r;
- darkColor.g = green * slot->getDarkColor().g;
- darkColor.b = blue * slot->getDarkColor().b;
+ darkColor = slot->getDarkColor();
} else {
darkColor.r = 0;
darkColor.g = 0;
darkColor.b = 0;
}
darkColor.a = darkPremultipliedAlpha;
-
- BlendFunc blendFunc;
- switch (slot->getData().getBlendMode()) {
- case BlendMode_Additive:
- blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
- blendFunc.dst = GL_ONE;
- break;
- case BlendMode_Multiply:
- blendFunc.src = GL_DST_COLOR;
- blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
- break;
- case BlendMode_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;
+
+ color.a *= nodeColor.a * _skeleton->getColor().a * slot->getColor().a;
+ // skip rendering if the color of this attachment is 0
+ if (color.a == 0){
+ _clipper->clipEnd(*slot);
+ continue;
}
-
- if (!isTwoColorTint) {
+ color.r *= nodeColor.r * _skeleton->getColor().r * slot->getColor().r;
+ color.g *= nodeColor.g * _skeleton->getColor().g * slot->getColor().g;
+ color.b *= nodeColor.b * _skeleton->getColor().b * slot->getColor().b;
+ if (_premultipliedAlpha)
+ {
+ color.r *= color.a;
+ color.g *= color.a;
+ color.b *= color.a;
+ }
+
+ const cocos2d::Color4B color4B = ColorToColor4B(color);
+ const cocos2d::Color4B darkColor4B = ColorToColor4B(darkColor);
+ const BlendFunc blendFunc = makeBlendFunc(slot->getData().getBlendMode(), _premultipliedAlpha);
+
+ if (hasSingleTint) {
if (_clipper->isClipping()) {
_clipper->clipTriangles((float*)&triangles.verts[0].vertices, triangles.indices, triangles.indexCount, (float*)&triangles.verts[0].texCoords, sizeof(cocos2d::V3F_C4B_T2F) / 4);
batch->deallocateVertices(triangles.vertCount);
-
+
if (_clipper->getClippedTriangles().size() == 0){
_clipper->clipEnd(*slot);
continue;
}
-
- triangles.vertCount = _clipper->getClippedVertices().size() >> 1;
+
+ triangles.vertCount = _clipper->getClippedVertices().size() / 2;
triangles.verts = batch->allocateVertices(triangles.vertCount);
triangles.indexCount = _clipper->getClippedTriangles().size();
- triangles.indices = batch->allocateIndices(triangles.indexCount);
+ triangles.indices =
+ batch->allocateIndices(triangles.indexCount);
memcpy(triangles.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size());
-
+
cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
-
- float* verts = _clipper->getClippedVertices().buffer();
- float* uvs = _clipper->getClippedUVs().buffer();
+
+ const float* verts = _clipper->getClippedVertices().buffer();
+ const float* uvs = _clipper->getClippedUVs().buffer();
if (_effect) {
- Color light;
- Color dark;
- light.r = color.r / 255.0f;
- light.g = color.g / 255.0f;
- light.b = color.b / 255.0f;
- light.a = color.a / 255.0f;
- dark.r = dark.g = dark.b = dark.a = 0;
- for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2) {
- V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
- Color lightCopy = light;
- Color darkCopy = dark;
+ V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
+ Color darkTmp;
+ for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2, ++vertex) {
+ Color lightCopy = color;
vertex->vertices.x = verts[vv];
vertex->vertices.y = verts[vv + 1];
vertex->texCoords.u = uvs[vv];
vertex->texCoords.v = uvs[vv + 1];
- _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy);
- vertex->colors.r = (GLubyte)(lightCopy.r * 255);
- vertex->colors.g = (GLubyte)(lightCopy.g * 255);
- vertex->colors.b = (GLubyte)(lightCopy.b * 255);
- vertex->colors.a = (GLubyte)(lightCopy.a * 255);
+ _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkTmp);
+ vertex->colors = ColorToColor4B(lightCopy);
}
} else {
- for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2) {
- V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+ V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
+ for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2, ++vertex) {
vertex->vertices.x = verts[vv];
vertex->vertices.y = verts[vv + 1];
vertex->texCoords.u = uvs[vv];
vertex->texCoords.v = uvs[vv + 1];
- vertex->colors.r = (GLubyte)color.r;
- vertex->colors.g = (GLubyte)color.g;
- vertex->colors.b = (GLubyte)color.b;
- vertex->colors.a = (GLubyte)color.a;
+ vertex->colors = color4B;
}
}
} else {
+ // Not clipping
+
cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
-
+
if (_effect) {
- Color light;
- Color dark;
- light.r = color.r / 255.0f;
- light.g = color.g / 255.0f;
- light.b = color.b / 255.0f;
- light.a = color.a / 255.0f;
- dark.r = dark.g = dark.b = dark.a = 0;
- for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
- V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
- Color lightCopy = light;
- Color darkCopy = dark;
- _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy);
- vertex->colors.r = (GLubyte)(lightCopy.r * 255);
- vertex->colors.g = (GLubyte)(lightCopy.g * 255);
- vertex->colors.b = (GLubyte)(lightCopy.b * 255);
- vertex->colors.a = (GLubyte)(lightCopy.a * 255);
+ V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
+ Color darkTmp;
+ for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) {
+ Color lightCopy = color;
+ _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkTmp);
+ vertex->colors = ColorToColor4B(lightCopy);
}
} else {
- for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
- V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
- vertex->colors.r = (GLubyte)color.r;
- vertex->colors.g = (GLubyte)color.g;
- vertex->colors.b = (GLubyte)color.b;
- vertex->colors.a = (GLubyte)color.a;
+ V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
+ for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) {
+ vertex->colors = color4B;
}
}
}
} else {
+ // Two tints
+
if (_clipper->isClipping()) {
_clipper->clipTriangles((float*)&trianglesTwoColor.verts[0].position, trianglesTwoColor.indices, trianglesTwoColor.indexCount, (float*)&trianglesTwoColor.verts[0].texCoords, sizeof(V3F_C4B_C4B_T2F) / 4);
twoColorBatch->deallocateVertices(trianglesTwoColor.vertCount);
-
+
if (_clipper->getClippedTriangles().size() == 0){
_clipper->clipEnd(*slot);
continue;
}
-
- trianglesTwoColor.vertCount = _clipper->getClippedVertices().size() >> 1;
+
+ trianglesTwoColor.vertCount = _clipper->getClippedVertices().size() / 2;
trianglesTwoColor.verts = twoColorBatch->allocateVertices(trianglesTwoColor.vertCount);
trianglesTwoColor.indexCount = _clipper->getClippedTriangles().size();
trianglesTwoColor.indices = twoColorBatch->allocateIndices(trianglesTwoColor.indexCount);
memcpy(trianglesTwoColor.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size());
-
+
TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
-
- float* verts = _clipper->getClippedVertices().buffer();
- float* uvs = _clipper->getClippedUVs().buffer();
-
+
+ const float* verts = _clipper->getClippedVertices().buffer();
+ const float* uvs = _clipper->getClippedUVs().buffer();
+
if (_effect) {
- Color light;
- Color dark;
- light.r = color.r / 255.0f;
- light.g = color.g / 255.0f;
- light.b = color.b / 255.0f;
- light.a = color.a / 255.0f;
- dark.r = darkColor.r / 255.0f;
- dark.g = darkColor.g / 255.0f;
- dark.b = darkColor.b / 255.0f;
- dark.a = darkColor.a / 255.0f;
- for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2) {
- V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
- Color lightCopy = light;
- Color darkCopy = dark;
+ V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
+ for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2, ++vertex) {
+ Color lightCopy = color;
+ Color darkCopy = darkColor;
vertex->position.x = verts[vv];
vertex->position.y = verts[vv + 1];
vertex->texCoords.u = uvs[vv];
vertex->texCoords.v = uvs[vv + 1];
_effect->transform(vertex->position.x, vertex->position.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy);
- vertex->color.r = (GLubyte)(lightCopy.r * 255);
- vertex->color.g = (GLubyte)(lightCopy.g * 255);
- vertex->color.b = (GLubyte)(lightCopy.b * 255);
- vertex->color.a = (GLubyte)(lightCopy.a * 255);
- vertex->color2.r = (GLubyte)(darkCopy.r * 255);
- vertex->color2.g = (GLubyte)(darkCopy.g * 255);
- vertex->color2.b = (GLubyte)(darkCopy.b * 255);
- vertex->color2.a = (GLubyte)darkColor.a;
+ vertex->color = ColorToColor4B(lightCopy);
+ vertex->color2 = ColorToColor4B(darkCopy);
}
} else {
- for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2) {
- V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+ V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
+ for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2, ++vertex) {
vertex->position.x = verts[vv];
vertex->position.y = verts[vv + 1];
vertex->texCoords.u = uvs[vv];
vertex->texCoords.v = uvs[vv + 1];
- vertex->color.r = (GLubyte)color.r;
- vertex->color.g = (GLubyte)color.g;
- vertex->color.b = (GLubyte)color.b;
- vertex->color.a = (GLubyte)color.a;
- vertex->color2.r = (GLubyte)darkColor.r;
- vertex->color2.g = (GLubyte)darkColor.g;
- vertex->color2.b = (GLubyte)darkColor.b;
- vertex->color2.a = (GLubyte)darkColor.a;
+ vertex->color = color4B;
+ vertex->color2 = darkColor4B;
}
}
} else {
TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
-
+
if (_effect) {
- Color light;
- Color dark;
- light.r = color.r / 255.0f;
- light.g = color.g / 255.0f;
- light.b = color.b / 255.0f;
- light.a = color.a / 255.0f;
- dark.r = darkColor.r / 255.0f;
- dark.g = darkColor.g / 255.0f;
- dark.b = darkColor.b / 255.0f;
- dark.a = darkColor.a / 255.0f;
-
- for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
- V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
- Color lightCopy = light;
- Color darkCopy = dark;
+ V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
+ for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) {
+ Color lightCopy = color;
+ Color darkCopy = darkColor;
_effect->transform(vertex->position.x, vertex->position.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy);
- vertex->color.r = (GLubyte)(lightCopy.r * 255);
- vertex->color.g = (GLubyte)(lightCopy.g * 255);
- vertex->color.b = (GLubyte)(lightCopy.b * 255);
- vertex->color.a = (GLubyte)(lightCopy.a * 255);
- vertex->color2.r = (GLubyte)(darkCopy.r * 255);
- vertex->color2.g = (GLubyte)(darkCopy.g * 255);
- vertex->color2.b = (GLubyte)(darkCopy.b * 255);
- vertex->color2.a = (GLubyte)darkColor.a;
+ vertex->color = ColorToColor4B(lightCopy);
+ vertex->color2 = ColorToColor4B(darkCopy);
}
} else {
- for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
- V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
- vertex->color.r = (GLubyte)color.r;
- vertex->color.g = (GLubyte)color.g;
- vertex->color.b = (GLubyte)color.b;
- vertex->color.a = (GLubyte)color.a;
- vertex->color2.r = (GLubyte)darkColor.r;
- vertex->color2.g = (GLubyte)darkColor.g;
- vertex->color2.b = (GLubyte)darkColor.b;
- vertex->color2.a = (GLubyte)darkColor.a;
+ V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
+ for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) {
+ vertex->color = color4B;
+ vertex->color2 = darkColor4B;
}
}
}
}
- _clipper->clipEnd(*slot);
+ _clipper->clipEnd(*slot);
}
_clipper->clipEnd();
-
+
if (lastTwoColorTrianglesCommand) {
Node* parent = this->getParent();
-
+
// We need to decide if we can postpone flushing the current
// batch. We can postpone if the next sibling node is a
// two color tinted skeleton with the same global-z.
@@ -648,7 +584,7 @@ namespace spine {
if (!parent || parent->getChildrenCount() > 100 || getChildrenCount() != 0) {
lastTwoColorTrianglesCommand->setForceFlush(true);
} else {
- cocos2d::Vector& children = parent->getChildren();
+ const cocos2d::Vector& children = parent->getChildren();
Node* sibling = nullptr;
for (ssize_t i = 0; i < children.size(); i++) {
if (children.at(i) == this) {
@@ -671,41 +607,70 @@ namespace spine {
}
}
}
-
+
if (_effect) _effect->end();
-
- if (_debugSlots || _debugBones || _debugMeshes) {
+
+ if (_debugBoundingRect || _debugSlots || _debugBones || _debugMeshes) {
drawDebug(renderer, transform, transformFlags);
}
+
+ VLA_FREE(worldCoords);
}
-
+
+
void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uint32_t transformFlags) {
-
+
+ #if !defined(USE_MATRIX_STACK_PROJECTION_ONLY)
Director* director = Director::getInstance();
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform);
-
+ #endif
+
DrawNode* drawNode = DrawNode::create();
-
+
+ // Draw bounding rectangle
+ if (_debugBoundingRect) {
+ glLineWidth(2);
+ const cocos2d::Rect brect = getBoundingBox();
+ const Vec2 points[4] =
+ {
+ brect.origin,
+ { brect.origin.x + brect.size.width, brect.origin.y },
+ { brect.origin.x + brect.size.width, brect.origin.y + brect.size.height },
+ { brect.origin.x, brect.origin.y + brect.size.height }
+ };
+ drawNode->drawPoly(points, 4, true, Color4F::GREEN);
+ }
+
if (_debugSlots) {
// Slots.
// DrawPrimitives::setDrawColor4B(0, 0, 255, 255);
glLineWidth(1);
- Vec2 points[4];
V3F_C4B_T2F_Quad quad;
for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) {
Slot* slot = _skeleton->getDrawOrder()[i];
+
if (!slot->getBone().isActive()) continue;
if (!slot->getAttachment() || !slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) continue;
+
+ if (slotIsOutRange(*slot, _startSlotIndex, _endSlotIndex)) {
+ continue;
+ }
+
RegionAttachment* attachment = (RegionAttachment*)slot->getAttachment();
+ float worldVertices[8];
attachment->computeWorldVertices(slot->getBone(), 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]);
+ const Vec2 points[4] =
+ {
+ { worldVertices[0], worldVertices[1] },
+ { worldVertices[2], worldVertices[3] },
+ { worldVertices[4], worldVertices[5] },
+ { worldVertices[6], worldVertices[7] }
+ };
drawNode->drawPoly(points, 4, true, Color4F::BLUE);
}
}
+
if (_debugBones) {
// Bone lengths.
glLineWidth(2);
@@ -725,7 +690,7 @@ namespace spine {
if (i == 0) color = Color4F::GREEN;
}
}
-
+
if (_debugMeshes) {
// Meshes.
glLineWidth(1);
@@ -733,63 +698,42 @@ namespace spine {
Slot* slot = _skeleton->getDrawOrder()[i];
if (!slot->getBone().isActive()) continue;
if (!slot->getAttachment() || !slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) continue;
- MeshAttachment* attachment = (MeshAttachment*)slot->getAttachment();
- ensureWorldVerticesCapacity(attachment->getWorldVerticesLength());
- attachment->computeWorldVertices(*slot, 0, attachment->getWorldVerticesLength(), worldVertices, 0, 2);
- for (int ii = 0; ii < attachment->getTriangles().size();) {
- Vec2 v1(worldVertices + (attachment->getTriangles()[ii++] * 2));
- Vec2 v2(worldVertices + (attachment->getTriangles()[ii++] * 2));
- Vec2 v3(worldVertices + (attachment->getTriangles()[ii++] * 2));
- drawNode->drawLine(v1, v2, Color4F::YELLOW);
- drawNode->drawLine(v2, v3, Color4F::YELLOW);
- drawNode->drawLine(v3, v1, Color4F::YELLOW);
+ MeshAttachment* const mesh = static_cast(slot->getAttachment());
+ VLA(float, worldCoord, mesh->getWorldVerticesLength());
+ mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), worldCoord, 0, 2);
+ for (size_t t = 0; t < mesh->getTriangles().size(); t += 3) {
+ // Fetch triangle indices
+ const int idx0 = mesh->getTriangles()[t + 0];
+ const int idx1 = mesh->getTriangles()[t + 1];
+ const int idx2 = mesh->getTriangles()[t + 2];
+ const Vec2 v[3] =
+ {
+ worldCoord + (idx0 * 2),
+ worldCoord + (idx1 * 2),
+ worldCoord + (idx2 * 2)
+ };
+ drawNode->drawPoly(v, 3, true, Color4F::YELLOW);
}
+ VLA_FREE(worldCoord);
}
-
}
-
+
drawNode->draw(renderer, transform, transformFlags);
+ #if !defined(USE_MATRIX_STACK_PROJECTION_ONLY)
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
+ #endif
}
-
- Rect SkeletonRenderer::getBoundingBox () const {
- float minX = FLT_MAX, minY = FLT_MAX, maxX = -FLT_MAX, maxY = -FLT_MAX;
- float scaleX = getScaleX(), scaleY = getScaleY();
- for (int i = 0; i < _skeleton->getSlots().size(); ++i) {
- Slot* slot = _skeleton->getSlots()[i];
- if (!slot->getAttachment()) continue;
- if (!slot->getBone().isActive()) continue;
- int verticesCount;
- if (slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) {
- RegionAttachment* attachment = (RegionAttachment*)slot->getAttachment();
- attachment->computeWorldVertices(slot->getBone(), worldVertices, 0, 2);
- verticesCount = 8;
- } else if (slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) {
- MeshAttachment* mesh = (MeshAttachment*)slot->getAttachment();
- ensureWorldVerticesCapacity(mesh->getWorldVerticesLength());
- mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), worldVertices, 0, 2);
- verticesCount = mesh->getWorldVerticesLength();
- } else
- continue;
- for (int ii = 0; ii < verticesCount; ii += 2) {
- float x = worldVertices[ii] * scaleX, y = worldVertices[ii + 1] * scaleY;
- minX = min(minX, x);
- minY = min(minY, y);
- maxX = max(maxX, x);
- maxY = max(maxY, y);
- }
- }
- Vec2 position = getPosition();
- if (minX == FLT_MAX) minX = minY = maxX = maxY = 0;
- return Rect(position.x + minX, position.y + minY, maxX - minX, maxY - minY);
+
+ cocos2d::Rect SkeletonRenderer::getBoundingBox () const {
+ return _boundingRect;
}
-
+
// --- Convenience methods for Skeleton_* functions.
-
- void SkeletonRenderer::updateWorldTransform () {
+
+ void SkeletonRenderer::updateWorldTransform() {
_skeleton->updateWorldTransform();
}
-
+
void SkeletonRenderer::setToSetupPose () {
_skeleton->setToSetupPose();
}
@@ -799,22 +743,22 @@ namespace spine {
void SkeletonRenderer::setSlotsToSetupPose () {
_skeleton->setSlotsToSetupPose();
}
-
+
Bone* SkeletonRenderer::findBone (const std::string& boneName) const {
return _skeleton->findBone(boneName.c_str());
}
-
+
Slot* SkeletonRenderer::findSlot (const std::string& slotName) const {
- return _skeleton->findSlot(slotName.c_str());
+ return _skeleton->findSlot( slotName.c_str());
}
-
+
void SkeletonRenderer::setSkin (const std::string& skinName) {
_skeleton->setSkin(skinName.empty() ? 0 : skinName.c_str());
}
void SkeletonRenderer::setSkin (const char* skinName) {
_skeleton->setSkin(skinName);
}
-
+
Attachment* SkeletonRenderer::getAttachment (const std::string& slotName, const std::string& attachmentName) const {
return _skeleton->getAttachment(slotName.c_str(), attachmentName.c_str());
}
@@ -828,7 +772,7 @@ namespace spine {
void SkeletonRenderer::setTwoColorTint(bool enabled) {
setupGLProgramState(enabled);
}
-
+
bool SkeletonRenderer::isTwoColorTint() {
return getGLProgramState() == SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState();
}
@@ -838,28 +782,28 @@ namespace spine {
}
void SkeletonRenderer::setSlotsRange(int startSlotIndex, int endSlotIndex) {
- this->_startSlotIndex = startSlotIndex;
- this->_endSlotIndex = endSlotIndex;
+ _startSlotIndex = startSlotIndex == -1 ? 0 : startSlotIndex;
+ _endSlotIndex = endSlotIndex == -1 ? std::numeric_limits::max() : endSlotIndex;
}
-
- Skeleton* SkeletonRenderer::getSkeleton () {
+
+ Skeleton* SkeletonRenderer::getSkeleton () const {
return _skeleton;
}
-
+
void SkeletonRenderer::setTimeScale (float scale) {
_timeScale = scale;
}
float SkeletonRenderer::getTimeScale () const {
return _timeScale;
}
-
+
void SkeletonRenderer::setDebugSlotsEnabled (bool enabled) {
_debugSlots = enabled;
}
bool SkeletonRenderer::getDebugSlotsEnabled () const {
return _debugSlots;
}
-
+
void SkeletonRenderer::setDebugBonesEnabled (bool enabled) {
_debugBones = enabled;
}
@@ -873,39 +817,261 @@ namespace spine {
bool SkeletonRenderer::getDebugMeshesEnabled () const {
return _debugMeshes;
}
-
+
+ void SkeletonRenderer::setDebugBoundingRectEnabled(bool enabled) {
+ _debugBoundingRect = enabled;
+ }
+
+ bool SkeletonRenderer::getDebugBoundingRectEnabled() const {
+ return _debugBoundingRect;
+ }
+
void SkeletonRenderer::onEnter () {
-#if CC_ENABLE_SCRIPT_BINDING
+ #if CC_ENABLE_SCRIPT_BINDING
if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter)) return;
-#endif
+ #endif
Node::onEnter();
scheduleUpdate();
}
-
+
void SkeletonRenderer::onExit () {
-#if CC_ENABLE_SCRIPT_BINDING
+ #if CC_ENABLE_SCRIPT_BINDING
if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit)) return;
-#endif
+ #endif
Node::onExit();
unscheduleUpdate();
}
-
+
// --- CCBlendProtocol
-
+
const BlendFunc& SkeletonRenderer::getBlendFunc () const {
return _blendFunc;
}
-
+
void SkeletonRenderer::setBlendFunc (const BlendFunc &blendFunc) {
_blendFunc = blendFunc;
}
-
+
void SkeletonRenderer::setOpacityModifyRGB (bool value) {
_premultipliedAlpha = value;
}
-
+
bool SkeletonRenderer::isOpacityModifyRGB () const {
return _premultipliedAlpha;
}
-
+
+ namespace {
+ cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount)
+ {
+ assert(coords);
+ assert(vertexCount > 0);
+
+ const float* v = coords;
+ float minX = v[0];
+ float minY = v[1];
+ float maxX = minX;
+ float maxY = minY;
+ for (int i = 1; i < vertexCount; ++i)
+ {
+ v += 2;
+ float x = v[0];
+ float y = v[1];
+ minX = std::min(minX, x);
+ minY = std::min(minY, y);
+ maxX = std::max(maxX, x);
+ maxY = std::max(maxY, y);
+ }
+ return { minX, minY, maxX - minX, maxY - minY };
+ }
+
+ bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex)
+ {
+ const int index = slot.getData().getIndex();
+ return startSlotIndex > index || endSlotIndex < index;
+ }
+
+ int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex)
+ {
+ int coordCount = 0;
+ for (size_t i = 0; i < skeleton.getSlots().size(); ++i)
+ {
+ Slot& slot = *skeleton.getSlots()[i];
+ Attachment* const attachment = slot.getAttachment();
+ if (!attachment)
+ {
+ continue;
+ }
+ if (slotIsOutRange(slot, startSlotIndex, endSlotIndex))
+ {
+ continue;
+ }
+ // Early exit if slot is invisible
+ if (slot.getColor().a == 0) {
+ continue;
+ }
+ if (attachment->getRTTI().isExactly(RegionAttachment::rtti))
+ {
+ coordCount += 8;
+ }
+ else if (attachment->getRTTI().isExactly(MeshAttachment::rtti))
+ {
+ MeshAttachment* const mesh = static_cast(attachment);
+ coordCount += mesh->getWorldVerticesLength();
+ }
+ }
+ return coordCount;
+ }
+
+
+ void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex)
+ {
+ float* dstPtr = dstCoord;
+ #ifndef NDEBUG
+ float* const dstEnd = dstCoord + coordCount;
+ #endif
+ for (size_t i = 0; i < skeleton.getSlots().size(); ++i)
+ {
+ /*const*/ Slot& slot = *skeleton.getDrawOrder()[i]; // match the draw order of SkeletonRenderer::Draw
+ Attachment* const attachment = slot.getAttachment();
+ if (!attachment)
+ {
+ continue;
+ }
+ if (slotIsOutRange(slot, startSlotIndex, endSlotIndex))
+ {
+ continue;
+ }
+ if (slot.getColor().a == 0) {
+ continue;
+ }
+ if (attachment->getRTTI().isExactly(RegionAttachment::rtti))
+ {
+ RegionAttachment* const regionAttachment = static_cast(attachment);
+ assert(dstPtr + 8 <= dstEnd);
+ regionAttachment->computeWorldVertices(slot.getBone(), dstPtr, 0, 2);
+ dstPtr += 8;
+ }
+ else if (attachment->getRTTI().isExactly(MeshAttachment::rtti))
+ {
+ MeshAttachment* const mesh = static_cast(attachment);
+ assert(dstPtr + mesh->getWorldVerticesLength() <= dstEnd);
+ mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), dstPtr, 0, 2);
+ dstPtr += mesh->getWorldVerticesLength();
+ }
+ }
+ assert(dstPtr == dstEnd);
+ }
+
+ void interleaveCoordinates(float* dst, const float* src, int count, int dstStride)
+ {
+ if (dstStride == 2)
+ {
+ memcpy(dst, src, sizeof(float) * count * 2);
+ }
+ else
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst += dstStride;
+ src += 2;
+ }
+ }
+
+ }
+
+ BlendFunc makeBlendFunc(int blendMode, bool premultipliedAlpha)
+ {
+ BlendFunc blendFunc;
+ switch (blendMode) {
+ case BlendMode_Additive:
+ blendFunc.src = premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ blendFunc.dst = GL_ONE;
+ break;
+ case BlendMode_Multiply:
+ blendFunc.src = GL_DST_COLOR;
+ blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case BlendMode_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;
+ break;
+ }
+ return blendFunc;
+ }
+
+
+ bool cullRectangle(const Mat4& transform, const cocos2d::Rect& rect, const Camera& camera)
+ {
+ // Compute rectangle center and half extents in local space
+ // TODO: Pass the bounding rectangle with this representation directly
+ const float halfRectWidth = rect.size.width * 0.5f;
+ const float halfRectHeight = rect.size.height * 0.5f;
+ const float l_cx = rect.origin.x + halfRectWidth;
+ const float l_cy = rect.origin.y + halfRectHeight;
+
+ // Transform rectangle center to world space
+ const float w_cx = (l_cx * transform.m[0] + l_cy * transform.m[4]) + transform.m[12];
+ const float w_cy = (l_cx * transform.m[1] + l_cy * transform.m[5]) + transform.m[13];
+
+ // Compute rectangle half extents in world space
+ const float w_ex = std::abs(halfRectWidth * transform.m[0]) + std::abs(halfRectHeight * transform.m[4]);
+ const float w_ey = std::abs(halfRectWidth * transform.m[1]) + std::abs(halfRectHeight * transform.m[5]);
+
+ // Transform rectangle to clip space
+ const Mat4& viewMatrix = camera.getViewMatrix();
+ const Mat4& projectionMatrix = camera.getProjectionMatrix();
+ const float c_cx = (w_cx + viewMatrix.m[12]) * projectionMatrix.m[0];
+ const float c_cy = (w_cy + viewMatrix.m[13]) * projectionMatrix.m[5];
+ const float c_ex = w_ex * projectionMatrix.m[0];
+ const float c_ey = w_ey * projectionMatrix.m[5];
+ // The rectangle has z == 0 in world space
+ // cw = projectionMatrix[11] * vz = -vz = wz -viewMatrix.m[14] = -viewMatrix.m[14]
+ const float c_w = -viewMatrix.m[14]; // w in clip space
+
+ // For each edge, test the rectangle corner closest to it
+ // If its distance to the edge is negative, the whole rectangle is outside the screen
+ // Note: the test is conservative and can return false positives in some cases
+ // The test is done in clip space [-1, +1]
+ // e.g. left culling <==> (c_cx + c_ex) / cw < -1 <==> (c_cx + c_ex) < -cw
+
+ // Left
+ if (c_cx + c_ex < -c_w)
+ {
+ return true;
+ }
+
+ // Right
+ if (c_cx - c_ex > c_w)
+ {
+ return true;
+ }
+
+ // Bottom
+ if (c_cy + c_ey < -c_w)
+ {
+ return true;
+ }
+
+ // Top
+ if (c_cy - c_ey > c_w)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ Color4B ColorToColor4B(const Color& color)
+ {
+ return { (GLubyte)(color.r * 255.f), (GLubyte)(color.g * 255.f), (GLubyte)(color.b * 255.f), (GLubyte)(color.a * 255.f) };
+ }
+ }
+
}
diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.h b/spine-cocos2dx/src/spine/SkeletonRenderer.h
index 3e9b21580..975cb1cdd 100644
--- a/spine-cocos2dx/src/spine/SkeletonRenderer.h
+++ b/spine-cocos2dx/src/spine/SkeletonRenderer.h
@@ -34,9 +34,9 @@
#include "cocos2d.h"
namespace spine {
-
+
class AttachmentVertices;
-
+
/* Draws a skeleton. */
class SkeletonRenderer: public cocos2d::Node, public cocos2d::BlendProtocol {
public:
@@ -45,48 +45,50 @@ namespace spine {
static SkeletonRenderer* createWithData (SkeletonData* skeletonData, bool ownsSkeletonData = false);
static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, Atlas* 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 drawDebug (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags);
- virtual cocos2d::Rect getBoundingBox () const override;
- virtual void onEnter () override;
- virtual void onExit () override;
-
- Skeleton* getSkeleton();
-
+
+ void update (float deltaTime) override;
+ void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override;
+ cocos2d::Rect getBoundingBox () const override;
+ void onEnter () override;
+ void onExit () override;
+
+ Skeleton* getSkeleton() const;
+
void setTimeScale(float scale);
float getTimeScale() const;
-
+
/* */
void setDebugSlotsEnabled(bool enabled);
bool getDebugSlotsEnabled() const;
-
+
void setDebugBonesEnabled(bool enabled);
bool getDebugBonesEnabled() const;
-
+
void setDebugMeshesEnabled(bool enabled);
bool getDebugMeshesEnabled() const;
-
+
+ void setDebugBoundingRectEnabled(bool enabled);
+ bool getDebugBoundingRectEnabled() const;
+
// --- Convenience methods for common Skeleton_* functions.
void updateWorldTransform ();
-
+
void setToSetupPose ();
void setBonesToSetupPose ();
void setSlotsToSetupPose ();
-
+
/* Returns 0 if the bone was not found. */
Bone* findBone (const std::string& boneName) const;
/* Returns 0 if the slot was not found. */
Slot* findSlot (const std::string& slotName) const;
-
+
/* Sets the skin used to look up attachments not found in the SkeletonData defaultSkin. Attachments from the new skin are
* attached if the corresponding attachment from the old skin was attached.
* @param skin May be empty string ("") for no skin.*/
void setSkin (const std::string& skinName);
/** @param skin May be 0 for no skin.*/
void setSkin (const char* skinName);
-
+
/* Returns 0 if the slot or attachment was not found. */
Attachment* getAttachment (const std::string& slotName, const std::string& attachmentName) const;
/* Returns false if the slot or attachment was not found.
@@ -94,52 +96,50 @@ namespace spine {
bool setAttachment (const std::string& slotName, const std::string& attachmentName);
/* @param attachmentName May be 0 for no attachment. */
bool setAttachment (const std::string& slotName, const char* attachmentName);
-
+
/* Enables/disables two color tinting for this instance. May break batching */
void setTwoColorTint(bool enabled);
/* Whether two color tinting is enabled */
bool isTwoColorTint();
-
+
/* Sets the vertex effect to be used, set to 0 to disable vertex effects */
void setVertexEffect(VertexEffect* effect);
-
+
/* Sets the range of slots that should be rendered. Use -1, -1 to clear the range */
void setSlotsRange(int startSlotIndex, int endSlotIndex);
-
+
// --- BlendProtocol
- virtual void setBlendFunc (const cocos2d::BlendFunc& blendFunc)override;
- 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();
-
+ void setBlendFunc (const cocos2d::BlendFunc& blendFunc)override;
+ const cocos2d::BlendFunc& getBlendFunc () const override;
+ void setOpacityModifyRGB (bool value) override;
+ bool isOpacityModifyRGB () const override;
+
CC_CONSTRUCTOR_ACCESS:
SkeletonRenderer ();
SkeletonRenderer(Skeleton* skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false, bool ownsAtlas = false);
SkeletonRenderer (SkeletonData* skeletonData, bool ownsSkeletonData = false);
SkeletonRenderer (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
-
+
virtual ~SkeletonRenderer ();
-
+
void initWithSkeleton(Skeleton* skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false, bool ownsAtlas = false);
void initWithData (SkeletonData* skeletonData, bool ownsSkeletonData = false);
void initWithJsonFile (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
void initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
void initWithBinaryFile (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
void initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
-
+
virtual void initialize ();
-
+
protected:
void setSkeletonData (SkeletonData* skeletonData, bool ownsSkeletonData);
void setupGLProgramState(bool twoColorTintEnabled);
-
+ virtual void drawDebug (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags);
+
bool _ownsSkeletonData;
bool _ownsSkeleton;
- bool _ownsAtlas;
+ bool _ownsAtlas = false;
Atlas* _atlas;
AttachmentLoader* _attachmentLoader;
cocos2d::CustomCommand _debugCommand;
@@ -150,13 +150,15 @@ namespace spine {
bool _debugSlots;
bool _debugBones;
bool _debugMeshes;
+ bool _debugBoundingRect;
SkeletonClipping* _clipper;
VertexEffect* _effect;
-
+ cocos2d::Rect _boundingRect;
+
int _startSlotIndex;
int _endSlotIndex;
};
-
+
}
#endif /* SPINE_SKELETONRENDERER_H_ */
diff --git a/spine-cocos2dx/src/spine/spine-cocos2dx.cpp b/spine-cocos2dx/src/spine/spine-cocos2dx.cpp
index 7bd2a9ebb..bcd18de2e 100644
--- a/spine-cocos2dx/src/spine/spine-cocos2dx.cpp
+++ b/spine-cocos2dx/src/spine/spine-cocos2dx.cpp
@@ -66,8 +66,6 @@ static void setAttachmentVertices(MeshAttachment* attachment) {
Cocos2dAtlasAttachmentLoader::Cocos2dAtlasAttachmentLoader(Atlas* atlas): AtlasAttachmentLoader(atlas) {
}
-Cocos2dAtlasAttachmentLoader::~Cocos2dAtlasAttachmentLoader() { }
-
void Cocos2dAtlasAttachmentLoader::configureAttachment(Attachment* attachment) {
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
setAttachmentVertices((RegionAttachment*)attachment);
@@ -102,34 +100,31 @@ GLuint filter (TextureFilter filter) {
return GL_LINEAR;
}
-Cocos2dTextureLoader::Cocos2dTextureLoader() : TextureLoader() { }
-Cocos2dTextureLoader::~Cocos2dTextureLoader() { }
-
void Cocos2dTextureLoader::load(AtlasPage& page, const spine::String& path) {
Texture2D* texture = Director::getInstance()->getTextureCache()->addImage(path.buffer());
CCASSERT(texture != nullptr, "Invalid image");
- texture->retain();
-
- Texture2D::TexParams textureParams = {filter(page.minFilter), filter(page.magFilter), wrap(page.uWrap), wrap(page.vWrap)};
- texture->setTexParameters(textureParams);
-
- page.setRendererObject(texture);
- page.width = texture->getPixelsWide();
- page.height = texture->getPixelsHigh();
+ if (texture)
+ {
+ texture->retain();
+ Texture2D::TexParams textureParams = { filter(page.minFilter), filter(page.magFilter), wrap(page.uWrap), wrap(page.vWrap) };
+ texture->setTexParameters(textureParams);
+ page.setRendererObject(texture);
+ page.width = texture->getPixelsWide();
+ page.height = texture->getPixelsHigh();
+ }
}
void Cocos2dTextureLoader::unload(void* texture) {
- ((Texture2D*)texture)->release();
+ if (texture)
+ {
+ ((Texture2D*)texture)->release();
+ }
}
-Cocos2dExtension::Cocos2dExtension() : DefaultSpineExtension() { }
-
-Cocos2dExtension::~Cocos2dExtension() { }
-
char *Cocos2dExtension::_readFile(const spine::String &path, int *length) {
Data data = FileUtils::getInstance()->getDataFromFile(FileUtils::getInstance()->fullPathForFilename(path.buffer()));
- if (data.isNull()) return 0;
+ if (data.isNull()) return nullptr;
// avoid buffer overflow (int is shorter than ssize_t in certain platforms)
#if COCOS2D_VERSION >= 0x00031200
diff --git a/spine-cocos2dx/src/spine/spine-cocos2dx.h b/spine-cocos2dx/src/spine/spine-cocos2dx.h
index 414cc5d53..08f23d0f7 100644
--- a/spine-cocos2dx/src/spine/spine-cocos2dx.h
+++ b/spine-cocos2dx/src/spine/spine-cocos2dx.h
@@ -41,15 +41,11 @@ namespace spine {
class Cocos2dAtlasAttachmentLoader: public AtlasAttachmentLoader {
public:
Cocos2dAtlasAttachmentLoader(Atlas* atlas);
- virtual ~Cocos2dAtlasAttachmentLoader();
virtual void configureAttachment(Attachment* attachment);
};
class Cocos2dTextureLoader: public TextureLoader {
public:
- Cocos2dTextureLoader();
-
- virtual ~Cocos2dTextureLoader();
virtual void load(AtlasPage& page, const String& path);
@@ -58,9 +54,6 @@ namespace spine {
class Cocos2dExtension: public DefaultSpineExtension {
public:
- Cocos2dExtension();
-
- virtual ~Cocos2dExtension();
protected:
virtual char *_readFile(const String &path, int *length);
diff --git a/spine-cpp/spine-cpp/include/spine/Atlas.h b/spine-cpp/spine-cpp/include/spine/Atlas.h
index fc6783346..9d0a35c95 100644
--- a/spine-cpp/spine-cpp/include/spine/Atlas.h
+++ b/spine-cpp/spine-cpp/include/spine/Atlas.h
@@ -67,6 +67,7 @@ enum TextureWrap {
class SP_API AtlasPage : public SpineObject, public HasRendererObject {
public:
String name;
+ String texturePath;
Format format;
TextureFilter minFilter;
TextureFilter magFilter;
@@ -76,10 +77,8 @@ public:
explicit AtlasPage(const String &inName) : name(inName), format(Format_RGBA8888), minFilter(TextureFilter_Nearest),
magFilter(TextureFilter_Nearest), uWrap(TextureWrap_ClampToEdge),
- vWrap(TextureWrap_ClampToEdge) {
+ vWrap(TextureWrap_ClampToEdge), width(0), height(0) {
}
-
- virtual ~AtlasPage() { }
};
class SP_API AtlasRegion : public SpineObject {
@@ -101,9 +100,9 @@ class TextureLoader;
class SP_API Atlas : public SpineObject {
public:
- Atlas(const String &path, TextureLoader *textureLoader);
+ Atlas(const String &path, TextureLoader *textureLoader, bool createTexture = true);
- Atlas(const char *data, int length, const char *dir, TextureLoader *textureLoader);
+ Atlas(const char *data, int length, const char *dir, TextureLoader *textureLoader, bool createTexture = true);
~Atlas();
@@ -121,7 +120,7 @@ private:
Vector _regions;
TextureLoader *_textureLoader;
- void load(const char *begin, int length, const char *dir);
+ void load(const char *begin, int length, const char *dir, bool createTexture);
class Str {
public:
diff --git a/spine-cpp/spine-cpp/src/spine/Atlas.cpp b/spine-cpp/spine-cpp/src/spine/Atlas.cpp
index c1b195125..1190670ae 100644
--- a/spine-cpp/spine-cpp/src/spine/Atlas.cpp
+++ b/spine-cpp/spine-cpp/src/spine/Atlas.cpp
@@ -39,7 +39,7 @@
using namespace spine;
-Atlas::Atlas(const String &path, TextureLoader *textureLoader) : _textureLoader(textureLoader) {
+Atlas::Atlas(const String &path, TextureLoader *textureLoader, bool createTexture) : _textureLoader(textureLoader) {
int dirLength;
char *dir;
int length;
@@ -57,16 +57,16 @@ Atlas::Atlas(const String &path, TextureLoader *textureLoader) : _textureLoader(
data = SpineExtension::readFile(path, &length);
if (data) {
- load(data, length, dir);
+ load(data, length, dir, createTexture);
}
SpineExtension::free(data, __FILE__, __LINE__);
SpineExtension::free(dir, __FILE__, __LINE__);
}
-Atlas::Atlas(const char *data, int length, const char *dir, TextureLoader *textureLoader) : _textureLoader(
+Atlas::Atlas(const char *data, int length, const char *dir, TextureLoader *textureLoader, bool createTexture) : _textureLoader(
textureLoader) {
- load(data, length, dir);
+ load(data, length, dir, createTexture);
}
Atlas::~Atlas() {
@@ -102,7 +102,7 @@ Vector &Atlas::getPages() {
return _pages;
}
-void Atlas::load(const char *begin, int length, const char *dir) {
+void Atlas::load(const char *begin, int length, const char *dir, bool createTexture) {
static const char *formatNames[] = {"", "Alpha", "Intensity", "LuminanceAlpha", "RGB565", "RGBA4444", "RGB888",
"RGBA8888"};
static const char *textureFilterNames[] = {"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest",
@@ -163,9 +163,15 @@ void Atlas::load(const char *begin, int length, const char *dir) {
}
}
- if (_textureLoader) _textureLoader->load(*page, String(path));
-
- SpineExtension::free(path, __FILE__, __LINE__);
+ if (createTexture)
+ {
+ if (_textureLoader) _textureLoader->load(*page, String(path));
+ SpineExtension::free(path, __FILE__, __LINE__);
+ }
+ else
+ {
+ page->texturePath = String(path, true);
+ }
_pages.add(page);
} else {