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