Commit 125e73ef authored by cutealien's avatar cutealien

Fix skinned meshes not playing their last frame.

Also clarified animation documentation to describe current behavior more exactly.
CSkinnedMesh had returned the last key instead of the number of keys.
Thx to whoever mentioned to me once that our example dwarf is not playing his full animation in the meshviewer.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@5118 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 44e73315
-------------------------- --------------------------
Changes in 1.9 (not yet released) Changes in 1.9 (not yet released)
- Fix skinned meshes not playing their last frame. Also clarified animation documentation to describe current behavior more exactly.
- Add IWriteFile::flush interface (thx @ JLouisB for the patch). - Add IWriteFile::flush interface (thx @ JLouisB for the patch).
- CLightSceneNode::updateAbsolutePosition does now light recalculations. This is to fix using animators with lights. - CLightSceneNode::updateAbsolutePosition does now light recalculations. This is to fix using animators with lights.
- Fix collada export for objects with rotations around more than 1 axis. - Fix collada export for objects with rotations around more than 1 axis.
......
...@@ -22,8 +22,9 @@ namespace scene ...@@ -22,8 +22,9 @@ namespace scene
public: public:
//! Gets the frame count of the animated mesh. //! Gets the frame count of the animated mesh.
/** \return The amount of frames. If the amount is 1, /** Note that the play-time is usually getFrameCount()-1 as it stops as soon as the last frame-key is reached.
it is a static, non animated mesh. */ \return The amount of frames. If the amount is 1,
it is a static, non animated mesh. */
virtual u32 getFrameCount() const = 0; virtual u32 getFrameCount() const = 0;
//! Gets the animation speed of the animated mesh. //! Gets the animation speed of the animated mesh.
......
...@@ -72,7 +72,11 @@ namespace scene ...@@ -72,7 +72,11 @@ namespace scene
virtual void setCurrentFrame(f32 frame) = 0; virtual void setCurrentFrame(f32 frame) = 0;
//! Sets the frame numbers between the animation is looped. //! Sets the frame numbers between the animation is looped.
/** The default is 0 - MaximalFrameCount of the mesh. /** The default is 0 to getFrameCount()-1 of the mesh.
Number of played frames is end-start.
It interpolates toward the last frame but stops when it is reached.
It does not interpolate back to start even when looping.
Looping animations should ensure last and first frame-key are identical.
\param begin: Start frame number of the loop. \param begin: Start frame number of the loop.
\param end: End frame number of the loop. \param end: End frame number of the loop.
\return True if successful, false if not. */ \return True if successful, false if not. */
......
...@@ -850,7 +850,7 @@ void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh* mesh) ...@@ -850,7 +850,7 @@ void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh* mesh)
// get start and begin time // get start and begin time
setAnimationSpeed(Mesh->getAnimationSpeed()); // NOTE: This had been commented out (but not removed!) in r3526. Which caused meshloader-values for speed to be ignored unless users specified explicitly. Missing a test-case where this could go wrong so I put the code back in. setAnimationSpeed(Mesh->getAnimationSpeed()); // NOTE: This had been commented out (but not removed!) in r3526. Which caused meshloader-values for speed to be ignored unless users specified explicitly. Missing a test-case where this could go wrong so I put the code back in.
setFrameLoop(0, Mesh->getFrameCount()); setFrameLoop(0, Mesh->getFrameCount()-1);
} }
......
...@@ -23,7 +23,7 @@ namespace ...@@ -23,7 +23,7 @@ namespace
irr::u32 n=1; // new index irr::u32 n=1; // new index
for(irr::u32 j=1;j<array.size();++j) for(irr::u32 j=1;j<array.size();++j)
{ {
if (array[j].frame < array[n-1].frame) if (array[j].frame < array[n-1].frame)
continue; //bad frame, unneeded and may cause problems continue; //bad frame, unneeded and may cause problems
if ( n != j ) if ( n != j )
array[n] = array[j]; array[n] = array[j];
...@@ -36,7 +36,7 @@ namespace ...@@ -36,7 +36,7 @@ namespace
} }
return d; return d;
} }
// drop identical middle keys - we only need the first and last // drop identical middle keys - we only need the first and last
// return number of kicked keys // return number of kicked keys
template <class T, typename Cmp> // Cmp = comparison for keys of type T template <class T, typename Cmp> // Cmp = comparison for keys of type T
...@@ -55,7 +55,7 @@ namespace ...@@ -55,7 +55,7 @@ namespace
if ( j > s+1 ) // had there been identical keys? if ( j > s+1 ) // had there been identical keys?
array[n++] = array[j-1]; // keep the last array[n++] = array[j-1]; // keep the last
array[n++] = array[j]; // keep the new one array[n++] = array[j]; // keep the new one
s = j; s = j;
} }
if ( array.size() > s+1 ) // identical keys at the array end? if ( array.size() > s+1 ) // identical keys at the array end?
array[n++] = array[array.size()-1]; // keep the last array[n++] = array[array.size()-1]; // keep the last
...@@ -67,21 +67,21 @@ namespace ...@@ -67,21 +67,21 @@ namespace
} }
return d; return d;
} }
bool identicalPos(const irr::scene::ISkinnedMesh::SPositionKey& a, const irr::scene::ISkinnedMesh::SPositionKey& b) bool identicalPos(const irr::scene::ISkinnedMesh::SPositionKey& a, const irr::scene::ISkinnedMesh::SPositionKey& b)
{ {
return a.position == b.position; return a.position == b.position;
} }
bool identicalScale(const irr::scene::ISkinnedMesh::SScaleKey& a, const irr::scene::ISkinnedMesh::SScaleKey& b) bool identicalScale(const irr::scene::ISkinnedMesh::SScaleKey& a, const irr::scene::ISkinnedMesh::SScaleKey& b)
{ {
return a.scale == b.scale; return a.scale == b.scale;
} }
bool identicalRotation(const irr::scene::ISkinnedMesh::SRotationKey& a, const irr::scene::ISkinnedMesh::SRotationKey& b) bool identicalRotation(const irr::scene::ISkinnedMesh::SRotationKey& a, const irr::scene::ISkinnedMesh::SRotationKey& b)
{ {
return a.rotation == b.rotation; return a.rotation == b.rotation;
} }
}; };
namespace irr namespace irr
...@@ -92,7 +92,7 @@ namespace scene ...@@ -92,7 +92,7 @@ namespace scene
//! constructor //! constructor
CSkinnedMesh::CSkinnedMesh() CSkinnedMesh::CSkinnedMesh()
: SkinningBuffers(0), AnimationFrames(0.f), FramesPerSecond(25.f), : SkinningBuffers(0), EndFrame(0.f), FramesPerSecond(25.f),
LastAnimatedFrame(-1), SkinnedLastFrame(false), LastAnimatedFrame(-1), SkinnedLastFrame(false),
InterpolationMode(EIM_LINEAR), InterpolationMode(EIM_LINEAR),
HasAnimation(false), PreparedForSkinning(false), HasAnimation(false), PreparedForSkinning(false),
...@@ -124,7 +124,7 @@ CSkinnedMesh::~CSkinnedMesh() ...@@ -124,7 +124,7 @@ CSkinnedMesh::~CSkinnedMesh()
//! If the amount is 1, it is a static (=non animated) mesh. //! If the amount is 1, it is a static (=non animated) mesh.
u32 CSkinnedMesh::getFrameCount() const u32 CSkinnedMesh::getFrameCount() const
{ {
return core::floor32(AnimationFrames); return core::floor32(EndFrame+1.f);
} }
...@@ -878,22 +878,22 @@ void CSkinnedMesh::checkForAnimation() ...@@ -878,22 +878,22 @@ void CSkinnedMesh::checkForAnimation()
if (HasAnimation) if (HasAnimation)
{ {
//--- Find the length of the animation --- //--- Find the length of the animation ---
AnimationFrames=0; EndFrame=0;
for(i=0;i<AllJoints.size();++i) for(i=0;i<AllJoints.size();++i)
{ {
if (AllJoints[i]->UseAnimationFrom) if (AllJoints[i]->UseAnimationFrom)
{ {
if (AllJoints[i]->UseAnimationFrom->PositionKeys.size()) if (AllJoints[i]->UseAnimationFrom->PositionKeys.size())
if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > AnimationFrames) if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > EndFrame)
AnimationFrames=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame; EndFrame=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame;
if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size()) if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size())
if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > AnimationFrames) if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > EndFrame)
AnimationFrames=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame; EndFrame=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame;
if (AllJoints[i]->UseAnimationFrom->RotationKeys.size()) if (AllJoints[i]->UseAnimationFrom->RotationKeys.size())
if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > AnimationFrames) if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > EndFrame)
AnimationFrames=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame; EndFrame=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame;
} }
} }
} }
...@@ -958,7 +958,7 @@ void CSkinnedMesh::checkForAnimation() ...@@ -958,7 +958,7 @@ void CSkinnedMesh::checkForAnimation()
//! called by loader after populating with mesh and bone data //! called by loader after populating with mesh and bone data
void CSkinnedMesh::finalize() void CSkinnedMesh::finalize()
{ {
os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG); os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG);
u32 i; u32 i;
// Make sure we recalc the next frame // Make sure we recalc the next frame
...@@ -1023,7 +1023,7 @@ void CSkinnedMesh::finalize() ...@@ -1023,7 +1023,7 @@ void CSkinnedMesh::finalize()
irr::u32 unorderedScaleKeys = 0; irr::u32 unorderedScaleKeys = 0;
irr::u32 redundantRotationKeys = 0; irr::u32 redundantRotationKeys = 0;
irr::u32 unorderedRotationKeys = 0; irr::u32 unorderedRotationKeys = 0;
//--- optimize and check keyframes --- //--- optimize and check keyframes ---
for(i=0;i<AllJoints.size();++i) for(i=0;i<AllJoints.size();++i)
{ {
...@@ -1053,11 +1053,11 @@ void CSkinnedMesh::finalize() ...@@ -1053,11 +1053,11 @@ void CSkinnedMesh::finalize()
} }
Key=&PositionKeys.getLast(); Key=&PositionKeys.getLast();
if (Key->frame!=AnimationFrames) if (Key->frame!=EndFrame)
{ {
PositionKeys.push_back(*Key); PositionKeys.push_back(*Key);
Key=&PositionKeys.getLast(); Key=&PositionKeys.getLast();
Key->frame=AnimationFrames; Key->frame=EndFrame;
} }
} }
...@@ -1073,11 +1073,11 @@ void CSkinnedMesh::finalize() ...@@ -1073,11 +1073,11 @@ void CSkinnedMesh::finalize()
} }
Key=&ScaleKeys.getLast(); Key=&ScaleKeys.getLast();
if (Key->frame!=AnimationFrames) if (Key->frame!=EndFrame)
{ {
ScaleKeys.push_back(*Key); ScaleKeys.push_back(*Key);
Key=&ScaleKeys.getLast(); Key=&ScaleKeys.getLast();
Key->frame=AnimationFrames; Key->frame=EndFrame;
} }
} }
...@@ -1093,11 +1093,11 @@ void CSkinnedMesh::finalize() ...@@ -1093,11 +1093,11 @@ void CSkinnedMesh::finalize()
} }
Key=&RotationKeys.getLast(); Key=&RotationKeys.getLast();
if (Key->frame!=AnimationFrames) if (Key->frame!=EndFrame)
{ {
RotationKeys.push_back(*Key); RotationKeys.push_back(*Key);
Key=&RotationKeys.getLast(); Key=&RotationKeys.getLast();
Key->frame=AnimationFrames; Key->frame=EndFrame;
} }
} }
} }
...@@ -1108,7 +1108,7 @@ void CSkinnedMesh::finalize() ...@@ -1108,7 +1108,7 @@ void CSkinnedMesh::finalize()
} }
if ( unorderedPosKeys > 0 ) if ( unorderedPosKeys > 0 )
{ {
irr::os::Printer::log("Skinned Mesh - unsorted position frames kicked:", irr::core::stringc(unorderedPosKeys).c_str(), irr::ELL_DEBUG); irr::os::Printer::log("Skinned Mesh - unsorted position frames kicked:", irr::core::stringc(unorderedPosKeys).c_str(), irr::ELL_DEBUG);
} }
if ( redundantScaleKeys > 0 ) if ( redundantScaleKeys > 0 )
{ {
......
...@@ -194,7 +194,7 @@ private: ...@@ -194,7 +194,7 @@ private:
core::aabbox3d<f32> BoundingBox; core::aabbox3d<f32> BoundingBox;
f32 AnimationFrames; f32 EndFrame;
f32 FramesPerSecond; f32 FramesPerSecond;
f32 LastAnimatedFrame; f32 LastAnimatedFrame;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment