1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_TransformAnimEvaluator.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #include "precompiled.h"
19 
20 #include <nw/gfx/gfx_CalculatedTransform.h>
21 #include <nw/gfx/gfx_TransformAnimBlendOp.h>
22 #include <nw/gfx/gfx_TransformAnimEvaluator.h>
23 
24 namespace nw
25 {
26 namespace gfx
27 {
28 
29 NW_UT_RUNTIME_TYPEINFO_DEFINITION(TransformAnimEvaluator   , BaseAnimEvaluator);
30 
31 //----------------------------------------------------------
32 void
EvaluateMemberAnim(CalculatedTransform * result,anim::ResTransformAnim transformAnim,float frame,const math::Transform3 * originalTransform,bool writeNoAnimMember) const33 TransformAnimEvaluator::EvaluateMemberAnim(
34     CalculatedTransform* result,
35     anim::ResTransformAnim transformAnim,
36     float frame,
37     const math::Transform3* originalTransform,
38     bool writeNoAnimMember
39 ) const
40 {
41     const u32 flags = transformAnim.GetFlags();
42 
43     const u32 FLAG_TRANSLATE_NOT_EXIST =
44         anim::ResTransformAnimData::FLAG_TRANSLATE_NOT_EXIST;
45     const u32 FLAG_ROTATE_NOT_EXIST =
46         anim::ResTransformAnimData::FLAG_ROTATE_NOT_EXIST;
47     const u32 FLAG_SCALE_NOT_EXIST =
48         anim::ResTransformAnimData::FLAG_SCALE_NOT_EXIST;
49 
50     if (writeNoAnimMember)
51     {
52         math::Transform3 transform;
53 
54         if (m_IsScaleDisabled)
55         {
56             transform.scale = originalTransform->scale;
57         }
58         else
59         {
60             transform.scale.x = (flags & anim::ResTransformAnimData::FLAG_SCALE_X_NOT_EXIST) ?
61                 originalTransform->scale.x : transformAnim.EvaluateScaleX(frame);
62             transform.scale.y = (flags & anim::ResTransformAnimData::FLAG_SCALE_Y_NOT_EXIST) ?
63                 originalTransform->scale.y : transformAnim.EvaluateScaleY(frame);
64             transform.scale.z = (flags & anim::ResTransformAnimData::FLAG_SCALE_Z_NOT_EXIST) ?
65                 originalTransform->scale.z : transformAnim.EvaluateScaleZ(frame);
66         }
67 
68         if (m_IsRotateDisabled)
69         {
70             transform.rotate = originalTransform->rotate;
71         }
72         else
73         {
74             transform.rotate.x = (flags & anim::ResTransformAnimData::FLAG_ROTATE_X_NOT_EXIST) ?
75                 originalTransform->rotate.x : transformAnim.EvaluateRotateX(frame);
76             transform.rotate.y = (flags & anim::ResTransformAnimData::FLAG_ROTATE_Y_NOT_EXIST) ?
77                 originalTransform->rotate.y : transformAnim.EvaluateRotateY(frame);
78             transform.rotate.z = (flags & anim::ResTransformAnimData::FLAG_ROTATE_Z_NOT_EXIST) ?
79                 originalTransform->rotate.z : transformAnim.EvaluateRotateZ(frame);
80         }
81 
82         if (m_IsTranslateDisabled)
83         {
84             transform.translate = originalTransform->translate;
85         }
86         else
87         {
88             transform.translate.x = (flags & anim::ResTransformAnimData::FLAG_TRANSLATE_X_NOT_EXIST) ?
89                 originalTransform->translate.x : transformAnim.EvaluateTranslateX(frame);
90             transform.translate.y = (flags & anim::ResTransformAnimData::FLAG_TRANSLATE_Y_NOT_EXIST) ?
91                 originalTransform->translate.y : transformAnim.EvaluateTranslateY(frame);
92             transform.translate.z = (flags & anim::ResTransformAnimData::FLAG_TRANSLATE_Z_NOT_EXIST) ?
93                 originalTransform->translate.z : transformAnim.EvaluateTranslateZ(frame);
94         }
95 
96         result->SetTransform(transform);
97     }
98     else
99     {
100         if (!m_IsScaleDisabled)
101         {
102             if (!(flags & anim::ResTransformAnimData::FLAG_SCALE_X_NOT_EXIST))
103             {
104                 result->DirectScale().x = transformAnim.EvaluateScaleX(frame);
105             }
106             if (!(flags & anim::ResTransformAnimData::FLAG_SCALE_Y_NOT_EXIST))
107             {
108                 result->DirectScale().y = transformAnim.EvaluateScaleY(frame);
109             }
110             if (!(flags & anim::ResTransformAnimData::FLAG_SCALE_Z_NOT_EXIST))
111             {
112                 result->DirectScale().z = transformAnim.EvaluateScaleZ(frame);
113             }
114         }
115 
116         if (!m_IsRotateDisabled)
117         {
118 
119             if ((flags & FLAG_ROTATE_NOT_EXIST) != FLAG_ROTATE_NOT_EXIST)
120             {
121                 const f32 rotX = (flags & anim::ResTransformAnimData::FLAG_ROTATE_X_NOT_EXIST) ?
122                     originalTransform->rotate.x : transformAnim.EvaluateRotateX(frame);
123                 const f32 rotY = (flags & anim::ResTransformAnimData::FLAG_ROTATE_Y_NOT_EXIST) ?
124                     originalTransform->rotate.y : transformAnim.EvaluateRotateY(frame);
125                 const f32 rotZ = (flags & anim::ResTransformAnimData::FLAG_ROTATE_Z_NOT_EXIST) ?
126                     originalTransform->rotate.z : transformAnim.EvaluateRotateZ(frame);
127                 result->SetRotateXYZ(rotX, rotY, rotZ);
128             }
129         }
130 
131         if (!m_IsTranslateDisabled)
132         {
133             if (!(flags & anim::ResTransformAnimData::FLAG_TRANSLATE_X_NOT_EXIST))
134             {
135                 result->DirectTransformMatrix().f._03 = transformAnim.EvaluateTranslateX(frame);
136             }
137             if (!(flags & anim::ResTransformAnimData::FLAG_TRANSLATE_Y_NOT_EXIST))
138             {
139                 result->DirectTransformMatrix().f._13 = transformAnim.EvaluateTranslateY(frame);
140             }
141             if (!(flags & anim::ResTransformAnimData::FLAG_TRANSLATE_Z_NOT_EXIST))
142             {
143                 result->DirectTransformMatrix().f._23 = transformAnim.EvaluateTranslateZ(frame);
144             }
145         }
146 
147         result->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
148     }
149     UpdateFlagsCommon(result);
150 
151     // 回転アニメーションが存在するならば、FLAG_IS_ROTATE_ZERO は無効にする。
152     if ((flags & FLAG_ROTATE_NOT_EXIST) != FLAG_ROTATE_NOT_EXIST)
153     {
154         result->DisableFlags(CalculatedTransform::FLAG_IS_ROTATE_ZERO);
155     }
156     // 同様に平行移動が存在するならば、FLAG_IS_TRANSLATE_ZERO は無効にする。
157     if ((flags & FLAG_TRANSLATE_NOT_EXIST) != FLAG_TRANSLATE_NOT_EXIST)
158     {
159         result->DisableFlags(CalculatedTransform::FLAG_IS_TRANSLATE_ZERO);
160     }
161     // 同様にスケールが存在するならば、FLAG_IS_SCALE_ONE は無効にする。
162     if ((flags & FLAG_SCALE_NOT_EXIST) != FLAG_SCALE_NOT_EXIST)
163     {
164         result->DisableFlags(CalculatedTransform::FLAG_IS_SCALE_ONE);
165     }
166     result->UpdateCompositeFlags();
167 }
168 
169 //----------------------------------------------------------
170 void
EvaluateMemberBakedAnim(CalculatedTransform * result,anim::ResBakedTransformAnim transformAnim,float frame,const math::Transform3 * originalTransform,bool writeNoAnimMember) const171 TransformAnimEvaluator::EvaluateMemberBakedAnim(
172     CalculatedTransform* result,
173     anim::ResBakedTransformAnim transformAnim,
174     float frame,
175     const math::Transform3* originalTransform,
176     bool writeNoAnimMember
177 ) const
178 {
179     const u32 flags = transformAnim.GetFlags();
180     bit32 frameFlags = 0;
181 
182     if (!writeNoAnimMember)
183     {
184         // OriginalValueが書き込み済みの場合は、
185         // アニメのない要素のフラグを再利用する
186         frameFlags = result->GetFlags();
187     }
188 
189     if (!(flags & anim::ResBakedTransformAnimData::FLAG_ROTATE_NOT_EXIST))
190     {
191         frameFlags = ut::DisableFlag(frameFlags,
192             gfx::CalculatedTransform::FLAG_IS_ROTATE_ZERO);
193 
194         transformAnim.EvaluateRotate(&result->m_TransformMatrix, &frameFlags, frame);
195         result->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
196     }
197 
198     if (!(flags & anim::ResBakedTransformAnimData::FLAG_TRANSLATE_NOT_EXIST))
199     {
200         frameFlags = ut::DisableFlag(frameFlags,
201             gfx::CalculatedTransform::FLAG_IS_TRANSLATE_ZERO);
202 
203         transformAnim.EvaluateTranslate(&result->m_TransformMatrix, &frameFlags, frame);
204         result->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
205     }
206 
207     if (!(flags & anim::ResBakedTransformAnimData::FLAG_SCALE_NOT_EXIST))
208     {
209         frameFlags = ut::DisableFlag(frameFlags,
210             gfx::CalculatedTransform::FLAG_IS_UNIFORM_SCALE |
211             gfx::CalculatedTransform::FLAG_IS_SCALE_ONE);
212 
213         transformAnim.EvaluateScale(&result->m_Scale, &frameFlags, frame);
214         result->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
215     }
216 
217     if (writeNoAnimMember)
218     {
219         if (flags & anim::ResBakedTransformAnimData::FLAG_ROTATE_NOT_EXIST)
220         {
221             // TODO: 回転行列の生成は重いので、originalValueをCalculatedTransform型で保存するようにする
222             result->SetRotateXYZ(
223                 originalTransform->rotate.x,
224                 originalTransform->rotate.y,
225                 originalTransform->rotate.z);
226 
227             if (originalTransform->rotate.IsZero())
228             {
229                 frameFlags |= gfx::CalculatedTransform::FLAG_IS_ROTATE_ZERO;
230             }
231         }
232 
233         if (flags & anim::ResBakedTransformAnimData::FLAG_TRANSLATE_NOT_EXIST)
234         {
235             result->SetTranslate(originalTransform->translate);
236 
237             if (originalTransform->translate.IsZero())
238             {
239                 frameFlags |= gfx::CalculatedTransform::FLAG_IS_TRANSLATE_ZERO;
240             }
241         }
242 
243         if (flags & anim::ResBakedTransformAnimData::FLAG_SCALE_NOT_EXIST)
244         {
245             result->SetScale(originalTransform->scale);
246 
247             const math::Vector3& scale = originalTransform->scale;
248             if (scale.x == scale.y && scale.x == scale.z)
249             {
250                 frameFlags |= gfx::CalculatedTransform::FLAG_IS_UNIFORM_SCALE;
251 
252                 if (scale.x == 1.f)
253                 {
254                     frameFlags |= gfx::CalculatedTransform::FLAG_IS_SCALE_ONE;
255                 }
256             }
257         }
258     }
259 
260     ApplyBakedFlags(result, frameFlags);
261 }
262 
263 //----------------------------------------------------------
264 void
UpdateFlagsCommon(CalculatedTransform * transform) const265 TransformAnimEvaluator::UpdateFlagsCommon(CalculatedTransform* transform) const
266 {
267     transform->DisableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
268 
269     transform->EnableFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE, m_IsScaleDisabled);
270     transform->EnableFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE, m_IsRotateDisabled);
271     transform->EnableFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE, m_IsTranslateDisabled);
272 }
273 
274 //----------------------------------------------------------
275 void
UpdateFlags(CalculatedTransform * transform) const276 TransformAnimEvaluator::UpdateFlags(CalculatedTransform* transform) const
277 {
278     UpdateFlagsCommon(transform);
279     transform->UpdateScaleFlags();
280     transform->UpdateRotateFlags();
281     transform->UpdateTranslateFlags();
282     transform->UpdateCompositeFlags();
283 }
284 
285 //----------------------------------------------------------
286 void
ApplyBakedFlags(CalculatedTransform * transform,bit32 flags) const287 TransformAnimEvaluator::ApplyBakedFlags(CalculatedTransform* transform, bit32 flags) const
288 {
289     UpdateFlagsCommon(transform);
290     // Bake済みデータで更新する
291     anim::ResBakedTransformAnim::ApplyBakedFlags(transform, flags);
292 }
293 
294 //----------------------------------------------------------
295 const anim::AnimResult*
GetResult(void * target,int memberIdx) const296 TransformAnimEvaluator::GetResult(
297     void* target,
298     int memberIdx
299 ) const
300 {
301     return GetResultCommon(target, memberIdx, true);
302 }
303 
304 //----------------------------------------------------------
ResetNoAnimMember(AnimGroup * animGroup,anim::ResAnim animData)305 void TransformAnimEvaluator::ResetNoAnimMember(AnimGroup* animGroup, anim::ResAnim animData)
306 {
307     using namespace anim;
308 
309     for (int memberIdx = 0; memberIdx < animGroup->GetMemberCount(); ++memberIdx)
310     {
311         const int animIdx = m_BindIndexTable[memberIdx];
312         if (animIdx == NotFoundIndex){ continue; }
313 
314         ResMemberAnim memberAnim = animData.GetMemberAnimSet(animIdx);
315         switch (memberAnim.GetPrimitiveType())
316         {
317         case ResMemberAnim::PRIMITIVETYPE_TRANSFORM:
318         case ResMemberAnim::PRIMITIVETYPE_BAKED_TRANSFORM:
319             {
320                 u32 rotateAndTranslateMask;
321                 u32 scaleMask;
322                 if (memberAnim.GetPrimitiveType() == ResMemberAnim::PRIMITIVETYPE_TRANSFORM)
323                 {
324                     rotateAndTranslateMask = ResTransformAnimData::FLAG_ROTATE_NOT_EXIST |
325                                              ResTransformAnimData::FLAG_TRANSLATE_NOT_EXIST;
326                     scaleMask = ResTransformAnimData::FLAG_SCALE_NOT_EXIST;
327                 }
328                 else
329                 {
330                     rotateAndTranslateMask = ResBakedTransformAnimData::FLAG_ROTATE_NOT_EXIST |
331                                              ResBakedTransformAnimData::FLAG_TRANSLATE_NOT_EXIST;
332                     scaleMask = ResBakedTransformAnimData::FLAG_SCALE_NOT_EXIST;
333                 }
334 
335                 CalculatedTransform* target =
336                     static_cast<CalculatedTransform*>(animGroup->GetTargetPtr(memberIdx));
337 
338                 const math::Transform3* originalValue =
339                     static_cast<const math::Transform3*>(animGroup->GetOriginalValue(memberIdx));
340 
341                 const u32 flags = memberAnim.GetFlags();
342                 bool modified = false;
343 
344                 if (flags & rotateAndTranslateMask)
345                 {
346                     // TODO: 回転行列の生成は重いので、originalValueをCalculatedTransform型で保存するようにする
347                     target->SetRotateAndTranslate(originalValue->rotate, originalValue->translate);
348                     modified = true;
349                 }
350 
351                 if (flags & scaleMask)
352                 {
353                     target->SetScale(originalValue->scale);
354                     modified = true;
355                 }
356 
357                 if (modified)
358                 {
359                     UpdateFlags(target);
360 
361                     if (!m_CacheTransforms.Empty())
362                     {
363                         m_CacheTransforms[animIdx] = *target;
364                     }
365                 }
366             }
367             break;
368         case ResMemberAnim::PRIMITIVETYPE_FULL_BAKED:
369             // 全てのボーンの行列に必ず書き込む仕様なので、Resetの必要はない
370             break;
371         default:
372             NW_ASSERT(false);
373         }
374     }
375 }
376 
377 //----------------------------------------------------------
378 const anim::AnimResult*
GetResultFast(void * target,int memberIdx) const379 TransformAnimEvaluator::GetResultFast(void* target, int memberIdx) const
380 {
381     return GetResultCommon(target, memberIdx, false);
382 }
383 
384 //----------------------------------------------------------
385 const anim::AnimResult*
GetResultCommon(void * target,int memberIdx,bool writeNoAnimMember) const386 TransformAnimEvaluator::GetResultCommon(void* target, int memberIdx, bool writeNoAnimMember) const
387 {
388     using namespace anim;
389 
390     //-----------------------------------------------------------------
391     // メンバに関連付けられたアニメーションが存在しない場合は
392     // target を変更せずに NULL を返す
393     if (!HasMemberAnim(memberIdx))
394     {
395         return NULL;
396     }
397 
398     //-----------------------------------------------------------------
399     CalculatedTransform* transform =
400         reinterpret_cast<CalculatedTransform*>(target);
401     if (!m_CacheTransforms.Empty() && !m_IsCacheDirty && m_AnimData.ptr() != NULL)
402     {
403         //-----------------------------------------------------------------
404         // キャッシュがあればキャッシュの値を target にコピー
405         const int animIdx = m_BindIndexTable[memberIdx];
406         *transform = m_CacheTransforms[animIdx];
407     }
408     else
409     {
410         //-----------------------------------------------------------------
411         // アニメーションカーブを評価して対象に書き込む
412         const math::Transform3* originalValue =
413             static_cast<const math::Transform3*>(m_AnimGroup->GetOriginalValue(memberIdx));
414         if (m_AnimData.ptr() != NULL)
415         {
416             const int animIdx = m_BindIndexTable[memberIdx];
417             ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
418 
419             switch (memberAnim.GetPrimitiveType())
420             {
421             case ResMemberAnim::PRIMITIVETYPE_TRANSFORM:
422                 {
423                     ResTransformAnim transformAnim = static_cast<ResTransformAnim>(memberAnim);
424                     EvaluateMemberAnim(transform, transformAnim, m_AnimFrameController.GetFrame(), originalValue, writeNoAnimMember);
425                 }
426                 break;
427             case ResMemberAnim::PRIMITIVETYPE_BAKED_TRANSFORM:
428                 {
429                     ResBakedTransformAnim transformAnim = static_cast<ResBakedTransformAnim>(memberAnim);
430                     EvaluateMemberBakedAnim(transform, transformAnim, m_AnimFrameController.GetFrame(), originalValue, writeNoAnimMember);
431                 }
432                 break;
433             case ResMemberAnim::PRIMITIVETYPE_FULL_BAKED:
434                 {
435                     ResFullBakedAnim transformAnim = static_cast<ResFullBakedAnim>(memberAnim);
436                     math::MTX34* worldMatrix = reinterpret_cast<math::MTX34*>(target);
437 
438                     transformAnim.EvaluateTransform(worldMatrix, m_AnimFrameController.GetFrame());
439                 }
440                 break;
441             default:
442                 NW_ASSERT(false);
443                 break;
444             }
445         }
446         else
447         {
448             // アニメーションデータがない場合はオリジナル値をコピー
449             transform->SetTransform(*originalValue);
450             UpdateFlags(transform);
451         }
452     }
453 
454     // target を AnimResult にキャストして返す(親のブレンダで使用)
455     return reinterpret_cast<AnimResult*>(target);
456 }
457 
458 //----------------------------------------------------------
459 Result
TryBind(AnimGroup * animGroup)460 TransformAnimEvaluator::TryBind(AnimGroup* animGroup)
461 {
462     Result result;
463     NW_NULL_ASSERT(m_AnimData.ptr());
464 
465     result = BaseAnimEvaluator::TryBind(animGroup);
466     if (result.IsFailure())
467     {
468         return result;
469     }
470 
471     ResetNoAnimMember(animGroup, m_AnimData);
472     m_AnimGroup = animGroup;
473 
474     return result;
475 }
476 
477 } // namespace gfx
478 } // namespace nw
479