Fix issue in Rocket.lua script.
[Cafu-Engine.git] / Libs / Models / AnimExpr.cpp
blobf7a40b5dc8851a84e51745395422c3970d682c54
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 #include "AnimExpr.hpp"
8 #include "Model_cmdl.hpp"
11 AnimExpressionT::AnimExpressionT(const CafuModelT& Model)
12 : m_Model(Model),
13 m_RefCount(0)
18 /*************************/
19 /*** AnimExprStandardT ***/
20 /*************************/
22 AnimExprStandardT::AnimExprStandardT(const CafuModelT& Model, int SequNr, float FrameNr)
23 : AnimExpressionT(Model),
24 m_SequNr(SequNr),
25 m_FrameNr(FrameNr),
26 m_ForceLoop(false)
28 NormalizeInput();
32 void AnimExprStandardT::GetData(unsigned int JointNr, float& Weight, Vector3fT& Pos, cf::math::QuaternionfT& Quat, Vector3fT& Scale) const
34 typedef CafuModelT::JointT JointT;
35 typedef CafuModelT::AnimT AnimT;
37 const ArrayT<JointT>& Joints=GetModel().GetJoints();
38 const ArrayT<AnimT>& Anims =GetModel().GetAnims();
40 if (m_SequNr==-1)
42 // Don't animate, just use the bind pose defined in the model file.
43 const JointT& J=Joints[JointNr];
45 Weight=1.0f;
46 Pos =J.Pos;
47 Quat =cf::math::QuaternionfT::FromXYZ(J.Qtr);
48 Scale =J.Scale;
50 else
52 // m_SequNr is a valid index into Anims -- use it.
53 const AnimT& Anim=Anims[m_SequNr];
54 const int Frame_0=int(m_FrameNr); // If m_FrameNr == 17.83, then Frame_0 == 17
55 const float Frame_f=m_FrameNr-Frame_0; // Frame_f == 0.83
56 const int Frame_1=(Frame_0+1) % int(Anim.Frames.Size()); // Frame_1 == 18
58 const AnimT::AnimJointT& AJ=Anim.AnimJoints[JointNr];
60 Vector3fT Data_0[3]={ AJ.DefaultPos, AJ.DefaultQtr, AJ.DefaultScale };
61 Vector3fT Data_1[3]={ AJ.DefaultPos, AJ.DefaultQtr, AJ.DefaultScale };
63 // Determine the position, quaternion and scale for Frame_0 and Frame_1.
64 unsigned int FlagCount=0;
66 for (int i=0; i<9; i++)
68 if ((AJ.Flags >> i) & 1)
70 Data_0[i/3][i % 3]=Anim.Frames[Frame_0].AnimData[AJ.FirstDataIdx+FlagCount];
71 Data_1[i/3][i % 3]=Anim.Frames[Frame_1].AnimData[AJ.FirstDataIdx+FlagCount];
73 FlagCount++;
77 if (Frame_1==0 && Frame_f<0.001f)
79 // This is most likely the end of a non-wrapping sequence.
80 Weight=1.0f;
81 Pos =Data_0[0];
82 Quat =cf::math::QuaternionfT::FromXYZ(Data_0[1]);
83 Scale =Data_0[2];
85 else
87 // Interpolate the position and quaternion according to the fraction Frame_f.
88 Weight=1.0f;
89 Pos =Data_0[0]*(1.0f-Frame_f) + Data_1[0]*Frame_f;
90 Quat =slerp(cf::math::QuaternionfT::FromXYZ(Data_0[1]), cf::math::QuaternionfT::FromXYZ(Data_1[1]), Frame_f);
91 Scale =Data_0[2]*(1.0f-Frame_f) + Data_1[2]*Frame_f;
97 bool AnimExprStandardT::AdvanceTime(float Time)
99 const ArrayT<CafuModelT::AnimT>& Anims = GetModel().GetAnims();
101 if (m_SequNr < 0 || m_SequNr >= int(Anims.Size())) { SetFrameNr(0.0f); return false; }
102 if (Anims[m_SequNr].Frames.Size() <= 1) { SetFrameNr(0.0f); return false; }
104 const float NumFrames = float(Anims[m_SequNr].Frames.Size());
105 const int Next = m_ForceLoop ? m_SequNr : Anims[m_SequNr].Next;
106 float FrameNr = m_FrameNr + Time*Anims[m_SequNr].FPS;
107 bool Wrapped = false;
109 if (Next < 0)
111 // This is a play-once (non-repeating) sequence, there is no "next" sequence.
112 // Thus clamp the frame number to NumFrames-1.
113 if (FrameNr >= NumFrames - 1.0f)
115 FrameNr = NumFrames - 1.0f;
116 if (m_FrameNr < FrameNr) Wrapped = true;
119 else
121 // There is a "next" sequence following this.
122 if (FrameNr >= NumFrames)
124 FrameNr -= NumFrames;
125 Wrapped = true;
127 /* Calling SetSequNr(Next) below would technically be the right thing to do to
128 * progress to the next sequence.
129 * However, this is not supported in AnimExprStandardT for several reasons:
130 * - Backwards-compatibility. See class documentation for details.
131 * - Requires changes to GetData(). The implementation as-is is not sufficient.
133 // SetSequNr(Next);
137 SetFrameNr(FrameNr);
138 return Wrapped;
142 AnimExpressionPtrT AnimExprStandardT::Clone() const
144 IntrusivePtrT<AnimExprStandardT> StdAE=GetModel().GetAnimExprPool().GetStandard(m_SequNr, m_FrameNr);
146 StdAE->SetForceLoop(m_ForceLoop);
147 return StdAE;
151 bool AnimExprStandardT::IsEqual(const AnimExpressionPtrT& AE) const
153 AnimExprStandardT* Other=dynamic_cast<AnimExprStandardT*>(AE.get());
155 if (!Other) return false;
156 return m_SequNr==Other->m_SequNr && m_FrameNr==Other->m_FrameNr && m_ForceLoop==Other->m_ForceLoop;
160 void AnimExprStandardT::SetSequNr(int SequNr)
162 if (m_SequNr==SequNr) return;
164 m_SequNr=SequNr;
165 NormalizeInput();
169 void AnimExprStandardT::SetFrameNr(float FrameNr)
171 if (m_FrameNr==FrameNr) return;
173 m_FrameNr=FrameNr;
174 NormalizeInput();
178 void AnimExprStandardT::SetForceLoop(bool ForceLoop)
180 m_ForceLoop=ForceLoop;
184 void AnimExprStandardT::NormalizeInput()
186 const ArrayT<CafuModelT::AnimT>& Anims=GetModel().GetAnims();
188 // m_SequNr==-1 means "use the bind pose from the model file only (no anim)".
189 if (m_SequNr < -1) m_SequNr = -1;
190 if (m_SequNr >= int(Anims.Size())) m_SequNr = -1;
191 if (m_SequNr != -1 && (Anims[m_SequNr].FPS<0.0 || Anims[m_SequNr].Frames.Size()==0)) m_SequNr = -1;
193 m_FrameNr=std::max(m_FrameNr, 0.0f);
194 m_FrameNr=(m_SequNr==-1) ? 0.0f : fmod(m_FrameNr, float(Anims[m_SequNr].Frames.Size()));
198 /***********************/
199 /*** AnimExprFilterT ***/
200 /***********************/
202 namespace
204 unsigned int FindChannelByName(const CafuModelT& Model, const std::string& ChannelName)
206 unsigned int ChannelNr;
208 for (ChannelNr=0; ChannelNr<Model.GetChannels().Size(); ChannelNr++)
209 if (ChannelName == Model.GetChannels()[ChannelNr].Name)
210 return ChannelNr;
212 return ChannelNr;
217 AnimExprFilterT::AnimExprFilterT(const CafuModelT& Model, AnimExpressionPtrT SubExpr, unsigned int ChannelNr)
218 : AnimExpressionT(Model),
219 m_SubExpr(SubExpr),
220 m_ChannelNr(ChannelNr)
225 AnimExprFilterT::AnimExprFilterT(const CafuModelT& Model, AnimExpressionPtrT SubExpr, const std::string& ChannelName)
226 : AnimExpressionT(Model),
227 m_SubExpr(SubExpr),
228 m_ChannelNr(FindChannelByName(Model, ChannelName))
233 void AnimExprFilterT::ReInit(AnimExpressionPtrT SubExpr, unsigned int ChannelNr)
235 if (m_SubExpr==SubExpr && m_ChannelNr==ChannelNr) return;
237 m_SubExpr =SubExpr;
238 m_ChannelNr=ChannelNr;
242 void AnimExprFilterT::GetData(unsigned int JointNr, float& Weight, Vector3fT& Pos, cf::math::QuaternionfT& Quat, Vector3fT& Scale) const
244 Weight=0.0f;
246 if (m_ChannelNr >= GetModel().GetChannels().Size() || GetModel().GetChannels()[m_ChannelNr].IsMember(JointNr))
248 m_SubExpr->GetData(JointNr, Weight, Pos, Quat, Scale);
253 AnimExpressionPtrT AnimExprFilterT::Clone() const
255 return GetModel().GetAnimExprPool().GetFilter(m_SubExpr->Clone(), m_ChannelNr);
259 bool AnimExprFilterT::IsEqual(const AnimExpressionPtrT& AE) const
261 AnimExprFilterT* Other=dynamic_cast<AnimExprFilterT*>(AE.get());
263 if (!Other) return false;
264 return m_ChannelNr==Other->m_ChannelNr && m_SubExpr->IsEqual(Other->m_SubExpr);
268 /************************/
269 /*** AnimExprCombineT ***/
270 /************************/
272 AnimExprCombineT::AnimExprCombineT(const CafuModelT& Model, AnimExpressionPtrT A, AnimExpressionPtrT B)
273 : AnimExpressionT(Model),
274 m_A(A),
275 m_B(B)
280 void AnimExprCombineT::ReInit(AnimExpressionPtrT A, AnimExpressionPtrT B)
282 if (m_A==A && m_B==B) return;
284 m_A=A;
285 m_B=B;
289 void AnimExprCombineT::GetData(unsigned int JointNr, float& Weight, Vector3fT& Pos, cf::math::QuaternionfT& Quat, Vector3fT& Scale) const
291 m_A->GetData(JointNr, Weight, Pos, Quat, Scale);
293 float WeightB;
294 Vector3fT PosB;
295 cf::math::QuaternionfT QuatB;
296 Vector3fT ScaleB;
298 // Pick the expression with the largest weight.
299 m_B->GetData(JointNr, WeightB, PosB, QuatB, ScaleB);
301 if (WeightB > Weight)
303 Weight = WeightB;
304 Pos = PosB;
305 Quat = QuatB;
306 Scale = ScaleB;
311 bool AnimExprCombineT::AdvanceTime(float Time)
313 const bool WrapA = m_A->AdvanceTime(Time);
314 const bool WrapB = m_B->AdvanceTime(Time);
316 return WrapA || WrapB;
320 AnimExpressionPtrT AnimExprCombineT::Clone() const
322 return GetModel().GetAnimExprPool().GetCombine(m_A->Clone(), m_B->Clone());
326 bool AnimExprCombineT::IsEqual(const AnimExpressionPtrT& AE) const
328 AnimExprCombineT* Other=dynamic_cast<AnimExprCombineT*>(AE.get());
330 if (!Other) return false;
331 return m_A->IsEqual(Other->m_A) && m_B->IsEqual(Other->m_B);
335 /**********************/
336 /*** AnimExprBlendT ***/
337 /**********************/
339 AnimExprBlendT::AnimExprBlendT(const CafuModelT& Model, AnimExpressionPtrT A, AnimExpressionPtrT B, float Duration)
340 : AnimExpressionT(Model),
341 m_A(A),
342 m_B(B),
343 m_Duration(Duration),
344 m_Frac(0.0f)
349 void AnimExprBlendT::ReInit(AnimExpressionPtrT A, AnimExpressionPtrT B, float Duration)
351 m_A=A;
352 m_B=B;
353 m_Duration=Duration;
354 m_Frac=0.0f;
358 void AnimExprBlendT::GetData(unsigned int JointNr, float& Weight, Vector3fT& Pos, cf::math::QuaternionfT& Quat, Vector3fT& Scale) const
360 float w[2];
361 Vector3fT p[2];
362 cf::math::QuaternionfT q[2];
363 Vector3fT s[2];
365 if (m_Frac <= 0.0f)
367 m_A->GetData(JointNr, Weight, Pos, Quat, Scale);
368 return;
371 if (m_Frac >= 1.0f)
373 m_B->GetData(JointNr, Weight, Pos, Quat, Scale);
374 return;
377 m_A->GetData(JointNr, w[0], p[0], q[0], s[0]);
378 m_B->GetData(JointNr, w[1], p[1], q[1], s[1]);
380 const float f0 = 1.0f - m_Frac;
381 const float f1 = m_Frac;
383 Weight = w[0]*f0 + w[1]*f1;
384 Pos = p[0]*f0 + p[1]*f1;
385 Quat = slerp(q[0], q[1], f1); // slerp() is why we cannot have generic "add" and "mul" AnimExpressionT's.
386 Scale = s[0]*f0 + s[1]*f1;
390 bool AnimExprBlendT::AdvanceTime(float Time)
392 // Advance the blend fraction.
393 if (m_Duration < 0.001f)
395 m_Frac = 1.0f;
397 else
399 m_Frac += Time/m_Duration;
402 m_Frac = std::min(m_Frac, 1.0f);
405 // Advance the sub-expressions.
406 if (m_Frac < 1.0f)
408 m_A->AdvanceTime(Time);
410 else
412 m_A=NULL; // m_A is unused now that m_Frac >= 1.0.
415 return m_B->AdvanceTime(Time);
419 AnimExpressionPtrT AnimExprBlendT::Clone() const
421 IntrusivePtrT<AnimExprBlendT> Blend=GetModel().GetAnimExprPool().GetBlend(
422 m_A==NULL ? NULL : m_A->Clone(), m_B->Clone(), m_Duration);
424 Blend->m_Frac=m_Frac;
425 return Blend;
429 bool AnimExprBlendT::IsEqual(const AnimExpressionPtrT& AE) const
431 AnimExprBlendT* Other=dynamic_cast<AnimExprBlendT*>(AE.get());
433 if (!Other) return false;
434 return m_Frac==Other->m_Frac && m_Duration==Other->m_Duration &&
435 m_B->IsEqual(Other->m_B) &&
436 (m_A==NULL ? Other->m_A==NULL : m_A->IsEqual(Other->m_A));
440 /*********************/
441 /*** AnimExprPoolT ***/
442 /*********************/
444 void AnimExprPoolT::FlattenUnused()
446 for (unsigned int AENr=0; AENr<m_Filter.Size(); AENr++)
447 if (m_Filter[AENr]->GetRefCount()==1)
448 m_Filter[AENr]->ReInit(NULL, 0);
450 for (unsigned int AENr=0; AENr<m_Combine.Size(); AENr++)
451 if (m_Combine[AENr]->GetRefCount()==1)
452 m_Combine[AENr]->ReInit(NULL, NULL);
454 for (unsigned int AENr=0; AENr<m_Blend.Size(); AENr++)
455 if (m_Blend[AENr]->GetRefCount()==1)
456 m_Blend[AENr]->ReInit(NULL, NULL, 0.0f);
460 IntrusivePtrT<AnimExprStandardT> AnimExprPoolT::GetStandard(int SequNr, float FrameNr)
462 FlattenUnused();
464 for (unsigned int AENr=0; AENr<m_Standard.Size(); AENr++)
466 if (m_Standard[AENr]->GetRefCount()==1)
468 m_Standard[AENr]->SetSequNr(SequNr);
469 m_Standard[AENr]->SetFrameNr(FrameNr);
470 m_Standard[AENr]->SetForceLoop(false);
472 return m_Standard[AENr];
476 IntrusivePtrT<AnimExprStandardT> NewAE(new AnimExprStandardT(m_Model, SequNr, FrameNr));
477 m_Standard.PushBack(NewAE);
479 return NewAE;
483 IntrusivePtrT<AnimExprFilterT> AnimExprPoolT::GetFilter(AnimExpressionPtrT SubExpr, unsigned int ChannelNr)
485 FlattenUnused();
487 for (unsigned int AENr=0; AENr<m_Filter.Size(); AENr++)
489 if (m_Filter[AENr]->GetRefCount()==1)
491 m_Filter[AENr]->ReInit(SubExpr, ChannelNr);
493 return m_Filter[AENr];
497 IntrusivePtrT<AnimExprFilterT> NewAE(new AnimExprFilterT(m_Model, SubExpr, ChannelNr));
498 m_Filter.PushBack(NewAE);
500 return NewAE;
504 IntrusivePtrT<AnimExprFilterT> AnimExprPoolT::GetFilter(AnimExpressionPtrT SubExpr, const std::string& ChannelName)
506 return GetFilter(SubExpr, FindChannelByName(m_Model, ChannelName));
510 IntrusivePtrT<AnimExprCombineT> AnimExprPoolT::GetCombine(AnimExpressionPtrT A, AnimExpressionPtrT B)
512 FlattenUnused();
514 for (unsigned int AENr=0; AENr<m_Combine.Size(); AENr++)
516 if (m_Combine[AENr]->GetRefCount()==1)
518 m_Combine[AENr]->ReInit(A, B);
520 return m_Combine[AENr];
524 IntrusivePtrT<AnimExprCombineT> NewAE(new AnimExprCombineT(m_Model, A, B));
525 m_Combine.PushBack(NewAE);
527 return NewAE;
531 IntrusivePtrT<AnimExprBlendT> AnimExprPoolT::GetBlend(AnimExpressionPtrT A, AnimExpressionPtrT B, float Duration)
533 FlattenUnused();
535 for (unsigned int AENr=0; AENr<m_Blend.Size(); AENr++)
537 if (m_Blend[AENr]->GetRefCount()==1)
539 m_Blend[AENr]->ReInit(A, B, Duration);
541 return m_Blend[AENr];
545 IntrusivePtrT<AnimExprBlendT> NewAE(new AnimExprBlendT(m_Model, A, B, Duration));
546 m_Blend.PushBack(NewAE);
548 return NewAE;