← Back to file list Raw

src/CDrawableAnimatable.cpp

#include "CDrawableAnimatable.h"
#include "U_Log.h"
#include "CEngine.h"
#include "glm/glm.hpp"
#include "glm/gtx/compatibility.hpp"
CDrawableAnimatable::CJoint::CJoint(const std::string& name, CDrawableAnimatable::CJoint* parent) : Name(name), Parent(parent) {}
//BONEMATRIX calculating transform pose here
glm::mat4x4 CDrawableAnimatable::CJoint::GetMatrix()
{
glm::mat4x4 GlobalMatrix = glm::mat4x4();
auto LocalMatrix = BindPose * Transform.GetModelMatrix();
if(Parent)
{
GlobalMatrix = Parent->GetMatrix() * LocalMatrix;
}
else
{
GlobalMatrix = LocalMatrix;
}
return GlobalMatrix;
}
CDrawableAnimatable::CDrawableAnimatable()
{
OnSetModel += [this](CDrawableModel* _this, CModelBase* _model)
{
auto setup = [this, _model]()
{
Joints.reserve(_model->BonesData.size());
for(auto& bone : _model->BonesData)
{
//BONEMATRIX applying bone params here
Joints.push_back({ bone.Name, nullptr });
auto& joint = Joints.back();
joint.BindPose = bone.BindTransform;
joint.GlobalBind = bone.GlobalBind;
if(bone.ParentIndex > -1)
{
for(auto& parent_joint : Joints)
{
if(parent_joint.Name == bone.ParentName)
{
joint.Parent = &parent_joint;
}
}
}
//joint.CalculateBind();
}
};
if(_model->IsReady())
{
setup();
}
else
{
_model->OnDoneLoading += [this, _model, setup](CResource* __this)
{
setup();
};
}
};
OnUpdate += [this](CDrawable* _this)
{
for(auto& anim : Animations)
{
if(!anim.Animation || !anim.Animation->IsReady()) { continue; }
float curPlayback = anim.PlaybackTime;
anim.PlaybackTime += CEngine::GetInstance()->Time.GetDeltaTime() * anim.PlaybackRate;
//75 frames
//at 30 fps
//2.5
//75 / 30 = 2.5 - max time
float maxAnimTime = anim.Animation->Frames.size() / anim.Animation->FPS;
if(anim.PlaybackTime > maxAnimTime) { anim.PlaybackTime -= maxAnimTime; }
//time: 2.5
//FPS: 30.0
//time * FPS = 2.5 * 30.0 = 75
//2.51 * 30.0 = 75.3
//2.52 * 30.0 = 75.6
//2.53 * 30.0 = 75.9
//2.533 * 30.0 = 75.99
//2.54 * 30.0 = 76.2
if(!anim.OldInterp)
{
for(auto& kv : anim.Animation->Splines)
{
CJoint* joint = nullptr;
for(auto& j : Joints)
{
if(j.Name == kv.first)
{
joint = &j;
break;
}
}
if(!joint) { continue; }
auto lpos = kv.second.PositionSpline.GetValue(anim.PlaybackTime, anim.InterpType);
auto lrot = kv.second.RotationSpline.GetValue(anim.PlaybackTime, anim.InterpType);
auto lscl = kv.second.ScaleSpline.GetValue(anim.PlaybackTime, anim.InterpType);
CTransformBase::CMeasurePack LerpMeasurePack;
LerpMeasurePack.Position = lpos;
LerpMeasurePack.Rotation = lrot;
LerpMeasurePack.Scale = lscl;
joint->Transform.SetPRS(LerpMeasurePack);
}
continue;
}
size_t FrameIndex = floorf(curPlayback * anim.Animation->FPS);
size_t NextFrameIndex = FrameIndex + 1;
if(FrameIndex >= anim.Animation->Frames.size()) { FrameIndex = 0; }
//75 / 30.0 = 2.5
//76 / 30.0 = 2.5(33)
//90 / 30.0 = 3
float FrameTime = FrameIndex / anim.Animation->FPS;
float NextFrameTime = NextFrameIndex / anim.Animation->FPS;
//curtime 2.51
//2.5 - 75
//2.533 - 76
//2.533 - 2.5 = 0.033 (delta)
//2.51 - 2.5 = 0.01 (delta curtime)
//curtime 2.5165
//2.5 - 75
//2.533 - 76
//2.533 - 2.5 = 0.33 (delta)
//2.5165 - 2.5 = 0.0165 (delta curtime)
float LerpFactor = (curPlayback - FrameTime) / (NextFrameTime - FrameTime);
LerpFactor = glm::clamp(LerpFactor, 0.0f, 1.0f);
if(NextFrameIndex >= anim.Animation->Frames.size())
{
NextFrameIndex = 0;
}
auto& Frame = anim.Animation->Frames[FrameIndex];
auto& NextFrame = anim.Animation->Frames[NextFrameIndex];
for(auto& capture : Frame.Bones) //TODO splines
{
CAnimation::CBoneCapture* nextCapture = nullptr;
for(auto& next_capture : NextFrame.Bones)
{
if(capture.Name == next_capture.Name)
{
nextCapture = &next_capture;
break;
}
}
if(!nextCapture) { continue; }
if(nextCapture->Matrix == capture.Matrix) { continue; }
CTransform Transform, NextTransform;
Transform.SetFromMatrix(capture.Matrix);
NextTransform.SetFromMatrix(nextCapture->Matrix);
CTransformBase::CMeasurePack MeasurePack, NextMeasurePack, LerpMeasurePack;
MeasurePack = Transform.GetPRS();
NextMeasurePack = NextTransform.GetPRS();
LerpMeasurePack.Position = glm::lerp(MeasurePack.Position, NextMeasurePack.Position, LerpFactor);
LerpMeasurePack.Rotation = glm::slerp(MeasurePack.Rotation, NextMeasurePack.Rotation, LerpFactor);
LerpMeasurePack.Scale = glm::lerp(MeasurePack.Scale, NextMeasurePack.Scale, LerpFactor);
CJoint* joint = nullptr;
for(auto& j : Joints)
{
if(j.Name == capture.Name)
{
joint = &j;
break;
}
}
if(!joint) { continue; }
joint->Transform.SetPRS(LerpMeasurePack);
}
}
};
}
void CDrawableAnimatable::AddAnimation(std::shared_ptr<CResource> _anim, float rate, float weight, float startTime)
{
auto __anim = std::dynamic_pointer_cast<CAnimation>(_anim);
if(!__anim) { return; } //not an animation!
CAnimationInstance instance;
instance.Animation = __anim;
instance.AnimationWeight = weight;
instance.PlaybackRate = rate;
instance.PlaybackTime = startTime;
Animations.push_back(std::move(instance));
}
LINK_SOL_USERTYPE(CDrawableAnimatable);