1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_AnimBinding.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #include "precompiled.h"
19 
20 #include <nw/gfx/gfx_AnimBinding.h>
21 #include <nw/gfx/gfx_AnimEvaluator.h>
22 #include <nw/gfx/gfx_TransformAnimEvaluator.h>
23 
24 namespace nw
25 {
26 namespace gfx
27 {
28 
29 //----------------------------------------------------------
30 void
Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing)31 AnimBinding::Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing)
32 {
33     for (int animGroupIdx = 0; animGroupIdx < m_AnimGroups.Size(); ++animGroupIdx)
34     {
35         AnimGroup* animGroup = m_AnimGroups[animGroupIdx];
36 
37         // アニメーションの有無と評価タイミングをチェック
38         if (animGroup == NULL || animGroup->GetResGraphicsAnimGroup().GetEvaluationTiming() != timing)
39         {
40             continue;
41         }
42 
43         for (int animObjectIdx = 0; animObjectIdx < m_AnimObjectCountPerGroup; ++animObjectIdx)
44         {
45             const int index = animGroupIdx * m_AnimObjectCountPerGroup + animObjectIdx;
46             AnimObject* animObj = m_AnimObjects[index];
47             if (animObj == NULL)
48             {
49                 continue;
50             }
51 
52             // 高速化のため、ブレンダの有無・Transformかどうかで分岐
53             switch (animObj->GetAnimType())
54             {
55             case AnimObject::ANIMTYPE_SIMPLE:
56                 static_cast<AnimEvaluator*>(animObj)->UpdateCacheNonVirtual();
57                 EvaluateSimple(animGroup, static_cast<AnimEvaluator*>(animObj));
58                 break;
59             case AnimObject::ANIMTYPE_TRANSFORM_SIMPLE:
60                 static_cast<TransformAnimEvaluator*>(animObj)->UpdateCacheNonVirtual();
61                 EvaluateTransformSimple(animGroup, static_cast<TransformAnimEvaluator*>(animObj));
62                 break;
63             default:
64                 // アニメーション評価結果の内部キャッシュが古ければ更新
65                 animObj->UpdateCache();
66                 EvaluateBlender(animGroup, animObj);
67             }
68         }
69     }
70 }
71 
72 //----------------------------------------------------------
EvaluateSimple(AnimGroup * animGroup,AnimEvaluator * evaluator)73 void AnimBinding::EvaluateSimple(AnimGroup* animGroup, AnimEvaluator* evaluator)
74 {
75     NW_ASSERT(!(animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM));
76 
77     // 汎用アニメーションを評価
78     int lastTargetObjIdx = -1;
79     bool targetObjSkipFlag = false;
80     int animCount = evaluator->GetAnimData().GetMemberAnimSetCount();
81     for (int animIdx = 0; animIdx < animCount; ++animIdx)
82     {
83         int memberIdx = evaluator->ReverseBindIndexTable()[animIdx];
84         if (memberIdx == BaseAnimEvaluator::NotFoundIndex)
85         {
86             continue;
87         }
88         EvaluateMember(animGroup, memberIdx, evaluator, lastTargetObjIdx, targetObjSkipFlag);
89     }
90 }
91 
92 //----------------------------------------------------------
EvaluateTransformSimple(AnimGroup * animGroup,TransformAnimEvaluator * evaluator)93 void AnimBinding::EvaluateTransformSimple(AnimGroup* animGroup, TransformAnimEvaluator* evaluator)
94 {
95     NW_ASSERT(animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM);
96 
97     // トランスフォームアニメーションを評価
98     int animCount = evaluator->GetAnimData().GetMemberAnimSetCount();
99     for (int animIdx = 0; animIdx < animCount; ++animIdx)
100     {
101         int memberIdx = evaluator->ReverseBindIndexTable()[animIdx];
102         if (memberIdx == BaseAnimEvaluator::NotFoundIndex)
103         {
104             continue;
105         }
106         EvaluateTransformMemberFast(animGroup, memberIdx, evaluator);
107     }
108 }
109 
110 //----------------------------------------------------------
EvaluateBlender(AnimGroup * animGroup,AnimObject * animObj)111 void AnimBinding::EvaluateBlender(AnimGroup* animGroup, AnimObject* animObj)
112 {
113     if (animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM)
114     {
115         // トランスフォームアニメーションを評価
116         int memberCount = animGroup->GetMemberCount();
117         for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
118         {
119             EvaluateTransformMember(animGroup, memberIdx, animObj);
120         }
121     }
122     else
123     {
124         // 汎用アニメーションを評価
125         int lastTargetObjIdx = -1;
126         bool targetObjSkipFlag = false;
127         int memberCount = animGroup->GetMemberCount();
128         for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
129         {
130             EvaluateMember(animGroup, memberIdx, animObj, lastTargetObjIdx, targetObjSkipFlag);
131         }
132     }
133 }
134 
135 //----------------------------------------------------------
EvaluateTransformMember(AnimGroup * animGroup,int memberIdx,AnimObject * animObj)136 void AnimBinding::EvaluateTransformMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj)
137 {
138     AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback();
139 
140     // 評価前コールバックの呼び出し
141     if (preEvaluateCallback != NULL)
142     {
143         const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx);
144         if (!preEvaluateCallback(animGroup, targetObjIdx))
145         {
146             return;
147         }
148     }
149 
150     // 評価
151     CalculatedTransform* target = static_cast<CalculatedTransform*>(animGroup->GetTargetPtr(memberIdx));
152     animObj->GetResult(target, memberIdx);
153 
154     // Setter経由で設定する必要はないので、Setterは呼び出さない
155     // Setter内部で回転行列の生成を行うので、呼び出すとパフォーマンスにも大きく影響する
156 }
157 
158 //----------------------------------------------------------
EvaluateTransformMemberFast(AnimGroup * animGroup,int memberIdx,TransformAnimEvaluator * evaluator)159 void AnimBinding::EvaluateTransformMemberFast(AnimGroup* animGroup, int memberIdx, TransformAnimEvaluator* evaluator)
160 {
161     AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback();
162 
163     // 評価前コールバックの呼び出し
164     if (preEvaluateCallback != NULL)
165     {
166         const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx);
167         if (!preEvaluateCallback(animGroup, targetObjIdx))
168         {
169             return;
170         }
171     }
172 
173     // 評価
174     CalculatedTransform* target = static_cast<CalculatedTransform*>(animGroup->GetTargetPtr(memberIdx));
175     evaluator->GetResultFast(target, memberIdx);
176 
177     // Setter経由で設定する必要はないので、Setterは呼び出さない
178     // Setter内部で回転行列の生成を行うので、呼び出すとパフォーマンスにも大きく影響する
179 }
180 
181 //----------------------------------------------------------
EvaluateMember(AnimGroup * animGroup,int memberIdx,AnimObject * animObj,int & lastTargetObjIdx,bool & targetObjSkipFlag)182 void AnimBinding::EvaluateMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj, int& lastTargetObjIdx, bool& targetObjSkipFlag)
183 {
184     AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback();
185 
186     // 評価前コールバックの呼び出し
187     if (preEvaluateCallback != NULL)
188     {
189         const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx);
190         if (targetObjIdx != lastTargetObjIdx)
191         {
192             // 高速化のため前回と対象オブジェクトが異なる場合だけ評価前コールバックを呼ぶ
193             targetObjSkipFlag = !preEvaluateCallback(animGroup, targetObjIdx);
194             lastTargetObjIdx = targetObjIdx;
195         }
196         if (targetObjSkipFlag)
197         {
198             return;
199         }
200     }
201 
202     // 評価
203     anim::ResAnimGroupMember member = animGroup->GetResAnimGroupMember(memberIdx);
204     void* target = NULL;
205     ut::Offset texturePatternTarget;
206 
207     if (member.GetObjectType() == anim::ResAnimGroupMember::OBJECT_TYPE_TEXTURE_MAPPER &&
208         member.GetMemberType() == anim::ResTextureMapperMember::MEMBER_TYPE_TEXTURE)
209     {
210         // テクスチャパターンアニメーションは、targetを上書きせずにSetterのみ呼び出す
211         //
212         // マテリアルのバッファが有効な場合は、targetは動的に確保されたReferenceTextureを指す
213         // それを上書きすると、解放時にアロケータで確保されていないポインタを解放しようとしてクラッシュする
214         target = &texturePatternTarget;
215     }
216     else
217     {
218         target = animGroup->GetTargetPtr(memberIdx);
219     }
220 
221     const anim::AnimBlendOp* blendOp = animGroup->GetBlendOperation(memberIdx);
222     const anim::AnimResult* resultPtr = NULL;
223     if (blendOp != NULL)
224     {
225         // ブレンドオペレーションがある場合は
226         // AnimResult オブジェクト経由でターゲットに書き込む
227         anim::AnimResult result;
228         resultPtr = animObj->GetResult(&result, memberIdx);
229         if (resultPtr != NULL)
230         {
231             blendOp->Apply(target, resultPtr); // VALID フラグがオンの成分のみ書き込み
232         }
233     }
234     else
235     {
236         // ブレンドオペレーションがない場合はターゲットを直接上書き
237         resultPtr = animObj->GetResult(target, memberIdx);
238     }
239 
240     // transformのメンバの場合は、setterを呼びださない。
241     bool isTransformMember = (
242         (member.GetObjectType() == anim::ResAnimGroupMember::OBJECT_TYPE_TRANSFORM) &&
243         (member.GetMemberType() == anim::ResTransformMember::MEMBER_TYPE_TRANSFORM)
244         );
245 
246     if (!isTransformMember && resultPtr)
247     {
248         // メモリ書き込み以外の処理が必要なメンバのためにSetterを呼び出す
249         // (コマンドキャッシュの更新などが行われる)
250         //
251         // Setterがtargetも書き換えるので2回書き込んでいる。
252         // 1回にしたいが、VALIDフラグがオフの成分があるとtargetの値の取得が必要。
253         // するとバッファの確保 -> Get -> Apply -> Setとなり、かえって遅くなりそう。
254         void* object = animGroup->GetTargetObject(memberIdx);
255         member.SetValueForType(object, target);
256     }
257 }
258 
259 } // namespace gfx
260 } // namespace nw
261