axmol/extensions/dragonbones/CCSlot.cpp

467 lines
16 KiB
C++

#include "CCSlot.h"
#include "CCTextureAtlasData.h"
#include "CCArmatureDisplay.h"
DRAGONBONES_NAMESPACE_BEGIN
void CCSlot::_onClear()
{
Slot::_onClear();
_textureScale = 1.0f;
_renderDisplay = nullptr;
}
void CCSlot::_initDisplay(void* value, bool isRetain)
{
const auto renderDisplay = static_cast<cocos2d::Node*>(value);
renderDisplay->retain();
}
void CCSlot::_disposeDisplay(void* value, bool isRelease)
{
const auto renderDisplay = static_cast<cocos2d::Node*>(value);
renderDisplay->release();
}
void CCSlot::_onUpdateDisplay()
{
_renderDisplay = static_cast<cocos2d::Node*>(_display != nullptr ? _display : _rawDisplay);
}
void CCSlot::_addDisplay()
{
const auto container = static_cast<CCArmatureDisplay*>(_armature->getDisplay());
container->addChild(_renderDisplay);
}
void CCSlot::_replaceDisplay(void* value, bool isArmatureDisplay)
{
const auto container = static_cast<CCArmatureDisplay*>(_armature->getDisplay());
const auto prevDisplay = isArmatureDisplay ? static_cast<cocos2d::Node*>(value) : static_cast<cocos2d::Node*>(value);
container->addChild(_renderDisplay, prevDisplay->getLocalZOrder());
container->removeChild(prevDisplay);
_textureScale = 1.0f;
}
void CCSlot::_removeDisplay()
{
_renderDisplay->removeFromParent();
}
void CCSlot::_updateZOrder()
{
if (_renderDisplay->getLocalZOrder() == _zOrder)
{
return;
}
_renderDisplay->setLocalZOrder(_zOrder);
}
void CCSlot::_updateFrame()
{
const auto currentVerticesData = (_deformVertices != nullptr && _display == _meshDisplay) ? _deformVertices->verticesData : nullptr;
const auto currentTextureData = static_cast<CCTextureData*>(_textureData);
const auto frameDisplay = static_cast<DBCCSprite*>(_renderDisplay); // In cocos2dx render meshDisplay and frameDisplay are the same display
if (_displayIndex >= 0 && _display != nullptr && currentTextureData != nullptr)
{
if (currentTextureData->spriteFrame != nullptr)
{
if (currentVerticesData != nullptr) // Mesh.
{
const auto data = currentVerticesData->data;
const auto intArray = data->intArray;
const auto floatArray = data->floatArray;
const unsigned vertexCount = intArray[currentVerticesData->offset + (unsigned)BinaryOffset::MeshVertexCount];
const unsigned triangleCount = intArray[currentVerticesData->offset + (unsigned)BinaryOffset::MeshTriangleCount];
int vertexOffset = intArray[currentVerticesData->offset + (unsigned)BinaryOffset::MeshFloatOffset];
if (vertexOffset < 0)
{
vertexOffset += 65536; // Fixed out of bouds bug.
}
const unsigned uvOffset = vertexOffset + vertexCount * 2;
const auto& region = currentTextureData->region;
const auto& textureAtlasSize = currentTextureData->spriteFrame->getTexture()->getContentSizeInPixels();
auto vertices = new cocos2d::V3F_C4B_T2F[vertexCount]; // does cocos2dx release it?
auto vertexIndices = new unsigned short[triangleCount * 3]; // does cocos2dx release it?
cocos2d::Rect boundsRect(999999.0f, 999999.0f, -999999.0f, -999999.0f);
for (std::size_t i = 0, l = vertexCount * 2; i < l; i += 2)
{
const auto iH = i / 2;
const auto x = floatArray[vertexOffset + i];
const auto y = floatArray[vertexOffset + i + 1];
auto u = floatArray[uvOffset + i];
auto v = floatArray[uvOffset + i + 1];
cocos2d::V3F_C4B_T2F vertexData;
vertexData.vertices.set(x, -y, 0.0f);
if (currentTextureData->rotated)
{
vertexData.texCoords.u = (region.x + (1.0f - v) * region.width) / textureAtlasSize.width;
vertexData.texCoords.v = (region.y + u * region.height) / textureAtlasSize.height;
}
else
{
vertexData.texCoords.u = (region.x + u * region.width) / textureAtlasSize.width;
vertexData.texCoords.v = (region.y + v * region.height) / textureAtlasSize.height;
}
vertexData.colors = cocos2d::Color4B::WHITE;
vertices[iH] = vertexData;
if (boundsRect.origin.x > x)
{
boundsRect.origin.x = x;
}
if (boundsRect.size.width < x)
{
boundsRect.size.width = x;
}
if (boundsRect.origin.y > -y)
{
boundsRect.origin.y = -y;
}
if (boundsRect.size.height < -y)
{
boundsRect.size.height = -y;
}
}
boundsRect.size.width -= boundsRect.origin.x;
boundsRect.size.height -= boundsRect.origin.y;
for (std::size_t i = 0; i < triangleCount * 3; ++i)
{
vertexIndices[i] = intArray[currentVerticesData->offset + (unsigned)BinaryOffset::MeshVertexIndices + i];
}
_textureScale = 1.0f;
frameDisplay->setSpriteFrame(currentTextureData->spriteFrame); // polygonInfo will be override
cocos2d::PolygonInfo polygonInfo;
auto& triangles = polygonInfo.triangles;
triangles.verts = vertices;
triangles.indices = vertexIndices;
triangles.vertCount = vertexCount;
triangles.indexCount = triangleCount * 3;
const auto& transform = frameDisplay->getNodeToParentTransform(); // Backup transform. (Set rect and polygon will override transform).
#if COCOS2D_VERSION >= 0x00031400
polygonInfo.setRect(boundsRect);
#else
polygonInfo.rect = boundsRect; // Copy
frameDisplay->setContentSize(boundsRect.size);
#endif
frameDisplay->setPolygonInfo(polygonInfo);
const auto isSkinned = currentVerticesData->weight != nullptr;
if (isSkinned)
{
_identityTransform();
}
else
{
frameDisplay->setNodeToParentTransform(transform);
}
}
else // Normal texture.
{
const auto scale = currentTextureData->parent->scale * _armature->_armatureData->scale;
_textureScale = scale * cocos2d::Director::getInstance()->getContentScaleFactor();
frameDisplay->setSpriteFrame(currentTextureData->spriteFrame); // polygonInfo will be override
}
_visibleDirty = true;
_blendModeDirty = true; // Relpace texture will override blendMode and color.
_colorDirty = true;
return;
}
}
frameDisplay->setTexture(nullptr);
frameDisplay->setTextureRect(cocos2d::Rect::ZERO);
frameDisplay->setPosition(0.0f, 0.0f);
frameDisplay->setVisible(false);
}
void CCSlot::_updateMesh()
{
const auto scale = _armature->_armatureData->scale;
const auto& deformVertices = _deformVertices->vertices;
const auto& bones = _deformVertices->bones;
const auto verticesData = _deformVertices->verticesData;
const auto weightData = verticesData->weight;
const auto hasFFD = !deformVertices.empty();
const auto textureData = static_cast<CCTextureData*>(_textureData);
const auto meshDisplay = static_cast<DBCCSprite*>(_renderDisplay);
const auto vertices = meshDisplay->getPolygonInfoModify().triangles.verts;
cocos2d::Rect boundsRect(999999.0f, 999999.0f, -999999.0f, -999999.0f);
if (!textureData || meshDisplay->getSpriteFrame() != textureData->spriteFrame)
{
return;
}
if (weightData != nullptr)
{
const auto data = verticesData->data;
const auto intArray = data->intArray;
const auto floatArray = data->floatArray;
const auto vertexCount = (std::size_t)intArray[verticesData->offset + (unsigned)BinaryOffset::MeshVertexCount];
int weightFloatOffset = intArray[weightData->offset + (unsigned)BinaryOffset::WeigthFloatOffset];
if (weightFloatOffset < 0)
{
weightFloatOffset += 65536; // Fixed out of bouds bug.
}
for (
std::size_t i = 0, iB = weightData->offset + (unsigned)BinaryOffset::WeigthBoneIndices + bones.size(), iV = (std::size_t)weightFloatOffset, iF = 0;
i < vertexCount;
++i
)
{
const auto boneCount = (std::size_t)intArray[iB++];
auto xG = 0.0f, yG = 0.0f;
for (std::size_t j = 0; j < boneCount; ++j)
{
const auto boneIndex = (unsigned)intArray[iB++];
const auto bone = bones[boneIndex];
if (bone != nullptr)
{
const auto& matrix = bone->globalTransformMatrix;
const auto weight = floatArray[iV++];
auto xL = floatArray[iV++] * scale;
auto yL = floatArray[iV++] * scale;
if (hasFFD)
{
xL += deformVertices[iF++];
yL += deformVertices[iF++];
}
xG += (matrix.a * xL + matrix.c * yL + matrix.tx) * weight;
yG += (matrix.b * xL + matrix.d * yL + matrix.ty) * weight;
}
}
auto& vertex = vertices[i];
auto& vertexPosition = vertex.vertices;
vertexPosition.set(xG, -yG, 0.0f);
if (boundsRect.origin.x > xG)
{
boundsRect.origin.x = xG;
}
if (boundsRect.size.width < xG)
{
boundsRect.size.width = xG;
}
if (boundsRect.origin.y > -yG)
{
boundsRect.origin.y = -yG;
}
if (boundsRect.size.height < -yG)
{
boundsRect.size.height = -yG;
}
}
}
else if (hasFFD)
{
const auto data = verticesData->data;
const auto intArray = data->intArray;
const auto floatArray = data->floatArray;
const auto vertexCount = (std::size_t)intArray[verticesData->offset + (unsigned)BinaryOffset::MeshVertexCount];
int vertexOffset = (std::size_t)intArray[verticesData->offset + (unsigned)BinaryOffset::MeshFloatOffset];
if (vertexOffset < 0)
{
vertexOffset += 65536; // Fixed out of bouds bug.
}
for (std::size_t i = 0, l = vertexCount * 2; i < l; i += 2)
{
const auto iH = i / 2;
const auto xG = floatArray[vertexOffset + i] * scale + deformVertices[i];
const auto yG = floatArray[vertexOffset + i + 1] * scale + deformVertices[i + 1];
auto& vertex = vertices[iH];
auto& vertexPosition = vertex.vertices;
vertexPosition.set(xG, -yG, 0.0f);
if (boundsRect.origin.x > xG)
{
boundsRect.origin.x = xG;
}
if (boundsRect.size.width < xG)
{
boundsRect.size.width = xG;
}
if (boundsRect.origin.y > -yG)
{
boundsRect.origin.y = -yG;
}
if (boundsRect.size.height < -yG)
{
boundsRect.size.height = -yG;
}
}
}
boundsRect.size.width -= boundsRect.origin.x;
boundsRect.size.height -= boundsRect.origin.y;
const auto& transform = meshDisplay->getNodeToParentTransform(); // Backup transform. (Set rect and polygon will override transform).
auto polygonInfo = meshDisplay->getPolygonInfo();
#if COCOS2D_VERSION >= 0x00031400
polygonInfo.setRect(boundsRect);
#else
polygonInfo.rect = boundsRect; // Copy
meshDisplay->setContentSize(boundsRect.size);
#endif
meshDisplay->setPolygonInfo(polygonInfo);
if (weightData != nullptr)
{
_identityTransform(); // ?!?!?!?!?!?!?!?!?!?!?!?!?!?! WTF
}
else
{
meshDisplay->setNodeToParentTransform(transform);
}
}
void CCSlot::_updateTransform()
{
static cocos2d::Mat4 transform;
transform.m[0] = globalTransformMatrix.a;
transform.m[1] = globalTransformMatrix.b;
transform.m[4] = -globalTransformMatrix.c;
transform.m[5] = -globalTransformMatrix.d;
if (_renderDisplay == _rawDisplay || _renderDisplay == _meshDisplay)
{
if (_textureScale != 1.0f)
{
transform.m[0] *= _textureScale;
transform.m[1] *= _textureScale;
transform.m[4] *= _textureScale;
transform.m[5] *= _textureScale;
}
transform.m[12] = globalTransformMatrix.tx - (globalTransformMatrix.a * _pivotX - globalTransformMatrix.c * _pivotY);
transform.m[13] = globalTransformMatrix.ty - (globalTransformMatrix.b * _pivotX - globalTransformMatrix.d * _pivotY);
}
else if (_childArmature)
{
transform.m[12] = globalTransformMatrix.tx;
transform.m[13] = globalTransformMatrix.ty;
}
else
{
const auto& anchorPoint = _renderDisplay->getAnchorPoint();
transform.m[12] = globalTransformMatrix.tx - (globalTransformMatrix.a * anchorPoint.x - globalTransformMatrix.c * anchorPoint.y);
transform.m[13] = globalTransformMatrix.ty - (globalTransformMatrix.b * anchorPoint.x - globalTransformMatrix.d * anchorPoint.y);
}
_renderDisplay->setNodeToParentTransform(transform);
}
void CCSlot::_identityTransform()
{
static cocos2d::Mat4 transform;
transform.m[0] = 1.0f;
transform.m[1] = 0.0f;
transform.m[4] = -0.0f;
transform.m[5] = -1.0f;
transform.m[12] = 0.0f;
transform.m[13] = 0.0f;
_renderDisplay->setNodeToParentTransform(transform);
}
void CCSlot::_updateVisible()
{
_renderDisplay->setVisible(_parent->getVisible());
}
void CCSlot::_updateBlendMode()
{
cocos2d::Sprite* spriteDisplay = dynamic_cast<cocos2d::Sprite*>(_renderDisplay);
if (spriteDisplay)
{
switch (_blendMode)
{
case BlendMode::Normal:
// spriteDisplay->setBlendFunc(cocos2d::BlendFunc::DISABLE);
break;
case BlendMode::Add:
{
const auto texture = spriteDisplay->getTexture();
if (texture && texture->hasPremultipliedAlpha())
{
#if COCOS2D_VERSION >= 0x00040000
cocos2d::BlendFunc blendFunc = { cocos2d::backend::BlendFactor::ONE, cocos2d::backend::BlendFactor::ONE };
#else
cocos2d::BlendFunc blendFunc = { GL_ONE, GL_ONE };
#endif
spriteDisplay->setBlendFunc(blendFunc);
}
else
{
spriteDisplay->setBlendFunc(cocos2d::BlendFunc::ADDITIVE);
}
break;
}
default:
break;
}
}
else if (_childArmature != nullptr)
{
for (const auto slot : _childArmature->getSlots())
{
slot->_blendMode = _blendMode;
slot->_updateBlendMode();
}
}
}
void CCSlot::_updateColor()
{
_renderDisplay->setOpacity(_colorTransform.alphaMultiplier * 255.0f);
static cocos2d::Color3B helpColor;
helpColor.r = _colorTransform.redMultiplier * 255.0f;
helpColor.g = _colorTransform.greenMultiplier * 255.0f;
helpColor.b = _colorTransform.blueMultiplier * 255.0f;
_renderDisplay->setColor(helpColor);
}
DRAGONBONES_NAMESPACE_END