mirror of
https://github.com/minetest/minetest.git
synced 2024-11-20 14:43:45 +01:00
Support floating-point animation frame numbers
This commit is contained in:
parent
323fc0a798
commit
06907aa99b
@ -8059,8 +8059,7 @@ child will follow movement and rotation of that bone.
|
|||||||
* Animation interpolates towards the end frame but stops when it is reached
|
* Animation interpolates towards the end frame but stops when it is reached
|
||||||
* If looped, there is no interpolation back to the start frame
|
* If looped, there is no interpolation back to the start frame
|
||||||
* If looped, the model should look identical at start and end
|
* If looped, the model should look identical at start and end
|
||||||
* Only integer numbers are supported
|
* default: `{x=1.0, y=1.0}`
|
||||||
* default: `{x=1, y=1}`
|
|
||||||
* `frame_speed`: How fast the animation plays, in frames per second (number)
|
* `frame_speed`: How fast the animation plays, in frames per second (number)
|
||||||
* default: `15.0`
|
* default: `15.0`
|
||||||
* `frame_blend`: number, default: `0.0`
|
* `frame_blend`: number, default: `0.0`
|
||||||
|
@ -55,10 +55,20 @@ minetest.register_entity("gltf:simple_skin", {
|
|||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Note: Model has an animation, but we can use it as a static test nevertheless
|
|
||||||
-- The claws rendering incorrectly from one side is expected behavior:
|
-- The claws rendering incorrectly from one side is expected behavior:
|
||||||
-- They use an unsupported double-sided material.
|
-- They use an unsupported double-sided material.
|
||||||
register_entity("frog", {"gltf_frog.png"}, false)
|
minetest.register_entity("gltf:frog", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "mesh",
|
||||||
|
mesh = "gltf_frog.gltf",
|
||||||
|
textures = {"gltf_frog.png"},
|
||||||
|
backface_culling = false
|
||||||
|
},
|
||||||
|
on_activate = function(self)
|
||||||
|
self.object:set_animation({x = 0, y = 0.75}, 1)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
minetest.register_node("gltf:frog", {
|
minetest.register_node("gltf:frog", {
|
||||||
description = "glTF frog, but it's a node",
|
description = "glTF frog, but it's a node",
|
||||||
|
@ -19,11 +19,8 @@ irr::scene::SMeshBuffer etc. */
|
|||||||
class IAnimatedMesh : public IMesh
|
class IAnimatedMesh : public IMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//! Gets the frame count of the animated mesh.
|
//! Gets the maximum frame number, 0 if the mesh is static.
|
||||||
/** Note that the play-time is usually getFrameCount()-1 as it stops as soon as the last frame-key is reached.
|
virtual f32 getMaxFrameNumber() const = 0;
|
||||||
\return The amount of frames. If the amount is 1,
|
|
||||||
it is a static, non animated mesh. */
|
|
||||||
virtual u32 getFrameCount() const = 0;
|
|
||||||
|
|
||||||
//! Gets the animation speed of the animated mesh.
|
//! Gets the animation speed of the animated mesh.
|
||||||
/** \return The number of frames per second to play the
|
/** \return The number of frames per second to play the
|
||||||
@ -39,19 +36,10 @@ public:
|
|||||||
virtual void setAnimationSpeed(f32 fps) = 0;
|
virtual void setAnimationSpeed(f32 fps) = 0;
|
||||||
|
|
||||||
//! Returns the IMesh interface for a frame.
|
//! Returns the IMesh interface for a frame.
|
||||||
/** \param frame: Frame number as zero based index. The maximum
|
/** \param frame: Frame number, >= 0, <= getMaxFrameNumber()
|
||||||
frame number is getFrameCount() - 1;
|
Linear interpolation is used if this is between two frames.
|
||||||
\param detailLevel: Level of detail. 0 is the lowest, 255 the
|
\return Returns the animated mesh for the given frame */
|
||||||
highest level of detail. Most meshes will ignore the detail level.
|
virtual IMesh *getMesh(f32 frame) = 0;
|
||||||
\param startFrameLoop: Because some animated meshes (.MD2) are
|
|
||||||
blended between 2 static frames, and maybe animated in a loop,
|
|
||||||
the startFrameLoop and the endFrameLoop have to be defined, to
|
|
||||||
prevent the animation to be blended between frames which are
|
|
||||||
outside of this loop.
|
|
||||||
If startFrameLoop and endFrameLoop are both -1, they are ignored.
|
|
||||||
\param endFrameLoop: see startFrameLoop.
|
|
||||||
\return Returns the animated mesh based on a detail level. */
|
|
||||||
virtual IMesh *getMesh(s32 frame, s32 detailLevel = 255, s32 startFrameLoop = -1, s32 endFrameLoop = -1) = 0;
|
|
||||||
|
|
||||||
//! Returns the type of the animated mesh.
|
//! Returns the type of the animated mesh.
|
||||||
/** In most cases it is not necessary to use this method.
|
/** In most cases it is not necessary to use this method.
|
||||||
|
@ -63,7 +63,7 @@ public:
|
|||||||
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 to getFrameCount()-1 of the mesh.
|
/** The default is 0 to getMaxFrameNumber() of the mesh.
|
||||||
Number of played frames is end-start.
|
Number of played frames is end-start.
|
||||||
It interpolates toward the last frame but stops when it is reached.
|
It interpolates toward the last frame but stops when it is reached.
|
||||||
It does not interpolate back to start even when looping.
|
It does not interpolate back to start even when looping.
|
||||||
@ -71,7 +71,7 @@ public:
|
|||||||
\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. */
|
||||||
virtual bool setFrameLoop(s32 begin, s32 end) = 0;
|
virtual bool setFrameLoop(f32 begin, f32 end) = 0;
|
||||||
|
|
||||||
//! Sets the speed with which the animation is played.
|
//! Sets the speed with which the animation is played.
|
||||||
/** \param framesPerSecond: Frames per second played. */
|
/** \param framesPerSecond: Frames per second played. */
|
||||||
@ -108,9 +108,9 @@ public:
|
|||||||
//! Returns the currently displayed frame number.
|
//! Returns the currently displayed frame number.
|
||||||
virtual f32 getFrameNr() const = 0;
|
virtual f32 getFrameNr() const = 0;
|
||||||
//! Returns the current start frame number.
|
//! Returns the current start frame number.
|
||||||
virtual s32 getStartFrame() const = 0;
|
virtual f32 getStartFrame() const = 0;
|
||||||
//! Returns the current end frame number.
|
//! Returns the current end frame number.
|
||||||
virtual s32 getEndFrame() const = 0;
|
virtual f32 getEndFrame() const = 0;
|
||||||
|
|
||||||
//! Sets looping mode which is on by default.
|
//! Sets looping mode which is on by default.
|
||||||
/** If set to false, animations will not be played looped. */
|
/** If set to false, animations will not be played looped. */
|
||||||
|
@ -36,11 +36,9 @@ struct SAnimatedMesh final : public IAnimatedMesh
|
|||||||
mesh->drop();
|
mesh->drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the frame count of the animated mesh.
|
f32 getMaxFrameNumber() const override
|
||||||
/** \return Amount of frames. If the amount is 1, it is a static, non animated mesh. */
|
|
||||||
u32 getFrameCount() const override
|
|
||||||
{
|
{
|
||||||
return static_cast<u32>(Meshes.size());
|
return static_cast<f32>(Meshes.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the default animation speed of the animated mesh.
|
//! Gets the default animation speed of the animated mesh.
|
||||||
@ -59,19 +57,14 @@ struct SAnimatedMesh final : public IAnimatedMesh
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Returns the IMesh interface for a frame.
|
//! Returns the IMesh interface for a frame.
|
||||||
/** \param frame: Frame number as zero based index. The maximum frame number is
|
/** \param frame: Frame number as zero based index.
|
||||||
getFrameCount() - 1;
|
\return The animated mesh based for the given frame */
|
||||||
\param detailLevel: Level of detail. 0 is the lowest,
|
IMesh *getMesh(f32 frame) override
|
||||||
255 the highest level of detail. Most meshes will ignore the detail level.
|
|
||||||
\param startFrameLoop: start frame
|
|
||||||
\param endFrameLoop: end frame
|
|
||||||
\return The animated mesh based on a detail level. */
|
|
||||||
IMesh *getMesh(s32 frame, s32 detailLevel = 255, s32 startFrameLoop = -1, s32 endFrameLoop = -1) override
|
|
||||||
{
|
{
|
||||||
if (Meshes.empty())
|
if (Meshes.empty())
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
return Meshes[frame];
|
return Meshes[static_cast<s32>(frame)];
|
||||||
}
|
}
|
||||||
|
|
||||||
//! adds a Mesh
|
//! adds a Mesh
|
||||||
|
@ -38,6 +38,12 @@ public:
|
|||||||
explicit constexpr vector2d(const std::array<T, 2> &arr) :
|
explicit constexpr vector2d(const std::array<T, 2> &arr) :
|
||||||
X(arr[0]), Y(arr[1]) {}
|
X(arr[0]), Y(arr[1]) {}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
constexpr static vector2d<T> from(const vector2d<U> &other)
|
||||||
|
{
|
||||||
|
return {static_cast<T>(other.X), static_cast<T>(other.Y)};
|
||||||
|
}
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
|
|
||||||
vector2d<T> operator-() const { return vector2d<T>(-X, -Y); }
|
vector2d<T> operator-() const { return vector2d<T>(-X, -Y); }
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "IAnimatedMesh.h"
|
#include "IAnimatedMesh.h"
|
||||||
#include "IFileSystem.h"
|
#include "IFileSystem.h"
|
||||||
#include "quaternion.h"
|
#include "quaternion.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
@ -80,7 +81,7 @@ void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (StartFrame == EndFrame) {
|
if (StartFrame == EndFrame) {
|
||||||
CurrentFrameNr = (f32)StartFrame; // Support for non animated meshes
|
CurrentFrameNr = StartFrame; // Support for non animated meshes
|
||||||
} else if (Looping) {
|
} else if (Looping) {
|
||||||
// play animation looped
|
// play animation looped
|
||||||
CurrentFrameNr += timeMs * FramesPerSecond;
|
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.
|
// the last frame must be identical to first one with our current solution.
|
||||||
if (FramesPerSecond > 0.f) { // forwards...
|
if (FramesPerSecond > 0.f) { // forwards...
|
||||||
if (CurrentFrameNr > EndFrame)
|
if (CurrentFrameNr > EndFrame)
|
||||||
CurrentFrameNr = StartFrame + fmodf(CurrentFrameNr - StartFrame, (f32)(EndFrame - StartFrame));
|
CurrentFrameNr = StartFrame + fmodf(CurrentFrameNr - StartFrame, EndFrame - StartFrame);
|
||||||
} else // backwards...
|
} else // backwards...
|
||||||
{
|
{
|
||||||
if (CurrentFrameNr < StartFrame)
|
if (CurrentFrameNr < StartFrame)
|
||||||
CurrentFrameNr = EndFrame - fmodf(EndFrame - CurrentFrameNr, (f32)(EndFrame - StartFrame));
|
CurrentFrameNr = EndFrame - fmodf(EndFrame - CurrentFrameNr, EndFrame - StartFrame);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// play animation non looped
|
// play animation non looped
|
||||||
|
|
||||||
CurrentFrameNr += timeMs * FramesPerSecond;
|
CurrentFrameNr += timeMs * FramesPerSecond;
|
||||||
if (FramesPerSecond > 0.f) { // forwards...
|
if (FramesPerSecond > 0.f) { // forwards...
|
||||||
if (CurrentFrameNr > (f32)EndFrame) {
|
if (CurrentFrameNr > EndFrame) {
|
||||||
CurrentFrameNr = (f32)EndFrame;
|
CurrentFrameNr = EndFrame;
|
||||||
if (LoopCallBack)
|
if (LoopCallBack)
|
||||||
LoopCallBack->OnAnimationEnd(this);
|
LoopCallBack->OnAnimationEnd(this);
|
||||||
}
|
}
|
||||||
} else // backwards...
|
} else // backwards...
|
||||||
{
|
{
|
||||||
if (CurrentFrameNr < (f32)StartFrame) {
|
if (CurrentFrameNr < StartFrame) {
|
||||||
CurrentFrameNr = (f32)StartFrame;
|
CurrentFrameNr = StartFrame;
|
||||||
if (LoopCallBack)
|
if (LoopCallBack)
|
||||||
LoopCallBack->OnAnimationEnd(this);
|
LoopCallBack->OnAnimationEnd(this);
|
||||||
}
|
}
|
||||||
@ -159,9 +160,7 @@ void CAnimatedMeshSceneNode::OnRegisterSceneNode()
|
|||||||
IMesh *CAnimatedMeshSceneNode::getMeshForCurrentFrame()
|
IMesh *CAnimatedMeshSceneNode::getMeshForCurrentFrame()
|
||||||
{
|
{
|
||||||
if (Mesh->getMeshType() != EAMT_SKINNED) {
|
if (Mesh->getMeshType() != EAMT_SKINNED) {
|
||||||
s32 frameNr = (s32)getFrameNr();
|
return Mesh->getMesh(getFrameNr());
|
||||||
s32 frameBlend = (s32)(core::fract(getFrameNr()) * 1000.f);
|
|
||||||
return Mesh->getMesh(frameNr, frameBlend, StartFrame, EndFrame);
|
|
||||||
} else {
|
} else {
|
||||||
// As multiple scene nodes may be sharing the same skinned mesh, we have to
|
// 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.
|
// 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.
|
//! Returns the current start frame number.
|
||||||
s32 CAnimatedMeshSceneNode::getStartFrame() const
|
f32 CAnimatedMeshSceneNode::getStartFrame() const
|
||||||
{
|
{
|
||||||
return StartFrame;
|
return StartFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns the current start frame number.
|
//! Returns the current start frame number.
|
||||||
s32 CAnimatedMeshSceneNode::getEndFrame() const
|
f32 CAnimatedMeshSceneNode::getEndFrame() const
|
||||||
{
|
{
|
||||||
return EndFrame;
|
return EndFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! sets the frames between the animation is looped.
|
//! sets the frames between the animation is looped.
|
||||||
//! the default is 0 - MaximalFrameCount of the mesh.
|
//! 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) {
|
if (end < begin) {
|
||||||
StartFrame = core::s32_clamp(end, 0, maxFrameCount);
|
StartFrame = std::clamp<f32>(end, 0, maxFrame);
|
||||||
EndFrame = core::s32_clamp(begin, StartFrame, maxFrameCount);
|
EndFrame = std::clamp<f32>(begin, StartFrame, maxFrame);
|
||||||
} else {
|
} else {
|
||||||
StartFrame = core::s32_clamp(begin, 0, maxFrameCount);
|
StartFrame = std::clamp<f32>(begin, 0, maxFrame);
|
||||||
EndFrame = core::s32_clamp(end, StartFrame, maxFrameCount);
|
EndFrame = std::clamp<f32>(end, StartFrame, maxFrame);
|
||||||
}
|
}
|
||||||
if (FramesPerSecond < 0)
|
if (FramesPerSecond < 0)
|
||||||
setCurrentFrame((f32)EndFrame);
|
setCurrentFrame(EndFrame);
|
||||||
else
|
else
|
||||||
setCurrentFrame((f32)StartFrame);
|
setCurrentFrame(StartFrame);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -532,7 +531,7 @@ void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh *mesh)
|
|||||||
// get materials and bounding box
|
// get materials and bounding box
|
||||||
Box = Mesh->getBoundingBox();
|
Box = Mesh->getBoundingBox();
|
||||||
|
|
||||||
IMesh *m = Mesh->getMesh(0, 0);
|
IMesh *m = Mesh->getMesh(0);
|
||||||
if (m) {
|
if (m) {
|
||||||
Materials.clear();
|
Materials.clear();
|
||||||
Materials.reallocate(m->getMeshBufferCount());
|
Materials.reallocate(m->getMeshBufferCount());
|
||||||
@ -554,7 +553,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() - 1);
|
setFrameLoop(0, Mesh->getMaxFrameNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
//! updates the absolute position based on the relative and the parents position
|
//! updates the absolute position based on the relative and the parents position
|
||||||
|
@ -45,7 +45,7 @@ public:
|
|||||||
//! sets the frames between the animation is looped.
|
//! sets the frames between the animation is looped.
|
||||||
//! the default is 0 - MaximalFrameCount of the mesh.
|
//! 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
|
//! 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,
|
//! Sets looping mode which is on by default. If set to false,
|
||||||
//! animations will not be looped.
|
//! animations will not be looped.
|
||||||
@ -93,9 +93,9 @@ public:
|
|||||||
//! Returns the current displayed frame number.
|
//! Returns the current displayed frame number.
|
||||||
f32 getFrameNr() const override;
|
f32 getFrameNr() const override;
|
||||||
//! Returns the current start frame number.
|
//! Returns the current start frame number.
|
||||||
s32 getStartFrame() const override;
|
f32 getStartFrame() const override;
|
||||||
//! Returns the current end frame number.
|
//! 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.
|
//! 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
|
/* 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;
|
core::aabbox3d<f32> Box;
|
||||||
IAnimatedMesh *Mesh;
|
IAnimatedMesh *Mesh;
|
||||||
|
|
||||||
s32 StartFrame;
|
f32 StartFrame;
|
||||||
s32 EndFrame;
|
f32 EndFrame;
|
||||||
f32 FramesPerSecond;
|
f32 FramesPerSecond;
|
||||||
f32 CurrentFrameNr;
|
f32 CurrentFrameNr;
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ s32 CMeshManipulator::getPolyCount(scene::IMesh *mesh) const
|
|||||||
//! Returns amount of polygons in mesh.
|
//! Returns amount of polygons in mesh.
|
||||||
s32 CMeshManipulator::getPolyCount(scene::IAnimatedMesh *mesh) const
|
s32 CMeshManipulator::getPolyCount(scene::IAnimatedMesh *mesh) const
|
||||||
{
|
{
|
||||||
if (mesh && mesh->getFrameCount() != 0)
|
if (mesh && mesh->getMaxFrameNumber() != 0)
|
||||||
return getPolyCount(mesh->getMesh(0));
|
return getPolyCount(mesh->getMesh(0));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -111,11 +111,9 @@ CSkinnedMesh::~CSkinnedMesh()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! returns the amount of frames in milliseconds.
|
f32 CSkinnedMesh::getMaxFrameNumber() const
|
||||||
//! If the amount is 1, it is a static (=non animated) mesh.
|
|
||||||
u32 CSkinnedMesh::getFrameCount() const
|
|
||||||
{
|
{
|
||||||
return core::floor32(EndFrame + 1.f);
|
return EndFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the default animation speed of the animated mesh.
|
//! Gets the default animation speed of the animated mesh.
|
||||||
@ -133,14 +131,14 @@ void CSkinnedMesh::setAnimationSpeed(f32 fps)
|
|||||||
FramesPerSecond = 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.
|
//! returns the animated mesh based
|
||||||
IMesh *CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
|
IMesh *CSkinnedMesh::getMesh(f32 frame)
|
||||||
{
|
{
|
||||||
// animate(frame,startFrameLoop, endFrameLoop);
|
// animate(frame,startFrameLoop, endFrameLoop);
|
||||||
if (frame == -1)
|
if (frame == -1)
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
animateMesh((f32)frame, 1.0f);
|
animateMesh(frame, 1.0f);
|
||||||
skinMesh();
|
skinMesh();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ public:
|
|||||||
//! destructor
|
//! destructor
|
||||||
virtual ~CSkinnedMesh();
|
virtual ~CSkinnedMesh();
|
||||||
|
|
||||||
//! returns the amount of frames. If the amount is 1, it is a static (=non animated) mesh.
|
//! If the duration is 0, it is a static (=non animated) mesh.
|
||||||
u32 getFrameCount() const override;
|
f32 getMaxFrameNumber() const override;
|
||||||
|
|
||||||
//! Gets the default animation speed of the animated mesh.
|
//! 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. */
|
/** \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.*/
|
The actual speed is set in the scene node the mesh is instantiated in.*/
|
||||||
void setAnimationSpeed(f32 fps) override;
|
void setAnimationSpeed(f32 fps) override;
|
||||||
|
|
||||||
//! returns the animated mesh based on a detail level (which is ignored)
|
//! returns the animated mesh for the given frame
|
||||||
IMesh *getMesh(s32 frame, s32 detailLevel = 255, s32 startFrameLoop = -1, s32 endFrameLoop = -1) override;
|
IMesh *getMesh(f32) override;
|
||||||
|
|
||||||
//! Animates this mesh's joints based on frame input
|
//! Animates this mesh's joints based on frame input
|
||||||
//! blend: {0-old position, 1-New position}
|
//! blend: {0-old position, 1-New position}
|
||||||
|
@ -1052,7 +1052,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
|
|||||||
walking = true;
|
walking = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
v2s32 new_anim = v2s32(0,0);
|
v2f new_anim(0,0);
|
||||||
bool allow_update = false;
|
bool allow_update = false;
|
||||||
|
|
||||||
// increase speed if using fast or flying fast
|
// increase speed if using fast or flying fast
|
||||||
@ -1799,10 +1799,9 @@ void GenericCAO::processMessage(const std::string &data)
|
|||||||
phys.speed_walk = override_speed_walk;
|
phys.speed_walk = override_speed_walk;
|
||||||
}
|
}
|
||||||
} else if (cmd == AO_CMD_SET_ANIMATION) {
|
} else if (cmd == AO_CMD_SET_ANIMATION) {
|
||||||
// TODO: change frames send as v2s32 value
|
|
||||||
v2f range = readV2F32(is);
|
v2f range = readV2F32(is);
|
||||||
if (!m_is_local_player) {
|
if (!m_is_local_player) {
|
||||||
m_animation_range = v2s32((s32)range.X, (s32)range.Y);
|
m_animation_range = range;
|
||||||
m_animation_speed = readF32(is);
|
m_animation_speed = readF32(is);
|
||||||
m_animation_blend = readF32(is);
|
m_animation_blend = readF32(is);
|
||||||
// these are sent inverted so we get true when the server sends nothing
|
// these are sent inverted so we get true when the server sends nothing
|
||||||
@ -1812,7 +1811,7 @@ void GenericCAO::processMessage(const std::string &data)
|
|||||||
LocalPlayer *player = m_env->getLocalPlayer();
|
LocalPlayer *player = m_env->getLocalPlayer();
|
||||||
if(player->last_animation == LocalPlayerAnimation::NO_ANIM)
|
if(player->last_animation == LocalPlayerAnimation::NO_ANIM)
|
||||||
{
|
{
|
||||||
m_animation_range = v2s32((s32)range.X, (s32)range.Y);
|
m_animation_range = range;
|
||||||
m_animation_speed = readF32(is);
|
m_animation_speed = readF32(is);
|
||||||
m_animation_blend = readF32(is);
|
m_animation_blend = readF32(is);
|
||||||
// these are sent inverted so we get true when the server sends nothing
|
// these are sent inverted so we get true when the server sends nothing
|
||||||
|
@ -99,7 +99,7 @@ private:
|
|||||||
v2s16 m_tx_basepos;
|
v2s16 m_tx_basepos;
|
||||||
bool m_initial_tx_basepos_set = false;
|
bool m_initial_tx_basepos_set = false;
|
||||||
bool m_tx_select_horiz_by_yawpitch = false;
|
bool m_tx_select_horiz_by_yawpitch = false;
|
||||||
v2s32 m_animation_range;
|
v2f m_animation_range;
|
||||||
float m_animation_speed = 15.0f;
|
float m_animation_speed = 15.0f;
|
||||||
float m_animation_blend = 0.0f;
|
float m_animation_blend = 0.0f;
|
||||||
bool m_animation_loop = true;
|
bool m_animation_loop = true;
|
||||||
|
@ -157,7 +157,7 @@ void GUIScene::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES> &sty
|
|||||||
/**
|
/**
|
||||||
* Sets the frame loop range for the mesh
|
* Sets the frame loop range for the mesh
|
||||||
*/
|
*/
|
||||||
void GUIScene::setFrameLoop(s32 begin, s32 end)
|
void GUIScene::setFrameLoop(f32 begin, f32 end)
|
||||||
{
|
{
|
||||||
if (m_mesh->getStartFrame() != begin || m_mesh->getEndFrame() != end)
|
if (m_mesh->getStartFrame() != begin || m_mesh->getEndFrame() != end)
|
||||||
m_mesh->setFrameLoop(begin, end);
|
m_mesh->setFrameLoop(begin, end);
|
||||||
|
@ -36,7 +36,7 @@ public:
|
|||||||
scene::IAnimatedMeshSceneNode *setMesh(scene::IAnimatedMesh *mesh = nullptr);
|
scene::IAnimatedMeshSceneNode *setMesh(scene::IAnimatedMesh *mesh = nullptr);
|
||||||
void setTexture(u32 idx, video::ITexture *texture);
|
void setTexture(u32 idx, video::ITexture *texture);
|
||||||
void setBackgroundColor(const video::SColor &color) noexcept { m_bgcolor = color; };
|
void setBackgroundColor(const video::SColor &color) noexcept { m_bgcolor = color; };
|
||||||
void setFrameLoop(s32 begin, s32 end);
|
void setFrameLoop(f32 begin, f32 end);
|
||||||
void setAnimationSpeed(f32 speed);
|
void setAnimationSpeed(f32 speed);
|
||||||
void enableMouseControl(bool enable) noexcept { m_mouse_ctrl = enable; };
|
void enableMouseControl(bool enable) noexcept { m_mouse_ctrl = enable; };
|
||||||
void setRotation(v2f rot) noexcept { m_custom_rot = rot; };
|
void setRotation(v2f rot) noexcept { m_custom_rot = rot; };
|
||||||
|
@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "client/client.h"
|
#include "client/client.h"
|
||||||
|
|
||||||
|
#include "irr_v2d.h"
|
||||||
#include "util/base64.h"
|
#include "util/base64.h"
|
||||||
#include "client/camera.h"
|
#include "client/camera.h"
|
||||||
#include "client/mesh_generator_thread.h"
|
#include "client/mesh_generator_thread.h"
|
||||||
@ -1516,11 +1517,15 @@ void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
|
|||||||
LocalPlayer *player = m_env.getLocalPlayer();
|
LocalPlayer *player = m_env.getLocalPlayer();
|
||||||
assert(player != NULL);
|
assert(player != NULL);
|
||||||
|
|
||||||
*pkt >> player->local_animations[0];
|
for (int i = 0; i < 4; ++i) {
|
||||||
*pkt >> player->local_animations[1];
|
if (getProtoVersion() >= 46) {
|
||||||
*pkt >> player->local_animations[2];
|
*pkt >> player->local_animations[i];
|
||||||
*pkt >> player->local_animations[3];
|
} else {
|
||||||
*pkt >> player->local_animation_speed;
|
v2s32 local_animation;
|
||||||
|
*pkt >> local_animation;
|
||||||
|
player->local_animations[i] = v2f::from(local_animation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
player->last_animation = LocalPlayerAnimation::NO_ANIM;
|
player->last_animation = LocalPlayerAnimation::NO_ANIM;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
old servers.
|
old servers.
|
||||||
Rename TOCLIENT_DEATHSCREEN to TOCLIENT_DEATHSCREEN_LEGACY
|
Rename TOCLIENT_DEATHSCREEN to TOCLIENT_DEATHSCREEN_LEGACY
|
||||||
Rename TOSERVER_RESPAWN to TOSERVER_RESPAWN_LEGACY
|
Rename TOSERVER_RESPAWN to TOSERVER_RESPAWN_LEGACY
|
||||||
|
Support float animation frame numbers in TOCLIENT_LOCAL_PLAYER_ANIMATIONS
|
||||||
[scheduled bump for 5.10.0]
|
[scheduled bump for 5.10.0]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ public:
|
|||||||
f32 movement_liquid_sink;
|
f32 movement_liquid_sink;
|
||||||
f32 movement_gravity;
|
f32 movement_gravity;
|
||||||
|
|
||||||
v2s32 local_animations[4];
|
v2f local_animations[4];
|
||||||
float local_animation_speed;
|
float local_animation_speed;
|
||||||
|
|
||||||
std::string inventory_formspec;
|
std::string inventory_formspec;
|
||||||
|
@ -113,14 +113,14 @@ public:
|
|||||||
|
|
||||||
inline void setModified(const bool x) { m_dirty = x; }
|
inline void setModified(const bool x) { m_dirty = x; }
|
||||||
|
|
||||||
void setLocalAnimations(v2s32 frames[4], float frame_speed)
|
void setLocalAnimations(v2f frames[4], float frame_speed)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
local_animations[i] = frames[i];
|
local_animations[i] = frames[i];
|
||||||
local_animation_speed = frame_speed;
|
local_animation_speed = frame_speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getLocalAnimations(v2s32 *frames, float *frame_speed)
|
void getLocalAnimations(v2f *frames, float *frame_speed)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
frames[i] = local_animations[i];
|
frames[i] = local_animations[i];
|
||||||
|
@ -433,10 +433,10 @@ int ObjectRef::l_set_local_animation(lua_State *L)
|
|||||||
if (player == nullptr)
|
if (player == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
v2s32 frames[4];
|
v2f frames[4];
|
||||||
for (int i=0;i<4;i++) {
|
for (int i=0;i<4;i++) {
|
||||||
if (!lua_isnil(L, 2+1))
|
if (!lua_isnil(L, 2+1))
|
||||||
frames[i] = read_v2s32(L, 2+i);
|
frames[i] = read_v2f(L, 2+i);
|
||||||
}
|
}
|
||||||
float frame_speed = readParam<float>(L, 6, 30.0f);
|
float frame_speed = readParam<float>(L, 6, 30.0f);
|
||||||
|
|
||||||
@ -453,12 +453,12 @@ int ObjectRef::l_get_local_animation(lua_State *L)
|
|||||||
if (player == nullptr)
|
if (player == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
v2s32 frames[4];
|
v2f frames[4];
|
||||||
float frame_speed;
|
float frame_speed;
|
||||||
player->getLocalAnimations(frames, &frame_speed);
|
player->getLocalAnimations(frames, &frame_speed);
|
||||||
|
|
||||||
for (const v2s32 &frame : frames) {
|
for (const v2f &frame : frames) {
|
||||||
push_v2s32(L, frame);
|
push_v2f(L, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pushnumber(L, frame_speed);
|
lua_pushnumber(L, frame_speed);
|
||||||
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "irr_v2d.h"
|
||||||
#include "network/connection.h"
|
#include "network/connection.h"
|
||||||
#include "network/networkprotocol.h"
|
#include "network/networkprotocol.h"
|
||||||
#include "network/serveropcodes.h"
|
#include "network/serveropcodes.h"
|
||||||
@ -1987,14 +1988,21 @@ void Server::SendPlayerFov(session_t peer_id)
|
|||||||
Send(&pkt);
|
Send(&pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
|
void Server::SendLocalPlayerAnimations(session_t peer_id, v2f animation_frames[4],
|
||||||
f32 animation_speed)
|
f32 animation_speed)
|
||||||
{
|
{
|
||||||
NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
|
NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
|
||||||
peer_id);
|
peer_id);
|
||||||
|
|
||||||
pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
|
for (int i = 0; i < 4; ++i) {
|
||||||
<< animation_frames[3] << animation_speed;
|
if (m_clients.getProtocolVersion(peer_id) >= 46) {
|
||||||
|
pkt << animation_frames[i];
|
||||||
|
} else {
|
||||||
|
pkt << v2s32::from(animation_frames[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt << animation_speed;
|
||||||
|
|
||||||
Send(&pkt);
|
Send(&pkt);
|
||||||
}
|
}
|
||||||
@ -3424,7 +3432,7 @@ Address Server::getPeerAddress(session_t peer_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Server::setLocalPlayerAnimations(RemotePlayer *player,
|
void Server::setLocalPlayerAnimations(RemotePlayer *player,
|
||||||
v2s32 animation_frames[4], f32 frame_speed)
|
v2f animation_frames[4], f32 frame_speed)
|
||||||
{
|
{
|
||||||
sanity_check(player);
|
sanity_check(player);
|
||||||
player->setLocalAnimations(animation_frames, frame_speed);
|
player->setLocalAnimations(animation_frames, frame_speed);
|
||||||
|
@ -344,7 +344,7 @@ public:
|
|||||||
|
|
||||||
Address getPeerAddress(session_t peer_id);
|
Address getPeerAddress(session_t peer_id);
|
||||||
|
|
||||||
void setLocalPlayerAnimations(RemotePlayer *player, v2s32 animation_frames[4],
|
void setLocalPlayerAnimations(RemotePlayer *player, v2f animation_frames[4],
|
||||||
f32 frame_speed);
|
f32 frame_speed);
|
||||||
void setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third, v3f third_front);
|
void setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third, v3f third_front);
|
||||||
|
|
||||||
@ -501,7 +501,7 @@ private:
|
|||||||
virtual void SendChatMessage(session_t peer_id, const ChatMessage &message);
|
virtual void SendChatMessage(session_t peer_id, const ChatMessage &message);
|
||||||
void SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed);
|
void SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed);
|
||||||
|
|
||||||
void SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
|
void SendLocalPlayerAnimations(session_t peer_id, v2f animation_frames[4],
|
||||||
f32 animation_speed);
|
f32 animation_speed);
|
||||||
void SendEyeOffset(session_t peer_id, v3f first, v3f third, v3f third_front);
|
void SendEyeOffset(session_t peer_id, v3f first, v3f third, v3f third_front);
|
||||||
void SendPlayerPrivileges(session_t peer_id);
|
void SendPlayerPrivileges(session_t peer_id);
|
||||||
|
Loading…
Reference in New Issue
Block a user