1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_AnimObject.cpp
4
5 Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Revision: 25777 $
14 *---------------------------------------------------------------------------*/
15
16 #include "precompiled.h"
17
18 #include <nw/gfx/gfx_TransformAnim.h>
19 #include <nw/gfx/gfx_AnimHelper.h>
20
21 namespace {
22 // HACK
23 using namespace nw::gfx;
24 using namespace nw::anim;
25
ClearMaterialHash(ResAnimGroupMember member)26 void ClearMaterialHash(ResAnimGroupMember member)
27 {
28 ResMaterial material(reinterpret_cast<void*>(member.GetResMaterialPtr()));
29
30 switch(member.GetObjectType())
31 {
32 case ResAnimGroupMember::OBJECT_TYPE_MATERIAL_COLOR:
33 material.SetMaterialColorHash(0x0);
34 break;
35
36 case ResAnimGroupMember::OBJECT_TYPE_TEXTURE_SAMPLER:
37 material.SetTextureMappersHash(0x0);
38 material.SetTextureSamplersHash(0x0);
39 break;
40
41 case ResAnimGroupMember::OBJECT_TYPE_TEXTURE_MAPPER:
42 // TODO: サンプラーが変化しない場合はHashの再計算が可能
43 material.SetTextureMappersHash(0x0);
44 break;
45
46 case ResAnimGroupMember::OBJECT_TYPE_BLEND_OPERATION:
47 material.SetFragmentOperationHash(0x0);
48 break;
49
50 case ResAnimGroupMember::OBJECT_TYPE_TEXTURE_COORDINATOR:
51 material.SetTextureCoordinatorsHash(0x0);
52 break;
53 }
54 }
55 }
56
57 namespace nw
58 {
59 namespace gfx
60 {
61
62 NW_UT_RUNTIME_TYPEINFO_ROOT_DEFINITION(AnimObject);
63 NW_UT_RUNTIME_TYPEINFO_DEFINITION(BaseAnimEvaluator, AnimObject);
64 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimEvaluator , BaseAnimEvaluator);
65 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimBlender , AnimObject);
66 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimInterpolator , AnimBlender);
67 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimAdder , AnimBlender);
68 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimOverrider , AnimBlender);
69
70 //! 汎用アニメーション評価で使用する定数です。
71 const int BaseAnimEvaluator::NotFoundIndex = -1;
72
73 namespace {
74
75 /*!--------------------------------------------------------------------------*
76 @brief タイプに対応するアニメーションのブレンドオペレーションを取得します。
77 *---------------------------------------------------------------------------*/
78 anim::AnimBlendOp*
GetAnimBlendOpByType(int blendOpType)79 GetAnimBlendOpByType(int blendOpType)
80 {
81 static anim::AnimBlendOpBool blendOpBool;
82 static anim::AnimBlendOpInt blendOpInt;
83 static anim::AnimBlendOpFloat blendOpFloat;
84 static anim::AnimBlendOpVector2 blendOpVector2;
85 static anim::AnimBlendOpVector3 blendOpVector3;
86 static anim::AnimBlendOpRgbaColor blendOpRgbaColor;
87 static anim::AnimBlendOpTexture blendOpTexture;
88
89 static TransformAnimBlendOpStandard blendOpTransform;
90 static TransformAnimBlendOpAccScale blendOpTransformAccScale;
91 static TransformAnimBlendOpQuat blendOpTransformQuat;
92 static TransformAnimBlendOpAccScaleQuat blendOpTransformAccScaleQuat;
93
94 switch (blendOpType)
95 {
96 case anim::ResAnimGroup::BLENDOP_BOOL:
97 return &blendOpBool;
98 case anim::ResAnimGroup::BLENDOP_INT:
99 return &blendOpInt;
100 case anim::ResAnimGroup::BLENDOP_FLOAT:
101 return &blendOpFloat;
102 case anim::ResAnimGroup::BLENDOP_VECTOR2:
103 return &blendOpVector2;
104 case anim::ResAnimGroup::BLENDOP_VECTOR3:
105 return &blendOpVector3;
106 case anim::ResAnimGroup::BLENDOP_RGBA_COLOR:
107 return &blendOpRgbaColor;
108 case anim::ResAnimGroup::BLENDOP_TEXTURE:
109 return &blendOpTexture;
110
111 case anim::ResAnimGroup::BLENDOP_CALCULATED_TRANSFORM:
112 return &blendOpTransform;
113 case anim::ResAnimGroup::BLENDOP_CALCULATED_TRANSFORM_ACCURATE_SCALE:
114 return &blendOpTransformAccScale;
115 case anim::ResAnimGroup::BLENDOP_CALCULATED_TRANSFORM_QUAT:
116 return &blendOpTransformQuat;
117 case anim::ResAnimGroup::BLENDOP_CALCULATED_TRANSFORM_ACCURATE_SCALE_QUAT:
118 return &blendOpTransformAccScaleQuat;
119
120 default:
121 return NULL;
122 }
123 }
124
125 } // namespace
126
127 //----------------------------------------------------------
AnimGroup(anim::ResAnimGroup resAnimGroup,SceneNode * sceneNode,os::IAllocator * allocator)128 AnimGroup::AnimGroup(
129 anim::ResAnimGroup resAnimGroup,
130 SceneNode* sceneNode,
131 os::IAllocator* allocator)
132 : GfxObject(allocator),
133 m_ResAnimGroup(resAnimGroup),
134 m_SceneNode(sceneNode),
135 m_PreEvaluateCallback(NULL)
136 {
137 }
138
139 //----------------------------------------------------------
140 void
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,const anim::ResAnimGroup resAnimGroup,bool useOriginalValue)141 AnimGroup::GetMemorySizeForInitialize(
142 os::MemorySizeCalculator* pSize,
143 const anim::ResAnimGroup resAnimGroup,
144 bool useOriginalValue)
145 {
146 const int blendOpCount = resAnimGroup.GetBlendOperationsCount();
147 const int memberCount = resAnimGroup.GetMemberInfoSetCount();
148
149 os::MemorySizeCalculator& size = *pSize;
150
151 size += sizeof(anim::AnimBlendOp*) * blendOpCount;
152 size += sizeof(int) * memberCount;
153 size += sizeof(void*) * memberCount;
154 size += sizeof(void*) * memberCount;
155
156 if (useOriginalValue)
157 {
158 size += sizeof(void*) * memberCount;
159 }
160 }
161
162 //----------------------------------------------------------
Initialize(bool useOriginalValue)163 Result AnimGroup::Initialize(bool useOriginalValue)
164 {
165 Result result = INITIALIZE_RESULT_OK;
166
167 {
168 const int blendOpCount = m_ResAnimGroup.GetBlendOperationsCount();
169 NW_ASSERT(blendOpCount > 0);
170
171 void* memory = GetAllocator().Alloc(sizeof(anim::AnimBlendOp*) * blendOpCount);
172
173 if (memory == NULL)
174 {
175 result |= Result::MASK_FAIL_BIT;
176 }
177 NW_ENSURE_AND_RETURN(result);
178
179 m_BlendOperations = ut::MoveArray<anim::AnimBlendOp*>(memory, blendOpCount, &GetAllocator());
180 for (int blendOpIdx = 0; blendOpIdx < blendOpCount; ++blendOpIdx)
181 {
182 const int blendOpType = m_ResAnimGroup.GetBlendOperations(blendOpIdx);
183 m_BlendOperations.PushBack(GetAnimBlendOpByType(blendOpType));
184 }
185 }
186
187 const int memberCount = GetMemberCount();
188 NW_ASSERT(memberCount > 0);
189
190 {
191 void* memory = GetAllocator().Alloc(sizeof(int) * memberCount);
192 if (memory == NULL)
193 {
194 result |= Result::MASK_FAIL_BIT;
195 }
196 NW_ENSURE_AND_RETURN(result);
197
198 m_TargetObjectIndicies = ut::MoveArray<int>(memory, memberCount, &GetAllocator());
199 m_TargetObjectIndicies.Resize(memberCount);
200 }
201
202 {
203 void* memory = GetAllocator().Alloc(sizeof(void*) * memberCount);
204 if (memory == NULL)
205 {
206 result |= Result::MASK_FAIL_BIT;
207 }
208 NW_ENSURE_AND_RETURN(result);
209
210 m_TargetObjects = ut::MoveArray<void*>(memory, memberCount, &GetAllocator());
211 m_TargetObjects.Resize(memberCount);
212 }
213
214 {
215 void* memory = GetAllocator().Alloc(sizeof(void*) * memberCount);
216 if (memory == NULL)
217 {
218 result |= Result::MASK_FAIL_BIT;
219 }
220 NW_ENSURE_AND_RETURN(result);
221
222 m_TargetPtrs = ut::MoveArray<void*>(memory, memberCount, &GetAllocator());
223 m_TargetPtrs.Resize(memberCount);
224 }
225
226 if (useOriginalValue)
227 {
228 void* memory = GetAllocator().Alloc(sizeof(void*) * memberCount);
229 if (memory == NULL)
230 {
231 result |= Result::MASK_FAIL_BIT;
232 }
233 NW_ENSURE_AND_RETURN(result);
234
235 m_OriginalValues = ut::MoveArray<const void*>(memory, memberCount, &GetAllocator());
236 m_OriginalValues.Resize(memberCount);
237 }
238
239 return result;
240 }
241
242 //----------------------------------------------------------
243 Result
TryBind(AnimGroup * animGroup)244 BaseAnimEvaluator::TryBind(AnimGroup* animGroup)
245 {
246 NW_NULL_ASSERT(animGroup);
247 NW_ASSERT(std::strcmp(m_AnimData.GetTargetAnimGroupName(), animGroup->GetName()) == 0);
248 NW_ASSERT(m_AnimGroup == NULL);
249
250 const int memberCount = animGroup->GetMemberCount();
251 bool resultResize = m_BindIndexTable.Resize(memberCount);
252 NW_ASSERTMSG(resultResize,
253 "Member count exceeded upper limit. Increase AnimEvaluator::Builder::MaxMembers.");
254
255 const int animMemberCount = m_AnimData.GetMemberAnimSetCount();
256 bool resultReverseResize = m_ReverseBindIndexTable.Resize(animMemberCount);
257 NW_ASSERTMSG(resultReverseResize,
258 "Animation member count exceeded upper limit. Increase AnimEvaluator::Builder::MaxAnimMembers.");
259
260 int boundAnimCount = 0;
261 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
262 {
263 // 見つからなかったときのインデックスで埋める
264 m_BindIndexTable[memberIdx] = NotFoundIndex;
265 }
266
267 for (int animIdx = 0; animIdx < animMemberCount; ++animIdx)
268 {
269 anim::ResMemberAnim member = m_AnimData.GetMemberAnimSet(animIdx);
270 const int bindTargetIdx = animGroup->GetResAnimGroupMemberIndex(member.GetPath());
271
272 // 辞書引きで見つからなかったときは、モデルに対象が存在しない
273 if (bindTargetIdx == -1)
274 {
275 m_ReverseBindIndexTable[animIdx] = NotFoundIndex;
276 continue;
277 }
278
279 m_BindIndexTable[bindTargetIdx] = animIdx;
280 m_ReverseBindIndexTable[animIdx] = bindTargetIdx;
281 ++boundAnimCount;
282
283 //HACK
284 anim::ResAnimGroupMember resAnimGroupMember =
285 animGroup->GetResAnimGroupMember(bindTargetIdx);
286 ClearMaterialHash(resAnimGroupMember);
287 }
288
289 m_AnimGroup = animGroup;
290
291 // すべてのメンバアニメーションがバインドされました。
292 if (boundAnimCount == m_AnimData.GetMemberAnimSetCount())
293 {
294 return Result(BIND_RESULT_OK);
295 }
296
297 // バインドされたメンバアニメーションが無かったので失敗とします。
298 if (boundAnimCount == 0)
299 {
300 return Result(BIND_RESULT_NO_MEMBER_BOUND | Result::MASK_FAIL_BIT);
301 }
302
303 // 上のどちらでもない場合は、バインドには成功したが
304 // すべてのメンバアニメがバインドされなかったことを通知します。
305 return Result(BIND_RESULT_NOT_ALL_ANIM_MEMBER_BOUND);
306 }
307
308 //----------------------------------------------------------
309 void
ResetMember(int memberIdx)310 BaseAnimEvaluator::ResetMember(int memberIdx)
311 {
312 NW_NULL_ASSERT(m_AnimGroup);
313
314 if (!m_AnimGroup->HasOriginalValue())
315 {
316 return;
317 }
318
319 anim::ResGraphicsAnimGroup data = m_AnimGroup->GetResGraphicsAnimGroup();
320 NW_ASSERT(data.IsValid());
321
322 // 使用先によってOriginalValueにどの型が入っているかが異なる
323 switch (data.GetTargetType())
324 {
325 case anim::ResGraphicsAnimGroup::TARGET_TYPE_BONE:
326 case anim::ResGraphicsAnimGroup::TARGET_TYPE_MATERIAL:
327 case anim::ResGraphicsAnimGroup::TARGET_TYPE_VISIBILITY:
328 case anim::ResGraphicsAnimGroup::TARGET_TYPE_LIGHT:
329 case anim::ResGraphicsAnimGroup::TARGET_TYPE_CAMERA:
330 {
331 const ResAnimGroupMember resAnimGroupMember = m_AnimGroup->GetResAnimGroupMember(memberIdx);
332 resAnimGroupMember.SetValueForType(
333 m_AnimGroup->GetTargetObject(memberIdx),
334 m_AnimGroup->GetOriginalValue(memberIdx));
335 }
336 break;
337
338 default:
339 // 未対応
340 // memo:
341 // そもそもHasOriginalValueがfalseならばここにはこないので、
342 // ここにきたら実装忘れのはず
343 NW_ASSERTMSG(false,
344 "The type[%d] has original value, but there is no implementation.\n",
345 data.GetTargetType());
346 }
347
348
349 m_IsCacheDirty = true;
350 }
351
352 //----------------------------------------------------------
353 int
GetCacheBufferSizeNeeded() const354 AnimEvaluator::GetCacheBufferSizeNeeded() const
355 {
356 return GetCacheBufferSizeNeeded(m_AnimData);
357 }
358
359 //----------------------------------------------------------
360 int
GetCacheBufferSizeNeeded(const anim::ResAnim & animData)361 AnimEvaluator::GetCacheBufferSizeNeeded(const anim::ResAnim& animData)
362 {
363 const int headBytes = anim::AnimResult().GetOffsetToValueBuffer();
364 int size = 0;
365
366 const int memberAnimCount = animData.GetMemberAnimSetCount();
367 for (int animIdx = 0; animIdx < memberAnimCount; ++animIdx)
368 {
369 const anim::ResMemberAnim memberAnim = animData.GetMemberAnimSet(animIdx);
370 const int primBytes = memberAnim.GetPrimitiveSize();
371 size += ut::RoundUp(headBytes + primBytes, sizeof(bit32));
372 }
373 return size;
374 }
375
376 //----------------------------------------------------------
377 void
SetCacheBufferPointers()378 AnimEvaluator::SetCacheBufferPointers()
379 {
380 const int headBytes = anim::AnimResult().GetOffsetToValueBuffer();
381 u8* cachePtr = reinterpret_cast<u8*>(m_CacheBuf);
382 const int memberAnimCount = m_AnimData.GetMemberAnimSetCount();
383 for (int animIdx = 0; animIdx < memberAnimCount; ++animIdx)
384 {
385 m_CachePtrs[animIdx] = reinterpret_cast<anim::AnimResult*>(cachePtr);
386 const anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
387 const int primBytes = memberAnim.GetPrimitiveSize();
388 cachePtr += ut::RoundUp(headBytes + primBytes, sizeof(bit32));
389 }
390 }
391
392 //----------------------------------------------------------
AnimEvaluator(os::IAllocator * allocator)393 AnimEvaluator::AnimEvaluator(
394 os::IAllocator* allocator)
395 : BaseAnimEvaluator(allocator),
396 m_CacheBuf(NULL)
397 {
398 }
399
400 //----------------------------------------------------------
401 void
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,const nw::anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers,bool allocCache)402 AnimEvaluator::GetMemorySizeForInitialize(
403 os::MemorySizeCalculator* pSize,
404 const nw::anim::ResAnim& animData,
405 const int maxMembers,
406 const int maxAnimMembers,
407 bool allocCache)
408 {
409 os::MemorySizeCalculator& size = *pSize;
410
411 BaseAnimEvaluator::GetMemorySizeForInitialize(pSize, maxMembers, maxAnimMembers);
412 size += sizeof(anim::AnimResult*) * maxAnimMembers;
413
414 if (allocCache)
415 {
416 size += AnimEvaluator::GetCacheBufferSizeNeeded(animData);
417 }
418 }
419
420 //----------------------------------------------------------
Initialize(const nw::anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers,bool allocCache)421 Result AnimEvaluator::Initialize(
422 const nw::anim::ResAnim& animData,
423 const int maxMembers,
424 const int maxAnimMembers,
425 bool allocCache)
426 {
427 // 親クラスの初期化を通す
428 Result result = BaseAnimEvaluator::Initialize(animData, maxMembers, maxAnimMembers);
429 NW_ENSURE_AND_RETURN(result);
430
431 void* memory = GetAllocator().Alloc(sizeof(anim::AnimResult*) * maxAnimMembers);
432 if (memory == NULL)
433 {
434 result |= Result::MASK_FAIL_BIT;
435 }
436 NW_ENSURE_AND_RETURN(result);
437
438 m_CachePtrs = ut::MoveArray<anim::AnimResult*>(memory, maxAnimMembers, &GetAllocator());
439 m_CachePtrs.Resize(animData.GetMemberAnimSetCount());
440
441 if (allocCache)
442 {
443 // サイズ0でのAllocを回避する
444 // CreateEmpty~Anim()などを使用した場合に起こりうる
445 if (animData.GetMemberAnimSetCount() != 0)
446 {
447 m_CacheBuf = GetAllocator().Alloc(GetCacheBufferSizeNeeded());
448 if (m_CacheBuf == NULL)
449 {
450 result |= Result::MASK_FAIL_BIT;
451 }
452 NW_ENSURE_AND_RETURN(result);
453
454 SetCacheBufferPointers();
455 }
456 }
457
458 return result;
459 }
460
461 //----------------------------------------------------------
462 const anim::AnimResult*
GetResult(void * target,int memberIdx) const463 AnimEvaluator::GetResult(
464 void* target,
465 int memberIdx
466 ) const
467 {
468 //-----------------------------------------------------------------
469 // メンバに関連付けられたアニメーションが存在しない場合は
470 // target を変更せずに NULL を返す
471 if (!HasMemberAnim(memberIdx))
472 {
473 return NULL;
474 }
475
476 //-----------------------------------------------------------------
477 const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
478 const int animIdx = m_BindIndexTable[memberIdx];
479 if (m_CacheBuf != NULL && !m_IsCacheDirty)
480 {
481 //-----------------------------------------------------------------
482 // キャッシュがあればキャッシュの値を返す
483 if (blendOp != NULL)
484 {
485 return m_CachePtrs[animIdx];
486 }
487 else
488 {
489 anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
490 memberAnim.ApplyCacheForType(target, m_CachePtrs[animIdx]);
491 // ブレンドオペレーションがない場合、返り値は使用されないが
492 // ブレンダに評価したことを伝えるために target を返す
493 return reinterpret_cast<anim::AnimResult*>(target);
494 }
495 }
496 else
497 {
498 //-----------------------------------------------------------------
499 // アニメーションカーブを評価して対象に書き込む
500 anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
501 const void* originalValue = m_AnimGroup->HasOriginalValue()
502 ? m_AnimGroup->GetOriginalValue(memberIdx)
503 : NULL;
504
505 if (blendOp != NULL)
506 {
507 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
508 bit32 flags = memberAnim.EvaluateResultForType(
509 result->GetValueBuffer(), result->GetFlags(),
510 m_AnimFrameController.GetFrame(), originalValue);
511 result->SetFlags(flags);
512 return result;
513 }
514 else
515 {
516 memberAnim.EvaluateResultForType(
517 target, 0, m_AnimFrameController.GetFrame(),
518 originalValue);
519
520 // ブレンドオペレーションがない場合、返り値は使用されないが
521 // ブレンダに評価したことを伝えるために target を返す
522 return reinterpret_cast<anim::AnimResult*>(target);
523 }
524 }
525 }
526
527 //----------------------------------------------------------
528 void
UpdateCache()529 AnimEvaluator::UpdateCache()
530 {
531 if (m_CacheBuf != NULL && m_IsCacheDirty)
532 {
533 int animCount = m_AnimData.GetMemberAnimSetCount();
534 for (int animIdx = 0; animIdx < animCount; ++animIdx)
535 {
536 anim::AnimResult* result = m_CachePtrs[animIdx];
537 result->ResetFlags();
538
539 // バインドされたメンバーがモデルに存在しない場合もあるのでチェック
540 const int memberIdx = m_ReverseBindIndexTable[animIdx];
541 if (memberIdx == BaseAnimEvaluator::NotFoundIndex)
542 {
543 continue;
544 }
545
546 this->GetResult(result, memberIdx);
547 }
548 m_IsCacheDirty = false;
549 }
550 }
551
552 //----------------------------------------------------------
553 const anim::AnimResult*
GetResult(void * target,int memberIdx) const554 AnimInterpolator::GetResult(
555 void* target,
556 int memberIdx
557 ) const
558 {
559 //----------------------------------------------------------
560 // ブレンドオペレーションがない場合および
561 // ブレンドオペレーションにブレンド処理がない場合は上書き処理
562 const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
563 if (blendOp == NULL || !blendOp->HasBlend())
564 {
565 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
566 {
567 if (m_AnimObjects[animIdx] == NULL)
568 {
569 continue;
570 }
571 const anim::AnimResult* childResult =
572 m_AnimObjects[animIdx]->GetResult(target, memberIdx);
573 if (childResult != NULL)
574 {
575 return childResult;
576 }
577 }
578 return NULL;
579 }
580
581 if (m_IsOldMethod)
582 {
583 // TODO: こちらのブロックを整理。
584
585 //----------------------------------------------------------
586 // 有効な子アニメーションの重みの合計を求める
587 float weightSum = 0.0f;
588 const AnimObject* lastAnimObj = NULL;
589 int validAnimCount = 0;
590 for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
591 {
592 if (m_AnimObjects[animIdx] == NULL)
593 {
594 continue;
595 }
596 const float weight = m_Weights[animIdx];
597 if (!AnimWeightNearlyEqualZero(weight))
598 {
599 if (m_AnimObjects[animIdx]->HasMemberAnim(memberIdx))
600 {
601 weightSum += weight;
602 lastAnimObj = m_AnimObjects[animIdx];
603 ++validAnimCount;
604 }
605 }
606 }
607
608 if (validAnimCount == 0)
609 {
610 // 有効な子アニメーションが存在しない場合は
611 // target を変更せずに NULL を返す
612 return NULL;
613 }
614 else if (validAnimCount == 1)
615 {
616 // 有効な子アニメーションが 1 つだけの場合は
617 // そのアニメーションの結果を返す
618 return lastAnimObj->GetResult(target, memberIdx);
619 }
620
621 // 重みの合計が 1.0 でない場合は正規化スケールを計算
622 const float weightNormalizeScale = GetAnimWeightNormalizeScale(weightSum);
623
624 //----------------------------------------------------------
625 // 補間は操作空間があればそこで行われるべきなので
626 // target の CONVERTED フラグを退避してからオンに
627 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
628 const bool convertedBak = result->IsEnabledFlags(anim::AnimResult::FLAG_CONVERTED);
629 result->EnableFlags(anim::AnimResult::FLAG_CONVERTED, true);
630
631 //----------------------------------------------------------
632 // すべての子アニメーションについてループ
633 anim::AnimResult workResult;
634 bool written = false;
635 float compWeights[anim::AnimResult::MAX_COMPONENTS];
636 //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
637 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
638 {
639 if (m_AnimObjects[animIdx] == NULL)
640 {
641 continue;
642 }
643 const float childWeight = m_Weights[animIdx] * weightNormalizeScale;
644 if (!AnimWeightNearlyEqualZero(childWeight))
645 {
646 // 退避した CONVERTED フラグを work に反映
647 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
648 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
649 workResult.EnableFlags(anim::AnimResult::FLAG_CONVERTED, convertedBak);
650
651 // 評価
652 const anim::AnimResult* childResult =
653 m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
654 if (childResult != NULL)
655 {
656 written = true;
657 if (!blendOp->Blend(result, compWeights, childResult, &childWeight))
658 {
659 break;
660 }
661 }
662 }
663 }
664
665 //----------------------------------------------------------
666 // target の CONVERTED フラグを復元
667 if (!convertedBak)
668 {
669 result->DisableFlags(anim::AnimResult::FLAG_CONVERTED);
670 }
671
672 if (!written) // 有効な子アニメーションなし
673 {
674 return NULL;
675 }
676
677 //----------------------------------------------------------
678 // ブレンド後の処理があれば実行
679 if (!convertedBak && blendOp->HasPostBlend())
680 {
681 blendOp->PostBlend(result, compWeights);
682 }
683 return result;
684 }
685 else
686 {
687 bool isValidAnim = false;
688 for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
689 {
690 if (m_AnimObjects[animIdx] && m_AnimObjects[animIdx]->HasMemberAnim(memberIdx))
691 {
692 isValidAnim = true;
693 break;
694 }
695 }
696
697 // 有効な子アニメーションが存在しない場合は
698 // target を変更せずに NULL を返す
699 if (!isValidAnim)
700 {
701 return NULL;
702 }
703
704 // アニメーション重みの正規化を必要なら行います。
705 if (m_IsWeightDirty && m_IsWeightNormalizationEnabled)
706 {
707 NormalizeWeight();
708 }
709
710 //----------------------------------------------------------
711 // 補間は操作空間があればそこで行われるべきなので
712 // target の CONVERTED フラグを退避してからオンに
713 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
714 const bool convertedBak = result->IsEnabledFlags(anim::AnimResult::FLAG_CONVERTED);
715 result->EnableFlags(anim::AnimResult::FLAG_CONVERTED, true);
716
717 //----------------------------------------------------------
718 // すべての子アニメーションについてループ
719 anim::AnimResult workResult;
720 float compWeights[anim::AnimResult::MAX_COMPONENTS];
721 //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
722 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
723 {
724 const float childWeight = m_NormalizedWeights[animIdx];
725 if (!AnimWeightNearlyEqualZero(childWeight))
726 {
727 // 退避した CONVERTED フラグを work に反映
728 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
729 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
730 workResult.EnableFlags(anim::AnimResult::FLAG_CONVERTED, convertedBak);
731
732 // 評価
733 const anim::AnimResult* childResult = NULL;
734 if (m_AnimObjects[animIdx] != NULL)
735 {
736 childResult = m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
737 }
738
739 if (childResult == NULL)
740 {
741 NW_ASSERT(GetAnimGroup()->HasOriginalValue());
742 blendOp->ConvertToAnimResult(
743 &workResult,
744 GetAnimGroup()->GetOriginalValue(memberIdx));
745 childResult = &workResult;
746
747 NW_NULL_ASSERT(childResult);
748 }
749
750 if (!blendOp->Blend(result, compWeights, childResult, &childWeight))
751 {
752 break;
753 }
754
755 }
756 }
757
758 //----------------------------------------------------------
759 // target の CONVERTED フラグを復元
760 if (!convertedBak)
761 {
762 result->DisableFlags(anim::AnimResult::FLAG_CONVERTED);
763 }
764
765 //----------------------------------------------------------
766 // ブレンド後の処理があれば実行
767 if (!convertedBak && blendOp->HasPostBlend())
768 {
769 blendOp->PostBlend(result, compWeights);
770 }
771 return result;
772 }
773 }
774
775 //----------------------------------------------------------
776 const anim::AnimResult*
GetResult(void * target,int memberIdx) const777 AnimAdder::GetResult(
778 void* target,
779 int memberIdx
780 ) const
781 {
782 //----------------------------------------------------------
783 // ブレンドオペレーションがない場合および
784 // ブレンドオペレーションにブレンド処理がない場合は上書き処理
785 const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
786 if (blendOp == NULL || !blendOp->HasBlend())
787 {
788 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
789 {
790 if (m_AnimObjects[animIdx] == NULL)
791 {
792 continue;
793 }
794 const anim::AnimResult* childResult =
795 m_AnimObjects[animIdx]->GetResult(target, memberIdx);
796 if (childResult != NULL)
797 {
798 return childResult;
799 }
800 }
801 return NULL;
802 }
803
804 //----------------------------------------------------------
805 // 補間は操作空間があればそこで行われるべきなので
806 // target の CONVERTED フラグを退避してからオンに
807 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
808 const bool convertedBak = result->IsEnabledFlags(anim::AnimResult::FLAG_CONVERTED);
809 result->EnableFlags(anim::AnimResult::FLAG_CONVERTED, true);
810
811 //----------------------------------------------------------
812 // すべての子アニメーションについてループ
813 anim::AnimResult workResult;
814 bool written = false;
815 //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
816 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
817 {
818 if (m_AnimObjects[animIdx] == NULL)
819 {
820 continue;
821 }
822 const float childWeight = m_Weights[animIdx];
823 if (!AnimWeightNearlyEqualZero(childWeight))
824 {
825 // 退避した CONVERTED フラグを work に反映
826 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
827 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
828 workResult.EnableFlags(anim::AnimResult::FLAG_CONVERTED, convertedBak);
829
830 // 評価
831 const anim::AnimResult* childResult =
832 m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
833 if (childResult != NULL)
834 {
835 written = true;
836 if (!blendOp->Blend(result, NULL, childResult, &childWeight))
837 {
838 break;
839 }
840 }
841 }
842 }
843
844 //----------------------------------------------------------
845 // target の CONVERTED フラグを復元
846 if (!convertedBak)
847 {
848 result->DisableFlags(anim::AnimResult::FLAG_CONVERTED);
849 }
850
851 if (!written) // 有効な子アニメーションなし
852 {
853 return NULL;
854 }
855
856 //----------------------------------------------------------
857 // ブレンド後の処理があれば実行
858 if (!convertedBak && blendOp->HasPostBlend())
859 {
860 blendOp->PostBlend(result, NULL);
861 }
862 return result;
863 }
864
865 //----------------------------------------------------------
866 const anim::AnimResult*
GetResult(void * target,int memberIdx) const867 AnimOverrider::GetResult(
868 void* target,
869 int memberIdx
870 ) const
871 {
872 //----------------------------------------------------------
873 // ブレンドオペレーションがない場合および
874 // ブレンドオペレーションにブレンド処理がない場合は上書き処理
875 const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
876 if (blendOp == NULL || !blendOp->HasBlend())
877 {
878 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
879 {
880 if (m_AnimObjects[animIdx] == NULL)
881 {
882 continue;
883 }
884 const anim::AnimResult* childResult =
885 m_AnimObjects[animIdx]->GetResult(target, memberIdx);
886 if (childResult != NULL)
887 {
888 return childResult;
889 }
890 }
891 return NULL;
892 }
893
894 //----------------------------------------------------------
895 // すべての子アニメーションについてループ
896 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
897 anim::AnimResult workResult;
898 bool written = false;
899 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
900 {
901 if (m_AnimObjects[animIdx] == NULL)
902 {
903 continue;
904 }
905 const anim::AnimResult* childResult =
906 m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
907 if (childResult != NULL)
908 {
909 written = true;
910 if (blendOp->Override(result, childResult)) // 全成分を上書きしたら true が返る
911 {
912 return result;
913 }
914 }
915 }
916
917 if (!written) // 有効な子アニメーションなし
918 {
919 return NULL;
920 }
921
922 return result;
923 }
924
925 //----------------------------------------------------------
926 void
Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing)927 AnimBinding::Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing)
928 {
929 for (int animGroupIdx = 0; animGroupIdx < m_AnimGroups.Size(); ++animGroupIdx)
930 {
931 AnimGroup* animGroup = m_AnimGroups[animGroupIdx];
932
933 // アニメーションの有無と評価タイミングをチェック
934 if (animGroup == NULL || animGroup->GetResGraphicsAnimGroup().GetEvaluationTiming() != timing)
935 {
936 continue;
937 }
938
939 for (int animObjectIdx = 0; animObjectIdx < m_AnimObjectCountPerGroup; ++animObjectIdx)
940 {
941 const int index = animGroupIdx * m_AnimObjectCountPerGroup + animObjectIdx;
942 AnimObject* animObj = m_AnimObjects[index];
943 if (animObj == NULL)
944 {
945 continue;
946 }
947
948 // アニメーション評価結果の内部キャッシュが古ければ更新
949 animObj->UpdateCache();
950
951 // 高速化のため、ブレンダの有無・Transformかどうかで分岐
952 if (ut::IsTypeOf<AnimEvaluator>(animObj))
953 {
954 EvaluateSimple(animGroup, static_cast<AnimEvaluator*>(animObj));
955 }
956 else if (ut::IsTypeOf<TransformAnimEvaluator>(animObj))
957 {
958 EvaluateTransformSimple(animGroup, static_cast<TransformAnimEvaluator*>(animObj));
959 }
960 else
961 {
962 EvaluateBlender(animGroup, animObj);
963 }
964 }
965 }
966 }
967
968 //----------------------------------------------------------
EvaluateSimple(AnimGroup * animGroup,AnimEvaluator * evaluator)969 void AnimBinding::EvaluateSimple(AnimGroup* animGroup, AnimEvaluator* evaluator)
970 {
971 NW_ASSERT(!(animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM));
972
973 // 汎用アニメーションを評価
974 int lastTargetObjIdx = -1;
975 bool targetObjSkipFlag = false;
976 int animCount = evaluator->GetAnimData().GetMemberAnimSetCount();
977 for (int animIdx = 0; animIdx < animCount; ++animIdx)
978 {
979 int memberIdx = evaluator->ReverseBindIndexTable()[animIdx];
980 if (memberIdx == BaseAnimEvaluator::NotFoundIndex)
981 {
982 continue;
983 }
984 EvaluateMember(animGroup, memberIdx, evaluator, lastTargetObjIdx, targetObjSkipFlag);
985 }
986 }
987
988 //----------------------------------------------------------
EvaluateTransformSimple(AnimGroup * animGroup,TransformAnimEvaluator * evaluator)989 void AnimBinding::EvaluateTransformSimple(AnimGroup* animGroup, TransformAnimEvaluator* evaluator)
990 {
991 NW_ASSERT(animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM);
992
993 // トランスフォームアニメーションを評価
994 int animCount = evaluator->GetAnimData().GetMemberAnimSetCount();
995 for (int animIdx = 0; animIdx < animCount; ++animIdx)
996 {
997 int memberIdx = evaluator->ReverseBindIndexTable()[animIdx];
998 if (memberIdx == BaseAnimEvaluator::NotFoundIndex)
999 {
1000 continue;
1001 }
1002 EvaluateTransformMemberFast(animGroup, memberIdx, evaluator);
1003 }
1004 }
1005
1006 //----------------------------------------------------------
EvaluateBlender(AnimGroup * animGroup,AnimObject * animObj)1007 void AnimBinding::EvaluateBlender(AnimGroup* animGroup, AnimObject* animObj)
1008 {
1009 if (animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM)
1010 {
1011 // トランスフォームアニメーションを評価
1012 int memberCount = animGroup->GetMemberCount();
1013 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1014 {
1015 EvaluateTransformMember(animGroup, memberIdx, animObj);
1016 }
1017 }
1018 else
1019 {
1020 // 汎用アニメーションを評価
1021 int lastTargetObjIdx = -1;
1022 bool targetObjSkipFlag = false;
1023 int memberCount = animGroup->GetMemberCount();
1024 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1025 {
1026 EvaluateMember(animGroup, memberIdx, animObj, lastTargetObjIdx, targetObjSkipFlag);
1027 }
1028 }
1029 }
1030
1031 //----------------------------------------------------------
EvaluateTransformMember(AnimGroup * animGroup,int memberIdx,AnimObject * animObj)1032 void AnimBinding::EvaluateTransformMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj)
1033 {
1034 AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback();
1035
1036 // 評価前コールバックの呼び出し
1037 if (preEvaluateCallback != NULL)
1038 {
1039 const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx);
1040 if (!preEvaluateCallback(animGroup, targetObjIdx))
1041 {
1042 return;
1043 }
1044 }
1045
1046 // 評価
1047 CalculatedTransform* target = static_cast<CalculatedTransform*>(animGroup->GetTargetPtr(memberIdx));
1048 animObj->GetResult(target, memberIdx);
1049
1050 // Setter経由で設定する必要はないので、Setterは呼び出さない
1051 // Setter内部で回転行列の生成を行うので、呼び出すとパフォーマンスにも大きく影響する
1052 }
1053
1054 //----------------------------------------------------------
EvaluateTransformMemberFast(AnimGroup * animGroup,int memberIdx,TransformAnimEvaluator * evaluator)1055 void AnimBinding::EvaluateTransformMemberFast(AnimGroup* animGroup, int memberIdx, TransformAnimEvaluator* evaluator)
1056 {
1057 AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback();
1058
1059 // 評価前コールバックの呼び出し
1060 if (preEvaluateCallback != NULL)
1061 {
1062 const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx);
1063 if (!preEvaluateCallback(animGroup, targetObjIdx))
1064 {
1065 return;
1066 }
1067 }
1068
1069 // 評価
1070 CalculatedTransform* target = static_cast<CalculatedTransform*>(animGroup->GetTargetPtr(memberIdx));
1071 evaluator->GetResultFast(target, memberIdx);
1072
1073 // Setter経由で設定する必要はないので、Setterは呼び出さない
1074 // Setter内部で回転行列の生成を行うので、呼び出すとパフォーマンスにも大きく影響する
1075 }
1076
1077 //----------------------------------------------------------
EvaluateMember(AnimGroup * animGroup,int memberIdx,AnimObject * animObj,int & lastTargetObjIdx,bool & targetObjSkipFlag)1078 void AnimBinding::EvaluateMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj, int& lastTargetObjIdx, bool& targetObjSkipFlag)
1079 {
1080 AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback();
1081
1082 // 評価前コールバックの呼び出し
1083 if (preEvaluateCallback != NULL)
1084 {
1085 const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx);
1086 if (targetObjIdx != lastTargetObjIdx)
1087 {
1088 // 高速化のため前回と対象オブジェクトが異なる場合だけ評価前コールバックを呼ぶ
1089 targetObjSkipFlag = !preEvaluateCallback(animGroup, targetObjIdx);
1090 lastTargetObjIdx = targetObjIdx;
1091 }
1092 if (targetObjSkipFlag)
1093 {
1094 return;
1095 }
1096 }
1097
1098 // 評価
1099 anim::ResAnimGroupMember member = animGroup->GetResAnimGroupMember(memberIdx);
1100 void* target = NULL;
1101 ut::Offset texturePatternTarget;
1102
1103 if (member.GetObjectType() == anim::ResAnimGroupMember::OBJECT_TYPE_TEXTURE_MAPPER &&
1104 member.GetMemberType() == anim::ResTextureMapperMember::MEMBER_TYPE_TEXTURE)
1105 {
1106 // テクスチャパターンアニメーションは、targetを上書きせずにSetterのみ呼び出す
1107 //
1108 // マテリアルのバッファが有効な場合は、targetは動的に確保されたReferenceTextureを指す
1109 // それを上書きすると、解放時にアロケータで確保されていないポインタを解放しようとしてクラッシュする
1110 target = &texturePatternTarget;
1111 }
1112 else
1113 {
1114 target = animGroup->GetTargetPtr(memberIdx);
1115 }
1116
1117 const anim::AnimBlendOp* blendOp = animGroup->GetBlendOperation(memberIdx);
1118 const anim::AnimResult* resultPtr = NULL;
1119 if (blendOp != NULL)
1120 {
1121 // ブレンドオペレーションがある場合は
1122 // AnimResult オブジェクト経由でターゲットに書き込む
1123 anim::AnimResult result;
1124 resultPtr = animObj->GetResult(&result, memberIdx);
1125 if (resultPtr != NULL)
1126 {
1127 blendOp->Apply(target, resultPtr); // VALID フラグがオンの成分のみ書き込み
1128 }
1129 }
1130 else
1131 {
1132 // ブレンドオペレーションがない場合はターゲットを直接上書き
1133 resultPtr = animObj->GetResult(target, memberIdx);
1134 }
1135
1136 // transformのメンバの場合は、setterを呼びださない。
1137 bool isTransformMember = (
1138 (member.GetObjectType() == anim::ResAnimGroupMember::OBJECT_TYPE_TRANSFORM) &&
1139 (member.GetMemberType() == anim::ResTransformMember::MEMBER_TYPE_TRANSFORM)
1140 );
1141
1142 if (!isTransformMember && resultPtr)
1143 {
1144 // メモリ書き込み以外の処理が必要なメンバのためにSetterを呼び出す
1145 // (コマンドキャッシュの更新などが行われる)
1146 //
1147 // Setterがtargetも書き換えるので2回書き込んでいる。
1148 // 1回にしたいが、VALIDフラグがオフの成分があるとtargetの値の取得が必要。
1149 // するとバッファの確保 -> Get -> Apply -> Setとなり、かえって遅くなりそう。
1150 void* object = animGroup->GetTargetObject(memberIdx);
1151 member.SetValueForType(object, target);
1152 }
1153 }
1154
1155 } // namespace gfx
1156 } // namespace nw
1157