You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

736 lines
23 KiB

#include "Slot.h"
#include "../animation/Animation.h"
#include "../event/EventObject.h"
#include "../model/BoundingBoxData.h"
#include "../model/DisplayData.h"
#include "../model/DragonBonesData.h"
#include "../model/SkinData.h"
#include "../model/TextureAtlasData.h"
#include "../model/UserData.h"
#include "Armature.h"
#include "Bone.h"
#include "DeformVertices.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