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