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