1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_TransformAnimInterpolator.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_AnimGroup.h>
21 #include <nw/gfx/gfx_CalculatedTransform.h>
22 #include <nw/gfx/gfx_TransformAnimBlendOp.h>
23 #include <nw/gfx/gfx_TransformAnimEvaluator.h>
24 #include <nw/gfx/gfx_TransformAnimInterpolator.h>
25
26 namespace nw
27 {
28 namespace gfx
29 {
30
31 NW_UT_RUNTIME_TYPEINFO_DEFINITION(TransformAnimInterpolator, AnimInterpolator);
32
33 //----------------------------------------------------------
34 const anim::AnimResult*
GetResult(void * target,int memberIdx) const35 TransformAnimInterpolator::GetResult(
36 void* target,
37 int memberIdx
38 ) const
39 {
40 //----------------------------------------------------------
41 // ブレンドオペレーションを取得
42 const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
43
44 const bit32 TRANSFORM_FLAG_MASK =
45 CalculatedTransform::FLAG_IS_IDENTITY |
46 CalculatedTransform::FLAG_IS_ROTATE_TRANSLATE_ZERO |
47 CalculatedTransform::FLAG_IS_ROTATE_ZERO |
48 CalculatedTransform::FLAG_IS_TRANSLATE_ZERO |
49 CalculatedTransform::FLAG_IS_SCALE_ONE |
50 CalculatedTransform::FLAG_IS_UNIFORM_SCALE;
51
52 if (m_IsOldMethod)
53 {
54 // TODO: こちらのブロックを整理。
55
56 //----------------------------------------------------------
57 // 有効な子アニメーションの重みの合計を SRT ごとに求める
58 float weightSums[3] = { 0.0f, 0.0f, 0.0f };
59 for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
60 {
61 if (m_AnimObjects[animIdx] == NULL)
62 {
63 continue;
64 }
65 const float weight = m_Weights[animIdx];
66 if (!AnimWeightNearlyEqualZero(weight))
67 {
68 const AnimObject* animObj = m_AnimObjects[animIdx];
69 if (animObj->HasMemberAnim(memberIdx))
70 {
71 const TransformAnimEvaluator* evaluator =
72 ut::DynamicCast<const TransformAnimEvaluator*>(animObj);
73 if (evaluator != NULL)
74 {
75 if (!evaluator->GetIsScaleDisabled())
76 {
77 weightSums[0] += weight;
78 }
79 if (!evaluator->GetIsRotateDisabled())
80 {
81 weightSums[1] += weight;
82 }
83 if (!evaluator->GetIsTranslateDisabled())
84 {
85 weightSums[2] += weight;
86 }
87 }
88 else
89 {
90 weightSums[0] += weight;
91 weightSums[1] += weight;
92 weightSums[2] += weight;
93 }
94 }
95 }
96 }
97
98 // 有効な子アニメーションが存在しない場合は
99 // target を変更せずに NULL を返す
100 if (TransformAnimEvaluator::CheckWeightsNearlyZero(weightSums))
101 {
102 return NULL;
103 }
104
105 // 重みの合計が 1.0 でない場合は正規化スケールを計算
106 float weightNormalizeScale[3] =
107 {
108 GetAnimWeightNormalizeScale(weightSums[0]),
109 GetAnimWeightNormalizeScale(weightSums[1]),
110 GetAnimWeightNormalizeScale(weightSums[2])
111 };
112
113 //----------------------------------------------------------
114 // 補間は操作空間があればそこで行われるべきなので
115 // target の CONVERTED フラグを退避してからオンに
116 CalculatedTransform* transform =
117 reinterpret_cast<CalculatedTransform*>(target);
118 const bit32 flagsBak = transform->GetFlags();
119 const bool convertedBak = transform->IsEnabledFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
120 transform->EnableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
121
122 //----------------------------------------------------------
123 // target の IGNORE フラグをオンにして未書き込み状態とする
124 transform->EnableFlags(CalculatedTransform::FLAG_IS_IGNORE_ALL);
125
126 //----------------------------------------------------------
127 // すべての子アニメーションについてループ
128 CalculatedTransform workResult;
129 bool written = false;
130 bool firstRotateFlag = true;
131 math::MTX34 firstRotateMtx;
132 bit32 transformFlag = TRANSFORM_FLAG_MASK;
133 //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
134 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
135 {
136 const AnimObject* animObj = m_AnimObjects[animIdx];
137 if (animObj == NULL)
138 {
139 continue;
140 }
141
142 const float childWeight = m_Weights[animIdx];
143 NW_ASSERT(childWeight >= 0.0f);
144 float srcWeights[3] =
145 {
146 childWeight * weightNormalizeScale[0],
147 childWeight * weightNormalizeScale[1],
148 childWeight * weightNormalizeScale[2]
149 };
150 TransformAnimEvaluator::DisableSRTWeightsIfNeeded(srcWeights, animObj);
151
152 if (!TransformAnimEvaluator::CheckWeightsNearlyZero(srcWeights))
153 {
154 // 退避した CONVERTED フラグを work に反映
155 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
156 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
157 workResult.EnableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND, convertedBak);
158
159 // 評価
160 const anim::AnimResult* childResult =
161 animObj->GetResult(&workResult, memberIdx);
162
163 if (childResult != NULL)
164 {
165 written = true;
166 const bool evaluatorFlag =
167 ut::DynamicCast<const TransformAnimEvaluator*>(animObj) != NULL;
168
169 // ブレンド結果の回転行列の行がゼロベクトルになった場合のために
170 // 最初のアニメーションの回転行列を保存しておく
171 if (evaluatorFlag && firstRotateFlag &&
172 !workResult.IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
173 {
174 firstRotateFlag = false;
175 firstRotateMtx = workResult.TransformMatrix();
176 }
177
178 // ブレンド
179 if (!blendOp->Blend(reinterpret_cast<anim::AnimResult*>(transform),
180 NULL, childResult, srcWeights))
181 {
182 break;
183 }
184
185 transformFlag &= workResult.GetFlags();
186 }
187 }
188 }
189
190 //----------------------------------------------------------
191 // target の CONVERTED フラグを復元
192 if (!convertedBak)
193 {
194 transform->DisableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
195 }
196
197 if (!written) // 有効な子アニメーションなし
198 {
199 transform->RestoreFlags(CalculatedTransform::FLAG_IS_IGNORE_ALL, flagsBak);
200 return NULL;
201 }
202
203 //----------------------------------------------------------
204 // ブレンド後の処理があれば実行
205 if (!convertedBak && blendOp->HasPostBlend())
206 {
207 if (!blendOp->PostBlend(reinterpret_cast<anim::AnimResult*>(transform), NULL))
208 {
209 // ブレンド結果の回転行列の行がゼロベクトルなら
210 // 最初のアニメーションの回転行列を採用します。
211 // 結果が品質上問題となる場合は
212 // 元データを微妙にずらして回避する必要があります。
213 transform->AdjustZeroRotateMatrix(!firstRotateFlag, firstRotateMtx);
214 }
215 }
216
217 transform->RestoreFlags(TRANSFORM_FLAG_MASK, transformFlag);
218 }
219 else
220 {
221 bool isValidAnim = false;
222 for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
223 {
224 if (m_AnimObjects[animIdx] && m_AnimObjects[animIdx]->HasMemberAnim(memberIdx))
225 {
226 isValidAnim = true;
227 break;
228 }
229 }
230
231 // 有効な子アニメーションが存在しない場合は
232 // target を変更せずに NULL を返す
233 if (!isValidAnim)
234 {
235 return NULL;
236 }
237
238 // アニメーション重みの正規化を必要なら行います。
239 if (m_IsWeightDirty && m_IsWeightNormalizationEnabled)
240 {
241 NormalizeWeight();
242 }
243
244 //----------------------------------------------------------
245 // 補間は操作空間があればそこで行われるべきなので
246 // target の CONVERTED フラグを退避してからオンに
247 CalculatedTransform* transform =
248 reinterpret_cast<CalculatedTransform*>(target);
249 const bit32 flagsBak = transform->GetFlags();
250 const bool convertedBak = transform->IsEnabledFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
251 transform->EnableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
252
253 //----------------------------------------------------------
254 // target の IGNORE フラグをオンにして未書き込み状態とする
255 transform->EnableFlags(CalculatedTransform::FLAG_IS_IGNORE_ALL);
256
257 //----------------------------------------------------------
258 // すべての子アニメーションについてループ
259 CalculatedTransform workResult;
260 bool firstRotateFlag = true;
261 math::MTX34 firstRotateMtx;
262 bit32 transformFlag = TRANSFORM_FLAG_MASK;
263 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
264 {
265 const AnimObject* animObj = m_AnimObjects[animIdx];
266
267 const float childWeight = m_NormalizedWeights[animIdx];
268 NW_ASSERT(childWeight >= 0.0f);
269 const float srcWeights[3] =
270 {
271 childWeight,
272 childWeight,
273 childWeight
274 };
275
276 if (!TransformAnimEvaluator::CheckWeightsNearlyZero(srcWeights))
277 {
278 // 退避した CONVERTED フラグを work に反映
279 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
280 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
281 workResult.EnableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND, convertedBak);
282
283 // 評価
284 const anim::AnimResult* childResult = NULL;
285 if (animObj != NULL)
286 {
287 childResult = animObj->GetResult(&workResult, memberIdx);
288 }
289
290 if (childResult == NULL)
291 {
292 const math::Transform3* originalValue =
293 static_cast<const math::Transform3*>(GetAnimGroup()->GetOriginalValue(memberIdx));
294 workResult.SetTransform(*originalValue);
295 workResult.UpdateScaleFlags();
296 workResult.UpdateRotateFlagsStrictly();
297 workResult.UpdateTranslateFlags();
298 workResult.UpdateCompositeFlags();
299 childResult = reinterpret_cast<anim::AnimResult*>(&workResult);
300 }
301
302 const bool evaluatorFlag =
303 ut::DynamicCast<const TransformAnimEvaluator*>(animObj) != NULL;
304
305 // ブレンド結果の回転行列の行がゼロベクトルになった場合のために
306 // 最初のアニメーションの回転行列を保存しておく
307 if (evaluatorFlag && firstRotateFlag &&
308 !workResult.IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
309 {
310 firstRotateFlag = false;
311 firstRotateMtx = workResult.TransformMatrix();
312 }
313
314 // ブレンド
315 if (!blendOp->Blend(reinterpret_cast<anim::AnimResult*>(transform),
316 NULL, childResult, srcWeights))
317 {
318 break;
319 }
320
321 transformFlag &= workResult.GetFlags();
322 }
323 }
324
325 //----------------------------------------------------------
326 // target の CONVERTED フラグを復元
327 if (!convertedBak)
328 {
329 transform->DisableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
330 }
331
332 //----------------------------------------------------------
333 // ブレンド後の処理があれば実行
334 if (!convertedBak && blendOp->HasPostBlend())
335 {
336 if (!blendOp->PostBlend(reinterpret_cast<anim::AnimResult*>(transform), NULL))
337 {
338 // ブレンド結果の回転行列の行がゼロベクトルなら
339 // 最初のアニメーションの回転行列を採用します。
340 // 結果が品質上問題となる場合は
341 // 元データを微妙にずらして回避する必要があります。
342 transform->AdjustZeroRotateMatrix(!firstRotateFlag, firstRotateMtx);
343 }
344 }
345
346 transform->RestoreFlags(TRANSFORM_FLAG_MASK, transformFlag);
347 }
348
349 // target を AnimResult にキャストして返す(親のブレンダで使用)
350 return reinterpret_cast<anim::AnimResult*>(target);
351 }
352
353 } // namespace gfx
354 } // namespace nw
355