diff --git a/extensions/spine/SkeletonRenderer.cpp b/extensions/spine/SkeletonRenderer.cpp index 124260c829..292a16edca 100644 --- a/extensions/spine/SkeletonRenderer.cpp +++ b/extensions/spine/SkeletonRenderer.cpp @@ -34,1049 +34,1041 @@ USING_NS_CC; - namespace spine { - namespace { - Cocos2dTextureLoader textureLoader; +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(BlendMode blendMode, bool premultipliedAlpha); - void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex); - bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect); - Color4B ColorToColor4B(const Color& color); - bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex); - bool nothingToDraw(Slot& slot, int startSlotIndex, int endSlotIndex); - } + 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(BlendMode blendMode, bool premultipliedAlpha); + void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex); + bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect); + Color4B ColorToColor4B(const Color& color); + bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex); + bool nothingToDraw(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) +// 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) +#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(); + return node; +} - SkeletonRenderer* SkeletonRenderer::createWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData) { - SkeletonRenderer* node = new SkeletonRenderer(skeleton, ownsSkeleton, ownsSkeletonData); - node->autorelease(); - return node; - } +SkeletonRenderer* SkeletonRenderer::createWithData (SkeletonData* skeletonData, bool ownsSkeletonData) { + SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData); + node->autorelease(); + return node; +} - SkeletonRenderer* SkeletonRenderer::createWithData (SkeletonData* skeletonData, bool ownsSkeletonData) { - SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData); - 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, 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; +} - 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 () { + _clipper = new (__FILE__, __LINE__) SkeletonClipping(); - void SkeletonRenderer::initialize () { - _clipper = new (__FILE__, __LINE__) SkeletonClipping(); + _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; + setOpacityModifyRGB(true); - _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; - setOpacityModifyRGB(true); + setTwoColorTint(false); - setTwoColorTint(false); + _skeleton->setToSetupPose(); + _skeleton->updateWorldTransform(); +} - _skeleton->setToSetupPose(); - _skeleton->updateWorldTransform(); - } - - void SkeletonRenderer::setupGLProgramState (bool twoColorTintEnabled) { - if (twoColorTintEnabled) { +void SkeletonRenderer::setupGLProgramState (bool twoColorTintEnabled) { + if (twoColorTintEnabled) { #if COCOS2D_VERSION < 0x00040000 - setGLProgramState(SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState()); + setGLProgramState(SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState()); #endif - return; + return; + } + + Texture2D *texture = nullptr; + for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) { + Slot* slot = _skeleton->getDrawOrder()[i]; + 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; } - Texture2D *texture = nullptr; - for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) { - Slot* slot = _skeleton->getDrawOrder()[i]; - 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; - } + if (texture != nullptr) { + break; } + } #if COCOS2D_VERSION < 0x00040000 - setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture)); + setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture)); #endif +} + +void SkeletonRenderer::setSkeletonData (SkeletonData *skeletonData, bool ownsSkeletonData) { + _skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData); + _ownsSkeletonData = ownsSkeletonData; +} + +SkeletonRenderer::SkeletonRenderer () + : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { +} + +SkeletonRenderer::SkeletonRenderer(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) + : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { + initWithSkeleton(skeleton, ownsSkeleton, ownsSkeletonData, ownsAtlas); +} + +SkeletonRenderer::SkeletonRenderer (SkeletonData *skeletonData, bool ownsSkeletonData) + : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _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), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _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), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _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; + delete _clipper; +} + +void SkeletonRenderer::initWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) { + _skeleton = skeleton; + _ownsSkeleton = ownsSkeleton; + _ownsSkeletonData = ownsSkeletonData; + _ownsAtlas = ownsAtlas; + initialize(); +} + +void SkeletonRenderer::initWithData (SkeletonData* skeletonData, bool ownsSkeletonData) { + _ownsSkeleton = true; + 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(_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, true); + CCASSERT(_atlas, "Error reading atlas file."); + + _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); + + 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(_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, true); + CCASSERT(_atlas, "Error reading atlas file."); + + _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); + + 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) { + // Early exit if the skeleton is invisible. + if (getDisplayedOpacity() == 0 || _skeleton->getColor().a == 0) { + return; } - void SkeletonRenderer::setSkeletonData (SkeletonData *skeletonData, bool ownsSkeletonData) { - _skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData); - _ownsSkeletonData = ownsSkeletonData; + 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 cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2); + + if (cullRectangle(renderer, transform, bb)) { + 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); } - SkeletonRenderer::SkeletonRenderer () - : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { - } + 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; - SkeletonRenderer::SkeletonRenderer(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) - : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { - initWithSkeleton(skeleton, ownsSkeleton, ownsSkeletonData, ownsAtlas); - } + Color color; + Color darkColor; + const float darkPremultipliedAlpha = _premultipliedAlpha ? 1.f : 0; + AttachmentVertices* attachmentVertices = nullptr; + TwoColorTrianglesCommand* lastTwoColorTrianglesCommand = nullptr; + for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) { + Slot* slot = _skeleton->getDrawOrder()[i];; - SkeletonRenderer::SkeletonRenderer (SkeletonData *skeletonData, bool ownsSkeletonData) - : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _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), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _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), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _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; - delete _clipper; - } - - void SkeletonRenderer::initWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) { - _skeleton = skeleton; - _ownsSkeleton = ownsSkeleton; - _ownsSkeletonData = ownsSkeletonData; - _ownsAtlas = ownsAtlas; - initialize(); - } - - void SkeletonRenderer::initWithData (SkeletonData* skeletonData, bool ownsSkeletonData) { - _ownsSkeleton = true; - 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(_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, true); - CCASSERT(_atlas, "Error reading atlas file."); - - _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); - - 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(_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, true); - CCASSERT(_atlas, "Error reading atlas file."); - - _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); - - 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) { - // Early exit if the skeleton is invisible - if (getDisplayedOpacity() == 0 || _skeleton->getColor().a == 0) { - return; - } - - 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 cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2); - - if (cullRectangle(renderer, transform, bb)) { - 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; - for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) { - Slot* slot = _skeleton->getDrawOrder()[i];; - - if (nothingToDraw(*slot, _startSlotIndex, _endSlotIndex)) { - _clipper->clipEnd(*slot); - continue; - } - - cocos2d::TrianglesCommand::Triangles triangles; - TwoColorTriangles trianglesTwoColor; - - if (slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) { - RegionAttachment* attachment = static_cast(slot->getAttachment()); - attachmentVertices = static_cast(attachment->getRendererObject()); - - 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); - 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; - assert(trianglesTwoColor.vertCount == 4); - for (int v = 0; v < trianglesTwoColor.vertCount; v++) { - trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords; - } - dstTriangleVertices = reinterpret_cast(trianglesTwoColor.verts); - dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float); - } - // 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(); - - 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); - 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 v = 0; v < trianglesTwoColor.vertCount; v++) { - trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords; - } - dstTriangleVertices = (float*)trianglesTwoColor.verts; - dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float); - dstVertexCount = trianglesTwoColor.vertCount; - } - - // 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(); - _clipper->clipStart(*slot, clip); - continue; - } else { - _clipper->clipEnd(*slot); - continue; - } - - if (slot->hasDarkColor()) { - darkColor = slot->getDarkColor(); - } else { - darkColor.r = 0; - darkColor.g = 0; - darkColor.b = 0; - } - darkColor.a = darkPremultipliedAlpha; - - color.a *= nodeColor.a * _skeleton->getColor().a * slot->getColor().a; - // skip rendering if the color of this attachment is 0 - if (color.a == 0){ + if (nothingToDraw(*slot, _startSlotIndex, _endSlotIndex)) { _clipper->clipEnd(*slot); - continue; - } - 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; - } + continue; + } - const cocos2d::Color4B color4B = ColorToColor4B(color); - const cocos2d::Color4B darkColor4B = ColorToColor4B(darkColor); - const BlendFunc blendFunc = makeBlendFunc(slot->getData().getBlendMode(), attachmentVertices->_texture->hasPremultipliedAlpha()); - _blendFunc = blendFunc; + cocos2d::TrianglesCommand::Triangles triangles; + TwoColorTriangles trianglesTwoColor; + if (slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) { + RegionAttachment* attachment = static_cast(slot->getAttachment()); + attachmentVertices = static_cast(attachment->getRendererObject()); + + float* dstTriangleVertices = nullptr; + int dstStride = 0; // in floats 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); + 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); + 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; + assert(trianglesTwoColor.vertCount == 4); + for (int v = 0; v < trianglesTwoColor.vertCount; v++) { + trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords; + } + dstTriangleVertices = reinterpret_cast(trianglesTwoColor.verts); + dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float); + } + // Copy world vertices to triangle vertices. + interleaveCoordinates(dstTriangleVertices, worldCoordPtr, 4, dstStride); + worldCoordPtr += 8; - if (_clipper->getClippedTriangles().size() == 0){ - _clipper->clipEnd(*slot); - continue; - } + color = attachment->getColor(); + } + else if (slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) { + MeshAttachment* attachment = (MeshAttachment*)slot->getAttachment(); + attachmentVertices = (AttachmentVertices*)attachment->getRendererObject(); - triangles.vertCount = _clipper->getClippedVertices().size() / 2; - triangles.verts = batch->allocateVertices(triangles.vertCount); - triangles.indexCount = _clipper->getClippedTriangles().size(); - triangles.indices = - batch->allocateIndices(triangles.indexCount); - memcpy(triangles.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size()); + 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); + 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 v = 0; v < trianglesTwoColor.vertCount; v++) { + trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords; + } + dstTriangleVertices = (float*)trianglesTwoColor.verts; + dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float); + dstVertexCount = trianglesTwoColor.vertCount; + } + + // 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(); + _clipper->clipStart(*slot, clip); + continue; + } else { + _clipper->clipEnd(*slot); + continue; + } + + if (slot->hasDarkColor()) { + darkColor = slot->getDarkColor(); + } else { + darkColor.r = 0; + darkColor.g = 0; + darkColor.b = 0; + } + darkColor.a = darkPremultipliedAlpha; + + color.a *= nodeColor.a * _skeleton->getColor().a * slot->getColor().a; + if (color.a == 0) { + _clipper->clipEnd(*slot); + continue; + } + 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(), attachmentVertices->_texture->hasPremultipliedAlpha()); + _blendFunc = blendFunc; + + 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() / 2; + triangles.verts = batch->allocateVertices(triangles.vertCount); + triangles.indexCount = _clipper->getClippedTriangles().size(); + triangles.indices = + batch->allocateIndices(triangles.indexCount); + memcpy(triangles.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size()); #if COCOS2D_VERSION < 0x00040000 - cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); + cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); #else - cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags); + cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _programState, blendFunc, triangles, transform, transformFlags); #endif - const float* verts = _clipper->getClippedVertices().buffer(); - const float* uvs = _clipper->getClippedUVs().buffer(); - if (_effect) { - 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, darkTmp); - vertex->colors = ColorToColor4B(lightCopy); - } - } else { - 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 = color4B; - } + const float* verts = _clipper->getClippedVertices().buffer(); + const float* uvs = _clipper->getClippedUVs().buffer(); + if (_effect) { + 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, darkTmp); + vertex->colors = ColorToColor4B(lightCopy); } } else { - // Not clipping -#if COCOS2D_VERSION < 0x00040000 - cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); -#else - cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags); -#endif - - if (_effect) { - 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 { - V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; - for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { - vertex->colors = color4B; - } + 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 = 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() / 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()); - + // Not clipping. #if COCOS2D_VERSION < 0x00040000 - TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags); + cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); #else - TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags); + cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _programState, blendFunc, triangles, transform, transformFlags); #endif - const float* verts = _clipper->getClippedVertices().buffer(); - const float* uvs = _clipper->getClippedUVs().buffer(); - - if (_effect) { - 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 = ColorToColor4B(lightCopy); - vertex->color2 = ColorToColor4B(darkCopy); - } - } else { - 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 = color4B; - vertex->color2 = darkColor4B; - } + if (_effect) { + 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 { - -#if COCOS2D_VERSION < 0x00040000 - TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags); -#else - TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags); -#endif - - if (_effect) { - 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 = ColorToColor4B(lightCopy); - vertex->color2 = ColorToColor4B(darkCopy); - } - } else { - 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; - } + V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { + vertex->colors = color4B; + } + } + } + } else { + // Two color tinting. + + 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() / 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()); + +#if COCOS2D_VERSION < 0x00040000 + TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags); +#else + TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _programState, blendFunc, trianglesTwoColor, transform, transformFlags); +#endif + + const float* verts = _clipper->getClippedVertices().buffer(); + const float* uvs = _clipper->getClippedUVs().buffer(); + + if (_effect) { + 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 = ColorToColor4B(lightCopy); + vertex->color2 = ColorToColor4B(darkCopy); + } + } else { + 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 = color4B; + vertex->color2 = darkColor4B; + } + } + } else { + +#if COCOS2D_VERSION < 0x00040000 + TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags); +#else + TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _programState, blendFunc, trianglesTwoColor, transform, transformFlags); +#endif + + if (_effect) { + 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 = ColorToColor4B(lightCopy); + vertex->color2 = ColorToColor4B(darkCopy); + } + } else { + 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(); + _clipper->clipEnd(*slot); + } + _clipper->clipEnd(); - if (lastTwoColorTrianglesCommand) { - Node* parent = this->getParent(); + 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. - // The parent->getChildrenCount() > 100 check is a hack - // as checking for a sibling is an O(n) operation, and if - // all children of this nodes parent are skeletons, we - // are in O(n2) territory. - if (!parent || parent->getChildrenCount() > 100 || getChildrenCount() != 0) { + // 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. + // The parent->getChildrenCount() > 100 check is a hack as checking for a sibling is an O(n) operation, and if all children + // of this nodes parent are skeletons, we are in O(n2) territory. + if (!parent || parent->getChildrenCount() > 100 || getChildrenCount() != 0) { + lastTwoColorTrianglesCommand->setForceFlush(true); + } else { + const cocos2d::Vector& children = parent->getChildren(); + Node* sibling = nullptr; + for (ssize_t i = 0; i < children.size(); i++) { + if (children.at(i) == this) { + if (i < children.size() - 1) { + sibling = children.at(i+1); + break; + } + } + } + if (!sibling) { lastTwoColorTrianglesCommand->setForceFlush(true); } else { - const cocos2d::Vector& children = parent->getChildren(); - Node* sibling = nullptr; - for (ssize_t i = 0; i < children.size(); i++) { - if (children.at(i) == this) { - if (i < children.size() - 1) { - sibling = children.at(i+1); - break; - } - } - } - if (!sibling) { + SkeletonRenderer* siblingSkeleton = dynamic_cast(sibling); + if (!siblingSkeleton || // flush is next sibling isn't a SkeletonRenderer + !siblingSkeleton->isTwoColorTint() || // flush if next sibling isn't two color tinted + !siblingSkeleton->isVisible() || // flush if next sibling is two color tinted but not visible + (siblingSkeleton->getGlobalZOrder() != this->getGlobalZOrder())) { // flush if next sibling is two color tinted but z-order differs lastTwoColorTrianglesCommand->setForceFlush(true); - } else { - SkeletonRenderer* siblingSkeleton = dynamic_cast(sibling); - if (!siblingSkeleton || // flush is next sibling isn't a SkeletonRenderer - !siblingSkeleton->isTwoColorTint() || // flush if next sibling isn't two color tinted - !siblingSkeleton->isVisible() || // flush if next sibling is two color tinted but not visible - (siblingSkeleton->getGlobalZOrder() != this->getGlobalZOrder())) { // flush if next sibling is two color tinted but z-order differs - lastTwoColorTrianglesCommand->setForceFlush(true); - } } } } - - if (_effect) _effect->end(); - - if (_debugBoundingRect || _debugSlots || _debugBones || _debugMeshes) { - drawDebug(renderer, transform, transformFlags); - } - - VLA_FREE(worldCoords); } + if (_effect) _effect->end(); - void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uint32_t transformFlags) { + 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); + 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(); - drawNode->setGlobalZOrder(getGlobalZOrder()); + DrawNode* drawNode = DrawNode::create(); + drawNode->setGlobalZOrder(getGlobalZOrder()); - // Draw bounding rectangle - if (_debugBoundingRect) { + // Draw bounding rectangle + if (_debugBoundingRect) { #if COCOS2D_VERSION < 0x00040000 - glLineWidth(2); + glLineWidth(2); #else - drawNode->setLineWidth(2.0f); + drawNode->setLineWidth(2.0f); #endif - const cocos2d::Rect brect = getBoundingBox(); + 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); +#if COCOS2D_VERSION < 0x00040000 + glLineWidth(2); +#else + drawNode->setLineWidth(2.0f); +#endif + 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); 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 } + { worldVertices[0], worldVertices[1] }, + { worldVertices[2], worldVertices[3] }, + { worldVertices[4], worldVertices[5] }, + { worldVertices[6], worldVertices[7] } }; - drawNode->drawPoly(points, 4, true, Color4F::GREEN); + drawNode->drawPoly(points, 4, true, Color4F::BLUE); } + } - if (_debugSlots) { - // Slots. - // DrawPrimitives::setDrawColor4B(0, 0, 255, 255); + if (_debugBones) { + // Bone lengths. #if COCOS2D_VERSION < 0x00040000 - glLineWidth(2); + glLineWidth(2); #else - drawNode->setLineWidth(2.0f); + drawNode->setLineWidth(2.0f); #endif - V3F_C4B_T2F_Quad quad; - for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) { - Slot* slot = _skeleton->getDrawOrder()[i]; + for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) { + Bone *bone = _skeleton->getBones()[i]; + if (!bone->isActive()) continue; + float x = bone->getData().getLength() * bone->getA() + bone->getWorldX(); + float y = bone->getData().getLength() * bone->getC() + bone->getWorldY(); + drawNode->drawLine(Vec2(bone->getWorldX(), bone->getWorldY()), Vec2(x, y), Color4F::RED); + } + // Bone origins. + auto color = Color4F::BLUE; // Root bone is blue. + for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) { + Bone *bone = _skeleton->getBones()[i]; + if (!bone->isActive()) continue; + drawNode->drawPoint(Vec2(bone->getWorldX(), bone->getWorldY()), 4, color); + if (i == 0) color = Color4F::GREEN; + } + } - 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); - const Vec2 points[4] = + if (_debugMeshes) { + // Meshes. +#if COCOS2D_VERSION < 0x00040000 + glLineWidth(2); +#else + drawNode->setLineWidth(2.0f); +#endif + 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(MeshAttachment::rtti)) continue; + 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] = { - { worldVertices[0], worldVertices[1] }, - { worldVertices[2], worldVertices[3] }, - { worldVertices[4], worldVertices[5] }, - { worldVertices[6], worldVertices[7] } + worldCoord + (idx0 * 2), + worldCoord + (idx1 * 2), + worldCoord + (idx2 * 2) }; - drawNode->drawPoly(points, 4, true, Color4F::BLUE); + drawNode->drawPoly(v, 3, true, Color4F::YELLOW); } + VLA_FREE(worldCoord); } + } - if (_debugBones) { - // Bone lengths. -#if COCOS2D_VERSION < 0x00040000 - glLineWidth(2); -#else - drawNode->setLineWidth(2.0f); -#endif - for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) { - Bone *bone = _skeleton->getBones()[i]; - if (!bone->isActive()) continue; - float x = bone->getData().getLength() * bone->getA() + bone->getWorldX(); - float y = bone->getData().getLength() * bone->getC() + bone->getWorldY(); - drawNode->drawLine(Vec2(bone->getWorldX(), bone->getWorldY()), Vec2(x, y), Color4F::RED); - } - // Bone origins. - auto color = Color4F::BLUE; // Root bone is blue. - for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) { - Bone *bone = _skeleton->getBones()[i]; - if (!bone->isActive()) continue; - drawNode->drawPoint(Vec2(bone->getWorldX(), bone->getWorldY()), 4, color); - if (i == 0) color = Color4F::GREEN; - } - } - - if (_debugMeshes) { - // Meshes. -#if COCOS2D_VERSION < 0x00040000 - glLineWidth(2); -#else - drawNode->setLineWidth(2.0f); -#endif - 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(MeshAttachment::rtti)) continue; - 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); + drawNode->draw(renderer, transform, transformFlags); #if !defined(USE_MATRIX_STACK_PROJECTION_ONLY) - director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); + director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); #endif - } +} - cocos2d::Rect SkeletonRenderer::getBoundingBox () const { - const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex); - if (coordCount == 0) return { 0, 0, 0, 0 }; - VLA(float, worldCoords, coordCount); - transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex); - const cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2); - VLA_FREE(worldCoords); - return bb; - } +cocos2d::Rect SkeletonRenderer::getBoundingBox () const { + const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex); + if (coordCount == 0) return { 0, 0, 0, 0 }; + VLA(float, worldCoords, coordCount); + transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex); + const cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2); + VLA_FREE(worldCoords); + return bb; +} - // --- Convenience methods for Skeleton_* functions. +// --- Convenience methods for Skeleton_* functions. - void SkeletonRenderer::updateWorldTransform() { - _skeleton->updateWorldTransform(); - } +void SkeletonRenderer::updateWorldTransform() { + _skeleton->updateWorldTransform(); +} - void SkeletonRenderer::setToSetupPose () { - _skeleton->setToSetupPose(); - } - void SkeletonRenderer::setBonesToSetupPose () { - _skeleton->setBonesToSetupPose(); - } - void SkeletonRenderer::setSlotsToSetupPose () { - _skeleton->setSlotsToSetupPose(); - } +void SkeletonRenderer::setToSetupPose () { + _skeleton->setToSetupPose(); +} +void SkeletonRenderer::setBonesToSetupPose () { + _skeleton->setBonesToSetupPose(); +} +void SkeletonRenderer::setSlotsToSetupPose () { + _skeleton->setSlotsToSetupPose(); +} - Bone* SkeletonRenderer::findBone (const std::string& boneName) const { - return _skeleton->findBone(boneName.c_str()); - } +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()); - } +Slot* SkeletonRenderer::findSlot (const std::string& slotName) const { + 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); - } +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()); - } - bool SkeletonRenderer::setAttachment (const std::string& slotName, const std::string& attachmentName) { - bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()) ? true : false; - _skeleton->setAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()); - return result; - } - bool SkeletonRenderer::setAttachment (const std::string& slotName, const char* attachmentName) { - bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName) ? true : false; - _skeleton->setAttachment(slotName.c_str(), attachmentName); - return result; - } +Attachment* SkeletonRenderer::getAttachment (const std::string& slotName, const std::string& attachmentName) const { + return _skeleton->getAttachment(slotName.c_str(), attachmentName.c_str()); +} +bool SkeletonRenderer::setAttachment (const std::string& slotName, const std::string& attachmentName) { + bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()) ? true : false; + _skeleton->setAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()); + return result; +} +bool SkeletonRenderer::setAttachment (const std::string& slotName, const char* attachmentName) { + bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName) ? true : false; + _skeleton->setAttachment(slotName.c_str(), attachmentName); + return result; +} - void SkeletonRenderer::setTwoColorTint(bool enabled) { +void SkeletonRenderer::setTwoColorTint(bool enabled) { #if COCOS2D_VERSION >= 0x00040000 - _twoColorTint = enabled; + _twoColorTint = enabled; #endif - setupGLProgramState(enabled); - } + setupGLProgramState(enabled); +} - bool SkeletonRenderer::isTwoColorTint() { +bool SkeletonRenderer::isTwoColorTint() { #if COCOS2D_VERSION < 0x00040000 - return getGLProgramState() == SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState(); + return getGLProgramState() == SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState(); #else - return _twoColorTint; + return _twoColorTint; #endif - } +} - void SkeletonRenderer::setVertexEffect(VertexEffect *effect) { - this->_effect = effect; - } +void SkeletonRenderer::setVertexEffect(VertexEffect *effect) { + this->_effect = effect; +} - void SkeletonRenderer::setSlotsRange(int startSlotIndex, int endSlotIndex) { - _startSlotIndex = startSlotIndex == -1 ? 0 : startSlotIndex; - _endSlotIndex = endSlotIndex == -1 ? std::numeric_limits::max() : endSlotIndex; - } +void SkeletonRenderer::setSlotsRange(int startSlotIndex, int endSlotIndex) { + _startSlotIndex = startSlotIndex == -1 ? 0 : startSlotIndex; + _endSlotIndex = endSlotIndex == -1 ? std::numeric_limits::max() : endSlotIndex; +} - Skeleton* SkeletonRenderer::getSkeleton () const { - return _skeleton; - } +Skeleton* SkeletonRenderer::getSkeleton () const { + return _skeleton; +} - void SkeletonRenderer::setTimeScale (float scale) { - _timeScale = scale; - } - float SkeletonRenderer::getTimeScale () const { - return _timeScale; - } +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::setDebugSlotsEnabled (bool enabled) { + _debugSlots = enabled; +} +bool SkeletonRenderer::getDebugSlotsEnabled () const { + return _debugSlots; +} - void SkeletonRenderer::setDebugBonesEnabled (bool enabled) { - _debugBones = enabled; - } - bool SkeletonRenderer::getDebugBonesEnabled () const { - return _debugBones; - } +void SkeletonRenderer::setDebugBonesEnabled (bool enabled) { + _debugBones = enabled; +} +bool SkeletonRenderer::getDebugBonesEnabled () const { + return _debugBones; +} - void SkeletonRenderer::setDebugMeshesEnabled (bool enabled) { - _debugMeshes = enabled; - } - bool SkeletonRenderer::getDebugMeshesEnabled () const { - return _debugMeshes; - } +void SkeletonRenderer::setDebugMeshesEnabled (bool enabled) { + _debugMeshes = enabled; +} +bool SkeletonRenderer::getDebugMeshesEnabled () const { + return _debugMeshes; +} - void SkeletonRenderer::setDebugBoundingRectEnabled(bool enabled) { - _debugBoundingRect = enabled; - } +void SkeletonRenderer::setDebugBoundingRectEnabled(bool enabled) { + _debugBoundingRect = enabled; +} - bool SkeletonRenderer::getDebugBoundingRectEnabled() const { - return _debugBoundingRect; - } +bool SkeletonRenderer::getDebugBoundingRectEnabled() const { + return _debugBoundingRect; +} - void SkeletonRenderer::onEnter () { +void SkeletonRenderer::onEnter () { #if CC_ENABLE_SCRIPT_BINDING && COCOS2D_VERSION < 0x00040000 - if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter)) return; + if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter)) return; #endif - Node::onEnter(); - scheduleUpdate(); - } + Node::onEnter(); + scheduleUpdate(); +} - void SkeletonRenderer::onExit () { +void SkeletonRenderer::onExit () { #if CC_ENABLE_SCRIPT_BINDING && COCOS2D_VERSION < 0x00040000 - if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit)) return; + if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit)) return; #endif - Node::onExit(); - unscheduleUpdate(); - } + Node::onExit(); + unscheduleUpdate(); +} - // --- CCBlendProtocol +// --- CCBlendProtocol - const BlendFunc& SkeletonRenderer::getBlendFunc () const { - return _blendFunc; - } +const BlendFunc& SkeletonRenderer::getBlendFunc () const { + return _blendFunc; +} - void SkeletonRenderer::setBlendFunc (const BlendFunc &blendFunc) { - _blendFunc = blendFunc; - } +void SkeletonRenderer::setBlendFunc (const BlendFunc &blendFunc) { + _blendFunc = blendFunc; +} - void SkeletonRenderer::setOpacityModifyRGB (bool value) { - _premultipliedAlpha = value; - } +void SkeletonRenderer::setOpacityModifyRGB (bool value) { + _premultipliedAlpha = value; +} - bool SkeletonRenderer::isOpacityModifyRGB () const { - return _premultipliedAlpha; - } +bool SkeletonRenderer::isOpacityModifyRGB () const { + return _premultipliedAlpha; +} - namespace { - cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount) { - assert(coords); - assert(vertexCount > 0); +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 }; + 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; - } + bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex) { + const int index = slot.getData().getIndex(); + return startSlotIndex > index || endSlotIndex < index; + } - bool nothingToDraw(Slot& slot, int startSlotIndex, int endSlotIndex) { - Attachment *attachment = slot.getAttachment(); - if (!attachment || - slotIsOutRange(slot, startSlotIndex, endSlotIndex) || - !slot.getBone().isActive() || - slot.getColor().a == 0) + bool nothingToDraw(Slot& slot, int startSlotIndex, int endSlotIndex) { + Attachment *attachment = slot.getAttachment(); + if (!attachment || + slotIsOutRange(slot, startSlotIndex, endSlotIndex) || + !slot.getBone().isActive() || + slot.getColor().a == 0) + return true; + if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { + if (static_cast(attachment)->getColor().a == 0) return true; + } + else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { + if (static_cast(attachment)->getColor().a == 0) + return true; + } + return false; + } + + 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]; + if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) { + continue; + } + Attachment* const attachment = slot.getAttachment(); if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { - if (static_cast(attachment)->getColor().a == 0) - return true; + coordCount += 8; } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { - if (static_cast(attachment)->getColor().a == 0) - return true; + MeshAttachment* const mesh = static_cast(attachment); + coordCount += mesh->getWorldVerticesLength(); } - return false; - } - - 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]; - if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) { - continue; - } - Attachment* const attachment = slot.getAttachment(); - 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 - if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) { - continue; - } - Attachment* const attachment = slot.getAttachment(); - 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(BlendMode blendMode, bool premultipliedAlpha) { - BlendFunc blendFunc; - -#if COCOS2D_VERSION < 0x00040000 - 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; - } -#else - switch (blendMode) { - case BlendMode_Additive: - blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA; - blendFunc.dst = backend::BlendFactor::ONE; - break; - case BlendMode_Multiply: - blendFunc.src = backend::BlendFactor::DST_COLOR; - blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - break; - case BlendMode_Screen: - blendFunc.src = backend::BlendFactor::ONE; - blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_COLOR; - break; - default: - blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA; - blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - } -#endif - return blendFunc; - } - - - bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect) { - if (Camera::getVisitingCamera() == nullptr) - return false; - - auto director = Director::getInstance(); - auto scene = director->getRunningScene(); - - if (!scene || (scene && Camera::getDefaultCamera() != Camera::getVisitingCamera())) - return false; - - Rect visibleRect(director->getVisibleOrigin(), director->getVisibleSize()); - - // transform center point to screen space - float hSizeX = rect.size.width/2; - float hSizeY = rect.size.height/2; - Vec3 v3p(rect.origin.x + hSizeX, rect.origin.y + hSizeY, 0); - transform.transformPoint(&v3p); - Vec2 v2p = Camera::getVisitingCamera()->projectGL(v3p); - - // convert content size to world coordinates - float wshw = std::max(fabsf(hSizeX * transform.m[0] + hSizeY * transform.m[4]), fabsf(hSizeX * transform.m[0] - hSizeY * transform.m[4])); - float wshh = std::max(fabsf(hSizeX * transform.m[1] + hSizeY * transform.m[5]), fabsf(hSizeX * transform.m[1] - hSizeY * transform.m[5])); - - // enlarge visible rect half size in screen coord - visibleRect.origin.x -= wshw; - visibleRect.origin.y -= wshh; - visibleRect.size.width += wshw * 2; - visibleRect.size.height += wshh * 2; - return !visibleRect.containsPoint(v2p); - } - - - Color4B ColorToColor4B(const Color& color) { - return { (uint8_t)(color.r * 255.f), (uint8_t)(color.g * 255.f), (uint8_t)(color.b * 255.f), (uint8_t)(color.a * 255.f) }; } + 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 + if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) { + continue; + } + Attachment* const attachment = slot.getAttachment(); + 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(BlendMode blendMode, bool premultipliedAlpha) { + BlendFunc blendFunc; + +#if COCOS2D_VERSION < 0x00040000 + 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; + } +#else + switch (blendMode) { + case BlendMode_Additive: + blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA; + blendFunc.dst = backend::BlendFactor::ONE; + break; + case BlendMode_Multiply: + blendFunc.src = backend::BlendFactor::DST_COLOR; + blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + break; + case BlendMode_Screen: + blendFunc.src = backend::BlendFactor::ONE; + blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_COLOR; + break; + default: + blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA; + blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + } +#endif + return blendFunc; + } + + + bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect) { + if (Camera::getVisitingCamera() == nullptr) + return false; + + auto director = Director::getInstance(); + auto scene = director->getRunningScene(); + + if (!scene || (scene && Camera::getDefaultCamera() != Camera::getVisitingCamera())) + return false; + + Rect visibleRect(director->getVisibleOrigin(), director->getVisibleSize()); + + // transform center point to screen space + float hSizeX = rect.size.width/2; + float hSizeY = rect.size.height/2; + Vec3 v3p(rect.origin.x + hSizeX, rect.origin.y + hSizeY, 0); + transform.transformPoint(&v3p); + Vec2 v2p = Camera::getVisitingCamera()->projectGL(v3p); + + // convert content size to world coordinates + float wshw = std::max(fabsf(hSizeX * transform.m[0] + hSizeY * transform.m[4]), fabsf(hSizeX * transform.m[0] - hSizeY * transform.m[4])); + float wshh = std::max(fabsf(hSizeX * transform.m[1] + hSizeY * transform.m[5]), fabsf(hSizeX * transform.m[1] - hSizeY * transform.m[5])); + + // enlarge visible rect half size in screen coord + visibleRect.origin.x -= wshw; + visibleRect.origin.y -= wshh; + visibleRect.size.width += wshw * 2; + visibleRect.size.height += wshh * 2; + return !visibleRect.containsPoint(v2p); + } + + + Color4B ColorToColor4B(const Color& color) { + return { (uint8_t)(color.r * 255.f), (uint8_t)(color.g * 255.f), (uint8_t)(color.b * 255.f), (uint8_t)(color.a * 255.f) }; + } +} + } diff --git a/extensions/spine/spine-cocos2dx.cpp b/extensions/spine/spine-cocos2dx.cpp index 2457c528a3..2e8989ae5e 100644 --- a/extensions/spine/spine-cocos2dx.cpp +++ b/extensions/spine/spine-cocos2dx.cpp @@ -167,7 +167,7 @@ Cocos2dExtension::Cocos2dExtension() : DefaultSpineExtension() { } Cocos2dExtension::~Cocos2dExtension() { } char *Cocos2dExtension::_readFile(const spine::String &path, int *length) { - Data data = FileUtils::getInstance()->getDataFromFile(path.buffer()); + Data data = FileUtils::getInstance()->getDataFromFile(path.buffer()); if (data.isNull()) return nullptr; // avoid buffer overflow (int is shorter than ssize_t in certain platforms) @@ -178,7 +178,7 @@ char *Cocos2dExtension::_readFile(const spine::String &path, int *length) { return ret; #else *length = static_cast(data.getSize()); - char* bytes = MALLOC(char, *length); + auto bytes = SpineExtension::alloc(*length, __FILE__, __LINE__); memcpy(bytes, data.getBytes(), *length); return bytes; #endif diff --git a/extensions/spine/v4/SkeletonBatch.cpp b/extensions/spine/v4/SkeletonBatch.cpp index 2cdf7f017c..62e39c1921 100644 --- a/extensions/spine/v4/SkeletonBatch.cpp +++ b/extensions/spine/v4/SkeletonBatch.cpp @@ -60,22 +60,8 @@ void SkeletonBatch::destroyInstance () { SkeletonBatch::SkeletonBatch () { auto program = backend::Program::getBuiltinProgram(backend::ProgramType::POSITION_TEXTURE_COLOR); - _programState = std::make_shared(program); - - auto vertexLayout = _programState->getVertexLayout(); - - auto locPosition = _programState->getAttributeLocation("a_position"); - auto locTexcoord = _programState->getAttributeLocation("a_texCoord"); - auto locColor = _programState->getAttributeLocation("a_color"); - vertexLayout->setAttribute("a_position", locPosition, backend::VertexFormat::FLOAT3, offsetof(V3F_C4B_T2F, vertices), false); - vertexLayout->setAttribute("a_color", locColor, backend::VertexFormat::UBYTE4, offsetof(V3F_C4B_T2F, colors), true); - vertexLayout->setAttribute("a_texCoord", locTexcoord, backend::VertexFormat::FLOAT2, offsetof(V3F_C4B_T2F, texCoords), false); - vertexLayout->setLayout(sizeof(_vertices[0])); - - - _locMVP = _programState->getUniformLocation("u_MVPMatrix"); - _locTexture = _programState->getUniformLocation("u_texture"); - + _programState = new backend::ProgramState(program); // new default program state + updateProgramStateLayout(_programState); for (unsigned int i = 0; i < INITIAL_SIZE; i++) { _commandsPool.push_back(createNewTrianglesCommand()); } @@ -95,6 +81,25 @@ SkeletonBatch::~SkeletonBatch () { delete _commandsPool[i]; _commandsPool[i] = nullptr; } + + CC_SAFE_RELEASE(_programState); +} + +void SkeletonBatch::updateProgramStateLayout(cocos2d::backend::ProgramState* programState) +{ + auto vertexLayout = programState->getVertexLayout(); + + auto locPosition = programState->getAttributeLocation("a_position"); + auto locTexcoord = programState->getAttributeLocation("a_texCoord"); + auto locColor = programState->getAttributeLocation("a_color"); + vertexLayout->setAttribute("a_position", locPosition, backend::VertexFormat::FLOAT3, offsetof(V3F_C4B_T2F, vertices), false); + vertexLayout->setAttribute("a_color", locColor, backend::VertexFormat::UBYTE4, offsetof(V3F_C4B_T2F, colors), true); + vertexLayout->setAttribute("a_texCoord", locTexcoord, backend::VertexFormat::FLOAT2, offsetof(V3F_C4B_T2F, texCoords), false); + vertexLayout->setLayout(sizeof(_vertices[0])); + + + _locMVP = programState->getUniformLocation("u_MVPMatrix"); + _locTexture = programState->getUniformLocation("u_texture"); } void SkeletonBatch::update (float delta) { @@ -148,15 +153,27 @@ void SkeletonBatch::deallocateIndices(uint32_t numIndices) { } -cocos2d::TrianglesCommand* SkeletonBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) { +cocos2d::TrianglesCommand* SkeletonBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, backend::ProgramState* programState, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) { TrianglesCommand* command = nextFreeCommand(); const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); - auto programState = command->getPipelineDescriptor().programState; - CCASSERT(programState, "programState should not be null"); + if (programState == nullptr) + programState = _programState; - programState->setUniform(_locMVP, projectionMat.m, sizeof(projectionMat.m)); - programState->setTexture(_locTexture, 0, texture->getBackendTexture()); + CCASSERT(programState, "programState should not be null"); + + auto& pipelinePS = command->getPipelineDescriptor().programState; + if (pipelinePS != programState) + { + CC_SAFE_RELEASE(pipelinePS); + pipelinePS = programState; + CC_SAFE_RETAIN(pipelinePS); + + updateProgramStateLayout(pipelinePS); + } + + pipelinePS->setUniform(_locMVP, projectionMat.m, sizeof(projectionMat.m)); + pipelinePS->setTexture(_locTexture, 0, texture->getBackendTexture()); command->init(globalOrder, texture, blendType, triangles, mv, flags); renderer->addCommand(command); @@ -177,12 +194,6 @@ cocos2d::TrianglesCommand* SkeletonBatch::nextFreeCommand() { } } auto* command = _commandsPool[_nextFreeCommand++]; - auto& pipelineDescriptor = command->getPipelineDescriptor(); - if (pipelineDescriptor.programState == nullptr) - { - CCASSERT(_programState, "programState should not be null"); - pipelineDescriptor.programState = _programState->clone(); - } return command; } diff --git a/extensions/spine/v4/SkeletonBatch.h b/extensions/spine/v4/SkeletonBatch.h index eac346fc54..107c1a4a43 100644 --- a/extensions/spine/v4/SkeletonBatch.h +++ b/extensions/spine/v4/SkeletonBatch.h @@ -35,6 +35,7 @@ #include #include +#include "renderer/backend/ProgramState.h" namespace spine { @@ -50,8 +51,10 @@ namespace spine { void deallocateVertices(uint32_t numVertices); unsigned short* allocateIndices(uint32_t numIndices); void deallocateIndices(uint32_t numVertices); - cocos2d::TrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); + cocos2d::TrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::backend::ProgramState* programState, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); + void updateProgramStateLayout(cocos2d::backend::ProgramState* programState); + protected: SkeletonBatch (); virtual ~SkeletonBatch (); @@ -61,7 +64,9 @@ namespace spine { cocos2d::TrianglesCommand* nextFreeCommand (); cocos2d::TrianglesCommand* createNewTrianglesCommand(); - std::shared_ptr _programState = nullptr; + + // the default program state for batch draw + cocos2d::backend::ProgramState* _programState = nullptr; cocos2d::backend::UniformLocation _locMVP; cocos2d::backend::UniformLocation _locTexture; diff --git a/extensions/spine/v4/SkeletonTwoColorBatch.cpp b/extensions/spine/v4/SkeletonTwoColorBatch.cpp index 9dde0ccbc9..7802740130 100644 --- a/extensions/spine/v4/SkeletonTwoColorBatch.cpp +++ b/extensions/spine/v4/SkeletonTwoColorBatch.cpp @@ -99,16 +99,7 @@ namespace { backend::UniformLocation __locPMatrix; backend::UniformLocation __locTexture; - void initTwoColorProgramState() - { - if (__twoColorProgramState) - { - return; - } - auto program = backend::Device::getInstance()->newProgram(TWO_COLOR_TINT_VERTEX_SHADER, TWO_COLOR_TINT_FRAGMENT_SHADER); - auto* programState = new backend::ProgramState(program); - program->autorelease(); - + static void updateProgramStateLayout(backend::ProgramState* programState) { __locPMatrix = programState->getUniformLocation("u_PMatrix"); __locTexture = programState->getUniformLocation("u_texture"); @@ -124,6 +115,19 @@ namespace { layout->setAttribute("a_color2", locColor2, backend::VertexFormat::UBYTE4, offsetof(spine::V3F_C4B_C4B_T2F, color2), true); layout->setAttribute("a_texCoords", locTexcoord, backend::VertexFormat::FLOAT2, offsetof(spine::V3F_C4B_C4B_T2F, texCoords), false); layout->setLayout(sizeof(spine::V3F_C4B_C4B_T2F)); + } + + static void initTwoColorProgramState() + { + if (__twoColorProgramState) + { + return; + } + auto program = backend::Device::getInstance()->newProgram(TWO_COLOR_TINT_VERTEX_SHADER, TWO_COLOR_TINT_FRAGMENT_SHADER); + auto* programState = new backend::ProgramState(program); + program->release(); + + updateProgramStateLayout(programState); __twoColorProgramState = std::shared_ptr(programState); } @@ -136,9 +140,9 @@ TwoColorTrianglesCommand::TwoColorTrianglesCommand() :_materialID(0), _texture(n _type = RenderCommand::Type::CUSTOM_COMMAND; } -void TwoColorTrianglesCommand::init(float globalOrder, cocos2d::Texture2D *texture, BlendFunc blendType, const TwoColorTriangles& triangles, const Mat4& mv, uint32_t flags) { +void TwoColorTrianglesCommand::init(float globalOrder, cocos2d::Texture2D *texture, cocos2d::backend::ProgramState* programState, BlendFunc blendType, const TwoColorTriangles& triangles, const Mat4& mv, uint32_t flags) { - updateCommandPipelineDescriptor(); + updateCommandPipelineDescriptor(programState); const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); auto finalMatrix = projectionMat * mv; @@ -177,18 +181,39 @@ void TwoColorTrianglesCommand::init(float globalOrder, cocos2d::Texture2D *textu -void TwoColorTrianglesCommand::updateCommandPipelineDescriptor() +void TwoColorTrianglesCommand::updateCommandPipelineDescriptor(cocos2d::backend::ProgramState* programState) { + // OPTIMIZE ME: all commands belong a same Node should share a same programState like SkeletonBatch if (!__twoColorProgramState) { initTwoColorProgramState(); } - CC_SAFE_RELEASE_NULL(_programState); - _programState = __twoColorProgramState->clone(); + bool needsUpdateStateLayout = false; + auto& pipelinePS = _pipelineDescriptor.programState; + if (programState != nullptr) + { + if (_programState != programState) { + CC_SAFE_RELEASE(_programState); + _programState = programState; // Because the programState belong to Node, so no need to clone + CC_SAFE_RETAIN(_programState); + needsUpdateStateLayout = true; + } + } + else { + needsUpdateStateLayout = _programState != nullptr && _programState->getProgram() != __twoColorProgramState->getProgram(); + CC_SAFE_RELEASE(_programState); + _programState = __twoColorProgramState->clone(); + } + + CCASSERT(_programState, "programState should not be null"); + pipelinePS = _programState; + + if (needsUpdateStateLayout) + updateProgramStateLayout(pipelinePS); + _locPMatrix = __locPMatrix; _locTexture = __locTexture; - _pipelineDescriptor.programState = _programState; } TwoColorTrianglesCommand::~TwoColorTrianglesCommand() @@ -330,9 +355,9 @@ void SkeletonTwoColorBatch::deallocateIndices(uint32_t numIndices) { _indices.setSize(_indices.size() - numIndices, 0); } -TwoColorTrianglesCommand* SkeletonTwoColorBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) { +TwoColorTrianglesCommand* SkeletonTwoColorBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, backend::ProgramState* programState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) { TwoColorTrianglesCommand* command = nextFreeCommand(); - command->init(globalOrder, texture, blendType, triangles, mv, flags); + command->init(globalOrder, texture, programState, blendType, triangles, mv, flags); command->updateVertexAndIndexBuffer(renderer, triangles.verts, triangles.vertCount, triangles.indices, triangles.indexCount); renderer->addCommand(command); return command; diff --git a/extensions/spine/v4/SkeletonTwoColorBatch.h b/extensions/spine/v4/SkeletonTwoColorBatch.h index 9eb2e1654d..e3e8309d22 100644 --- a/extensions/spine/v4/SkeletonTwoColorBatch.h +++ b/extensions/spine/v4/SkeletonTwoColorBatch.h @@ -35,6 +35,7 @@ #include #include +#include "renderer/backend/ProgramState.h" namespace spine { struct V3F_C4B_C4B_T2F { @@ -57,9 +58,9 @@ namespace spine { ~TwoColorTrianglesCommand(); - void init(float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); + void init(float globalOrder, cocos2d::Texture2D* texture, cocos2d::backend::ProgramState* programState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); - void updateCommandPipelineDescriptor(); + void updateCommandPipelineDescriptor(cocos2d::backend::ProgramState* programState); inline cocos2d::backend::TextureBackend* getTexture() const { return _texture; } @@ -118,7 +119,7 @@ namespace spine { unsigned short* allocateIndices(uint32_t numIndices); void deallocateIndices(uint32_t numIndices); - TwoColorTrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); + TwoColorTrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::backend::ProgramState* programState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); void batch(cocos2d::Renderer* renderer, TwoColorTrianglesCommand* command);