mirror of https://github.com/axmolengine/axmol.git
408 lines
10 KiB
C++
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
|