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