axmol/extensions/DragonBones/armature/Bone.cpp

408 lines
10 KiB
C++

#include "Bone.h"
#include "../geom/Matrix.h"
#include "../geom/Transform.h"
#include "Armature.h"
#include "Slot.h"
#include "Constraint.h"
#include "../animation/AnimationState.h"
DRAGONBONES_NAMESPACE_BEGIN
void Bone::_onClear()
{
TransformObject::_onClear();
offsetMode = OffsetMode::Additive;
animationPose.identity();
_transformDirty = false;
_childrenTransformDirty = false;
_localDirty = true;
_hasConstraint = false;
_visible = true;
_cachedFrameIndex = -1;
_blendState.clear();
_boneData = nullptr;
_parent = nullptr;
_cachedFrameIndices = nullptr;
}
void Bone::_updateGlobalTransformMatrix(bool isCache)
{
const auto flipX = _armature->getFlipX();
const auto flipY = _armature->getFlipY() == DragonBones::yDown;
auto inherit = _parent != nullptr;
auto rotation = 0.0f;
if (offsetMode == OffsetMode::Additive)
{
if (origin != nullptr)
{
// global = *origin; // Copy.
// global.add(offset).add(animationPose);
global.x = origin->x + offset.x + animationPose.x;
global.y = origin->y + offset.y + animationPose.y;
global.skew = origin->skew + offset.skew + animationPose.skew;
global.rotation = origin->rotation + offset.rotation + animationPose.rotation;
global.scaleX = origin->scaleX * offset.scaleX * animationPose.scaleX;
global.scaleY = origin->scaleY * offset.scaleY * animationPose.scaleY;
}
else
{
global = offset; // Copy.
global.add(animationPose);
}
}
else if (offsetMode == OffsetMode::None)
{
if (origin != nullptr)
{
global = *origin;
global.add(animationPose);
}
else
{
global = animationPose;
}
}
else
{
inherit = false;
global = offset;
}
if (inherit)
{
const auto& parentMatrix = _parent->globalTransformMatrix;
if (_boneData->inheritScale)
{
if (!_boneData->inheritRotation)
{
_parent->updateGlobalTransform();
if (flipX && flipY)
{
rotation = global.rotation - (_parent->global.rotation + Transform::PI);
}
else if (flipX)
{
rotation = global.rotation + _parent->global.rotation + Transform::PI;
}
else if (flipY)
{
rotation = global.rotation + _parent->global.rotation;
}
else
{
rotation = global.rotation - _parent->global.rotation;
}
global.rotation = rotation;
}
global.toMatrix(globalTransformMatrix);
globalTransformMatrix.concat(parentMatrix);
if (_boneData->inheritTranslation)
{
global.x = globalTransformMatrix.tx;
global.y = globalTransformMatrix.ty;
}
else
{
globalTransformMatrix.tx = global.x;
globalTransformMatrix.ty = global.y;
}
if (isCache)
{
global.fromMatrix(globalTransformMatrix);
}
else
{
_globalDirty = true;
}
}
else
{
if (_boneData->inheritTranslation)
{
const auto x = global.x;
const auto y = global.y;
global.x = parentMatrix.a * x + parentMatrix.c * y + parentMatrix.tx;
global.y = parentMatrix.b * x + parentMatrix.d * y + parentMatrix.ty;
}
else
{
if (flipX)
{
global.x = -global.x;
}
if (flipY)
{
global.y = -global.y;
}
}
if (_boneData->inheritRotation)
{
_parent->updateGlobalTransform();
if (_parent->global.scaleX < 0.0f)
{
rotation = global.rotation + _parent->global.rotation + Transform::PI;
}
else
{
rotation = global.rotation + _parent->global.rotation;
}
if (parentMatrix.a * parentMatrix.d - parentMatrix.b * parentMatrix.c < 0.0f)
{
rotation -= global.rotation * 2.0f;
if (flipX != flipY || _boneData->inheritReflection)
{
global.skew += Transform::PI;
}
}
global.rotation = rotation;
}
else if (flipX || flipY)
{
if (flipX && flipY)
{
rotation = global.rotation + Transform::PI;
}
else
{
if (flipX)
{
rotation = Transform::PI - global.rotation;
}
else
{
rotation = -global.rotation;
}
global.skew += Transform::PI;
}
global.rotation = rotation;
}
global.toMatrix(globalTransformMatrix);
}
}
else
{
if (flipX || flipY)
{
if (flipX)
{
global.x = -global.x;
}
if (flipY)
{
global.y = -global.y;
}
if (flipX && flipY)
{
rotation = global.rotation + Transform::PI;
}
else
{
if (flipX)
{
rotation = Transform::PI - global.rotation;
}
else
{
rotation = -global.rotation;
}
global.skew += Transform::PI;
}
global.rotation = rotation;
}
global.toMatrix(globalTransformMatrix);
}
}
void Bone::init(const BoneData* boneData, Armature* armatureValue)
{
if (_boneData != nullptr)
{
return;
}
_boneData = boneData;
_armature = armatureValue;
if (_boneData->parent != nullptr)
{
_parent = _armature->getBone(_boneData->parent->name);
}
_armature->_addBone(this);
//
origin = &(_boneData->transform);
}
void Bone::update(int cacheFrameIndex)
{
_blendState.dirty = false;
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 (_hasConstraint) // Update constraints.
{
for (const auto constraint : _armature->_constraints)
{
if (constraint->_root == this)
{
constraint->update();
}
}
}
if (_transformDirty || (_parent != nullptr && _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 (_hasConstraint) // Update constraints.
{
for (const auto constraint : _armature->_constraints)
{
if (constraint->_root == this)
{
constraint->update();
}
}
}
if (_transformDirty || (_parent != nullptr && _parent->_childrenTransformDirty)) // Dirty.
{
cacheFrameIndex = -1;
_transformDirty = true;
_cachedFrameIndex = -1;
}
}
if (_transformDirty)
{
_transformDirty = false;
_childrenTransformDirty = true;
//
if (_cachedFrameIndex < 0)
{
const auto isCache = cacheFrameIndex >= 0;
if (_localDirty)
{
_updateGlobalTransformMatrix(isCache);
}
if (isCache && _cachedFrameIndices != nullptr)
{
_cachedFrameIndex = (*_cachedFrameIndices)[cacheFrameIndex] =
_armature->_armatureData->setCacheFrame(globalTransformMatrix, global);
}
}
else
{
_armature->_armatureData->getCacheFrame(globalTransformMatrix, global, _cachedFrameIndex);
}
//
}
else if (_childrenTransformDirty)
{
_childrenTransformDirty = false;
}
_localDirty = true;
}
void Bone::updateByConstraint()
{
if (_localDirty)
{
_localDirty = false;
if (_transformDirty || (_parent != nullptr && _parent->_childrenTransformDirty))
{
_updateGlobalTransformMatrix(true);
}
_transformDirty = true;
}
}
bool Bone::contains(const Bone* value) const
{
if (value == this)
{
return false;
}
auto ancestor = value;
while (ancestor != this && ancestor != nullptr)
{
ancestor = ancestor->getParent();
}
return ancestor == this;
}
void Bone::setVisible(bool value)
{
if (_visible == value)
{
return;
}
_visible = value;
for (const auto& slot : _armature->getSlots())
{
if (slot->getParent() == this)
{
slot->_updateVisible();
}
}
}
DRAGONBONES_NAMESPACE_END