From 1e59b9a75651130aa7061c2c67dd588d74bb6cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:33:08 +0100 Subject: [PATCH] Refactor `SkinnedMesh` (#15522) --- irr/include/SkinnedMesh.h | 308 +++++++----- irr/src/CAnimatedMeshSceneNode.cpp | 13 +- irr/src/CAnimatedMeshSceneNode.h | 2 +- irr/src/CB3DMeshFileLoader.cpp | 99 +--- irr/src/CB3DMeshFileLoader.h | 2 +- irr/src/CGLTFMeshFileLoader.cpp | 24 +- irr/src/CGLTFMeshFileLoader.h | 4 +- irr/src/CXMeshFileLoader.cpp | 51 +- irr/src/CXMeshFileLoader.h | 2 +- irr/src/SkinnedMesh.cpp | 778 ++++++----------------------- 10 files changed, 387 insertions(+), 896 deletions(-) diff --git a/irr/include/SkinnedMesh.h b/irr/include/SkinnedMesh.h index 54ce8ed2c..4cf5905c9 100644 --- a/irr/include/SkinnedMesh.h +++ b/irr/include/SkinnedMesh.h @@ -9,6 +9,7 @@ #include "SMeshBuffer.h" #include "SSkinMeshBuffer.h" #include "quaternion.h" +#include "vector3d.h" #include #include @@ -18,18 +19,6 @@ namespace irr namespace scene { -enum E_INTERPOLATION_MODE -{ - // constant does use the current key-values without interpolation - EIM_CONSTANT = 0, - - // linear interpolation - EIM_LINEAR, - - //! count of all available interpolation modes - EIM_COUNT -}; - class IAnimatedMeshSceneNode; class IBoneSceneNode; class ISceneManager; @@ -38,7 +27,14 @@ class SkinnedMesh : public IAnimatedMesh { public: //! constructor - SkinnedMesh(); + SkinnedMesh() : + EndFrame(0.f), FramesPerSecond(25.f), + LastAnimatedFrame(-1), SkinnedLastFrame(false), + HasAnimation(false), PreparedForSkinning(false), + AnimateNormals(true), HardwareSkinning(false) + { + SkinningBuffers = &LocalBuffers; + } //! destructor virtual ~SkinnedMesh(); @@ -58,9 +54,8 @@ public: //! returns the animated mesh for the given frame IMesh *getMesh(f32) override; - //! Animates this mesh's joints based on frame input - //! blend: {0-old position, 1-New position} - void animateMesh(f32 frame, f32 blend); + //! Animates joints based on frame input + void animateMesh(f32 frame); //! Performs a software skin on this mesh based of joint positions void skinMesh(); @@ -82,10 +77,14 @@ public: void setTextureSlot(u32 meshbufNr, u32 textureSlot); //! returns an axis aligned bounding box - const core::aabbox3d &getBoundingBox() const override; + const core::aabbox3d &getBoundingBox() const override { + return BoundingBox; + } //! set user axis aligned bounding box - void setBoundingBox(const core::aabbox3df &box) override; + void setBoundingBox(const core::aabbox3df &box) override { + BoundingBox = box; + } //! set the hardware mapping hint, for driver void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer = EBT_VERTEX_AND_INDEX) override; @@ -94,7 +93,9 @@ public: void setDirty(E_BUFFER_TYPE buffer = EBT_VERTEX_AND_INDEX) override; //! Returns the type of the animated mesh. - E_ANIMATED_MESH_TYPE getMeshType() const override; + E_ANIMATED_MESH_TYPE getMeshType() const override { + return EAMT_SKINNED; + } //! Gets joint count. u32 getJointCount() const; @@ -112,18 +113,19 @@ public: //! Update Normals when Animating /** \param on If false don't animate, which is faster. Else update normals, which allows for proper lighting of - animated meshes. */ - void updateNormalsWhenAnimating(bool on); - - //! Sets Interpolation Mode - void setInterpolationMode(E_INTERPOLATION_MODE mode); + animated meshes (default). */ + void updateNormalsWhenAnimating(bool on) { + AnimateNormals = on; + } //! converts the vertex type of all meshbuffers to tangents. /** E.g. used for bump mapping. */ void convertMeshToTangents(); //! Does the mesh have no animation - bool isStatic() const; + bool isStatic() const { + return !HasAnimation; + } //! Allows to enable hardware skinning. /* This feature is not implemented in Irrlicht yet */ @@ -138,16 +140,13 @@ public: virtual void updateBoundingBox(); //! Recovers the joints from the mesh - void recoverJointsFromMesh(core::array &jointChildSceneNodes); + void recoverJointsFromMesh(std::vector &jointChildSceneNodes); //! Transfers the joint data to the mesh - void transferJointsToMesh(const core::array &jointChildSceneNodes); - - //! Transfers the joint hints to the mesh - void transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes); + void transferJointsToMesh(const std::vector &jointChildSceneNodes); //! Creates an array of joints from this mesh as children of node - void addJoints(core::array &jointChildSceneNodes, + void addJoints(std::vector &jointChildSceneNodes, IAnimatedMeshSceneNode *node, ISceneManager *smgr); @@ -171,35 +170,133 @@ public: core::vector3df StaticNormal; }; - //! Animation keyframe which describes a new position - struct SPositionKey - { - f32 frame; - core::vector3df position; + template + struct Channel { + struct Frame { + f32 time; + T value; + }; + std::vector frames; + bool interpolate = true; + + bool empty() const { + return frames.empty(); + } + + f32 getEndFrame() const { + return frames.empty() ? 0 : frames.back().time; + } + + void pushBack(f32 time, const T &value) { + frames.push_back({time, value}); + } + + void append(const Channel &other) { + frames.insert(frames.end(), other.frames.begin(), other.frames.end()); + } + + void cleanup() { + if (frames.empty()) + return; + + std::vector ordered; + ordered.push_back(frames.front()); + // Drop out-of-order frames + for (auto it = frames.begin() + 1; it != frames.end(); ++it) { + if (it->time > ordered.back().time) { + ordered.push_back(*it); + } + } + frames.clear(); + // Drop redundant middle keys + frames.push_back(ordered.front()); + for (u32 i = 1; i < ordered.size() - 1; ++i) { + if (ordered[i - 1].value != ordered[i].value + || ordered[i + 1].value != ordered[i].value) { + frames.push_back(ordered[i]); + } + } + if (ordered.size() > 1) + frames.push_back(ordered.back()); + frames.shrink_to_fit(); + } + + static core::quaternion interpolateValue(core::quaternion from, core::quaternion to, f32 time) { + core::quaternion result; + result.slerp(from, to, time, 0.001f); + return result; + } + + static core::vector3df interpolateValue(core::vector3df from, core::vector3df to, f32 time) { + // Note: `from` and `to` are swapped here compared to quaternion slerp + return to.getInterpolated(from, time); + } + + std::optional get(f32 time) const { + if (frames.empty()) + return std::nullopt; + + const auto next = std::lower_bound(frames.begin(), frames.end(), time, [](const auto& frame, f32 time) { + return frame.time < time; + }); + if (next == frames.begin()) + return next->value; + if (next == frames.end()) + return frames.back().value; + + const auto prev = next - 1; + if (!interpolate) + return prev->value; + + return interpolateValue(prev->value, next->value, (time - prev->time) / (next->time - prev->time)); + } }; - //! Animation keyframe which describes a new scale - struct SScaleKey - { - f32 frame; - core::vector3df scale; - }; + struct Keys { + Channel position; + Channel rotation; + Channel scale; - //! Animation keyframe which describes a new rotation - struct SRotationKey - { - f32 frame; - core::quaternion rotation; + bool empty() const { + return position.empty() && rotation.empty() && scale.empty(); + } + + void append(const Keys &other) { + position.append(other.position); + rotation.append(other.rotation); + scale.append(other.scale); + } + + f32 getEndFrame() const { + return std::max({ + position.getEndFrame(), + rotation.getEndFrame(), + scale.getEndFrame() + }); + } + + void updateTransform(f32 frame, + core::vector3df &t, core::quaternion &r, core::vector3df &s) const + { + if (auto pos = position.get(frame)) + t = *pos; + if (auto rot = rotation.get(frame)) + r = *rot; + if (auto scl = scale.get(frame)) + s = *scl; + } + + void cleanup() { + position.cleanup(); + rotation.cleanup(); + scale.cleanup(); + } }; //! Joints struct SJoint { - SJoint() : - UseAnimationFrom(0), GlobalSkinningSpace(false), - positionHint(-1), scaleHint(-1), rotationHint(-1) - { - } + SJoint() : GlobalSkinningSpace(false) {} //! The name of this joint std::optional Name; @@ -208,22 +305,16 @@ public: core::matrix4 LocalMatrix; //! List of child joints - core::array Children; + std::vector Children; //! List of attached meshes - core::array AttachedMeshes; + std::vector AttachedMeshes; - //! Animation keys causing translation change - core::array PositionKeys; - - //! Animation keys causing scale change - core::array ScaleKeys; - - //! Animation keys causing rotation change - core::array RotationKeys; + // Animation keyframes for translation, rotation, scale + Keys keys; //! Skin weights - core::array Weights; + std::vector Weights; //! Unnecessary for loaders, will be overwritten on finalize core::matrix4 GlobalMatrix; // loaders may still choose to set this (temporarily) to calculate absolute vertex data. @@ -241,49 +332,14 @@ public: //! Internal members used by SkinnedMesh friend class SkinnedMesh; - SJoint *UseAnimationFrom; bool GlobalSkinningSpace; - - s32 positionHint; - s32 scaleHint; - s32 rotationHint; }; - // Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_ - // these functions will use the needed arrays, set values, etc to help the loaders + const std::vector &getAllJoints() const { + return AllJoints; + } - //! exposed for loaders to add mesh buffers - core::array &getMeshBuffers(); - - //! alternative method for adding joints - core::array &getAllJoints(); - - //! alternative method for reading joints - const core::array &getAllJoints() const; - - //! loaders should call this after populating the mesh - void finalize(); - - //! Adds a new meshbuffer to the mesh, access it as last one - SSkinMeshBuffer *addMeshBuffer(); - - //! Adds a new meshbuffer to the mesh, access it as last one - void addMeshBuffer(SSkinMeshBuffer *meshbuf); - - //! Adds a new joint to the mesh, access it as last one - SJoint *addJoint(SJoint *parent = 0); - - //! Adds a new position key to the mesh, access it as last one - SPositionKey *addPositionKey(SJoint *joint); - //! Adds a new rotation key to the mesh, access it as last one - SRotationKey *addRotationKey(SJoint *joint); - //! Adds a new scale key to the mesh, access it as last one - SScaleKey *addScaleKey(SJoint *joint); - - //! Adds a new weight to the mesh, access it as last one - SWeight *addWeight(SJoint *joint); - -private: +protected: void checkForAnimation(); void normalizeWeights(); @@ -292,11 +348,6 @@ private: void buildAllGlobalAnimatedMatrices(SJoint *Joint = 0, SJoint *ParentJoint = 0); - void getFrameData(f32 frame, SJoint *Node, - core::vector3df &position, s32 &positionHint, - core::vector3df &scale, s32 &scaleHint, - core::quaternion &rotation, s32 &rotationHint); - void calculateGlobalMatrices(SJoint *Joint, SJoint *ParentJoint); void skinJoint(SJoint *Joint, SJoint *ParentJoint); @@ -306,18 +357,18 @@ private: const core::vector3df &vt1, const core::vector3df &vt2, const core::vector3df &vt3, const core::vector2df &tc1, const core::vector2df &tc2, const core::vector2df &tc3); - core::array *SkinningBuffers; // Meshbuffer to skin, default is to skin localBuffers + std::vector *SkinningBuffers; // Meshbuffer to skin, default is to skin localBuffers - core::array LocalBuffers; + std::vector LocalBuffers; //! Mapping from meshbuffer number to bindable texture slot std::vector TextureSlots; - core::array AllJoints; - core::array RootJoints; + std::vector AllJoints; + std::vector RootJoints; // bool can't be used here because std::vector // doesn't allow taking a reference to individual elements. - core::array> Vertices_Moved; + std::vector> Vertices_Moved; core::aabbox3d BoundingBox; @@ -327,13 +378,42 @@ private: f32 LastAnimatedFrame; bool SkinnedLastFrame; - E_INTERPOLATION_MODE InterpolationMode : 8; - bool HasAnimation; bool PreparedForSkinning; bool AnimateNormals; bool HardwareSkinning; }; +// Interface for mesh loaders +class SkinnedMeshBuilder : public SkinnedMesh { +public: + SkinnedMeshBuilder() : SkinnedMesh() {} + + //! loaders should call this after populating the mesh + // returns *this, so do not try to drop the mesh builder instance + SkinnedMesh *finalize(); + + //! alternative method for adding joints + std::vector &getAllJoints() { + return AllJoints; + } + + //! Adds a new meshbuffer to the mesh, access it as last one + SSkinMeshBuffer *addMeshBuffer(); + + //! Adds a new meshbuffer to the mesh, access it as last one + void addMeshBuffer(SSkinMeshBuffer *meshbuf); + + //! Adds a new joint to the mesh, access it as last one + SJoint *addJoint(SJoint *parent = nullptr); + + void addPositionKey(SJoint *joint, f32 frame, core::vector3df pos); + void addRotationKey(SJoint *joint, f32 frame, core::quaternion rotation); + void addScaleKey(SJoint *joint, f32 frame, core::vector3df scale); + + //! Adds a new weight to the mesh, access it as last one + SWeight *addWeight(SJoint *joint); +}; + } // end namespace scene } // end namespace irr diff --git a/irr/src/CAnimatedMeshSceneNode.cpp b/irr/src/CAnimatedMeshSceneNode.cpp index 5250fe889..d249e37c5 100644 --- a/irr/src/CAnimatedMeshSceneNode.cpp +++ b/irr/src/CAnimatedMeshSceneNode.cpp @@ -170,7 +170,7 @@ IMesh *CAnimatedMeshSceneNode::getMeshForCurrentFrame() if (JointMode == EJUOR_CONTROL) // write to mesh skinnedMesh->transferJointsToMesh(JointChildSceneNodes); else - skinnedMesh->animateMesh(getFrameNr(), 1.0f); + skinnedMesh->animateMesh(getFrameNr()); // Update the skinned mesh for the current joint transforms. skinnedMesh->skinMesh(); @@ -299,12 +299,10 @@ void CAnimatedMeshSceneNode::render() if (Mesh->getMeshType() == EAMT_SKINNED) { // draw skeleton - for (u32 g = 0; g < ((SkinnedMesh *)Mesh)->getAllJoints().size(); ++g) { - auto *joint = ((SkinnedMesh *)Mesh)->getAllJoints()[g]; - - for (u32 n = 0; n < joint->Children.size(); ++n) { + for (auto *joint : ((SkinnedMesh *)Mesh)->getAllJoints()) { + for (const auto *childJoint : joint->Children) { driver->draw3DLine(joint->GlobalAnimatedMatrix.getTranslation(), - joint->Children[n]->GlobalAnimatedMatrix.getTranslation(), + childJoint->GlobalAnimatedMatrix.getTranslation(), video::SColor(255, 51, 66, 255)); } } @@ -598,8 +596,7 @@ void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions) SkinnedMesh *skinnedMesh = static_cast(Mesh); - skinnedMesh->transferOnlyJointsHintsToMesh(JointChildSceneNodes); - skinnedMesh->animateMesh(frame, 1.0f); + skinnedMesh->animateMesh(frame); skinnedMesh->recoverJointsFromMesh(JointChildSceneNodes); //----------------------------------------- diff --git a/irr/src/CAnimatedMeshSceneNode.h b/irr/src/CAnimatedMeshSceneNode.h index e45edca86..047a4030f 100644 --- a/irr/src/CAnimatedMeshSceneNode.h +++ b/irr/src/CAnimatedMeshSceneNode.h @@ -169,7 +169,7 @@ private: IAnimationEndCallBack *LoopCallBack; s32 PassCount; - core::array JointChildSceneNodes; + std::vector JointChildSceneNodes; core::array PretransitingSave; }; diff --git a/irr/src/CB3DMeshFileLoader.cpp b/irr/src/CB3DMeshFileLoader.cpp index 6923cde04..3bcc4b85f 100644 --- a/irr/src/CB3DMeshFileLoader.cpp +++ b/irr/src/CB3DMeshFileLoader.cpp @@ -10,6 +10,7 @@ #include "IVideoDriver.h" #include "IFileSystem.h" +#include "SkinnedMesh.h" #include "coreutil.h" #include "os.h" @@ -51,12 +52,12 @@ IAnimatedMesh *CB3DMeshFileLoader::createMesh(io::IReadFile *file) return 0; B3DFile = file; - AnimatedMesh = new scene::SkinnedMesh(); + AnimatedMesh = new scene::SkinnedMeshBuilder(); ShowWarning = true; // If true a warning is issued if too many textures are used VerticesStart = 0; if (load()) { - AnimatedMesh->finalize(); + return AnimatedMesh->finalize(); } else { AnimatedMesh->drop(); AnimatedMesh = 0; @@ -254,7 +255,7 @@ bool CB3DMeshFileLoader::readChunkMESH(SkinnedMesh::SJoint *inJoint) meshBuffer->Material = Materials[brushID].Material; } - if (readChunkTRIS(meshBuffer, AnimatedMesh->getMeshBuffers().size() - 1, VerticesStart) == false) + if (readChunkTRIS(meshBuffer, AnimatedMesh->getMeshBufferCount() - 1, VerticesStart) == false) return false; if (!NormalsInFile) { @@ -569,7 +570,7 @@ bool CB3DMeshFileLoader::readChunkKEYS(SkinnedMesh::SJoint *inJoint) { #ifdef _B3D_READER_DEBUG // Only print first, that's just too much output otherwise - if (!inJoint || (inJoint->PositionKeys.empty() && inJoint->ScaleKeys.empty() && inJoint->RotationKeys.empty())) { + if (!inJoint || inJoint->keys.empty()) { core::stringc logStr; for (u32 i = 1; i < B3dStack.size(); ++i) logStr += "-"; @@ -584,13 +585,6 @@ bool CB3DMeshFileLoader::readChunkKEYS(SkinnedMesh::SJoint *inJoint) flags = os::Byteswap::byteswap(flags); #endif - SkinnedMesh::SPositionKey *oldPosKey = 0; - core::vector3df oldPos[2]; - SkinnedMesh::SScaleKey *oldScaleKey = 0; - core::vector3df oldScale[2]; - SkinnedMesh::SRotationKey *oldRotKey = 0; - core::quaternion oldRot[2]; - bool isFirst[3] = {true, true, true}; while ((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats { s32 frame; @@ -600,91 +594,24 @@ bool CB3DMeshFileLoader::readChunkKEYS(SkinnedMesh::SJoint *inJoint) frame = os::Byteswap::byteswap(frame); #endif + if (frame < 1) { + os::Printer::log("Illegal frame number found", B3DFile->getFileName(), ELL_ERROR); + frame = 1; + } + // Add key frames, frames in Irrlicht are zero-based f32 data[4]; if (flags & 1) { readFloats(data, 3); - if ((oldPosKey != 0) && (oldPos[0] == oldPos[1])) { - const core::vector3df pos(data[0], data[1], data[2]); - if (oldPos[1] == pos) - oldPosKey->frame = (f32)frame - 1; - else { - oldPos[0] = oldPos[1]; - oldPosKey = AnimatedMesh->addPositionKey(inJoint); - oldPosKey->frame = (f32)frame - 1; - oldPos[1].set(oldPosKey->position.set(pos)); - } - } else if (oldPosKey == 0 && isFirst[0]) { - oldPosKey = AnimatedMesh->addPositionKey(inJoint); - oldPosKey->frame = (f32)frame - 1; - oldPos[0].set(oldPosKey->position.set(data[0], data[1], data[2])); - oldPosKey = 0; - isFirst[0] = false; - } else { - if (oldPosKey != 0) - oldPos[0] = oldPos[1]; - oldPosKey = AnimatedMesh->addPositionKey(inJoint); - oldPosKey->frame = (f32)frame - 1; - oldPos[1].set(oldPosKey->position.set(data[0], data[1], data[2])); - } + AnimatedMesh->addPositionKey(inJoint, frame - 1, {data[0], data[1], data[2]}); } if (flags & 2) { readFloats(data, 3); - if ((oldScaleKey != 0) && (oldScale[0] == oldScale[1])) { - const core::vector3df scale(data[0], data[1], data[2]); - if (oldScale[1] == scale) - oldScaleKey->frame = (f32)frame - 1; - else { - oldScale[0] = oldScale[1]; - oldScaleKey = AnimatedMesh->addScaleKey(inJoint); - oldScaleKey->frame = (f32)frame - 1; - oldScale[1].set(oldScaleKey->scale.set(scale)); - } - } else if (oldScaleKey == 0 && isFirst[1]) { - oldScaleKey = AnimatedMesh->addScaleKey(inJoint); - oldScaleKey->frame = (f32)frame - 1; - oldScale[0].set(oldScaleKey->scale.set(data[0], data[1], data[2])); - oldScaleKey = 0; - isFirst[1] = false; - } else { - if (oldScaleKey != 0) - oldScale[0] = oldScale[1]; - oldScaleKey = AnimatedMesh->addScaleKey(inJoint); - oldScaleKey->frame = (f32)frame - 1; - oldScale[1].set(oldScaleKey->scale.set(data[0], data[1], data[2])); - } + AnimatedMesh->addScaleKey(inJoint, frame - 1, {data[0], data[1], data[2]}); } if (flags & 4) { readFloats(data, 4); - if ((oldRotKey != 0) && (oldRot[0] == oldRot[1])) { - // meant to be in this order since b3d stores W first - const core::quaternion rot(data[1], data[2], data[3], data[0]); - if (oldRot[1] == rot) - oldRotKey->frame = (f32)frame - 1; - else { - oldRot[0] = oldRot[1]; - oldRotKey = AnimatedMesh->addRotationKey(inJoint); - oldRotKey->frame = (f32)frame - 1; - oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); - oldRot[1].normalize(); - } - } else if (oldRotKey == 0 && isFirst[2]) { - oldRotKey = AnimatedMesh->addRotationKey(inJoint); - oldRotKey->frame = (f32)frame - 1; - // meant to be in this order since b3d stores W first - oldRot[0].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); - oldRot[0].normalize(); - oldRotKey = 0; - isFirst[2] = false; - } else { - if (oldRotKey != 0) - oldRot[0] = oldRot[1]; - oldRotKey = AnimatedMesh->addRotationKey(inJoint); - oldRotKey->frame = (f32)frame - 1; - // meant to be in this order since b3d stores W first - oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); - oldRot[1].normalize(); - } + AnimatedMesh->addRotationKey(inJoint, frame - 1, core::quaternion(data[1], data[2], data[3], data[0])); } } diff --git a/irr/src/CB3DMeshFileLoader.h b/irr/src/CB3DMeshFileLoader.h index 711f2737f..55978d743 100644 --- a/irr/src/CB3DMeshFileLoader.h +++ b/irr/src/CB3DMeshFileLoader.h @@ -63,7 +63,7 @@ private: core::array BaseVertices; - SkinnedMesh *AnimatedMesh; + SkinnedMeshBuilder *AnimatedMesh; io::IReadFile *B3DFile; // B3Ds have Vertex ID's local within the mesh I don't want this diff --git a/irr/src/CGLTFMeshFileLoader.cpp b/irr/src/CGLTFMeshFileLoader.cpp index 139b4f670..79c68355b 100644 --- a/irr/src/CGLTFMeshFileLoader.cpp +++ b/irr/src/CGLTFMeshFileLoader.cpp @@ -346,14 +346,14 @@ IAnimatedMesh* SelfType::createMesh(io::IReadFile* file) const char *filename = file->getFileName().c_str(); try { tiniergltf::GlTF model = parseGLTF(file); - irr_ptr mesh(new SkinnedMesh()); + irr_ptr mesh(new SkinnedMeshBuilder()); MeshExtractor extractor(std::move(model), mesh.get()); try { extractor.load(); for (const auto &warning : extractor.getWarnings()) { os::Printer::log(filename, warning.c_str(), ELL_WARNING); } - return mesh.release(); + return mesh.release()->finalize(); } catch (const std::runtime_error &e) { os::Printer::log("error converting gltf to irrlicht mesh", e.what(), ELL_ERROR); } @@ -691,27 +691,27 @@ void SelfType::MeshExtractor::loadAnimation(const std::size_t animIdx) case tiniergltf::AnimationChannelTarget::Path::TRANSLATION: { const auto outputAccessor = Accessor::make(m_gltf_model, sampler.output); for (std::size_t i = 0; i < n_frames; ++i) { - auto *key = m_irr_model->addPositionKey(joint); - key->frame = inputAccessor.get(i); - key->position = convertHandedness(outputAccessor.get(i)); + f32 frame = inputAccessor.get(i); + core::vector3df position = outputAccessor.get(i); + m_irr_model->addPositionKey(joint, frame, convertHandedness(position)); } break; } case tiniergltf::AnimationChannelTarget::Path::ROTATION: { const auto outputAccessor = Accessor::make(m_gltf_model, sampler.output); for (std::size_t i = 0; i < n_frames; ++i) { - auto *key = m_irr_model->addRotationKey(joint); - key->frame = inputAccessor.get(i); - key->rotation = convertHandedness(outputAccessor.get(i)); + f32 frame = inputAccessor.get(i); + core::quaternion rotation = outputAccessor.get(i); + m_irr_model->addRotationKey(joint, frame, convertHandedness(rotation)); } break; } case tiniergltf::AnimationChannelTarget::Path::SCALE: { const auto outputAccessor = Accessor::make(m_gltf_model, sampler.output); for (std::size_t i = 0; i < n_frames; ++i) { - auto *key = m_irr_model->addScaleKey(joint); - key->frame = inputAccessor.get(i); - key->scale = outputAccessor.get(i); + f32 frame = inputAccessor.get(i); + core::vector3df scale = outputAccessor.get(i); + m_irr_model->addScaleKey(joint, frame, scale); } break; } @@ -756,8 +756,6 @@ void SelfType::MeshExtractor::load() } catch (const std::bad_optional_access &e) { throw std::runtime_error(e.what()); } - - m_irr_model->finalize(); } /** diff --git a/irr/src/CGLTFMeshFileLoader.h b/irr/src/CGLTFMeshFileLoader.h index 1671d2903..a4eac8baa 100644 --- a/irr/src/CGLTFMeshFileLoader.h +++ b/irr/src/CGLTFMeshFileLoader.h @@ -100,7 +100,7 @@ private: { public: MeshExtractor(tiniergltf::GlTF &&model, - SkinnedMesh *mesh) noexcept + SkinnedMeshBuilder *mesh) noexcept : m_gltf_model(std::move(model)), m_irr_model(mesh) {}; /* Gets indices for the given mesh/primitive. @@ -124,7 +124,7 @@ private: private: const tiniergltf::GlTF m_gltf_model; - SkinnedMesh *m_irr_model; + SkinnedMeshBuilder *m_irr_model; std::vector> m_mesh_loaders; std::vector m_loaded_nodes; diff --git a/irr/src/CXMeshFileLoader.cpp b/irr/src/CXMeshFileLoader.cpp index 19d4e5b01..cb02298eb 100644 --- a/irr/src/CXMeshFileLoader.cpp +++ b/irr/src/CXMeshFileLoader.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CXMeshFileLoader.h" +#include "SkinnedMesh.h" #include "os.h" #include "fast_atof.h" @@ -57,7 +58,7 @@ IAnimatedMesh *CXMeshFileLoader::createMesh(io::IReadFile *file) u32 time = os::Timer::getRealTime(); #endif - AnimatedMesh = new SkinnedMesh(); + AnimatedMesh = new SkinnedMeshBuilder(); if (load(file)) { AnimatedMesh->finalize(); @@ -92,7 +93,7 @@ IAnimatedMesh *CXMeshFileLoader::createMesh(io::IReadFile *file) delete Meshes[i]; Meshes.clear(); - return AnimatedMesh; + return AnimatedMesh->finalize(); } bool CXMeshFileLoader::load(io::IReadFile *file) @@ -124,7 +125,7 @@ bool CXMeshFileLoader::load(io::IReadFile *file) if (!mesh->HasSkinning) { // Set up rigid animation if (mesh->AttachedJointID != -1) { - AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back(AnimatedMesh->getMeshBuffers().size() - 1); + AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back(AnimatedMesh->getMeshBufferCount() - 1); } } } @@ -965,7 +966,7 @@ bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh) u32 i; const u32 jointStart = joint->Weights.size(); - joint->Weights.reallocate(jointStart + nWeights); + joint->Weights.resize(jointStart + nWeights); mesh.WeightJoint.reallocate(mesh.WeightJoint.size() + nWeights); mesh.WeightNum.reallocate(mesh.WeightNum.size() + nWeights); @@ -1411,20 +1412,7 @@ bool CXMeshFileLoader::parseDataObjectAnimation() joint->Name = FrameName.c_str(); } - joint->PositionKeys.reallocate(joint->PositionKeys.size() + animationDump.PositionKeys.size()); - for (u32 n = 0; n < animationDump.PositionKeys.size(); ++n) { - joint->PositionKeys.push_back(animationDump.PositionKeys[n]); - } - - joint->ScaleKeys.reallocate(joint->ScaleKeys.size() + animationDump.ScaleKeys.size()); - for (u32 n = 0; n < animationDump.ScaleKeys.size(); ++n) { - joint->ScaleKeys.push_back(animationDump.ScaleKeys[n]); - } - - joint->RotationKeys.reallocate(joint->RotationKeys.size() + animationDump.RotationKeys.size()); - for (u32 n = 0; n < animationDump.RotationKeys.size(); ++n) { - joint->RotationKeys.push_back(animationDump.RotationKeys[n]); - } + joint->keys.append(animationDump.keys); } else os::Printer::log("joint name was never given", ELL_WARNING); @@ -1488,10 +1476,9 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(SkinnedMesh::SJoint *joint) os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); } - SkinnedMesh::SRotationKey *key = AnimatedMesh->addRotationKey(joint); - key->frame = time; - key->rotation.set(X, Y, Z, W); - key->rotation.normalize(); + core::quaternion rotation(X, Y, Z, W); + rotation.normalize(); + AnimatedMesh->addRotationKey(joint, time, rotation); } break; case 1: // scale case 2: // position @@ -1514,13 +1501,9 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(SkinnedMesh::SJoint *joint) } if (keyType == 2) { - SkinnedMesh::SPositionKey *key = AnimatedMesh->addPositionKey(joint); - key->frame = time; - key->position = vector; + AnimatedMesh->addPositionKey(joint, time, vector); } else { - SkinnedMesh::SScaleKey *key = AnimatedMesh->addScaleKey(joint); - key->frame = time; - key->scale = vector; + AnimatedMesh->addScaleKey(joint, time, vector); } } break; case 3: @@ -1547,16 +1530,8 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(SkinnedMesh::SJoint *joint) // core::vector3df rotation = mat.getRotationDegrees(); - SkinnedMesh::SRotationKey *keyR = AnimatedMesh->addRotationKey(joint); - keyR->frame = time; - - // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility. - // Not tested so far if this was correct or wrong before quaternion fix! - keyR->rotation = core::quaternion(mat.getTransposed()); - - SkinnedMesh::SPositionKey *keyP = AnimatedMesh->addPositionKey(joint); - keyP->frame = time; - keyP->position = mat.getTranslation(); + AnimatedMesh->addRotationKey(joint, time, core::quaternion(mat.getTransposed())); + AnimatedMesh->addPositionKey(joint, time, mat.getTranslation()); /* core::vector3df scale=mat.getScale(); diff --git a/irr/src/CXMeshFileLoader.h b/irr/src/CXMeshFileLoader.h index 0902651a9..36610d3b3 100644 --- a/irr/src/CXMeshFileLoader.h +++ b/irr/src/CXMeshFileLoader.h @@ -155,7 +155,7 @@ private: bool readRGB(video::SColor &color); bool readRGBA(video::SColor &color); - SkinnedMesh *AnimatedMesh; + SkinnedMeshBuilder *AnimatedMesh; c8 *Buffer; const c8 *P; diff --git a/irr/src/SkinnedMesh.cpp b/irr/src/SkinnedMesh.cpp index 76bce0b87..64b25205e 100644 --- a/irr/src/SkinnedMesh.cpp +++ b/irr/src/SkinnedMesh.cpp @@ -8,106 +8,22 @@ #include "IAnimatedMeshSceneNode.h" #include "SSkinMeshBuffer.h" #include "os.h" - -namespace -{ -// Frames must always be increasing, so we remove objects where this isn't the case -// return number of kicked keys -template // T = objects containing a "frame" variable -irr::u32 dropBadKeys(irr::core::array &array) -{ - if (array.size() < 2) - return 0; - - irr::u32 n = 1; // new index - for (irr::u32 j = 1; j < array.size(); ++j) { - if (array[j].frame < array[n - 1].frame) - continue; // bad frame, unneeded and may cause problems - if (n != j) - array[n] = array[j]; - ++n; - } - irr::u32 d = array.size() - n; // remove already copied keys - if (d > 0) { - array.erase(n, d); - } - return d; -} - -// drop identical middle keys - we only need the first and last -// return number of kicked keys -template // Cmp = comparison for keys of type T -irr::u32 dropMiddleKeys(irr::core::array &array, Cmp &cmp) -{ - if (array.size() < 3) - return 0; - - irr::u32 s = 0; // old index for current key - irr::u32 n = 1; // new index for next key - for (irr::u32 j = 1; j < array.size(); ++j) { - if (cmp(array[j], array[s])) - continue; // same key, handle later - - if (j > s + 1) // had there been identical keys? - array[n++] = array[j - 1]; // keep the last - array[n++] = array[j]; // keep the new one - s = j; - } - if (array.size() > s + 1) // identical keys at the array end? - array[n++] = array[array.size() - 1]; // keep the last - - irr::u32 d = array.size() - n; // remove already copied keys - if (d > 0) { - array.erase(n, d); - } - return d; -} - -bool identicalPos(const irr::scene::SkinnedMesh::SPositionKey &a, const irr::scene::SkinnedMesh::SPositionKey &b) -{ - return a.position == b.position; -} - -bool identicalScale(const irr::scene::SkinnedMesh::SScaleKey &a, const irr::scene::SkinnedMesh::SScaleKey &b) -{ - return a.scale == b.scale; -} - -bool identicalRotation(const irr::scene::SkinnedMesh::SRotationKey &a, const irr::scene::SkinnedMesh::SRotationKey &b) -{ - return a.rotation == b.rotation; -} -} +#include namespace irr { namespace scene { -//! constructor -SkinnedMesh::SkinnedMesh() : - SkinningBuffers(0), EndFrame(0.f), FramesPerSecond(25.f), - LastAnimatedFrame(-1), SkinnedLastFrame(false), - InterpolationMode(EIM_LINEAR), - HasAnimation(false), PreparedForSkinning(false), - AnimateNormals(true), HardwareSkinning(false) -{ -#ifdef _DEBUG - setDebugName("SkinnedMesh"); -#endif - - SkinningBuffers = &LocalBuffers; -} - //! destructor SkinnedMesh::~SkinnedMesh() { - for (u32 i = 0; i < AllJoints.size(); ++i) - delete AllJoints[i]; + for (auto *joint : AllJoints) + delete joint; - for (u32 j = 0; j < LocalBuffers.size(); ++j) { - if (LocalBuffers[j]) - LocalBuffers[j]->drop(); + for (auto *buffer : LocalBuffers) { + if (buffer) + buffer->drop(); } } @@ -138,7 +54,7 @@ IMesh *SkinnedMesh::getMesh(f32 frame) if (frame == -1) return this; - animateMesh(frame, 1.0f); + animateMesh(frame); skinMesh(); return this; } @@ -147,9 +63,8 @@ IMesh *SkinnedMesh::getMesh(f32 frame) // Keyframe Animation //-------------------------------------------------------------------------- -//! Animates this mesh's joints based on frame input -//! blend: {0-old position, 1-New position} -void SkinnedMesh::animateMesh(f32 frame, f32 blend) +//! Animates joints based on frame input +void SkinnedMesh::animateMesh(f32 frame) { if (!HasAnimation || LastAnimatedFrame == frame) return; @@ -157,39 +72,14 @@ void SkinnedMesh::animateMesh(f32 frame, f32 blend) LastAnimatedFrame = frame; SkinnedLastFrame = false; - if (blend <= 0.f) - return; // No need to animate - - for (u32 i = 0; i < AllJoints.size(); ++i) { + for (auto *joint : AllJoints) { // The joints can be animated here with no input from their // parents, but for setAnimationMode extra checks are needed // to their parents - SJoint *joint = AllJoints[i]; - - const core::vector3df oldPosition = joint->Animatedposition; - const core::vector3df oldScale = joint->Animatedscale; - const core::quaternion oldRotation = joint->Animatedrotation; - - core::vector3df position = oldPosition; - core::vector3df scale = oldScale; - core::quaternion rotation = oldRotation; - - getFrameData(frame, joint, - position, joint->positionHint, - scale, joint->scaleHint, - rotation, joint->rotationHint); - - if (blend == 1.0f) { - // No blending needed - joint->Animatedposition = position; - joint->Animatedscale = scale; - joint->Animatedrotation = rotation; - } else { - // Blend animation - joint->Animatedposition = core::lerp(oldPosition, position, blend); - joint->Animatedscale = core::lerp(oldScale, scale, blend); - joint->Animatedrotation.slerp(oldRotation, rotation, blend); - } + joint->keys.updateTransform(frame, + joint->Animatedposition, + joint->Animatedrotation, + joint->Animatedscale); } // Note: @@ -207,15 +97,10 @@ void SkinnedMesh::animateMesh(f32 frame, f32 blend) void SkinnedMesh::buildAllLocalAnimatedMatrices() { - for (u32 i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - + for (auto *joint : AllJoints) { // Could be faster: - if (joint->UseAnimationFrom && - (joint->UseAnimationFrom->PositionKeys.size() || - joint->UseAnimationFrom->ScaleKeys.size() || - joint->UseAnimationFrom->RotationKeys.size())) { + if (!joint->keys.empty()) { joint->GlobalSkinningSpace = false; // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility. @@ -240,7 +125,7 @@ void SkinnedMesh::buildAllLocalAnimatedMatrices() m1[14] += Pos.Z * m1[15]; // ----------------------------------- - if (joint->ScaleKeys.size()) { + if (!joint->keys.scale.empty()) { /* core::matrix4 scaleMatrix; scaleMatrix.setScale(joint->Animatedscale); @@ -273,8 +158,8 @@ void SkinnedMesh::buildAllLocalAnimatedMatrices() void SkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint) { if (!joint) { - for (u32 i = 0; i < RootJoints.size(); ++i) - buildAllGlobalAnimatedMatrices(RootJoints[i], 0); + for (auto *rootJoint : RootJoints) + buildAllGlobalAnimatedMatrices(rootJoint, 0); return; } else { // Find global matrix... @@ -284,168 +169,8 @@ void SkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJo joint->GlobalAnimatedMatrix = parentJoint->GlobalAnimatedMatrix * joint->LocalAnimatedMatrix; } - for (u32 j = 0; j < joint->Children.size(); ++j) - buildAllGlobalAnimatedMatrices(joint->Children[j], joint); -} - -void SkinnedMesh::getFrameData(f32 frame, SJoint *joint, - core::vector3df &position, s32 &positionHint, - core::vector3df &scale, s32 &scaleHint, - core::quaternion &rotation, s32 &rotationHint) -{ - s32 foundPositionIndex = -1; - s32 foundScaleIndex = -1; - s32 foundRotationIndex = -1; - - if (joint->UseAnimationFrom) { - const core::array &PositionKeys = joint->UseAnimationFrom->PositionKeys; - const core::array &ScaleKeys = joint->UseAnimationFrom->ScaleKeys; - const core::array &RotationKeys = joint->UseAnimationFrom->RotationKeys; - - if (PositionKeys.size()) { - foundPositionIndex = -1; - - // Test the Hints... - if (positionHint >= 0 && (u32)positionHint < PositionKeys.size()) { - // check this hint - if (positionHint > 0 && PositionKeys[positionHint].frame >= frame && PositionKeys[positionHint - 1].frame < frame) - foundPositionIndex = positionHint; - else if (positionHint + 1 < (s32)PositionKeys.size()) { - // check the next index - if (PositionKeys[positionHint + 1].frame >= frame && - PositionKeys[positionHint + 0].frame < frame) { - positionHint++; - foundPositionIndex = positionHint; - } - } - } - - // The hint test failed, do a full scan... - if (foundPositionIndex == -1) { - for (u32 i = 0; i < PositionKeys.size(); ++i) { - if (PositionKeys[i].frame >= frame) { // Keys should to be sorted by frame - foundPositionIndex = i; - positionHint = i; - break; - } - } - } - - // Do interpolation... - if (foundPositionIndex != -1) { - if (InterpolationMode == EIM_CONSTANT || foundPositionIndex == 0) { - position = PositionKeys[foundPositionIndex].position; - } else if (InterpolationMode == EIM_LINEAR) { - const SPositionKey &KeyA = PositionKeys[foundPositionIndex]; - const SPositionKey &KeyB = PositionKeys[foundPositionIndex - 1]; - - const f32 fd1 = frame - KeyA.frame; - const f32 fd2 = KeyB.frame - frame; - position = ((KeyB.position - KeyA.position) / (fd1 + fd2)) * fd1 + KeyA.position; - } - } - } - - //------------------------------------------------------------ - - if (ScaleKeys.size()) { - foundScaleIndex = -1; - - // Test the Hints... - if (scaleHint >= 0 && (u32)scaleHint < ScaleKeys.size()) { - // check this hint - if (scaleHint > 0 && ScaleKeys[scaleHint].frame >= frame && ScaleKeys[scaleHint - 1].frame < frame) - foundScaleIndex = scaleHint; - else if (scaleHint + 1 < (s32)ScaleKeys.size()) { - // check the next index - if (ScaleKeys[scaleHint + 1].frame >= frame && - ScaleKeys[scaleHint + 0].frame < frame) { - scaleHint++; - foundScaleIndex = scaleHint; - } - } - } - - // The hint test failed, do a full scan... - if (foundScaleIndex == -1) { - for (u32 i = 0; i < ScaleKeys.size(); ++i) { - if (ScaleKeys[i].frame >= frame) { // Keys should to be sorted by frame - foundScaleIndex = i; - scaleHint = i; - break; - } - } - } - - // Do interpolation... - if (foundScaleIndex != -1) { - if (InterpolationMode == EIM_CONSTANT || foundScaleIndex == 0) { - scale = ScaleKeys[foundScaleIndex].scale; - } else if (InterpolationMode == EIM_LINEAR) { - const SScaleKey &KeyA = ScaleKeys[foundScaleIndex]; - const SScaleKey &KeyB = ScaleKeys[foundScaleIndex - 1]; - - const f32 fd1 = frame - KeyA.frame; - const f32 fd2 = KeyB.frame - frame; - scale = ((KeyB.scale - KeyA.scale) / (fd1 + fd2)) * fd1 + KeyA.scale; - } - } - } - - //------------------------------------------------------------- - - if (RotationKeys.size()) { - foundRotationIndex = -1; - - // Test the Hints... - if (rotationHint >= 0 && (u32)rotationHint < RotationKeys.size()) { - // check this hint - if (rotationHint > 0 && RotationKeys[rotationHint].frame >= frame && RotationKeys[rotationHint - 1].frame < frame) - foundRotationIndex = rotationHint; - else if (rotationHint + 1 < (s32)RotationKeys.size()) { - // check the next index - if (RotationKeys[rotationHint + 1].frame >= frame && - RotationKeys[rotationHint + 0].frame < frame) { - rotationHint++; - foundRotationIndex = rotationHint; - } - } - } - - // The hint test failed, do a full scan... - if (foundRotationIndex == -1) { - for (u32 i = 0; i < RotationKeys.size(); ++i) { - if (RotationKeys[i].frame >= frame) { // Keys should be sorted by frame - foundRotationIndex = i; - rotationHint = i; - break; - } - } - } - - // Do interpolation... - if (foundRotationIndex != -1) { - if (InterpolationMode == EIM_CONSTANT || foundRotationIndex == 0) { - rotation = RotationKeys[foundRotationIndex].rotation; - } else if (InterpolationMode == EIM_LINEAR) { - const SRotationKey &KeyA = RotationKeys[foundRotationIndex]; - const SRotationKey &KeyB = RotationKeys[foundRotationIndex - 1]; - - const f32 fd1 = frame - KeyA.frame; - const f32 fd2 = KeyB.frame - frame; - const f32 t = fd1 / (fd1 + fd2); - - /* - f32 t = 0; - if (KeyA.frame!=KeyB.frame) - t = (frame-KeyA.frame) / (KeyB.frame - KeyA.frame); - */ - - rotation.slerp(KeyA.rotation, KeyB.rotation, t); - } - } - } - } + for (auto *childJoint : joint->Children) + buildAllGlobalAnimatedMatrices(childJoint, joint); } //-------------------------------------------------------------------------- @@ -465,28 +190,24 @@ void SkinnedMesh::skinMesh() SkinnedLastFrame = true; if (!HardwareSkinning) { - // Software skin.... - u32 i; - // rigid animation - for (i = 0; i < AllJoints.size(); ++i) { - for (u32 j = 0; j < AllJoints[i]->AttachedMeshes.size(); ++j) { - SSkinMeshBuffer *Buffer = (*SkinningBuffers)[AllJoints[i]->AttachedMeshes[j]]; - Buffer->Transformation = AllJoints[i]->GlobalAnimatedMatrix; + for (auto *joint : AllJoints) { + for (u32 attachedMeshIdx : joint->AttachedMeshes) { + SSkinMeshBuffer *Buffer = (*SkinningBuffers)[attachedMeshIdx]; + Buffer->Transformation = joint->GlobalAnimatedMatrix; } } // clear skinning helper array - for (i = 0; i < Vertices_Moved.size(); ++i) - for (u32 j = 0; j < Vertices_Moved[i].size(); ++j) - Vertices_Moved[i][j] = false; + for (std::vector &buf : Vertices_Moved) + std::fill(buf.begin(), buf.end(), false); // skin starting with the root joints - for (i = 0; i < RootJoints.size(); ++i) - skinJoint(RootJoints[i], 0); + for (auto *rootJoint : RootJoints) + skinJoint(rootJoint, 0); - for (i = 0; i < SkinningBuffers->size(); ++i) - (*SkinningBuffers)[i]->setDirty(EBT_VERTEX); + for (auto *buffer : *SkinningBuffers) + buffer->setDirty(EBT_VERTEX); } updateBoundingBox(); } @@ -500,12 +221,10 @@ void SkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint) core::vector3df thisVertexMove, thisNormalMove; - core::array &buffersUsed = *SkinningBuffers; + auto &buffersUsed = *SkinningBuffers; // Skin Vertices Positions and Normals... - for (u32 i = 0; i < joint->Weights.size(); ++i) { - SWeight &weight = joint->Weights[i]; - + for (const auto &weight : joint->Weights) { // Pull this vertex... jointVertexPull.transformVect(thisVertexMove, weight.StaticPos); @@ -537,13 +256,8 @@ void SkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint) } // Skin all children - for (u32 j = 0; j < joint->Children.size(); ++j) - skinJoint(joint->Children[j], joint); -} - -E_ANIMATED_MESH_TYPE SkinnedMesh::getMeshType() const -{ - return EAMT_SKINNED; + for (auto *childJoint : joint->Children) + skinJoint(childJoint, joint); } //! Gets joint count. @@ -607,18 +321,6 @@ void SkinnedMesh::setTextureSlot(u32 meshbufNr, u32 textureSlot) { TextureSlots.at(meshbufNr) = textureSlot; } -//! returns an axis aligned bounding box -const core::aabbox3d &SkinnedMesh::getBoundingBox() const -{ - return BoundingBox; -} - -//! set user axis aligned bounding box -void SkinnedMesh::setBoundingBox(const core::aabbox3df &box) -{ - BoundingBox = box; -} - //! set the hardware mapping hint, for driver void SkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer) @@ -634,35 +336,6 @@ void SkinnedMesh::setDirty(E_BUFFER_TYPE buffer) LocalBuffers[i]->setDirty(buffer); } -//! Update Normals when Animating -//! False= Don't animate them, faster -//! True= Update normals (default) -void SkinnedMesh::updateNormalsWhenAnimating(bool on) -{ - AnimateNormals = on; -} - -//! Sets Interpolation Mode -void SkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode) -{ - InterpolationMode = mode; -} - -core::array &SkinnedMesh::getMeshBuffers() -{ - return LocalBuffers; -} - -core::array &SkinnedMesh::getAllJoints() -{ - return AllJoints; -} - -const core::array &SkinnedMesh::getAllJoints() const -{ - return AllJoints; -} - //! (This feature is not implemented in irrlicht yet) bool SkinnedMesh::setHardwareSkinning(bool on) { @@ -670,13 +343,12 @@ bool SkinnedMesh::setHardwareSkinning(bool on) if (on) { // set mesh to static pose... - for (u32 i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (u32 j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal; + for (auto *joint : AllJoints) { + for (const auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = weight.StaticPos; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = weight.StaticNormal; LocalBuffers[buffer_id]->boundingBoxNeedsRecalculated(); } } @@ -690,13 +362,12 @@ bool SkinnedMesh::setHardwareSkinning(bool on) void SkinnedMesh::refreshJointCache() { // copy cache from the mesh... - for (u32 i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (u32 j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; - joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; - joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; + for (auto *joint : AllJoints) { + for (auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; + weight.StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; + weight.StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; } } } @@ -704,13 +375,12 @@ void SkinnedMesh::refreshJointCache() void SkinnedMesh::resetAnimation() { // copy from the cache to the mesh... - for (u32 i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (u32 j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal; + for (auto *joint : AllJoints) { + for (const auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = weight.StaticPos; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = weight.StaticNormal; } } SkinnedLastFrame = false; @@ -724,8 +394,8 @@ void SkinnedMesh::calculateGlobalMatrices(SJoint *joint, SJoint *parentJoint) // Go through the root bones if (!joint) { - for (u32 i = 0; i < RootJoints.size(); ++i) - calculateGlobalMatrices(RootJoints[i], 0); + for (auto *rootJoint : RootJoints) + calculateGlobalMatrices(rootJoint, nullptr); return; } @@ -742,51 +412,36 @@ void SkinnedMesh::calculateGlobalMatrices(SJoint *joint, SJoint *parentJoint) joint->GlobalInversedMatrix->makeInverse(); // slow } - for (u32 j = 0; j < joint->Children.size(); ++j) - calculateGlobalMatrices(joint->Children[j], joint); + for (auto *childJoint : joint->Children) + calculateGlobalMatrices(childJoint, joint); SkinnedLastFrame = false; } void SkinnedMesh::checkForAnimation() { - u32 i, j; // Check for animation... HasAnimation = false; - for (i = 0; i < AllJoints.size(); ++i) { - if (AllJoints[i]->UseAnimationFrom) { - if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() || - AllJoints[i]->UseAnimationFrom->ScaleKeys.size() || - AllJoints[i]->UseAnimationFrom->RotationKeys.size()) { - HasAnimation = true; - } + for (auto *joint : AllJoints) { + if (!joint->keys.empty()) { + HasAnimation = true; + break; } } // meshes with weights, are still counted as animated for ragdolls, etc if (!HasAnimation) { - for (i = 0; i < AllJoints.size(); ++i) { - if (AllJoints[i]->Weights.size()) + for (auto *joint : AllJoints) { + if (joint->Weights.size()) { HasAnimation = true; + break; + } } } if (HasAnimation) { - //--- Find the length of the animation --- - EndFrame = 0; - for (i = 0; i < AllJoints.size(); ++i) { - if (AllJoints[i]->UseAnimationFrom) { - if (AllJoints[i]->UseAnimationFrom->PositionKeys.size()) - if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > EndFrame) - EndFrame = AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame; - - if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size()) - if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > EndFrame) - EndFrame = AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame; - - if (AllJoints[i]->UseAnimationFrom->RotationKeys.size()) - if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > EndFrame) - EndFrame = AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame; - } + EndFrame = 0.0f; + for (const auto *joint : AllJoints) { + EndFrame = std::max(EndFrame, joint->keys.getEndFrame()); } } @@ -794,42 +449,40 @@ void SkinnedMesh::checkForAnimation() PreparedForSkinning = true; // check for bugs: - for (i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; + for (auto *joint : AllJoints) { + for (auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; // check for invalid ids if (buffer_id >= LocalBuffers.size()) { os::Printer::log("Skinned Mesh: Weight buffer id too large", ELL_WARNING); - joint->Weights[j].buffer_id = joint->Weights[j].vertex_id = 0; + weight.buffer_id = weight.vertex_id = 0; } else if (vertex_id >= LocalBuffers[buffer_id]->getVertexCount()) { os::Printer::log("Skinned Mesh: Weight vertex id too large", ELL_WARNING); - joint->Weights[j].buffer_id = joint->Weights[j].vertex_id = 0; + weight.buffer_id = weight.vertex_id = 0; } } } // An array used in skinning - for (i = 0; i < Vertices_Moved.size(); ++i) - for (j = 0; j < Vertices_Moved[i].size(); ++j) + for (u32 i = 0; i < Vertices_Moved.size(); ++i) + for (u32 j = 0; j < Vertices_Moved[i].size(); ++j) Vertices_Moved[i][j] = false; // For skinning: cache weight values for speed - for (i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; + for (auto *joint : AllJoints) { + for (auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; - joint->Weights[j].Moved = &Vertices_Moved[buffer_id][vertex_id]; - joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; - joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; + weight.Moved = &Vertices_Moved[buffer_id][vertex_id]; + weight.StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; + weight.StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; - // joint->Weights[j]._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos; + // weight._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos; } } @@ -840,148 +493,52 @@ void SkinnedMesh::checkForAnimation() } //! called by loader after populating with mesh and bone data -void SkinnedMesh::finalize() +SkinnedMesh *SkinnedMeshBuilder::finalize() { os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG); - u32 i; // Make sure we recalc the next frame LastAnimatedFrame = -1; SkinnedLastFrame = false; // calculate bounding box - for (i = 0; i < LocalBuffers.size(); ++i) { - LocalBuffers[i]->recalculateBoundingBox(); + for (auto *buffer : LocalBuffers) { + buffer->recalculateBoundingBox(); } if (AllJoints.size() || RootJoints.size()) { // populate AllJoints or RootJoints, depending on which is empty - if (!RootJoints.size()) { + if (RootJoints.empty()) { - for (u32 CheckingIdx = 0; CheckingIdx < AllJoints.size(); ++CheckingIdx) { + for (auto *joint : AllJoints) { bool foundParent = false; - for (i = 0; i < AllJoints.size(); ++i) { - for (u32 n = 0; n < AllJoints[i]->Children.size(); ++n) { - if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx]) + for (const auto *parentJoint : AllJoints) { + for (const auto *childJoint : parentJoint->Children) { + if (childJoint == joint) foundParent = true; } } if (!foundParent) - RootJoints.push_back(AllJoints[CheckingIdx]); + RootJoints.push_back(joint); } } else { AllJoints = RootJoints; } } - for (i = 0; i < AllJoints.size(); ++i) { - AllJoints[i]->UseAnimationFrom = AllJoints[i]; - } - // Set array sizes... - for (i = 0; i < LocalBuffers.size(); ++i) { - Vertices_Moved.push_back(core::array()); - Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount()); + for (u32 i = 0; i < LocalBuffers.size(); ++i) { + Vertices_Moved.emplace_back(LocalBuffers[i]->getVertexCount()); } checkForAnimation(); if (HasAnimation) { - irr::u32 redundantPosKeys = 0; - irr::u32 unorderedPosKeys = 0; - irr::u32 redundantScaleKeys = 0; - irr::u32 unorderedScaleKeys = 0; - irr::u32 redundantRotationKeys = 0; - irr::u32 unorderedRotationKeys = 0; - - //--- optimize and check keyframes --- - for (i = 0; i < AllJoints.size(); ++i) { - core::array &PositionKeys = AllJoints[i]->PositionKeys; - core::array &ScaleKeys = AllJoints[i]->ScaleKeys; - core::array &RotationKeys = AllJoints[i]->RotationKeys; - - // redundant = identical middle keys - we only need the first and last frame - // unordered = frames which are out of order - we can't handle those - redundantPosKeys += dropMiddleKeys(PositionKeys, identicalPos); - unorderedPosKeys += dropBadKeys(PositionKeys); - redundantScaleKeys += dropMiddleKeys(ScaleKeys, identicalScale); - unorderedScaleKeys += dropBadKeys(ScaleKeys); - redundantRotationKeys += dropMiddleKeys(RotationKeys, identicalRotation); - unorderedRotationKeys += dropBadKeys(RotationKeys); - - // Fill empty keyframe areas - if (PositionKeys.size()) { - SPositionKey *Key; - Key = &PositionKeys[0]; // getFirst - if (Key->frame != 0) { - PositionKeys.push_front(*Key); - Key = &PositionKeys[0]; // getFirst - Key->frame = 0; - } - - Key = &PositionKeys.getLast(); - if (Key->frame != EndFrame) { - PositionKeys.push_back(*Key); - Key = &PositionKeys.getLast(); - Key->frame = EndFrame; - } - } - - if (ScaleKeys.size()) { - SScaleKey *Key; - Key = &ScaleKeys[0]; // getFirst - if (Key->frame != 0) { - ScaleKeys.push_front(*Key); - Key = &ScaleKeys[0]; // getFirst - Key->frame = 0; - } - - Key = &ScaleKeys.getLast(); - if (Key->frame != EndFrame) { - ScaleKeys.push_back(*Key); - Key = &ScaleKeys.getLast(); - Key->frame = EndFrame; - } - } - - if (RotationKeys.size()) { - SRotationKey *Key; - Key = &RotationKeys[0]; // getFirst - if (Key->frame != 0) { - RotationKeys.push_front(*Key); - Key = &RotationKeys[0]; // getFirst - Key->frame = 0; - } - - Key = &RotationKeys.getLast(); - if (Key->frame != EndFrame) { - RotationKeys.push_back(*Key); - Key = &RotationKeys.getLast(); - Key->frame = EndFrame; - } - } - } - - if (redundantPosKeys > 0) { - os::Printer::log("Skinned Mesh - redundant position frames kicked", core::stringc(redundantPosKeys).c_str(), ELL_DEBUG); - } - if (unorderedPosKeys > 0) { - irr::os::Printer::log("Skinned Mesh - unsorted position frames kicked", irr::core::stringc(unorderedPosKeys).c_str(), irr::ELL_DEBUG); - } - if (redundantScaleKeys > 0) { - os::Printer::log("Skinned Mesh - redundant scale frames kicked", core::stringc(redundantScaleKeys).c_str(), ELL_DEBUG); - } - if (unorderedScaleKeys > 0) { - irr::os::Printer::log("Skinned Mesh - unsorted scale frames kicked", irr::core::stringc(unorderedScaleKeys).c_str(), irr::ELL_DEBUG); - } - if (redundantRotationKeys > 0) { - os::Printer::log("Skinned Mesh - redundant rotation frames kicked", core::stringc(redundantRotationKeys).c_str(), ELL_DEBUG); - } - if (unorderedRotationKeys > 0) { - irr::os::Printer::log("Skinned Mesh - unsorted rotation frames kicked", irr::core::stringc(unorderedRotationKeys).c_str(), irr::ELL_DEBUG); + for (auto *joint : AllJoints) { + joint->keys.cleanup(); } } @@ -989,15 +546,11 @@ void SkinnedMesh::finalize() calculateGlobalMatrices(0, 0); - // animateMesh(0, 1); - // buildAllLocalAnimatedMatrices(); - // buildAllGlobalAnimatedMatrices(); - // rigid animation for non animated meshes - for (i = 0; i < AllJoints.size(); ++i) { - for (u32 j = 0; j < AllJoints[i]->AttachedMeshes.size(); ++j) { - SSkinMeshBuffer *Buffer = (*SkinningBuffers)[AllJoints[i]->AttachedMeshes[j]]; - Buffer->Transformation = AllJoints[i]->GlobalAnimatedMatrix; + for (auto *joint : AllJoints) { + for (u32 attachedMeshIdx : joint->AttachedMeshes) { + SSkinMeshBuffer *Buffer = (*SkinningBuffers)[attachedMeshIdx]; + Buffer->Transformation = joint->GlobalAnimatedMatrix; } } @@ -1016,6 +569,8 @@ void SkinnedMesh::finalize() BoundingBox.addInternalBox(bb); } } + + return this; } void SkinnedMesh::updateBoundingBox(void) @@ -1023,21 +578,18 @@ void SkinnedMesh::updateBoundingBox(void) if (!SkinningBuffers) return; - core::array &buffer = *SkinningBuffers; BoundingBox.reset(0, 0, 0); - if (!buffer.empty()) { - for (u32 j = 0; j < buffer.size(); ++j) { - buffer[j]->recalculateBoundingBox(); - core::aabbox3df bb = buffer[j]->BoundingBox; - buffer[j]->Transformation.transformBoxEx(bb); + for (auto *buffer : *SkinningBuffers) { + buffer->recalculateBoundingBox(); + core::aabbox3df bb = buffer->BoundingBox; + buffer->Transformation.transformBoxEx(bb); - BoundingBox.addInternalBox(bb); - } + BoundingBox.addInternalBox(bb); } } -scene::SSkinMeshBuffer *SkinnedMesh::addMeshBuffer() +scene::SSkinMeshBuffer *SkinnedMeshBuilder::addMeshBuffer() { scene::SSkinMeshBuffer *buffer = new scene::SSkinMeshBuffer(); TextureSlots.push_back(LocalBuffers.size()); @@ -1045,13 +597,13 @@ scene::SSkinMeshBuffer *SkinnedMesh::addMeshBuffer() return buffer; } -void SkinnedMesh::addMeshBuffer(SSkinMeshBuffer *meshbuf) +void SkinnedMeshBuilder::addMeshBuffer(SSkinMeshBuffer *meshbuf) { TextureSlots.push_back(LocalBuffers.size()); LocalBuffers.push_back(meshbuf); } -SkinnedMesh::SJoint *SkinnedMesh::addJoint(SJoint *parent) +SkinnedMesh::SJoint *SkinnedMeshBuilder::addJoint(SJoint *parent) { SJoint *joint = new SJoint; @@ -1066,45 +618,31 @@ SkinnedMesh::SJoint *SkinnedMesh::addJoint(SJoint *parent) return joint; } -SkinnedMesh::SPositionKey *SkinnedMesh::addPositionKey(SJoint *joint) +void SkinnedMeshBuilder::addPositionKey(SJoint *joint, f32 frame, core::vector3df pos) { - if (!joint) - return 0; - - joint->PositionKeys.push_back(SPositionKey()); - return &joint->PositionKeys.getLast(); + _IRR_DEBUG_BREAK_IF(!joint); + joint->keys.position.pushBack(frame, pos); } -SkinnedMesh::SScaleKey *SkinnedMesh::addScaleKey(SJoint *joint) +void SkinnedMeshBuilder::addScaleKey(SJoint *joint, f32 frame, core::vector3df scale) { - if (!joint) - return 0; - - joint->ScaleKeys.push_back(SScaleKey()); - return &joint->ScaleKeys.getLast(); + _IRR_DEBUG_BREAK_IF(!joint); + joint->keys.scale.pushBack(frame, scale); } -SkinnedMesh::SRotationKey *SkinnedMesh::addRotationKey(SJoint *joint) +void SkinnedMeshBuilder::addRotationKey(SJoint *joint, f32 frame, core::quaternion rot) { - if (!joint) - return 0; - - joint->RotationKeys.push_back(SRotationKey()); - return &joint->RotationKeys.getLast(); + _IRR_DEBUG_BREAK_IF(!joint); + joint->keys.rotation.pushBack(frame, rot); } -SkinnedMesh::SWeight *SkinnedMesh::addWeight(SJoint *joint) +SkinnedMesh::SWeight *SkinnedMeshBuilder::addWeight(SJoint *joint) { if (!joint) - return 0; + return nullptr; - joint->Weights.push_back(SWeight()); - return &joint->Weights.getLast(); -} - -bool SkinnedMesh::isStatic() const -{ - return !HasAnimation; + joint->Weights.emplace_back(); + return &joint->Weights.back(); } void SkinnedMesh::normalizeWeights() @@ -1113,42 +651,39 @@ void SkinnedMesh::normalizeWeights() // Normalise the weights on bones.... - u32 i, j; - core::array> verticesTotalWeight; + std::vector> verticesTotalWeight; - verticesTotalWeight.reallocate(LocalBuffers.size()); - for (i = 0; i < LocalBuffers.size(); ++i) { - verticesTotalWeight.push_back(core::array()); - verticesTotalWeight[i].set_used(LocalBuffers[i]->getVertexCount()); + verticesTotalWeight.reserve(LocalBuffers.size()); + for (u32 i = 0; i < LocalBuffers.size(); ++i) { + verticesTotalWeight.emplace_back(LocalBuffers[i]->getVertexCount()); } - for (i = 0; i < verticesTotalWeight.size(); ++i) - for (j = 0; j < verticesTotalWeight[i].size(); ++j) + for (u32 i = 0; i < verticesTotalWeight.size(); ++i) + for (u32 j = 0; j < verticesTotalWeight[i].size(); ++j) verticesTotalWeight[i][j] = 0; - for (i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (j = 0; j < joint->Weights.size(); ++j) { - if (joint->Weights[j].strength <= 0) { // Check for invalid weights - joint->Weights.erase(j); - --j; - } else { - verticesTotalWeight[joint->Weights[j].buffer_id][joint->Weights[j].vertex_id] += joint->Weights[j].strength; - } + for (auto *joint : AllJoints) { + auto &weights = joint->Weights; + + weights.erase(std::remove_if(weights.begin(), weights.end(), [](const auto &weight) { + return weight.strength <= 0; + }), weights.end()); + + for (const auto &weight : weights) { + verticesTotalWeight[weight.buffer_id][weight.vertex_id] += weight.strength; } } - for (i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (j = 0; j < joint->Weights.size(); ++j) { - const f32 total = verticesTotalWeight[joint->Weights[j].buffer_id][joint->Weights[j].vertex_id]; + for (auto *joint : AllJoints) { + for (auto &weight : joint->Weights) { + const f32 total = verticesTotalWeight[weight.buffer_id][weight.vertex_id]; if (total != 0 && total != 1) - joint->Weights[j].strength /= total; + weight.strength /= total; } } } -void SkinnedMesh::recoverJointsFromMesh(core::array &jointChildSceneNodes) +void SkinnedMesh::recoverJointsFromMesh(std::vector &jointChildSceneNodes) { for (u32 i = 0; i < AllJoints.size(); ++i) { IBoneSceneNode *node = jointChildSceneNodes[i]; @@ -1157,15 +692,11 @@ void SkinnedMesh::recoverJointsFromMesh(core::array &jointChil node->setRotation(joint->LocalAnimatedMatrix.getRotationDegrees()); node->setScale(joint->LocalAnimatedMatrix.getScale()); - node->positionHint = joint->positionHint; - node->scaleHint = joint->scaleHint; - node->rotationHint = joint->rotationHint; - node->updateAbsolutePosition(); } } -void SkinnedMesh::transferJointsToMesh(const core::array &jointChildSceneNodes) +void SkinnedMesh::transferJointsToMesh(const std::vector &jointChildSceneNodes) { for (u32 i = 0; i < AllJoints.size(); ++i) { const IBoneSceneNode *const node = jointChildSceneNodes[i]; @@ -1175,10 +706,6 @@ void SkinnedMesh::transferJointsToMesh(const core::array &join joint->LocalAnimatedMatrix.setTranslation(node->getPosition()); joint->LocalAnimatedMatrix *= core::matrix4().setScale(node->getScale()); - joint->positionHint = node->positionHint; - joint->scaleHint = node->scaleHint; - joint->rotationHint = node->rotationHint; - joint->GlobalSkinningSpace = (node->getSkinningSpace() == EBSS_GLOBAL); } // Make sure we recalc the next frame @@ -1186,20 +713,7 @@ void SkinnedMesh::transferJointsToMesh(const core::array &join SkinnedLastFrame = false; } -void SkinnedMesh::transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes) -{ - for (u32 i = 0; i < AllJoints.size(); ++i) { - const IBoneSceneNode *const node = jointChildSceneNodes[i]; - SJoint *joint = AllJoints[i]; - - joint->positionHint = node->positionHint; - joint->scaleHint = node->scaleHint; - joint->rotationHint = node->rotationHint; - } - SkinnedLastFrame = false; -} - -void SkinnedMesh::addJoints(core::array &jointChildSceneNodes, +void SkinnedMesh::addJoints(std::vector &jointChildSceneNodes, IAnimatedMeshSceneNode *node, ISceneManager *smgr) { // Create new joints