12#include <assimp/anim.h>
21 ticksPerSecond(!
IS_ZERO(pAnim->mTicksPerSecond)
22 ? pAnim->mTicksPerSecond
25 duration(pAnim->mDuration);
26 name(pAnim->mName.length > 0 ? pAnim->mName.data :
Util::StringFormat(
"unnamed_anim_{}", idx));
30 _channels.resize(pAnim->mNumChannels);
31 for (
U32 a = 0; a < pAnim->mNumChannels; a++) {
32 const aiNodeAnim* srcChannel = pAnim->mChannels[a];
35 dstChannel.
_name = srcChannel->mNodeName.data;
38 for (
U32 i(0); i < srcChannel->mNumPositionKeys; i++) {
39 dstChannel.
_positionKeys.push_back(srcChannel->mPositionKeys[i]);
41 for (
U32 i(0); i < srcChannel->mNumRotationKeys; i++) {
42 dstChannel.
_rotationKeys.push_back(srcChannel->mRotationKeys[i]);
44 for (
U32 i(0); i < srcChannel->mNumScalingKeys; i++) {
45 dstChannel.
_scalingKeys.push_back(srcChannel->mScalingKeys[i]);
52 _lastPositions.resize(pAnim->mNumChannels,
vec3<U32>());
60 "AnimEvaluator error: can't create bone buffer at current stage!");
63 "AnimEvaluator error: Too many bones for current node! "
64 "Increase MAX_BONE_COUNT_PER_NODE in Config!");
71 for (
const mat4<F32>& mat : transform.matrices())
73 animationData.push_back(mat);
77 if (!animationData.empty())
82 bufferDescriptor._bufferParams._elementCount =
to_U32(animationData.size());
83 bufferDescriptor._bufferParams._elementSize =
sizeof(
mat4<F32>);
87 bufferDescriptor._initialData = { animationData.data(), animationData.size() *
sizeof(
mat4<F32>) };
100 if (duration() > 0.0)
103 time = std::fmod(elapsedTimeS * ticksPerSecond(), duration());
106 const D64 percent = time / duration();
109 if (!_transforms.empty())
112 if (playAnimationForward())
114 ret.
_curr = std::min(
to_I32(_transforms.size() * percent),
to_I32(_transforms.size() - 1));
120 ret.
_curr = std::min(
to_I32(_transforms.size() * ((percent - 1.0f) * -1.0f)),
to_I32(_transforms.size() - 1));
132 const D64 pTime = dt * ticksPerSecond();
135 if (duration() > 0.0) {
136 time = std::fmod(pTime, duration());
139 const aiQuaternion presentRotationDefault(1, 0, 0, 0);
141 aiVector3D presentPosition(0, 0, 0);
142 aiQuaternion presentRotation(1, 0, 0, 0);
143 aiVector3D presentScaling(1, 1, 1);
151 if (bonenode ==
nullptr) {
157 if (!
channel->_positionKeys.empty()) {
163 while (frame < channel->_positionKeys.size() - 1) {
164 if (time < channel->_positionKeys[frame + 1].mTime) {
171 const U32 nextFrame = (frame + 1) %
channel->_positionKeys.size();
173 const aiVectorKey& key =
channel->_positionKeys[frame];
174 const aiVectorKey& nextKey =
channel->_positionKeys[nextFrame];
175 D64 diffTime = nextKey.mTime - key.mTime;
176 if (diffTime < 0.0) diffTime += duration();
178 const F32 factor =
to_F32((time - key.mTime) / diffTime);
180 key.mValue + (nextKey.mValue - key.mValue) * factor;
182 presentPosition = key.mValue;
186 presentPosition.Set(0.0f, 0.0f, 0.0f);
190 if (!
channel->_rotationKeys.empty()) {
192 while (frame < channel->_rotationKeys.size() - 1) {
193 if (time < channel->_rotationKeys[frame + 1].mTime)
break;
198 const U32 nextFrame = (frame + 1) %
channel->_rotationKeys.size();
200 const aiQuatKey& key =
channel->_rotationKeys[frame];
201 const aiQuatKey& nextKey =
channel->_rotationKeys[nextFrame];
202 D64 diffTime = nextKey.mTime - key.mTime;
203 if (diffTime < 0.0) diffTime += duration();
205 const F32 factor =
to_F32((time - key.mTime) / diffTime);
206 presentRotation = presentRotationDefault;
207 aiQuaternion::Interpolate(presentRotation, key.mValue,
208 nextKey.mValue, factor);
210 presentRotation = key.mValue;
214 presentRotation = presentRotationDefault;
218 if (!
channel->_scalingKeys.empty()) {
220 while (frame < channel->_scalingKeys.size() - 1) {
221 if (time < channel->_scalingKeys[frame + 1].mTime)
break;
225 presentScaling =
channel->_scalingKeys[frame].mValue;
228 presentScaling.Set(1.0f, 1.0f, 1.0f);
231 aiMatrix4x4 mat(presentRotation.GetMatrix());
232 mat.a1 *= presentScaling.x;
233 mat.b1 *= presentScaling.x;
234 mat.c1 *= presentScaling.x;
235 mat.a2 *= presentScaling.y;
236 mat.b2 *= presentScaling.y;
237 mat.c2 *= presentScaling.y;
238 mat.a3 *= presentScaling.z;
239 mat.b3 *= presentScaling.z;
240 mat.c3 *= presentScaling.z;
241 mat.a4 = presentPosition.x;
242 mat.b4 = presentPosition.y;
243 mat.c4 = presentPosition.z;
246 bonenode->localTransform(out);
bool initBuffers(GFXDevice &context)
FrameIndex frameIndexAt(D64 elapsedTimeS) const noexcept
ShaderBuffer_uptr _boneBuffer
GPU buffer to hold bone transforms.
U32 frameCount() const noexcept
vector< AnimationChannel > _channels
vector that holds all bone channels
void evaluate(D64 dt, Bone *skeleton)
vector< BoneTransform > _transforms
Array to return transformations results inside.
vector< vec3< U32 > > _lastPositions
ShaderBuffer * boneBuffer() const
Bone * find(const string &name)
Rough around the edges Adapter pattern abstracting the actual rendering API and access to the GPU.
ShaderBuffer_uptr newSB(const ShaderBufferDescriptor &descriptor)
void TransformMatrix(const aiMatrix4x4 &in, mat4< F32 > &out, const bool rowMajor) noexcept
constexpr U16 MAX_BONE_COUNT_PER_NODE
Maximum number of bones available per node.
Str StringFormat(const char *fmt, Args &&...args)
Handle console commands that start with a forward slash.
bool IS_ZERO(const T X) noexcept
constexpr U32 to_U32(const T value)
constexpr F32 to_F32(const T value)
eastl::vector< Type > vector
constexpr U64 _ID(const char *const str, const U64 value=val_64_const) noexcept
static constexpr F32 ANIMATION_TICKS_PER_SECOND
constexpr I32 to_I32(const T value)
vector< aiVectorKey > _positionKeys
vector< aiQuatKey > _rotationKeys
vector< aiVectorKey > _scalingKeys
static NO_INLINE void d_printfn(const char *format, T &&... args)
static NO_INLINE void d_errorfn(const char *format, T &&... args)