diff --git a/irr/include/SkinnedMesh.h b/irr/include/SkinnedMesh.h index 5a1a9c4c8..fbfd29aa8 100644 --- a/irr/include/SkinnedMesh.h +++ b/irr/include/SkinnedMesh.h @@ -75,7 +75,7 @@ public: //! Turns the given array of local matrices into an array of global matrices //! by multiplying with respective parent matrices. - void calculateGlobalMatrices(std::vector &matrices); + void calculateGlobalMatrices(std::vector &matrices) const; //! Performs a software skin on this mesh based on the given joint matrices void skinMesh(const std::vector &animated_transforms); diff --git a/irr/src/CXMeshFileLoader.cpp b/irr/src/CXMeshFileLoader.cpp index 69ab2d0ca..59455a3cf 100644 --- a/irr/src/CXMeshFileLoader.cpp +++ b/irr/src/CXMeshFileLoader.cpp @@ -514,6 +514,8 @@ bool CXMeshFileLoader::parseDataObjectFrame(SkinnedMesh::SJoint *Parent) if (n.has_value()) { JointID = *n; joint = AnimatedMesh->getAllJoints()[JointID]; + if (Parent) + joint->ParentJointID = Parent->JointID; } } diff --git a/irr/src/SkinnedMesh.cpp b/irr/src/SkinnedMesh.cpp index e9dcc40f5..1237c3b6d 100644 --- a/irr/src/SkinnedMesh.cpp +++ b/irr/src/SkinnedMesh.cpp @@ -265,7 +265,7 @@ void SkinnedMesh::resetAnimation() //! Turns the given array of local matrices into an array of global matrices //! by multiplying with respective parent matrices. -void SkinnedMesh::calculateGlobalMatrices(std::vector &matrices) +void SkinnedMesh::calculateGlobalMatrices(std::vector &matrices) const { // Note that the joints are topologically sorted. for (u16 i = 0; i < AllJoints.size(); ++i) { @@ -409,40 +409,45 @@ void SkinnedMesh::recalculateBaseBoundingBoxes() { calculateBufferBoundingBoxes(); } -// TODO this can be removed: Our API guarantees topo sorting if we prevent mutation void SkinnedMesh::topoSortJoints() { size_t n = AllJoints.size(); - std::vector permutation; // new id -> old id + std::vector new_to_old_id; // new id -> old id - std::vector> children(AllJoints.size()); + std::vector> children(n); for (u16 i = 0; i < n; ++i) { if (auto parentId = AllJoints[i]->ParentJointID) children[*parentId].push_back(i); else - permutation.push_back(i); + new_to_old_id.push_back(i); } // Levelorder for (u16 i = 0; i < n; ++i) { - permutation.insert(permutation.end(), - children[i].begin(), children[i].end()); + new_to_old_id.insert(new_to_old_id.end(), + children[new_to_old_id[i]].begin(), + children[new_to_old_id[i]].end()); } // old id -> new id - std::vector inverse_permutation(n); + std::vector old_to_new_id(n); for (u16 i = 0; i < n; ++i) - inverse_permutation[permutation[i]] = i; + old_to_new_id[new_to_old_id[i]] = i; std::vector joints(n); for (u16 i = 0; i < n; ++i) { - joints[i] = AllJoints[permutation[i]]; + joints[i] = AllJoints[new_to_old_id[i]]; joints[i]->JointID = i; if (auto parentId = joints[i]->ParentJointID) - joints[i]->ParentJointID = inverse_permutation[*parentId]; + joints[i]->ParentJointID = old_to_new_id[*parentId]; + } + AllJoints = std::move(joints); + + for (u16 i = 0; i < n; ++i) { + if (auto pjid = AllJoints[i]->ParentJointID) + assert(*pjid < i); } - AllJoints = joints; } //! called by loader after populating with mesh and bone data @@ -469,7 +474,6 @@ SkinnedMesh *SkinnedMeshBuilder::finalize() } calculateGlobalMatrices(matrices); - for (size_t i = 0; i < AllJoints.size(); ++i) { auto *joint = AllJoints[i]; if (!joint->GlobalInversedMatrix) {