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