1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-15 18:57:08 +00:00

Support floating-point animation frame numbers

This commit is contained in:
Lars Mueller 2024-09-02 21:11:08 +02:00 committed by Lars Müller
parent 323fc0a798
commit 06907aa99b
22 changed files with 111 additions and 105 deletions

View file

@ -16,6 +16,7 @@
#include "IAnimatedMesh.h"
#include "IFileSystem.h"
#include "quaternion.h"
#include <algorithm>
namespace irr
{
@ -80,7 +81,7 @@ void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs)
}
if (StartFrame == EndFrame) {
CurrentFrameNr = (f32)StartFrame; // Support for non animated meshes
CurrentFrameNr = StartFrame; // Support for non animated meshes
} else if (Looping) {
// play animation looped
CurrentFrameNr += timeMs * FramesPerSecond;
@ -89,26 +90,26 @@ void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs)
// the last frame must be identical to first one with our current solution.
if (FramesPerSecond > 0.f) { // forwards...
if (CurrentFrameNr > EndFrame)
CurrentFrameNr = StartFrame + fmodf(CurrentFrameNr - StartFrame, (f32)(EndFrame - StartFrame));
CurrentFrameNr = StartFrame + fmodf(CurrentFrameNr - StartFrame, EndFrame - StartFrame);
} else // backwards...
{
if (CurrentFrameNr < StartFrame)
CurrentFrameNr = EndFrame - fmodf(EndFrame - CurrentFrameNr, (f32)(EndFrame - StartFrame));
CurrentFrameNr = EndFrame - fmodf(EndFrame - CurrentFrameNr, EndFrame - StartFrame);
}
} else {
// play animation non looped
CurrentFrameNr += timeMs * FramesPerSecond;
if (FramesPerSecond > 0.f) { // forwards...
if (CurrentFrameNr > (f32)EndFrame) {
CurrentFrameNr = (f32)EndFrame;
if (CurrentFrameNr > EndFrame) {
CurrentFrameNr = EndFrame;
if (LoopCallBack)
LoopCallBack->OnAnimationEnd(this);
}
} else // backwards...
{
if (CurrentFrameNr < (f32)StartFrame) {
CurrentFrameNr = (f32)StartFrame;
if (CurrentFrameNr < StartFrame) {
CurrentFrameNr = StartFrame;
if (LoopCallBack)
LoopCallBack->OnAnimationEnd(this);
}
@ -159,9 +160,7 @@ void CAnimatedMeshSceneNode::OnRegisterSceneNode()
IMesh *CAnimatedMeshSceneNode::getMeshForCurrentFrame()
{
if (Mesh->getMeshType() != EAMT_SKINNED) {
s32 frameNr = (s32)getFrameNr();
s32 frameBlend = (s32)(core::fract(getFrameNr()) * 1000.f);
return Mesh->getMesh(frameNr, frameBlend, StartFrame, EndFrame);
return Mesh->getMesh(getFrameNr());
} else {
// As multiple scene nodes may be sharing the same skinned mesh, we have to
// re-animate it every frame to ensure that this node gets the mesh that it needs.
@ -331,33 +330,33 @@ void CAnimatedMeshSceneNode::render()
}
//! Returns the current start frame number.
s32 CAnimatedMeshSceneNode::getStartFrame() const
f32 CAnimatedMeshSceneNode::getStartFrame() const
{
return StartFrame;
}
//! Returns the current start frame number.
s32 CAnimatedMeshSceneNode::getEndFrame() const
f32 CAnimatedMeshSceneNode::getEndFrame() const
{
return EndFrame;
}
//! sets the frames between the animation is looped.
//! the default is 0 - MaximalFrameCount of the mesh.
bool CAnimatedMeshSceneNode::setFrameLoop(s32 begin, s32 end)
bool CAnimatedMeshSceneNode::setFrameLoop(f32 begin, f32 end)
{
const s32 maxFrameCount = Mesh->getFrameCount() - 1;
const f32 maxFrame = Mesh->getMaxFrameNumber();
if (end < begin) {
StartFrame = core::s32_clamp(end, 0, maxFrameCount);
EndFrame = core::s32_clamp(begin, StartFrame, maxFrameCount);
StartFrame = std::clamp<f32>(end, 0, maxFrame);
EndFrame = std::clamp<f32>(begin, StartFrame, maxFrame);
} else {
StartFrame = core::s32_clamp(begin, 0, maxFrameCount);
EndFrame = core::s32_clamp(end, StartFrame, maxFrameCount);
StartFrame = std::clamp<f32>(begin, 0, maxFrame);
EndFrame = std::clamp<f32>(end, StartFrame, maxFrame);
}
if (FramesPerSecond < 0)
setCurrentFrame((f32)EndFrame);
setCurrentFrame(EndFrame);
else
setCurrentFrame((f32)StartFrame);
setCurrentFrame(StartFrame);
return true;
}
@ -532,7 +531,7 @@ void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh *mesh)
// get materials and bounding box
Box = Mesh->getBoundingBox();
IMesh *m = Mesh->getMesh(0, 0);
IMesh *m = Mesh->getMesh(0);
if (m) {
Materials.clear();
Materials.reallocate(m->getMeshBufferCount());
@ -554,7 +553,7 @@ void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh *mesh)
// 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.
setFrameLoop(0, Mesh->getFrameCount() - 1);
setFrameLoop(0, Mesh->getMaxFrameNumber());
}
//! updates the absolute position based on the relative and the parents position

View file

@ -45,7 +45,7 @@ public:
//! sets the frames between the animation is looped.
//! the default is 0 - MaximalFrameCount of the mesh.
//! NOTE: setMesh will also change this value and set it to the full range of animations of the mesh
bool setFrameLoop(s32 begin, s32 end) override;
bool setFrameLoop(f32 begin, f32 end) override;
//! Sets looping mode which is on by default. If set to false,
//! animations will not be looped.
@ -93,9 +93,9 @@ public:
//! Returns the current displayed frame number.
f32 getFrameNr() const override;
//! Returns the current start frame number.
s32 getStartFrame() const override;
f32 getStartFrame() const override;
//! Returns the current end frame number.
s32 getEndFrame() const override;
f32 getEndFrame() const override;
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
@ -148,8 +148,8 @@ private:
core::aabbox3d<f32> Box;
IAnimatedMesh *Mesh;
s32 StartFrame;
s32 EndFrame;
f32 StartFrame;
f32 EndFrame;
f32 FramesPerSecond;
f32 CurrentFrameNr;

View file

@ -193,7 +193,7 @@ s32 CMeshManipulator::getPolyCount(scene::IMesh *mesh) const
//! Returns amount of polygons in mesh.
s32 CMeshManipulator::getPolyCount(scene::IAnimatedMesh *mesh) const
{
if (mesh && mesh->getFrameCount() != 0)
if (mesh && mesh->getMaxFrameNumber() != 0)
return getPolyCount(mesh->getMesh(0));
return 0;

View file

@ -111,11 +111,9 @@ CSkinnedMesh::~CSkinnedMesh()
}
}
//! returns the amount of frames in milliseconds.
//! If the amount is 1, it is a static (=non animated) mesh.
u32 CSkinnedMesh::getFrameCount() const
f32 CSkinnedMesh::getMaxFrameNumber() const
{
return core::floor32(EndFrame + 1.f);
return EndFrame;
}
//! Gets the default animation speed of the animated mesh.
@ -133,14 +131,14 @@ void CSkinnedMesh::setAnimationSpeed(f32 fps)
FramesPerSecond = fps;
}
//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
IMesh *CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
//! returns the animated mesh based
IMesh *CSkinnedMesh::getMesh(f32 frame)
{
// animate(frame,startFrameLoop, endFrameLoop);
if (frame == -1)
return this;
animateMesh((f32)frame, 1.0f);
animateMesh(frame, 1.0f);
skinMesh();
return this;
}

View file

@ -27,8 +27,8 @@ public:
//! destructor
virtual ~CSkinnedMesh();
//! returns the amount of frames. If the amount is 1, it is a static (=non animated) mesh.
u32 getFrameCount() const override;
//! If the duration is 0, it is a static (=non animated) mesh.
f32 getMaxFrameNumber() const override;
//! Gets the default animation speed of the animated mesh.
/** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */
@ -39,8 +39,8 @@ public:
The actual speed is set in the scene node the mesh is instantiated in.*/
void setAnimationSpeed(f32 fps) override;
//! returns the animated mesh based on a detail level (which is ignored)
IMesh *getMesh(s32 frame, s32 detailLevel = 255, s32 startFrameLoop = -1, s32 endFrameLoop = -1) override;
//! 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}