axmol/extensions/DragonBones/armature/Slot.cpp

920 lines
25 KiB
C++

#include "Slot.h"
#include "../model/DragonBonesData.h"
#include "../model/UserData.h"
#include "../model/SkinData.h"
#include "../model/DisplayData.h"
#include "../model/BoundingBoxData.h"
#include "../model/TextureAtlasData.h"
#include "Armature.h"
#include "Bone.h"
#include "DeformVertices.h"
#include "../animation/Animation.h"
#include "../event/EventObject.h"
DRAGONBONES_NAMESPACE_BEGIN
void Slot::_onClear()
{
TransformObject::_onClear();
std::vector<std::pair<void*, DisplayType>> disposeDisplayList;
for (const auto& pair : this->_displayList)
{
if (pair.first != nullptr && pair.first != _rawDisplay && pair.first != _meshDisplay &&
std::find(disposeDisplayList.cbegin(), disposeDisplayList.cend(), pair) == disposeDisplayList.cend())
{
disposeDisplayList.push_back(pair);
}
}
for (const auto& pair : disposeDisplayList)
{
if (pair.second == DisplayType::Armature)
{
static_cast<Armature*>(pair.first)->returnToPool();
}
else
{
_disposeDisplay(pair.first, true);
}
}
if (_deformVertices != nullptr)
{
_deformVertices->returnToPool();
}
if (_meshDisplay && _meshDisplay != _rawDisplay)
{
_disposeDisplay(_meshDisplay, false);
}
if (_rawDisplay)
{
_disposeDisplay(_rawDisplay, false);
}
displayController = "";
_displayDirty = false;
_zOrderDirty = false;
_blendModeDirty = false;
_colorDirty = false;
_transformDirty = false;
_visible = true;
_blendMode = BlendMode::Normal;
_displayIndex = -1;
_animationDisplayIndex = -1;
_zOrder = 0;
_cachedFrameIndex = -1;
_pivotX = 0.0f;
_pivotY = 0.0f;
_localMatrix.identity();
_colorTransform.identity();
_displayList.clear();
_displayDatas.clear();
_slotData = nullptr;
_rawDisplayDatas = nullptr; //
_displayData = nullptr;
_boundingBoxData = nullptr;
_textureData = nullptr;
_deformVertices = nullptr;
_rawDisplay = nullptr;
_meshDisplay = nullptr;
_display = nullptr;
_childArmature = nullptr;
_parent = nullptr;
_cachedFrameIndices = nullptr;
}
DisplayData* Slot::_getDefaultRawDisplayData(unsigned displayIndex) const
{
const auto defaultSkin = _armature->_armatureData->defaultSkin;
if (defaultSkin != nullptr)
{
const auto defaultRawDisplayDatas = defaultSkin->getDisplays(_slotData->name);
if (defaultRawDisplayDatas != nullptr)
{
return displayIndex < defaultRawDisplayDatas->size() ? (*defaultRawDisplayDatas)[displayIndex] : nullptr;
}
}
return nullptr;
}
void Slot::_updateDisplayData()
{
const auto prevDisplayData = _displayData;
const auto prevVerticesData = _deformVertices != nullptr ? _deformVertices->verticesData : nullptr;
const auto prevTextureData = _textureData;
DisplayData* rawDisplayData = nullptr;
VerticesData* currentVerticesData = nullptr;
_displayData = nullptr;
_boundingBoxData = nullptr;
_textureData = nullptr;
if (_displayIndex >= 0)
{
if (_rawDisplayDatas != nullptr)
{
rawDisplayData =
(unsigned)_displayIndex < _rawDisplayDatas->size() ? (*_rawDisplayDatas)[_displayIndex] : nullptr;
}
if (rawDisplayData == nullptr)
{
rawDisplayData = _getDefaultRawDisplayData(_displayIndex);
}
if ((unsigned)_displayIndex < _displayDatas.size())
{
_displayData = _displayDatas[_displayIndex];
}
}
// Update texture and mesh data.
if (_displayData != nullptr)
{
if (_displayData->type == DisplayType::Mesh)
{
currentVerticesData = &static_cast<MeshDisplayData*>(_displayData)->vertices;
}
else if (_displayData->type == DisplayType::Path)
{
// TODO
}
else if (rawDisplayData != nullptr)
{
if (rawDisplayData->type == DisplayType::Mesh)
{
currentVerticesData = &static_cast<MeshDisplayData*>(rawDisplayData)->vertices;
}
else if (rawDisplayData->type == DisplayType::Path)
{
// TODO
}
}
if (_displayData->type == DisplayType::BoundingBox)
{
_boundingBoxData = static_cast<BoundingBoxDisplayData*>(_displayData)->boundingBox;
}
else if (rawDisplayData != nullptr)
{
if (rawDisplayData->type == DisplayType::BoundingBox)
{
_boundingBoxData = static_cast<BoundingBoxDisplayData*>(rawDisplayData)->boundingBox;
}
}
if (_displayData->type == DisplayType::Image)
{
_textureData = static_cast<ImageDisplayData*>(_displayData)->texture;
}
else if (_displayData->type == DisplayType::Mesh)
{
_textureData = static_cast<MeshDisplayData*>(_displayData)->texture;
}
}
// Update bounding box data.
if (_displayData != nullptr && _displayData->type == DisplayType::BoundingBox)
{
_boundingBoxData = static_cast<BoundingBoxDisplayData*>(_displayData)->boundingBox;
}
else if (rawDisplayData != nullptr && rawDisplayData->type == DisplayType::BoundingBox)
{
_boundingBoxData = static_cast<BoundingBoxDisplayData*>(rawDisplayData)->boundingBox;
}
else
{
_boundingBoxData = nullptr;
}
if (_displayData != prevDisplayData || currentVerticesData != prevVerticesData || _textureData != prevTextureData)
{
if (currentVerticesData == nullptr && _textureData != nullptr)
{
const auto imageDisplayData = static_cast<ImageDisplayData*>(_displayData);
const auto scale = _textureData->parent->scale * _armature->_armatureData->scale;
const auto frame = _textureData->frame;
_pivotX = imageDisplayData->pivot.x;
_pivotY = imageDisplayData->pivot.y;
const auto& rect = frame != nullptr ? *frame : _textureData->region;
float width = rect.width;
float height = rect.height;
if (_textureData->rotated && frame == nullptr)
{
width = rect.height;
height = rect.width;
}
_pivotX *= width * scale;
_pivotY *= height * scale;
if (frame != nullptr)
{
_pivotX += frame->x * scale;
_pivotY += frame->y * scale;
}
// Update replace pivot.
if (_displayData != nullptr && rawDisplayData != nullptr && _displayData != rawDisplayData)
{
rawDisplayData->transform.toMatrix(_helpMatrix);
_helpMatrix.invert();
_helpMatrix.transformPoint(0.0f, 0.0f, _helpPoint);
_pivotX -= _helpPoint.x;
_pivotY -= _helpPoint.y;
_displayData->transform.toMatrix(_helpMatrix);
_helpMatrix.invert();
_helpMatrix.transformPoint(0.0f, 0.0f, _helpPoint);
_pivotX += _helpPoint.x;
_pivotY += _helpPoint.y;
}
if (!DragonBones::yDown)
{
_pivotY = (_textureData->rotated ? _textureData->region.width : _textureData->region.height) * scale -
_pivotY;
}
}
else
{
_pivotX = 0.0f;
_pivotY = 0.0f;
}
// Update original transform.
if (rawDisplayData != nullptr)
{
origin = &rawDisplayData->transform;
}
else if (_displayData != nullptr)
{
origin = &_displayData->transform;
}
else
{
origin = nullptr;
}
// Update vertices.
if (currentVerticesData != prevVerticesData)
{
if (_deformVertices == nullptr)
{
_deformVertices = BaseObject::borrowObject<DeformVertices>();
}
_deformVertices->init(currentVerticesData, _armature);
}
else if (_deformVertices != nullptr && _textureData != prevTextureData) // Update mesh after update frame.
{
_deformVertices->verticesDirty = true;
}
_displayDirty = true;
_transformDirty = true;
}
}
void Slot::_updateDisplay()
{
const auto prevDisplay = _display != nullptr ? _display : _rawDisplay;
const auto prevChildArmature = _childArmature;
// Update display and child armature.
if (_displayIndex >= 0 && (std::size_t)_displayIndex < _displayList.size())
{
const auto& displayPair = _displayList[_displayIndex];
_display = displayPair.first;
if (_display != nullptr && displayPair.second == DisplayType::Armature)
{
_childArmature = static_cast<Armature*>(displayPair.first);
_display = _childArmature->getDisplay();
}
else
{
_childArmature = nullptr;
}
}
else
{
_display = nullptr;
_childArmature = nullptr;
}
const auto currentDisplay = _display != nullptr ? _display : _rawDisplay;
if (currentDisplay != prevDisplay)
{
_onUpdateDisplay();
_replaceDisplay(prevDisplay, prevChildArmature != nullptr);
_transformDirty = true;
_visibleDirty = true;
_blendModeDirty = true;
_colorDirty = true;
}
// Update frame.
if (currentDisplay == _rawDisplay || currentDisplay == _meshDisplay)
{
_updateFrame();
}
// Update child armature.
if (_childArmature != prevChildArmature)
{
if (prevChildArmature != nullptr)
{
prevChildArmature->_parent = nullptr; // Update child armature parent.
prevChildArmature->setClock(nullptr);
if (prevChildArmature->inheritAnimation)
{
prevChildArmature->getAnimation()->reset();
}
}
if (_childArmature != nullptr)
{
_childArmature->_parent = this; // Update child armature parent.
_childArmature->setClock(_armature->getClock());
if (_childArmature->inheritAnimation) // Set child armature cache frameRate.
{
if (_childArmature->getCacheFrameRate() == 0)
{
const auto chacheFrameRate = this->_armature->getCacheFrameRate();
if (chacheFrameRate != 0)
{
_childArmature->setCacheFrameRate(chacheFrameRate);
}
}
// Child armature action.
std::vector<ActionData*>* actions = nullptr;
if (_displayData != nullptr && _displayData->type == DisplayType::Armature)
{
actions = &(static_cast<ArmatureDisplayData*>(_displayData)->actions);
}
else if (_displayIndex >= 0 && _rawDisplayDatas != nullptr)
{
auto rawDisplayData = (unsigned)_displayIndex < _rawDisplayDatas->size()
? (*_rawDisplayDatas)[_displayIndex]
: nullptr;
if (rawDisplayData == nullptr)
{
rawDisplayData = _getDefaultRawDisplayData(_displayIndex);
}
if (rawDisplayData != nullptr && rawDisplayData->type == DisplayType::Armature)
{
actions = &(static_cast<ArmatureDisplayData*>(rawDisplayData)->actions);
}
}
if (actions != nullptr && !actions->empty())
{
for (const auto action : *actions)
{
const auto eventObject = BaseObject::borrowObject<EventObject>();
EventObject::actionDataToInstance(action, eventObject, _armature);
eventObject->slot = this;
_armature->_bufferAction(eventObject, false);
}
}
else
{
_childArmature->getAnimation()->play();
}
}
}
}
}
void Slot::_updateGlobalTransformMatrix(bool isCache)
{
const auto& parentMatrix = _parent->globalTransformMatrix;
globalTransformMatrix = _localMatrix; // Copy.
globalTransformMatrix.concat(parentMatrix);
if (isCache)
{
global.fromMatrix(globalTransformMatrix);
}
else
{
_globalDirty = true;
}
}
bool Slot::_setDisplayIndex(int value, bool isAnimation)
{
if (isAnimation)
{
if (_animationDisplayIndex == value)
{
return false;
}
_animationDisplayIndex = value;
}
if (_displayIndex == value)
{
return false;
}
_displayIndex = value;
_displayDirty = true;
_updateDisplayData();
return _displayDirty;
}
bool Slot::_setZorder(int value)
{
if (_zOrder == value)
{
// return false;
}
_zOrder = value;
_zOrderDirty = true;
return _zOrderDirty;
}
bool Slot::_setColor(const ColorTransform& value)
{
_colorTransform = value; // copy
_colorDirty = true;
return true;
}
bool Slot::_setDisplayList(const std::vector<std::pair<void*, DisplayType>>& value)
{
if (!value.empty())
{
if (_displayList.size() != value.size())
{
_displayList.resize(value.size());
}
for (std::size_t i = 0, l = value.size(); i < l; ++i)
{
const auto& eachPair = value[i];
if (eachPair.first != nullptr && eachPair.first != _rawDisplay && eachPair.first != _meshDisplay &&
eachPair.second != DisplayType::Armature &&
std::find(_displayList.cbegin(), _displayList.cend(), eachPair) == _displayList.cend())
{
_initDisplay(eachPair.first, true);
}
_displayList[i].first = eachPair.first;
_displayList[i].second = eachPair.second;
}
}
else if (!_displayList.empty())
{
_displayList.clear();
}
if (_displayIndex >= 0 && (std::size_t)_displayIndex < _displayList.size())
{
_displayDirty = _display != _displayList[_displayIndex].first;
}
else
{
_displayDirty = _display != nullptr;
}
_updateDisplayData();
return _displayDirty;
}
void Slot::init(const SlotData* slotData, Armature* armatureValue, void* rawDisplay, void* meshDisplay)
{
if (_slotData != nullptr)
{
return;
}
_slotData = slotData;
//
_visibleDirty = true;
_blendModeDirty = true;
_colorDirty = true;
_blendMode = _slotData->blendMode;
_zOrder = _slotData->zOrder;
_colorTransform = *(_slotData->color);
_rawDisplay = rawDisplay;
_meshDisplay = meshDisplay;
//
_armature = armatureValue;
//
const auto slotParent = _armature->getBone(_slotData->parent->name);
if (slotParent != nullptr)
{
_parent = slotParent;
}
else
{
// Never;
}
_armature->_addSlot(this);
//
_initDisplay(_rawDisplay, false);
if (_rawDisplay != _meshDisplay)
{
_initDisplay(_meshDisplay, false);
}
_onUpdateDisplay();
_addDisplay();
}
void Slot::update(int cacheFrameIndex)
{
if (_displayDirty)
{
_displayDirty = false;
_updateDisplay();
// TODO remove slot offset.
if (_transformDirty) // Update local matrix. (Only updated when both display and transform are dirty.)
{
if (origin != nullptr)
{
global = *origin; // Copy.
global.add(offset).toMatrix(_localMatrix);
}
else
{
global = offset; // Copy.
global.toMatrix(_localMatrix);
}
}
}
if (_zOrderDirty)
{
_zOrderDirty = false;
_updateZOrder();
}
if (cacheFrameIndex >= 0 && _cachedFrameIndices != nullptr)
{
const auto cachedFrameIndex = (*_cachedFrameIndices)[cacheFrameIndex];
if (cachedFrameIndex >= 0 && _cachedFrameIndex == cachedFrameIndex) // Same cache.
{
_transformDirty = false;
}
else if (cachedFrameIndex >= 0) // Has been Cached.
{
_transformDirty = true;
_cachedFrameIndex = cachedFrameIndex;
}
else if (_transformDirty || _parent->_childrenTransformDirty) // Dirty.
{
_transformDirty = true;
_cachedFrameIndex = -1;
}
else if (_cachedFrameIndex >= 0) // Same cache, but not set index yet.
{
_transformDirty = false;
(*_cachedFrameIndices)[cacheFrameIndex] = _cachedFrameIndex;
}
else // Dirty.
{
_transformDirty = true;
_cachedFrameIndex = -1;
}
}
else if (_transformDirty || this->_parent->_childrenTransformDirty)
{
cacheFrameIndex = -1;
_transformDirty = true;
_cachedFrameIndex = -1;
}
if (_display == nullptr)
{
return;
}
if (_visibleDirty)
{
_visibleDirty = false;
_updateVisible();
}
if (_blendModeDirty)
{
_blendModeDirty = false;
_updateBlendMode();
}
if (_colorDirty)
{
_colorDirty = false;
_updateColor();
}
if (_deformVertices != nullptr && _deformVertices->verticesData != nullptr && _display == _meshDisplay)
{
const auto isSkinned = _deformVertices->verticesData->weight != nullptr;
if (_deformVertices->verticesDirty || (isSkinned && _deformVertices->isBonesUpdate()))
{
_deformVertices->verticesDirty = false;
_updateMesh();
}
if (isSkinned) // Compatible.
{
return;
}
}
if (_transformDirty)
{
_transformDirty = false;
if (_cachedFrameIndex < 0)
{
const auto isCache = cacheFrameIndex >= 0;
_updateGlobalTransformMatrix(isCache);
if (isCache && _cachedFrameIndices != nullptr)
{
_cachedFrameIndex = (*_cachedFrameIndices)[cacheFrameIndex] =
_armature->_armatureData->setCacheFrame(globalTransformMatrix, global);
}
}
else
{
_armature->_armatureData->getCacheFrame(globalTransformMatrix, global, _cachedFrameIndex);
}
_updateTransform();
}
}
void Slot::updateTransformAndMatrix()
{
if (_transformDirty)
{
_transformDirty = false;
_updateGlobalTransformMatrix(false);
}
}
void Slot::replaceDisplayData(DisplayData* displayData, int displayIndex)
{
if (displayIndex < 0)
{
if (_displayIndex < 0)
{
displayIndex = 0;
}
else
{
displayIndex = _displayIndex;
}
}
if (_displayDatas.size() <= (unsigned)displayIndex)
{
_displayDatas.resize(displayIndex + 1, nullptr);
}
_displayDatas[displayIndex] = displayData;
}
bool Slot::containsPoint(float x, float y)
{
if (_boundingBoxData == nullptr)
{
return false;
}
updateTransformAndMatrix();
_helpMatrix = globalTransformMatrix; // Copy.
_helpMatrix.invert();
_helpMatrix.transformPoint(x, y, _helpPoint);
return _boundingBoxData->containsPoint(_helpPoint.x, _helpPoint.y);
}
int Slot::intersectsSegment(float xA,
float yA,
float xB,
float yB,
Point* intersectionPointA,
Point* intersectionPointB,
Point* normalRadians)
{
if (_boundingBoxData == nullptr)
{
return 0;
}
updateTransformAndMatrix();
_helpMatrix = globalTransformMatrix;
_helpMatrix.invert();
_helpMatrix.transformPoint(xA, yA, _helpPoint);
xA = _helpPoint.x;
yA = _helpPoint.y;
_helpMatrix.transformPoint(xB, yB, _helpPoint);
xB = _helpPoint.x;
yB = _helpPoint.y;
const auto intersectionCount =
_boundingBoxData->intersectsSegment(xA, yA, xB, yB, intersectionPointA, intersectionPointB, normalRadians);
if (intersectionCount > 0)
{
if (intersectionCount == 1 || intersectionCount == 2)
{
if (intersectionPointA != nullptr)
{
globalTransformMatrix.transformPoint(intersectionPointA->x, intersectionPointA->y, *intersectionPointA);
if (intersectionPointB != nullptr)
{
intersectionPointB->x = intersectionPointA->x;
intersectionPointB->y = intersectionPointA->y;
}
}
else if (intersectionPointB != nullptr)
{
globalTransformMatrix.transformPoint(intersectionPointB->x, intersectionPointB->y, *intersectionPointB);
}
}
else
{
if (intersectionPointA != nullptr)
{
globalTransformMatrix.transformPoint(intersectionPointA->x, intersectionPointA->y, *intersectionPointA);
}
if (intersectionPointB != nullptr)
{
globalTransformMatrix.transformPoint(intersectionPointB->x, intersectionPointB->y, *intersectionPointB);
}
}
if (normalRadians != nullptr)
{
globalTransformMatrix.transformPoint(cos(normalRadians->x), sin(normalRadians->x), _helpPoint, true);
normalRadians->x = atan2(_helpPoint.y, _helpPoint.x);
globalTransformMatrix.transformPoint(cos(normalRadians->y), sin(normalRadians->y), _helpPoint, true);
normalRadians->y = atan2(_helpPoint.y, _helpPoint.x);
}
}
return intersectionCount;
}
void Slot::setVisible(bool value)
{
if (_visible == value)
{
return;
}
_visible = value;
_updateVisible();
}
void Slot::setDisplayIndex(int value)
{
if (_setDisplayIndex(value))
{
update(-1);
}
}
// TODO lsc check
void Slot::setDisplayList(const std::vector<std::pair<void*, DisplayType>>& value)
{
const auto backupDisplayList = _displayList; // copy
auto disposeDisplayList = backupDisplayList; // copy
disposeDisplayList.clear();
if (_setDisplayList(value))
{
update(-1);
}
for (const auto& pair : backupDisplayList)
{
if (pair.first != nullptr && pair.first != _rawDisplay && pair.first != _meshDisplay &&
std::find(_displayList.cbegin(), _displayList.cend(), pair) == _displayList.cend() &&
std::find(disposeDisplayList.cbegin(), disposeDisplayList.cend(), pair) == disposeDisplayList.cend())
{
disposeDisplayList.push_back(pair);
}
}
for (const auto& pair : disposeDisplayList)
{
if (pair.second == DisplayType::Armature)
{
static_cast<Armature*>(pair.first)->returnToPool();
}
else
{
_disposeDisplay(pair.first, true);
}
}
}
void Slot::setRawDisplayDatas(const std::vector<DisplayData*>* value)
{
if (_rawDisplayDatas == value)
{
return;
}
_displayDirty = true;
_rawDisplayDatas = value;
if (_rawDisplayDatas != nullptr)
{
_displayDatas.resize(_rawDisplayDatas->size());
for (std::size_t i = 0, l = _displayDatas.size(); i < l; ++i)
{
auto rawDisplayData = (*_rawDisplayDatas)[i];
if (rawDisplayData == nullptr)
{
rawDisplayData = _getDefaultRawDisplayData(i);
}
_displayDatas[i] = rawDisplayData;
}
}
else
{
_displayDatas.clear();
}
}
void Slot::setDisplay(void* value, DisplayType displayType)
{
if (_display == value)
{
return;
}
const auto displayListLength = _displayList.size();
if (_displayIndex < 0 && displayListLength == 0) // Emprty
{
_displayIndex = 0;
}
if (_displayIndex < 0)
{
return;
}
else
{
auto relpaceDisplayList = _displayList; // copy
if (displayListLength <= (std::size_t)_displayIndex)
{
relpaceDisplayList.resize(_displayIndex + 1);
}
relpaceDisplayList[_displayIndex].first = value;
relpaceDisplayList[_displayIndex].second = displayType;
setDisplayList(relpaceDisplayList);
}
}
void Slot::setChildArmature(Armature* value)
{
if (_childArmature == value)
{
return;
}
setDisplay(value, DisplayType::Armature);
}
DRAGONBONES_NAMESPACE_END