1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_AnimInterpolator.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/anim/anim_AnimBlend.h>
21 #include <nw/gfx/gfx_AnimGroup.h>
22 #include <nw/gfx/gfx_AnimInterpolator.h>
23 
24 namespace nw
25 {
26 namespace gfx
27 {
28 
29 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimInterpolator , AnimBlender);
30 
31 //----------------------------------------------------------
32 const anim::AnimResult*
GetResult(void * target,int memberIdx) const33 AnimInterpolator::GetResult(
34     void* target,
35     int memberIdx
36 ) const
37 {
38     //----------------------------------------------------------
39     // ブレンドオペレーションがない場合および
40     // ブレンドオペレーションにブレンド処理がない場合は上書き処理
41     const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
42     if (blendOp == NULL || !blendOp->HasBlend())
43     {
44         for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
45         {
46             if (m_AnimObjects[animIdx] == NULL)
47             {
48                 continue;
49             }
50             const anim::AnimResult* childResult =
51                 m_AnimObjects[animIdx]->GetResult(target, memberIdx);
52             if (childResult != NULL)
53             {
54                 return childResult;
55             }
56         }
57         return NULL;
58     }
59 
60     if (m_IsOldMethod)
61     {
62         // TODO: こちらのブロックを整理。
63 
64         //----------------------------------------------------------
65         // 有効な子アニメーションの重みの合計を求める
66         float weightSum = 0.0f;
67         const AnimObject* lastAnimObj = NULL;
68         int validAnimCount = 0;
69         for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
70         {
71             if (m_AnimObjects[animIdx] == NULL)
72             {
73                 continue;
74             }
75             const float weight = m_Weights[animIdx];
76             if (!AnimWeightNearlyEqualZero(weight))
77             {
78                 if (m_AnimObjects[animIdx]->HasMemberAnim(memberIdx))
79                 {
80                     weightSum += weight;
81                     lastAnimObj = m_AnimObjects[animIdx];
82                     ++validAnimCount;
83                 }
84             }
85         }
86 
87         if (validAnimCount == 0)
88         {
89             // 有効な子アニメーションが存在しない場合は
90             // target を変更せずに NULL を返す
91             return NULL;
92         }
93         else if (validAnimCount == 1)
94         {
95             // 有効な子アニメーションが 1 つだけの場合は
96             // そのアニメーションの結果を返す
97             return lastAnimObj->GetResult(target, memberIdx);
98         }
99 
100         // 重みの合計が 1.0 でない場合は正規化スケールを計算
101         const float weightNormalizeScale = GetAnimWeightNormalizeScale(weightSum);
102 
103         //----------------------------------------------------------
104         // 補間は操作空間があればそこで行われるべきなので
105         // target の CONVERTED フラグを退避してからオンに
106         anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
107         const bool convertedBak = result->IsEnabledFlags(anim::AnimResult::FLAG_CONVERTED);
108         result->EnableFlags(anim::AnimResult::FLAG_CONVERTED, true);
109 
110         //----------------------------------------------------------
111         // すべての子アニメーションについてループ
112         anim::AnimResult workResult;
113         bool written = false;
114         float compWeights[anim::AnimResult::MAX_COMPONENTS];
115         //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
116         for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
117         {
118             if (m_AnimObjects[animIdx] == NULL)
119             {
120                 continue;
121             }
122             const float childWeight = m_Weights[animIdx] * weightNormalizeScale;
123             if (!AnimWeightNearlyEqualZero(childWeight))
124             {
125                 // 退避した CONVERTED フラグを work に反映
126                 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
127                 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
128                 workResult.EnableFlags(anim::AnimResult::FLAG_CONVERTED, convertedBak);
129 
130                 // 評価
131                 const anim::AnimResult* childResult =
132                     m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
133                 if (childResult != NULL)
134                 {
135                     written = true;
136                     if (!blendOp->Blend(result, compWeights, childResult, &childWeight))
137                     {
138                         break;
139                     }
140                 }
141             }
142         }
143 
144         //----------------------------------------------------------
145         // target の CONVERTED フラグを復元
146         if (!convertedBak)
147         {
148             result->DisableFlags(anim::AnimResult::FLAG_CONVERTED);
149         }
150 
151         if (!written) // 有効な子アニメーションなし
152         {
153             return NULL;
154         }
155 
156         //----------------------------------------------------------
157         // ブレンド後の処理があれば実行
158         if (!convertedBak && blendOp->HasPostBlend())
159         {
160             blendOp->PostBlend(result, compWeights);
161         }
162         return result;
163     }
164     else
165     {
166         bool isValidAnim = false;
167         for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
168         {
169             if (m_AnimObjects[animIdx] && m_AnimObjects[animIdx]->HasMemberAnim(memberIdx))
170             {
171                 isValidAnim = true;
172                 break;
173             }
174         }
175 
176         // 有効な子アニメーションが存在しない場合は
177         // target を変更せずに NULL を返す
178         if (!isValidAnim)
179         {
180             return NULL;
181         }
182 
183         // アニメーション重みの正規化を必要なら行います。
184         if (m_IsWeightDirty && m_IsWeightNormalizationEnabled)
185         {
186             NormalizeWeight();
187         }
188 
189         //----------------------------------------------------------
190         // 補間は操作空間があればそこで行われるべきなので
191         // target の CONVERTED フラグを退避してからオンに
192         anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
193         const bool convertedBak = result->IsEnabledFlags(anim::AnimResult::FLAG_CONVERTED);
194         result->EnableFlags(anim::AnimResult::FLAG_CONVERTED, true);
195 
196         //----------------------------------------------------------
197         // すべての子アニメーションについてループ
198         anim::AnimResult workResult;
199         float compWeights[anim::AnimResult::MAX_COMPONENTS];
200         //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
201         for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
202         {
203             const float childWeight = m_NormalizedWeights[animIdx];
204             if (!AnimWeightNearlyEqualZero(childWeight))
205             {
206                 // 退避した CONVERTED フラグを work に反映
207                 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
208                 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
209                 workResult.EnableFlags(anim::AnimResult::FLAG_CONVERTED, convertedBak);
210 
211                 // 評価
212                 const anim::AnimResult* childResult = NULL;
213                 if (m_AnimObjects[animIdx] != NULL)
214                 {
215                     childResult = m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
216                 }
217 
218                 if (childResult == NULL)
219                 {
220                     NW_ASSERT(GetAnimGroup()->HasOriginalValue());
221                     blendOp->ConvertToAnimResult(
222                         &workResult,
223                         GetAnimGroup()->GetOriginalValue(memberIdx));
224                     childResult = &workResult;
225 
226                     NW_NULL_ASSERT(childResult);
227                 }
228 
229                 if (!blendOp->Blend(result, compWeights, childResult, &childWeight))
230                 {
231                     break;
232                 }
233 
234             }
235         }
236 
237         //----------------------------------------------------------
238         // target の CONVERTED フラグを復元
239         if (!convertedBak)
240         {
241             result->DisableFlags(anim::AnimResult::FLAG_CONVERTED);
242         }
243 
244         //----------------------------------------------------------
245         // ブレンド後の処理があれば実行
246         if (!convertedBak && blendOp->HasPostBlend())
247         {
248             blendOp->PostBlend(result, compWeights);
249         }
250         return result;
251     }
252 }
253 
254 } // namespace gfx
255 } // namespace nw
256