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