bool StdMeshUpdate::UpdateAnimationNode(StdMeshInstance* instance, const StdMesh& new_mesh, StdMeshInstance::AnimationNode* node) const { switch (node->GetType()) { case StdMeshInstance::AnimationNode::LeafNode: { // Find dead animation std::map<const StdMeshAnimation*, StdCopyStrBuf>::const_iterator iter = AnimationNames.find(node->Leaf.Animation); assert(iter != AnimationNames.end()); // Update to new animation node->Leaf.Animation = new_mesh.GetSkeleton().GetAnimationByName(iter->second); if(!node->Leaf.Animation) return false; // Clamp provider value StdMeshInstance::ValueProvider* provider = node->GetPositionProvider(); C4Real min = Fix0; C4Real max = ftofix(node->GetAnimation()->Length); provider->Value = BoundBy(provider->Value, min, max); return true; } case StdMeshInstance::AnimationNode::CustomNode: { // Update bone index by bone name StdCopyStrBuf bone_name = BoneNamesByIndex[node->Custom.BoneIndex]; const StdMeshBone* bone = new_mesh.GetSkeleton().GetBoneByName(bone_name); if(!bone) return false; node->Custom.BoneIndex = bone->Index; return true; } case StdMeshInstance::AnimationNode::LinearInterpolationNode: { const bool left_result = UpdateAnimationNode(instance, new_mesh, node->GetLeftChild()); const bool right_result = UpdateAnimationNode(instance, new_mesh, node->GetRightChild()); // Remove this node completely if (!left_result && !right_result) return false; // Note that either of this also removes this node (and replaces by // the other child in the tree). if (!left_result) instance->StopAnimation(node->GetLeftChild()); if (!right_result) instance->StopAnimation(node->GetRightChild()); return true; } default: assert(false); return false; } }
bool StdMeshAnimationUpdate::UpdateAnimationNode(StdMeshInstance* instance, StdMeshInstance::AnimationNode* node) const { const StdMesh& new_mesh = *instance->Mesh; switch (node->GetType()) { case StdMeshInstance::AnimationNode::LeafNode: { // Find dead animation std::map<const StdMeshAnimation*, StdCopyStrBuf>::const_iterator iter = AnimationNames.find(node->Leaf.Animation); // If this assertion fires, it typically means that UpdateAnimations() was called twice for the same mesh instance assert(iter != AnimationNames.end()); // Update to new animation node->Leaf.Animation = new_mesh.GetSkeleton().GetAnimationByName(iter->second); if(!node->Leaf.Animation) return false; // Clamp provider value StdMeshInstance::ValueProvider* provider = node->GetPositionProvider(); C4Real min = Fix0; C4Real max = ftofix(node->GetAnimation()->Length); provider->Value = Clamp(provider->Value, min, max); return true; } case StdMeshInstance::AnimationNode::CustomNode: // Nothing to do here; bone index is updated in StdMeshUpdate return true; case StdMeshInstance::AnimationNode::LinearInterpolationNode: { const bool left_result = UpdateAnimationNode(instance, node->GetLeftChild()); const bool right_result = UpdateAnimationNode(instance, node->GetRightChild()); // Remove this node completely if (!left_result && !right_result) return false; // Note that either of this also removes this node (and replaces by // the other child in the tree). if (!left_result) instance->StopAnimation(node->GetLeftChild()); if (!right_result) instance->StopAnimation(node->GetRightChild()); return true; } default: assert(false); return false; } }
void StdMeshUpdate::Update(StdMeshInstance* instance, const StdMesh& new_mesh) const { assert(&instance->GetMesh() == OldMesh); // Update instance to represent new mesh instance->Mesh = &new_mesh; instance->BoneTransforms = std::vector<StdMeshMatrix>(new_mesh.GetSkeleton().GetNumBones(), StdMeshMatrix::Identity()); instance->BoneTransformsDirty = true; for (unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i) delete instance->SubMeshInstances[i]; instance->SubMeshInstances.resize(new_mesh.GetNumSubMeshes()); for (unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i) { instance->SubMeshInstances[i] = new StdSubMeshInstance(*instance, new_mesh.GetSubMesh(i), instance->GetCompletion()); // Submeshes are reset to their default material, so the submesh order is unaltered instance->SubMeshInstancesOrdered = instance->SubMeshInstances; // TODO: We might try to store the previous mesh material here } // Update child bone of attach parent. If the bone does not exist anymore // in the updated mesh, then detach the mesh from its parent if(instance->AttachParent) { if(!instance->AttachParent->SetChildBone(BoneNamesByIndex[instance->AttachParent->ChildBone])) { bool OwnChild = instance->AttachParent->OwnChild; instance->AttachParent->Parent->DetachMesh(instance->AttachParent->Number); // If the attachment owned the child instance then detach procedure // deleted the child instance. In that case we do not want to proceed // with the mesh update procedure. if(OwnChild) return; } } // Update parent bones of attach children. If a bone does not exist in the // updated mesh then detach the mesh from its parent. std::vector<unsigned int> Removal; for(StdMeshInstance::AttachedMeshIter iter = instance->AttachedMeshesBegin(); iter != instance->AttachedMeshesEnd(); ++iter) { if(!(*iter)->SetParentBone(BoneNamesByIndex[(*iter)->ParentBone])) { // Do not detach the mesh right here so we can finish iterating over // all attached meshes first. Removal.push_back((*iter)->Number); } } for(unsigned int i = 0; i < Removal.size(); ++i) instance->DetachMesh(Removal[i]); // Update the animation tree. Leaf nodes which refer to an animation that // does not exist anymore are removed. for (unsigned int i = instance->AnimationStack.size(); i > 0; --i) if(!UpdateAnimationNode(instance, new_mesh, instance->AnimationStack[i-1])) instance->StopAnimation(instance->AnimationStack[i-1]); }
void StdMeshAnimationUpdate::Update(StdMeshInstance* instance) const { // Update the animation tree. Leaf nodes which refer to an animation that // does not exist anymore are removed. for (unsigned int i = instance->AnimationStack.size(); i > 0; --i) if(!UpdateAnimationNode(instance, instance->AnimationStack[i-1])) instance->StopAnimation(instance->AnimationStack[i-1]); }
bool StdMeshUpdate::UpdateAnimationNode(StdMeshInstance* instance, StdMeshInstance::AnimationNode* node) const { const StdMesh& new_mesh = *instance->Mesh; switch (node->GetType()) { case StdMeshInstance::AnimationNode::LeafNode: // Animation pointer is updated by StdMeshAnimationUpdate return true; case StdMeshInstance::AnimationNode::CustomNode: { // Update bone index by bone name StdCopyStrBuf bone_name = BoneNamesByIndex[node->Custom.BoneIndex]; const StdMeshBone* bone = new_mesh.GetSkeleton().GetBoneByName(bone_name); if(!bone) return false; node->Custom.BoneIndex = bone->Index; return true; } case StdMeshInstance::AnimationNode::LinearInterpolationNode: { const bool left_result = UpdateAnimationNode(instance, node->GetLeftChild()); const bool right_result = UpdateAnimationNode(instance, node->GetRightChild()); // Remove this node completely if (!left_result && !right_result) return false; // Note that either of this also removes this node (and replaces by // the other child in the tree). if (!left_result) instance->StopAnimation(node->GetLeftChild()); if (!right_result) instance->StopAnimation(node->GetRightChild()); return true; } default: assert(false); return false; } }