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.
331 lines
10 KiB
331 lines
10 KiB
#include "Bone.h"
|
|
#include "../animation/AnimationState.h"
|
|
#include "../geom/Matrix.h"
|
|
#include "../geom/Transform.h"
|
|
#include "Armature.h"
|
|
#include "Constraint.h"
|
|
#include "Slot.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.scaleX = origin->scaleX * offset.scaleX * animationPose.scaleX;
|
|
global.scaleY = origin->scaleY * offset.scaleY * animationPose.scaleY;
|
|
if (DragonBones::yDown) {
|
|
global.y = origin->y + offset.y + animationPose.y;
|
|
global.skew = origin->skew + offset.skew + animationPose.skew;
|
|
global.rotation = origin->rotation + offset.rotation + animationPose.rotation;
|
|
} else {
|
|
global.y = origin->y - offset.y + animationPose.y;
|
|
global.skew = origin->skew - offset.skew + animationPose.skew;
|
|
global.rotation = origin->rotation - offset.rotation + animationPose.rotation;
|
|
}
|
|
} else {
|
|
global = offset; // Copy.
|
|
if (!DragonBones::yDown) {
|
|
global.y = -global.y;
|
|
global.skew = -global.skew;
|
|
global.rotation = -global.rotation;
|
|
}
|
|
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 (!DragonBones::yDown) {
|
|
global.y = -global.y;
|
|
global.skew = -global.skew;
|
|
global.rotation = -global.rotation;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (!DragonBones::yDown) {
|
|
global.skew = -global.skew;
|
|
}
|
|
}
|
|
|
|
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
|
|
|