1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_AnimBinding.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_ANIMBINDING_H_
19 #define NW_GFX_ANIMBINDING_H_
20 
21 #include <nw/gfx/gfx_AnimGroup.h>
22 #include <nw/gfx/gfx_AnimObject.h>
23 #include <nw/gfx/gfx_GfxObject.h>
24 #include <nw/ut/ut_MoveArray.h>
25 #include <nw/ut/ut_RuntimeTypeInfo.h>
26 
27 namespace nw {
28 namespace gfx {
29 
30 class AnimEvaluator;
31 class TransformAnimEvaluator;
32 
33 //---------------------------------------------------------------------------
34 //! @brief アニメーションの関連付け情報のクラスです。
35 //!
36 //! AnimObject と AnimGroup を関連付けて、アニメーションの再生を行います。
37 //---------------------------------------------------------------------------
38 class AnimBinding : public GfxObject
39 {
40 public:
41 
42     //! アニメーショングループの MoveArray の定義です。
43     //!
44     //! :private
45     typedef ut::MoveArray<AnimGroup*> AnimGroupArray;
46 
47     //! アニメーションオブジェクトの MoveArray の定義です。
48     //!
49     //! :private
50     typedef ut::MoveArray<AnimObject*> AnimObjectArray;
51 
52     //----------------------------------------
53     //! @name 作成
54     //@{
55 
56     //! アニメーションバインディングを構築するクラスです。
57     class Builder
58     {
59     public:
60         //! コンストラクタです。
Builder()61         Builder()
62         :
63           m_MaxAnimGroups(1),
64           m_MaxAnimObjectsPerGroup(1) {}
65 
66         //! 最大アニメーショングループ数を設定します。
MaxAnimGroups(int maxAnimGroups)67         Builder& MaxAnimGroups(int maxAnimGroups)
68         {
69             NW_ASSERT(maxAnimGroups > 0);
70             m_MaxAnimGroups = maxAnimGroups;
71             return *this;
72         }
73 
74         //! @brief アニメーショングループ内での最大アニメーションオブジェクト数を設定します。
75         //!
76         //! @details 複数のアニメーショングループを持つ場合は、そのうち最大のものを指定してください。
MaxAnimObjectsPerGroup(int maxAnimObjects)77         Builder& MaxAnimObjectsPerGroup(int maxAnimObjects)
78         {
79             NW_ASSERT(maxAnimObjects > 0);
80             m_MaxAnimObjectsPerGroup = maxAnimObjects;
81             return *this;
82         }
83 
84         //! @brief 生成時に必要なメモリサイズを取得します。
85         //!
86         //! メモリサイズは Builder の設定によって変化します。
87         //! すべての設定が終わった後にこの関数を呼び出してください。
88         //!
89         //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
90         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
91         {
92             os::MemorySizeCalculator size(alignment);
93 
94             GetMemorySizeInternal(&size);
95 
96             return size.GetSizeWithPadding(alignment);
97         }
98 
99         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)100         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
101         {
102             os::MemorySizeCalculator& size = *pSize;
103 
104             size += sizeof(AnimBinding);
105             AnimBinding::GetMemorySizeForInitialize(pSize, m_MaxAnimGroups, m_MaxAnimObjectsPerGroup);
106         }
107 
108         //! @brief アニメーションバインディングを生成します。
109         //!
110         //! @param[in] allocator アロケータです。
111         //!
112         //! @return 生成されたアニメーションバインディングです。
113         //!
Create(os::IAllocator * allocator)114         AnimBinding* Create(os::IAllocator* allocator)
115         {
116             void* buf = allocator->Alloc(sizeof(AnimBinding));
117 
118             if (buf == NULL)
119             {
120                 return NULL;
121             }
122 
123             AnimBinding* animBinding = new(buf) AnimBinding(allocator, m_MaxAnimObjectsPerGroup);
124 
125             Result result = animBinding->Initialize(m_MaxAnimGroups, m_MaxAnimObjectsPerGroup);
126 
127             if (result.IsSuccess())
128             {
129                 return animBinding;
130             }
131             else
132             {
133                 SafeDestroy(animBinding);
134                 return NULL;
135             }
136         }
137 
138     private:
139         int m_MaxAnimGroups;
140         int m_MaxAnimObjectsPerGroup;
141     };
142 
143     //@}
144 
145     //----------------------------------------
146     //! @name 基本操作
147     //@{
148 
149     //! @brief アニメーションを評価して対象に書き込みます。
150     //!
151     //! SceneUpdater::UpdateAll から自動的に呼び出されます。
152     //! 通常は、ユーザーが呼び出す必要はありません。
153     //!
154     //! @param[in] timing 評価タイミングです。
155     //!
156     void Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing);
157 
158     //! @brief 設定されたすべてのアニメーションオブジェクトのフレームを更新します。
159     //!
160     //! SceneUpdater::UpdateAll から自動的に呼び出されます。
161     //! 通常は、ユーザーが呼び出す必要はありません。
UpdateFrame()162     void UpdateFrame()
163     {
164         for (int animObjIdx = 0; animObjIdx < m_AnimObjects.Size(); ++animObjIdx)
165         {
166             if (m_AnimObjects[animObjIdx] != NULL)
167             {
168                 m_AnimObjects[animObjIdx]->UpdateFrame();
169             }
170         }
171     }
172 
173     //@}
174 
175     //----------------------------------------
176     //! @name 取得/設定
177     //@{
178 
179     //! アニメーショングループ数を取得します。
GetAnimGroupCount()180     int GetAnimGroupCount() const { return m_AnimGroups.Size(); }
181 
182     //! アニメーショングループを取得します。
GetAnimGroup(int groupIdx)183     const AnimGroup* GetAnimGroup(int groupIdx) const
184     {
185         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size());
186         return m_AnimGroups[groupIdx];
187     }
188 
189     //! アニメーショングループを取得します。
GetAnimGroup(int groupIdx)190     AnimGroup* GetAnimGroup(int groupIdx)
191     {
192         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size());
193         return m_AnimGroups[groupIdx];
194     }
195 
196     //! @brief アニメーショングループ名から、登録されているグループのインデックスを取得します。
197     //!
198     //! @param[in] animGroupName アニメーショングループ名です。
199     //!
200     //! @return アニメーショングループのインデックスです。
201     //! animGroupName に対応するアニメーショングループがない場合は -1 を返します。
202     //!
GetAnimGroupIndex(const char * animGroupName)203     int GetAnimGroupIndex(const char* animGroupName) const
204     {
205         for (int groupIdx = 0; groupIdx < m_AnimGroups.Size(); ++groupIdx)
206         {
207             if (m_AnimGroups[groupIdx] != NULL &&
208                 ::std::strcmp(m_AnimGroups[groupIdx]->GetName(), animGroupName) == 0)
209             {
210                 return groupIdx;
211             }
212         }
213         return -1;
214     }
215 
216     //! アニメーショングループを設定します。
SetAnimGroup(int groupIdx,AnimGroup * animGroup)217     void SetAnimGroup(int groupIdx, AnimGroup* animGroup)
218     {
219         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size());
220         m_AnimGroups[groupIdx] = animGroup;
221     }
222 
223     //! アニメーションオブジェクトを取得します。
224     const AnimObject* GetAnimObject(int groupIdx, int objectIdx = 0) const
225     {
226         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimObjects.Size());
227         NW_MINMAXLT_ASSERT(objectIdx, 0, m_AnimObjectCountPerGroup);
228 
229         const int index = groupIdx * m_AnimObjectCountPerGroup + objectIdx;
230         return m_AnimObjects[index];
231     }
232 
233     //! アニメーションオブジェクトを取得します。
234     AnimObject* GetAnimObject(int groupIdx, int objectIdx = 0)
235     {
236         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size());
237         NW_MINMAXLT_ASSERT(objectIdx, 0, m_AnimObjectCountPerGroup);
238 
239         const int index = groupIdx * m_AnimObjectCountPerGroup + objectIdx;
240         return m_AnimObjects[index];
241     }
242 
243     //! @brief アニメーションオブジェクトを設定します。
244     //! アニメーションオブジェクトにバインドされたアニメーショングループの名前から、
245     //! アニメーションバインディング中の設定先グループを決定します。
246     //!
247     //! @param[in] animObject アニメーションオブジェクトです。
248     //! アニメーショングループにバインドされている必要があります。
249     //! @param[in] objectIdx アニメーショングループについてのアニメーションオブジェクトのindexです。
250     //!                      複数個のアニメーションオブジェクトを一つのグループにバインドする際に指定します。
251     //!
252     //! @return 成功すれば true を返します。
253     //!
254     bool SetAnimObject(AnimObject* animObject, int objectIdx = 0)
255     {
256         const AnimGroup* animGroup = animObject->GetAnimGroup();
257         NW_NULL_ASSERT(animGroup);
258         return SetAnimObject(animGroup->GetName(), animObject, objectIdx);
259     }
260 
261     //! @brief アニメーションオブジェクトを設定します。
262     //!
263     //! @param[in] groupIdx アニメーションバインディング中の、バインド対象のグループのインデックスです。
264     //! @param[in] animObject アニメーションオブジェクトです。
265     //! @param[in] objectIdx アニメーショングループについてのアニメーションオブジェクトのindexです。
266     //!                      複数個のアニメーションオブジェクトを一つのグループにバインドする際に指定します。
267     //!
268     //! @return 成功すれば true を返します。
269     //!
270     bool SetAnimObject(int groupIdx, AnimObject* animObject, int objectIdx = 0)
271     {
272         // ここでgroupIdxに入っているのは、対象のグループのインデックス
273         if ((0 <= groupIdx && groupIdx < m_AnimGroups.Size()) &&
274             (0 <= objectIdx && objectIdx < m_AnimObjectCountPerGroup))
275         {
276             const int index = groupIdx * m_AnimObjectCountPerGroup + objectIdx;
277             m_AnimObjects[index] = animObject;
278             return true;
279         }
280         return false;
281     }
282 
283     //! @brief アニメーションオブジェクトを設定します。
284     //!
285     //! @param[in] animGroupName アニメーショングループ名です。
286     //! @param[in] animObject アニメーションオブジェクトです。
287     //! @param[in] objectIdx アニメーショングループについてのアニメーションオブジェクトのindexです。
288     //!                      複数個のアニメーションオブジェクトを一つのグループにバインドする際に指定します。
289     //!
290     //! @return 成功すれば true を返します。
291     //!
292     bool SetAnimObject(const char* animGroupName, AnimObject* animObject, int objectIdx = 0)
293     {
294         return SetAnimObject(GetAnimGroupIndex(animGroupName), animObject, objectIdx);
295     }
296 
297     //@}
298 
299 protected:
300     //----------------------------------------
301     //! @name コンストラクタ/デストラクタ
302     //@{
303 
304     //! コンストラクタです。
305     //!
306     //! :private
AnimBinding(os::IAllocator * allocator,int maxAnimObjects)307     AnimBinding(
308         os::IAllocator* allocator,
309         int maxAnimObjects)
310     : GfxObject(allocator)
311     , m_AnimObjectCountPerGroup(maxAnimObjects)
312     {
313     }
314 
315     //! デストラクタです。
316     //!
317     //! :private
~AnimBinding()318     virtual ~AnimBinding()
319     {
320         // AnimGroups, AnimObjects共に、中身は生成元で削除します。
321         // AnimBindingでは参照しているだけなので、何も行いません。
322     }
323 
324     //@}
325 
326     //! Initialize() の実行に必要なメモリサイズを取得します。
327     //!
328     //! :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,int maxAnimGroups,int maxAnimObjects)329     static void GetMemorySizeForInitialize(os::MemorySizeCalculator* pSize, int maxAnimGroups, int maxAnimObjects)
330     {
331         os::MemorySizeCalculator& size = *pSize;
332 
333         const int animObjectCount = maxAnimGroups * maxAnimObjects;
334 
335         size += sizeof(AnimGroup*) * maxAnimGroups;
336         size += sizeof(AnimObject*) * animObjectCount;
337     }
338 
339     //! メンバを初期化します。
340     //!
341     //! :private
Initialize(int maxAnimGroups,int maxAnimObjects)342     Result Initialize(int maxAnimGroups, int maxAnimObjects)
343     {
344         // AnimObjectの個数は、Builderで設定されたAnimObjectsの数 * Groupの数です。
345         const int animObjectCount = maxAnimGroups * maxAnimObjects;
346 
347         Result result = INITIALIZE_RESULT_OK;
348 
349         {
350             void* memory = GetAllocator().Alloc(sizeof(AnimGroup*) * maxAnimGroups);
351             if (memory == NULL)
352             {
353                 result |= Result::MASK_FAIL_BIT;
354             }
355             NW_ENSURE_AND_RETURN(result);
356 
357             m_AnimGroups = AnimGroupArray(memory, maxAnimGroups, &GetAllocator());
358         }
359         {
360             void* memory = GetAllocator().Alloc(sizeof(AnimObject*) * animObjectCount);
361             if (memory == NULL)
362             {
363                 result |= Result::MASK_FAIL_BIT;
364             }
365             NW_ENSURE_AND_RETURN(result);
366 
367             m_AnimObjects = AnimObjectArray(memory, animObjectCount, &GetAllocator());
368         }
369 
370         for (int animGroupIdx = 0; animGroupIdx < maxAnimGroups; ++animGroupIdx)
371         {
372             m_AnimGroups.PushBackFast<AnimGroup*>(NULL);
373         }
374 
375         for (int animObjectIdx = 0; animObjectIdx < animObjectCount; ++animObjectIdx)
376         {
377             m_AnimObjects.PushBackFast<AnimObject*>(NULL);
378         }
379 
380         return result;
381     }
382 
383 private:
384     //----------------------------------------
385     // 評価
386 
387     // ブレンダを使用しない場合の評価処理です。
388     // 不要なループを省略し、高速に処理します。
389     NW_FORCE_INLINE void EvaluateSimple(AnimGroup* animGroup, AnimEvaluator* evaluator);
390     NW_FORCE_INLINE void EvaluateTransformSimple(AnimGroup* animGroup, TransformAnimEvaluator* evaluator);
391 
392     // ブレンダを使用する場合の評価処理です。
393     NW_FORCE_INLINE void EvaluateBlender(AnimGroup* animGroup, AnimObject* animObj);
394 
395     NW_FORCE_INLINE void EvaluateTransformMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj); //!< @details :private
396     NW_FORCE_INLINE void EvaluateTransformMemberFast(AnimGroup* animGroup, int memberIdx, TransformAnimEvaluator* evaluator); //!< @details :private
397     NW_FORCE_INLINE void EvaluateMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj, int& lastTargetObjIdx, bool& targetObjSkipFlag); //!< @details :private
398 
399     AnimGroupArray m_AnimGroups; //!< @details :private
400     AnimObjectArray m_AnimObjects; //!< @details :private
401     const int m_AnimObjectCountPerGroup; //!< @details :private
402 };
403 
404 } // namespace gfx
405 } // namespace nw
406 
407 #endif // NW_GFX_ANIMBINDING_H_
408