#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> 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(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(_displayData)->vertices; } else if (_displayData->type == DisplayType::Path) { // TODO } else if (rawDisplayData != nullptr) { if (rawDisplayData->type == DisplayType::Mesh) { currentVerticesData = &static_cast(rawDisplayData)->vertices; } else if (rawDisplayData->type == DisplayType::Path) { // TODO } } if (_displayData->type == DisplayType::BoundingBox) { _boundingBoxData = static_cast(_displayData)->boundingBox; } else if (rawDisplayData != nullptr) { if (rawDisplayData->type == DisplayType::BoundingBox) { _boundingBoxData = static_cast(rawDisplayData)->boundingBox; } } if (_displayData->type == DisplayType::Image) { _textureData = static_cast(_displayData)->texture; } else if (_displayData->type == DisplayType::Mesh) { _textureData = static_cast(_displayData)->texture; } } // Update bounding box data. if (_displayData != nullptr && _displayData->type == DisplayType::BoundingBox) { _boundingBoxData = static_cast(_displayData)->boundingBox; } else if (rawDisplayData != nullptr && rawDisplayData->type == DisplayType::BoundingBox) { _boundingBoxData = static_cast(rawDisplayData)->boundingBox; } else { _boundingBoxData = nullptr; } if (_displayData != prevDisplayData || currentVerticesData != prevVerticesData || _textureData != prevTextureData) { if (currentVerticesData == nullptr && _textureData != nullptr) { const auto imageDisplayData = static_cast(_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->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(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* actions = nullptr; if (_displayData != nullptr && _displayData->type == DisplayType::Armature) { actions = &(static_cast(_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(rawDisplayData)->actions); } } if (actions != nullptr && !actions->empty()) { for (const auto action : *actions) { const auto eventObject = BaseObject::borrowObject(); 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>& 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>& 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(pair.first)->returnToPool(); } else { _disposeDisplay(pair.first, true); } } } void Slot::setRawDisplayDatas(const std::vector* 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