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.
7 #include "AnimExpr.hpp"
8 #include "Model_cmdl.hpp"
11 AnimExpressionT::AnimExpressionT(const CafuModelT
& Model
)
18 /*************************/
19 /*** AnimExprStandardT ***/
20 /*************************/
22 AnimExprStandardT::AnimExprStandardT(const CafuModelT
& Model
, int SequNr
, float FrameNr
)
23 : AnimExpressionT(Model
),
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();
42 // Don't animate, just use the bind pose defined in the model file.
43 const JointT
& J
=Joints
[JointNr
];
47 Quat
=cf::math::QuaternionfT::FromXYZ(J
.Qtr
);
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
];
77 if (Frame_1
==0 && Frame_f
<0.001f
)
79 // This is most likely the end of a non-wrapping sequence.
82 Quat
=cf::math::QuaternionfT::FromXYZ(Data_0
[1]);
87 // Interpolate the position and quaternion according to the fraction Frame_f.
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;
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;
121 // There is a "next" sequence following this.
122 if (FrameNr
>= NumFrames
)
124 FrameNr
-= NumFrames
;
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.
142 AnimExpressionPtrT
AnimExprStandardT::Clone() const
144 IntrusivePtrT
<AnimExprStandardT
> StdAE
=GetModel().GetAnimExprPool().GetStandard(m_SequNr
, m_FrameNr
);
146 StdAE
->SetForceLoop(m_ForceLoop
);
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;
169 void AnimExprStandardT::SetFrameNr(float FrameNr
)
171 if (m_FrameNr
==FrameNr
) return;
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 /***********************/
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
)
217 AnimExprFilterT::AnimExprFilterT(const CafuModelT
& Model
, AnimExpressionPtrT SubExpr
, unsigned int ChannelNr
)
218 : AnimExpressionT(Model
),
220 m_ChannelNr(ChannelNr
)
225 AnimExprFilterT::AnimExprFilterT(const CafuModelT
& Model
, AnimExpressionPtrT SubExpr
, const std::string
& ChannelName
)
226 : AnimExpressionT(Model
),
228 m_ChannelNr(FindChannelByName(Model
, ChannelName
))
233 void AnimExprFilterT::ReInit(AnimExpressionPtrT SubExpr
, unsigned int ChannelNr
)
235 if (m_SubExpr
==SubExpr
&& m_ChannelNr
==ChannelNr
) return;
238 m_ChannelNr
=ChannelNr
;
242 void AnimExprFilterT::GetData(unsigned int JointNr
, float& Weight
, Vector3fT
& Pos
, cf::math::QuaternionfT
& Quat
, Vector3fT
& Scale
) const
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
),
280 void AnimExprCombineT::ReInit(AnimExpressionPtrT A
, AnimExpressionPtrT B
)
282 if (m_A
==A
&& m_B
==B
) return;
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
);
295 cf::math::QuaternionfT QuatB
;
298 // Pick the expression with the largest weight.
299 m_B
->GetData(JointNr
, WeightB
, PosB
, QuatB
, ScaleB
);
301 if (WeightB
> Weight
)
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
),
343 m_Duration(Duration
),
349 void AnimExprBlendT::ReInit(AnimExpressionPtrT A
, AnimExpressionPtrT B
, float Duration
)
358 void AnimExprBlendT::GetData(unsigned int JointNr
, float& Weight
, Vector3fT
& Pos
, cf::math::QuaternionfT
& Quat
, Vector3fT
& Scale
) const
362 cf::math::QuaternionfT q
[2];
367 m_A
->GetData(JointNr
, Weight
, Pos
, Quat
, Scale
);
373 m_B
->GetData(JointNr
, Weight
, Pos
, Quat
, Scale
);
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
)
399 m_Frac
+= Time
/m_Duration
;
402 m_Frac
= std::min(m_Frac
, 1.0f
);
405 // Advance the sub-expressions.
408 m_A
->AdvanceTime(Time
);
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
;
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
)
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
);
483 IntrusivePtrT
<AnimExprFilterT
> AnimExprPoolT::GetFilter(AnimExpressionPtrT SubExpr
, unsigned int ChannelNr
)
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
);
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
)
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
);
531 IntrusivePtrT
<AnimExprBlendT
> AnimExprPoolT::GetBlend(AnimExpressionPtrT A
, AnimExpressionPtrT B
, float Duration
)
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
);