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.
 
 
 
 
 
 

445 lines
12 KiB

#include "Armature.h"
#include "../animation/Animation.h"
#include "../animation/WorldClock.h"
#include "../event/EventObject.h"
#include "../model/TextureAtlasData.h"
#include "../model/UserData.h"
#include "Bone.h"
#include "Constraint.h"
#include "IArmatureProxy.h"
#include "Slot.h"
DRAGONBONES_NAMESPACE_BEGIN
bool Armature::_onSortSlots(Slot* a, Slot* b) {
return a->_zOrder < b->_zOrder ? true : false;
}
void Armature::_onClear() {
if (_clock != nullptr) // Remove clock before slots clear.
{
_clock->remove(this);
}
for (const auto bone : _bones) {
bone->returnToPool();
}
for (const auto slot : _slots) {
slot->returnToPool();
}
for (const auto constraint : _constraints) {
constraint->returnToPool();
}
for (const auto action : _actions) {
action->returnToPool();
}
if (_animation != nullptr) {
_animation->returnToPool();
}
if (_proxy != nullptr) {
_proxy->dbClear();
}
if (_replaceTextureAtlasData != nullptr) {
_replaceTextureAtlasData->returnToPool();
}
inheritAnimation = true;
userData = nullptr;
_debugDraw = false;
_lockUpdate = false;
_slotsDirty = false;
_zOrderDirty = false;
_flipX = false;
_flipY = false;
_cacheFrameIndex = -1;
_bones.clear();
_slots.clear();
_constraints.clear();
_actions.clear();
_armatureData = nullptr;
_animation = nullptr;
_proxy = nullptr;
_display = nullptr;
_replaceTextureAtlasData = nullptr;
_replacedTexture = nullptr;
_dragonBones = nullptr;
_clock = nullptr;
_parent = nullptr;
}
void Armature::_sortZOrder(const int16_t* slotIndices, unsigned offset) {
const auto& slotDatas = _armatureData->sortedSlots;
const auto isOriginal = slotIndices == nullptr;
if (_zOrderDirty || !isOriginal) {
for (std::size_t i = 0, l = slotDatas.size(); i < l; ++i) {
const auto slotIndex = isOriginal ? i : (std::size_t)slotIndices[offset + i];
if (slotIndex < 0 || slotIndex >= l) {
continue;
}
const auto slotData = slotDatas[slotIndex];
const auto slot = getSlot(slotData->name);
if (slot != nullptr) {
slot->_setZorder(i);
}
}
_slotsDirty = true;
_zOrderDirty = !isOriginal;
}
}
void Armature::_addBone(Bone* value) {
if (std::find(_bones.begin(), _bones.end(), value) == _bones.end()) {
_bones.push_back(value);
}
}
void Armature::_addSlot(Slot* value) {
if (std::find(_slots.begin(), _slots.end(), value) == _slots.end()) {
_slots.push_back(value);
}
}
void Armature::_addConstraint(Constraint* value) {
if (std::find(_constraints.cbegin(), _constraints.cend(), value) == _constraints.cend()) {
_constraints.push_back(value);
}
}
void Armature::_bufferAction(EventObject* action, bool append) {
if (std::find(_actions.cbegin(), _actions.cend(), action) == _actions.cend()) {
if (append) {
_actions.push_back(action);
} else {
_actions.insert(_actions.begin(), action);
}
}
}
void Armature::dispose() {
if (_armatureData != nullptr) {
_lockUpdate = true;
_dragonBones->bufferObject(this);
}
}
void Armature::init(ArmatureData* armatureData, IArmatureProxy* proxy, void* display, DragonBones* dragonBones) {
if (_armatureData != nullptr) {
return;
}
_armatureData = armatureData;
_animation = BaseObject::borrowObject<Animation>();
_proxy = proxy;
_display = display;
_dragonBones = dragonBones;
_proxy->dbInit(this);
_animation->init(this);
_animation->setAnimations(_armatureData->animations);
}
void Armature::advanceTime(float passedTime) {
if (_lockUpdate) {
return;
}
if (_armatureData == nullptr) {
DRAGONBONES_ASSERT(false, "The armature has been disposed.");
return;
} else if (_armatureData->parent == nullptr) {
DRAGONBONES_ASSERT(false, "The armature data has been disposed.\nPlease make sure dispose armature before call factory.clear().");
return;
}
const auto prevCacheFrameIndex = _cacheFrameIndex;
// Update animation.
_animation->advanceTime(passedTime);
// Sort slots.
if (_slotsDirty) {
_slotsDirty = false;
std::sort(_slots.begin(), _slots.end(), Armature::_onSortSlots);
}
// Update bones and slots.
if (_cacheFrameIndex < 0 || _cacheFrameIndex != prevCacheFrameIndex) {
for (const auto bone : _bones) {
bone->update(_cacheFrameIndex);
}
for (const auto slot : _slots) {
slot->update(_cacheFrameIndex);
}
}
// Do actions.
if (!_actions.empty()) {
_lockUpdate = true;
for (const auto action : _actions) {
const auto actionData = action->actionData;
if (actionData != nullptr) {
if (actionData->type == ActionType::Play) {
if (action->slot != nullptr) {
const auto childArmature = action->slot->getChildArmature();
if (childArmature != nullptr) {
childArmature->getAnimation()->fadeIn(actionData->name);
}
} else if (action->bone != nullptr) {
for (const auto slot : getSlots()) {
if (slot->getParent() == action->bone) {
const auto childArmature = slot->getChildArmature();
if (childArmature != nullptr) {
childArmature->getAnimation()->fadeIn(actionData->name);
}
}
}
} else {
_animation->fadeIn(actionData->name);
}
}
}
action->returnToPool();
}
_actions.clear();
_lockUpdate = false;
}
_proxy->dbUpdate();
}
void Armature::render() {
if (_proxy) {
_proxy->dbRender();
}
}
void Armature::invalidUpdate(const std::string& boneName, bool updateSlot) {
if (!boneName.empty()) {
const auto bone = getBone(boneName);
if (bone != nullptr) {
bone->invalidUpdate();
if (updateSlot) {
for (const auto slot : _slots) {
if (slot->getParent() == bone) {
slot->invalidUpdate();
}
}
}
}
} else {
for (const auto bone : _bones) {
bone->invalidUpdate();
}
if (updateSlot) {
for (const auto slot : _slots) {
slot->invalidUpdate();
}
}
}
}
Slot* Armature::containsPoint(float x, float y) const {
for (const auto slot : _slots) {
if (slot->containsPoint(x, y)) {
return slot;
}
}
return nullptr;
}
Slot* Armature::intersectsSegment(
float xA, float yA, float xB, float yB,
Point* intersectionPointA,
Point* intersectionPointB,
Point* normalRadians) const {
const auto isV = xA == xB;
auto dMin = 0.0f;
auto dMax = 0.0f;
auto intXA = 0.0f;
auto intYA = 0.0f;
auto intXB = 0.0f;
auto intYB = 0.0f;
auto intAN = 0.0f;
auto intBN = 0.0f;
Slot* intSlotA = nullptr;
Slot* intSlotB = nullptr;
for (const auto& slot : _slots) {
auto intersectionCount = slot->intersectsSegment(xA, yA, xB, yB, intersectionPointA, intersectionPointB, normalRadians);
if (intersectionCount > 0) {
if (intersectionPointA != nullptr || intersectionPointB != nullptr) {
if (intersectionPointA != nullptr) {
float d = isV ? intersectionPointA->y - yA : intersectionPointA->x - xA;
if (d < 0.0f) {
d = -d;
}
if (intSlotA == nullptr || d < dMin) {
dMin = d;
intXA = intersectionPointA->x;
intYA = intersectionPointA->y;
intSlotA = slot;
if (normalRadians) {
intAN = normalRadians->x;
}
}
}
if (intersectionPointB != nullptr) {
float d = intersectionPointB->x - xA;
if (d < 0.0f) {
d = -d;
}
if (intSlotB == nullptr || d > dMax) {
dMax = d;
intXB = intersectionPointB->x;
intYB = intersectionPointB->y;
intSlotB = slot;
if (normalRadians != nullptr) {
intBN = normalRadians->y;
}
}
}
} else {
intSlotA = slot;
break;
}
}
}
if (intSlotA != nullptr && intersectionPointA != nullptr) {
intersectionPointA->x = intXA;
intersectionPointA->y = intYA;
if (normalRadians != nullptr) {
normalRadians->x = intAN;
}
}
if (intSlotB != nullptr && intersectionPointB != nullptr) {
intersectionPointB->x = intXB;
intersectionPointB->y = intYB;
if (normalRadians != nullptr) {
normalRadians->y = intBN;
}
}
return intSlotA;
}
Bone* Armature::getBone(const std::string& name) const {
for (const auto& bone : _bones) {
if (bone->getName() == name) {
return bone;
}
}
return nullptr;
}
Bone* Armature::getBoneByDisplay(void* display) const {
const auto slot = getSlotByDisplay(display);
return slot != nullptr ? slot->getParent() : nullptr;
}
Slot* Armature::getSlot(const std::string& name) const {
for (const auto slot : _slots) {
if (slot->getName() == name) {
return slot;
}
}
return nullptr;
}
Slot* Armature::getSlotByDisplay(void* display) const {
if (display != nullptr) {
for (const auto slot : _slots) {
if (slot->getDisplay() == display) {
return slot;
}
}
}
return nullptr;
}
void Armature::setCacheFrameRate(unsigned value) {
if (_armatureData->cacheFrameRate != value) {
_armatureData->cacheFrames(value);
for (const auto& slot : _slots) {
const auto childArmature = slot->getChildArmature();
if (childArmature != nullptr && childArmature->getCacheFrameRate() == 0) {
childArmature->setCacheFrameRate(value);
}
}
}
}
void Armature::setClock(WorldClock* value) {
if (_clock == value) {
return;
}
if (_clock) {
_clock->remove(this);
}
_clock = value;
if (_clock) {
_clock->add(this);
}
// Update childArmature clock.
for (const auto& slot : _slots) {
const auto childArmature = slot->getChildArmature();
if (childArmature != nullptr) {
childArmature->setClock(_clock);
}
}
}
void Armature::setReplacedTexture(void* value) {
if (_replacedTexture == value) {
return;
}
if (_replaceTextureAtlasData != nullptr) {
_replaceTextureAtlasData->returnToPool();
_replaceTextureAtlasData = nullptr;
}
_replacedTexture = value;
for (const auto& slot : _slots) {
slot->invalidUpdate();
slot->update(-1);
}
}
DRAGONBONES_NAMESPACE_END