1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_AnimInterpolator.h
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 #ifndef NW_GFX_ANIMINTERPOLATOR_H_
19 #define NW_GFX_ANIMINTERPOLATOR_H_
20 
21 #include <nw/gfx/gfx_AnimBlender.h>
22 #include <nw/ut/ut_MoveArray.h>
23 #include <nw/ut/ut_RuntimeTypeInfo.h>
24 
25 namespace nw {
26 namespace gfx {
27 
28 //---------------------------------------------------------------------------
29 //! @brief 汎用アニメーション評価結果を補間ブレンドするクラスです。
30 //!
31 //! 登録された全てのアニメーションオブジェクトの結果に重みをかけて、ブレンドした結果を採用します。
32 //! アニメーションが無いメンバの場合は、モデルのロード時の状態(OriginalValue)をブレンド計算に使用します。
33 //!
34 //! デフォルトでは、ブレンドの重みは合計が 1.0 となるように正規化されてからブレンドされるので、重みの比率だけが意味を持ちます。
35 //! 正規化が不要な場合は、 SetNormalizationEnabled() で無効化できます。
36 //---------------------------------------------------------------------------
37 class AnimInterpolator : public AnimBlender
38 {
39 public:
40     NW_UT_RUNTIME_TYPEINFO;
41 
42     //----------------------------------------
43     //! @name 作成
44     //@{
45 
46     //! @brief 汎用アニメーション補間を構築するクラスです。
47     //!
48     //! バージョン 1.0.1 以前の補間法に戻すためには、IsOldMethod か IgnoreNoAnimMember に true を指定してください。
49     //!
50     //! 1.0.1 以前の補間方法と現在の補間方法の違いの詳細については、アニメーションのドキュメント(高度な機能)を参照ください。
51     class Builder
52     {
53     public:
54         //! コンストラクタです。
Builder()55         Builder()
56         : m_MaxAnimObjects(2),
57           m_IgnoreNoAnimMember(false) {}
58 
59         //! 最大アニメーションオブジェクト数を設定します。
MaxAnimObjects(int maxAnimObjects)60         Builder& MaxAnimObjects(int maxAnimObjects)
61         {
62             NW_ASSERT(maxAnimObjects > 0);
63             m_MaxAnimObjects = maxAnimObjects;
64             return *this;
65         }
66 
67         //! @brief アニメーションが存在しないメンバを無視するかどうかを設定します。
68         //!
69         //! デフォルトでは、アニメーションが存在しないメンバはバインド時の値がブレンドされます。
70         //! IgnoreNoAnimMember に true を設定すると、
71         //! 重みの正規化がメンバ毎に行なわれ、アニメーションが存在しないメンバは重み 0 としてブレンドされます。
72         //!
73         //! この挙動は バージョン 1.0.1 以前の補間法と同じです。
74         //!
IgnoreNoAnimMember(bool ignoreNoAnimMember)75         Builder& IgnoreNoAnimMember(bool ignoreNoAnimMember) { m_IgnoreNoAnimMember = ignoreNoAnimMember; return *this; }
76 
77         //! @brief 生成時に必要なメモリサイズを取得します。
78         //!
79         //! メモリサイズは Builder の設定によって変化します。
80         //! すべての設定が終わった後にこの関数を呼び出してください。
81         //!
82         //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
83         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
84         {
85             os::MemorySizeCalculator size(alignment);
86 
87             GetMemorySizeInternal(&size);
88 
89             return size.GetSizeWithPadding(alignment);
90         }
91 
92         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)93         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
94         {
95             os::MemorySizeCalculator& size = *pSize;
96 
97             size += sizeof(AnimInterpolator);
98             AnimInterpolator::GetMemorySizeForInitialize(pSize, m_MaxAnimObjects);
99         }
100 
101         //! @brief 汎用アニメーション補間を生成します。
102         //!
103         //! @param[in] allocator アロケータです。
104         //!
105         //! @return 生成された汎用アニメーション補間です。
106         //!
Create(os::IAllocator * allocator)107         AnimInterpolator* Create(os::IAllocator* allocator)
108         {
109             void* buf = allocator->Alloc(sizeof(AnimInterpolator));
110 
111             if (buf == NULL)
112             {
113                 return NULL;
114             }
115 
116             AnimInterpolator* animInterpolator = new(buf) AnimInterpolator(allocator);
117 
118             Result result = animInterpolator->Initialize(m_MaxAnimObjects, m_IgnoreNoAnimMember);
119             NW_ASSERT(result.IsSuccess());
120 
121             return animInterpolator;
122         }
123 
124     private:
125         int m_MaxAnimObjects;
126         bool m_IgnoreNoAnimMember;
127     };
128 
129     //@}
130 
131     //----------------------------------------
132     //! @name 評価
133     //@{
134 
135     //! @brief メンバ単位でアニメーション結果を取得します。
136     //!
137     //! @param[out] target アニメーション結果を書き込む対象です。
138     //! @param[in] memberIdx メンバインデックスです。
139     //!
140     //! @return アニメーション結果を返します。
141     //! ブレンドオペレーションを使用する場合は、返り値のアニメーション結果を使用してください。
142     //!
143     virtual const anim::AnimResult* GetResult(
144         void* target,
145         int memberIdx) const;
146 
147     //@}
148 
149     //----------------------------------------
150     //! @name 取得/設定
151     //@{
152 
153     //! @brief アニメーションのブレンド重みを取得します。
154     //!
155     //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。
156     //!
157     //! @return 重みです。
158     //!
GetWeight(int animObjIdx)159     float GetWeight(int animObjIdx) const
160     {
161         NW_MINMAXLT_ASSERT(animObjIdx, 0, m_Weights.Size());
162         return m_Weights[animObjIdx];
163     }
164 
165     //! @brief アニメーションのブレンド重みを設定します。
166     //!
167     //! ブレンド重みの解釈については、 SetNormalizationEnabled() を参照してください。
168     //!
169     //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。
170     //! @param[in] weight 重みです。
171     //! @sa SetNormalizationEnabled
172     //!
SetWeight(int animObjIdx,float weight)173     void SetWeight(int animObjIdx, float weight)
174     {
175         NW_MINMAXLT_ASSERT(animObjIdx, 0, m_Weights.Size());
176         m_Weights[animObjIdx] = weight;
177         m_NormalizedWeights[animObjIdx] = weight;
178         m_IsWeightDirty = true;
179     }
180 
181     //! @brief アニメーションのブレンド重みを正規化するかを設定します。
182     //!
183     //! true を指定すると、ブレンド重みが合計で 1 になるよう正規化してからブレンドを行います。
184     //! false を指定すると、SetWeight() で指定された重みがそのままブレンドに使用されますので、
185     //! 重みの設定に注意してください。
186     //!
187     //! 正規化処理は、 SetWeight() 実行後の最初のアニメーションブレンド時に 1 度だけ行われます。
188     //!
189     //! Builder::IsOldMethod で true を指定していると、この設定は無視されます。
190     //!
191     //! デフォルト値は true です。
SetNormalizationEnabled(bool enabled)192     void SetNormalizationEnabled(bool enabled){ m_IsWeightNormalizationEnabled = enabled; }
193 
194     //! @brief アニメーションのブレンド重みを正規化するかの設定を取得します。
GetNormalizationEnabled()195     bool GetNormalizationEnabled() const { return m_IsWeightNormalizationEnabled; }
196 
197     //@}
198 
199 protected:
200     //----------------------------------------
201     //! @name コンストラクタ/デストラクタ
202     //@{
203 
204     //! コンストラクタです。
205     //!
206     //! :private
AnimInterpolator(os::IAllocator * allocator)207     AnimInterpolator(
208         os::IAllocator* allocator)
209     : AnimBlender(allocator),
210       m_IsOldMethod(false),
211       m_IsWeightDirty(false),
212       m_IsWeightNormalizationEnabled(true)
213     {
214     }
215 
216     //! デストラクタです。
217     //!
218     //! :private
~AnimInterpolator()219     virtual ~AnimInterpolator() {}
220 
221     //@}
222 
223     //! Initialize() の実行に必要なメモリサイズを取得します。
224     //!
225     //! :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,int maxAnimObjects)226     static void GetMemorySizeForInitialize(os::MemorySizeCalculator* pSize, int maxAnimObjects)
227     {
228         os::MemorySizeCalculator& size = *pSize;
229 
230         AnimBlender::GetMemorySizeForInitialize(pSize, maxAnimObjects);
231         size += sizeof(float) * maxAnimObjects;
232         size += sizeof(float) * maxAnimObjects;
233     }
234 
235     //! @details :private
Initialize(int maxAnimObjects,bool ignoreNoAnimMember)236     Result Initialize(int maxAnimObjects, bool ignoreNoAnimMember)
237     {
238         Result result = AnimBlender::Initialize(maxAnimObjects);
239         NW_ENSURE_AND_RETURN(result);
240 
241         {
242             void* memory = GetAllocator().Alloc(sizeof(float) * maxAnimObjects);
243             if (memory == NULL)
244             {
245                 result |= Result::MASK_FAIL_BIT;
246             }
247             NW_ENSURE_AND_RETURN(result);
248 
249             m_Weights = ut::MoveArray<float>(memory, maxAnimObjects, &GetAllocator());
250             for (int animObjIdx = 0; animObjIdx < maxAnimObjects; ++animObjIdx)
251             {
252                 m_Weights.PushBackFast(animObjIdx == 0 ? 1.0f : 0.0f);
253             }
254         }
255 
256         {
257             void* memory = GetAllocator().Alloc(sizeof(float) * maxAnimObjects);
258             if (memory == NULL)
259             {
260                 result |= Result::MASK_FAIL_BIT;
261             }
262             NW_ENSURE_AND_RETURN(result);
263 
264             m_NormalizedWeights = ut::MoveArray<float>(memory, maxAnimObjects, &GetAllocator());
265             for (int animObjIdx = 0; animObjIdx < maxAnimObjects; ++animObjIdx)
266             {
267                 m_NormalizedWeights.PushBackFast(animObjIdx == 0 ? 1.0f : 0.0f);
268             }
269         }
270 
271         // TODO: 変数名その他を変更。
272         m_IsOldMethod = ignoreNoAnimMember;
273 
274         return result;
275     }
276 
277     //! @brief ブレンド重みを正規化します。
278     //!
279     //! :private
NormalizeWeight()280     void NormalizeWeight() const
281     {
282         float weightSum = 0.0f;
283         float normalizeScale;
284         for (int i = 0; i < m_Weights.Size(); ++i)
285         {
286             weightSum += m_Weights[i];
287         }
288         normalizeScale = GetAnimWeightNormalizeScale(weightSum);
289         for (int i = 0; i < m_Weights.Size(); ++i)
290         {
291             m_NormalizedWeights[i] = m_Weights[i] * normalizeScale;
292         }
293         m_IsWeightDirty = false;
294     }
295 
296     ut::MoveArray<float> m_Weights; //!< @details :private
297     mutable ut::MoveArray<float> m_NormalizedWeights; //!< @details :private
298 
299     bool m_IsOldMethod; //!< @details :private
300     mutable bool m_IsWeightDirty; //!< @details :private
301     bool m_IsWeightNormalizationEnabled; //!< @details :private
302 };
303 
304 } // namespace gfx
305 } // namespace nw
306 
307 #endif // NW_GFX_ANIMINTERPOLATOR_H_
308