mirror of https://github.com/axmolengine/axmol.git
553 lines
13 KiB
C++
553 lines
13 KiB
C++
#include "Armature.h"
|
|
#include "../model/TextureAtlasData.h"
|
|
#include "../model/UserData.h"
|
|
#include "../animation/WorldClock.h"
|
|
#include "../animation/Animation.h"
|
|
#include "../event/EventObject.h"
|
|
#include "IArmatureProxy.h"
|
|
#include "Bone.h"
|
|
#include "Slot.h"
|
|
#include "Constraint.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 >= 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::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
|