#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