1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_AnimObject.h
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 25986 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_GFX_ANIMOBJECT_H_
17 #define NW_GFX_ANIMOBJECT_H_
18 
19 #include <nw/anim/anim_AnimFrameController.h>
20 #include <nw/anim/res/anim_ResAnim.h>
21 #include <nw/anim/res/anim_ResAnimGroup.h>
22 #include <nw/gfx/gfx_GfxObject.h>
23 #include <nw/math.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 SceneNode;
31 class AnimEvaluator;
32 class TransformAnimEvaluator;
33 
34 //---------------------------------------------------------------------------
35 //! @brief アニメーションの重みを比較します。
36 //!
37 //! @param[in] weight 重み
38 //! @param[in] value 比較する値
39 //!
40 //! @return 重みと比較する値の誤差が許容値以下なら true を返します。
41 //---------------------------------------------------------------------------
42 NW_INLINE bool
AnimWeightNearlyEqual(const float weight,const float value)43 AnimWeightNearlyEqual(const float weight, const float value)
44 {
45     // 0.1%未満は無視することとします。
46     const float Epsilon = 0.001f;
47     return math::FAbs(weight - value) <= Epsilon;
48 }
49 
50 //---------------------------------------------------------------------------
51 //! @brief アニメーションの重みが 0 にほぼ等しいか比較します。
52 //!
53 //! @param[in] weight 重み
54 //!
55 //! @return 重みと 0 との誤差が許容値以下なら true を返します。
56 //---------------------------------------------------------------------------
57 NW_INLINE bool
AnimWeightNearlyEqualZero(const float weight)58 AnimWeightNearlyEqualZero(const float weight)
59 {
60     return AnimWeightNearlyEqual(weight, 0.0f);
61 }
62 
63 //---------------------------------------------------------------------------
64 //! @brief アニメーションの重みが 1 にほぼ等しいか比較します。
65 //!
66 //! @param[in] weight 重み
67 //!
68 //! @return 重みと 1 との誤差が許容値以下なら true を返します。
69 //---------------------------------------------------------------------------
70 NW_INLINE bool
AnimWeightNearlyEqualOne(const float weight)71 AnimWeightNearlyEqualOne(const float weight)
72 {
73     return AnimWeightNearlyEqual(weight, 1.0f);
74 }
75 
76 //---------------------------------------------------------------------------
77 //! @brief アニメーションブレンドの重みを正規化するスケールを取得します。
78 //!
79 //! @param[in] weightSum 重みの合計です。
80 //!
81 //! @return 重みを正規化するスケールです。
82 //---------------------------------------------------------------------------
83 NW_INLINE float
GetAnimWeightNormalizeScale(float weightSum)84 GetAnimWeightNormalizeScale(float weightSum)
85 {
86     return
87         AnimWeightNearlyEqualOne(weightSum) ||
88         AnimWeightNearlyEqualZero(weightSum) ?
89         1.0f : 1.0f / weightSum;
90 }
91 
92 //---------------------------------------------------------------------------
93 //! @brief アニメーション対象を抽象化するクラスです。
94 //!
95 //! アニメーション対象メンバへのポインタを保持します。
96 //! 対象メンバとはボーンのトランスフォーム、マテリアルのディフューズカラーといった単位です。
97 //!
98 //! また、対象メンバのオリジナル値(インスタンス生成時の値)を保存しています。
99 //---------------------------------------------------------------------------
100 class AnimGroup : public GfxObject
101 {
102 public:
103     //! @brief 評価前コールバック関数の定義です。
104     //! 対象オブジェクトの評価が必要なら true を返します。
105     typedef bool (*PreEvaluateCallback)(AnimGroup* animGroup, int targetObjIdx);
106 
107     //----------------------------------------
108     //! @name 作成
109     //@{
110 
111     //! アニメーショングループを構築するクラスです。
112     class Builder
113     {
114     public:
115         //! コンストラクタです。
Builder()116         Builder()
117         : m_SceneNode(NULL),
118           m_UseOriginalValue(false) {}
119 
120         //! アニメーショングループリソースを設定します。
ResAnimGroup(anim::ResAnimGroup resAnimGroup)121         Builder& ResAnimGroup(anim::ResAnimGroup resAnimGroup)
122         {
123             m_ResAnimGroup = resAnimGroup;
124             return *this;
125         }
126 
127         //! 対象となるシーンノードを設定します。
SetSceneNode(SceneNode * sceneNode)128         Builder& SetSceneNode(SceneNode* sceneNode) { m_SceneNode = sceneNode; return *this; }
129 
130         //! オリジナル値を使用するかどうかを設定します。
UseOriginalValue(bool use)131         Builder& UseOriginalValue(bool use) { m_UseOriginalValue = use; return *this; }
132 
133         //! @brief 生成時に必要なメモリサイズを取得します。
134         //!
135         //! メモリサイズは Builder の設定によって変化します。
136         //! すべての設定が終わった後にこの関数を呼び出してください。
137         //!
138         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
139         {
140             os::MemorySizeCalculator size(alignment);
141 
142             GetMemorySizeInternal(&size);
143 
144             return size.GetSizeWithPadding(alignment);
145         }
146 
147         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)148         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
149         {
150             os::MemorySizeCalculator& size = *pSize;
151 
152             size += sizeof(AnimGroup);
153             AnimGroup::GetMemorySizeForInitialize(pSize, m_ResAnimGroup, m_UseOriginalValue);
154         }
155 
156         //! @brief アニメーショングループを生成します。
157         //!
158         //! @param[in] allocator アロケータです。
159         //!
160         //! @return 生成されたアニメーショングループです。
161         //!
Create(os::IAllocator * allocator)162         AnimGroup* Create(os::IAllocator* allocator)
163         {
164             void* buf = allocator->Alloc(sizeof(AnimGroup));
165 
166             if (buf == NULL)
167             {
168                 return NULL;
169             }
170 
171             AnimGroup* animGroup = new(buf) AnimGroup(m_ResAnimGroup, m_SceneNode, allocator);
172 
173             Result result = animGroup->Initialize(m_UseOriginalValue);
174 
175             if (result.IsSuccess())
176             {
177                 return animGroup;
178             }
179             else
180             {
181                 SafeDestroy(animGroup);
182                 return NULL;
183             }
184         }
185 
186     private:
187         SceneNode* m_SceneNode;
188         anim::ResAnimGroup m_ResAnimGroup;
189         bool m_UseOriginalValue;
190     };
191 
192     //@}
193 
194     //----------------------------------------
195     //! @name 取得/設定
196     //@{
197 
198     //! アニメーショングループリソースを取得します。
GetResAnimGroup()199     anim::ResAnimGroup GetResAnimGroup() const { return m_ResAnimGroup; }
200 
201     //! グラフィックスアニメーショングループリソースを取得します。
GetResGraphicsAnimGroup()202     anim::ResGraphicsAnimGroup GetResGraphicsAnimGroup() const
203     {
204         return *reinterpret_cast<const anim::ResGraphicsAnimGroup*>(&m_ResAnimGroup);
205     }
206 
207     //! アニメーショングループメンバリソースを取得します。
GetResAnimGroupMember(int memberIdx)208     anim::ResAnimGroupMember GetResAnimGroupMember(int memberIdx) const { return m_ResAnimGroup.GetMemberInfoSet(memberIdx); }
209 
210     //! アニメーショングループメンバリソースを取得します。
GetResAnimGroupMember(const char * key)211     anim::ResAnimGroupMember GetResAnimGroupMember(const char* key) const { return m_ResAnimGroup.GetMemberInfoSet(key); }
212 
213     //! アニメーショングループメンバリソースのインデックスを取得します。
GetResAnimGroupMemberIndex(const char * key)214     int GetResAnimGroupMemberIndex(const char* key) const { return m_ResAnimGroup.GetMemberInfoSetIndex(key); }
215 
216     //! 名前を取得します。
GetName()217     const char* GetName() const { return m_ResAnimGroup.GetName(); }
218 
219     //! アニメーショングループメンバ数を取得します。
GetMemberCount()220     s32 GetMemberCount() const { return m_ResAnimGroup.GetMemberInfoSetCount(); }
221 
222     //! アニメーショングループ内のブレンドオペレーションを取得します。
GetBlendOperationInGroup(int blendOpIdx)223     const anim::AnimBlendOp* GetBlendOperationInGroup(int blendOpIdx) const
224     {
225         NW_MINMAXLT_ASSERT(blendOpIdx, 0, m_BlendOperations.Size());
226         return m_BlendOperations[blendOpIdx];
227     }
228 
229     //! アニメーショングループ内のブレンドオペレーションを設定します。
SetBlendOperationInGroup(int blendOpIdx,anim::AnimBlendOp * blendOp)230     void SetBlendOperationInGroup(int blendOpIdx, anim::AnimBlendOp* blendOp)
231     {
232         NW_MINMAXLT_ASSERT(blendOpIdx, 0, m_BlendOperations.Size());
233         m_BlendOperations[blendOpIdx] = blendOp;
234     }
235 
236     //! メンバに対するブレンドオペレーションを取得します。
GetBlendOperation(int memberIdx)237     const anim::AnimBlendOp* GetBlendOperation(int memberIdx) const
238     {
239         return GetBlendOperationInGroup(
240             GetResAnimGroupMember(memberIdx).GetBlendOperationIndex());
241     }
242 
243     //! 対象オブジェクトが属するシーンノードを取得します。
GetSceneNode()244     SceneNode* GetSceneNode() const { return m_SceneNode; }
245 
246     //! 対象オブジェクトのインデックスを取得します。
GetTargetObjectIndex(int memberIdx)247     int GetTargetObjectIndex(int memberIdx) const
248     {
249         NW_MINMAXLT_ASSERT(memberIdx, 0, m_TargetObjectIndicies.Size());
250         return m_TargetObjectIndicies[memberIdx];
251     }
252 
253     //! 対象オブジェクトのインデックスを設定します。
SetTargetObjectIndex(int memberIdx,const int targetObjIdx)254     void SetTargetObjectIndex(int memberIdx, const int targetObjIdx)
255     {
256         NW_MINMAXLT_ASSERT(memberIdx, 0, m_TargetObjectIndicies.Size());
257         m_TargetObjectIndicies[memberIdx] = targetObjIdx;
258     }
259 
260     //! 対象オブジェクトのポインタを取得します。
GetTargetObject(int memberIdx)261     void* GetTargetObject(int memberIdx) const
262     {
263         NW_MINMAXLT_ASSERT(memberIdx, 0, m_TargetObjects.Size());
264         return m_TargetObjects[memberIdx];
265     }
266 
267     //! 対象オブジェクトのポインタを設定します。
SetTargetObject(int memberIdx,void * object)268     void SetTargetObject(int memberIdx, void* object)
269     {
270         NW_MINMAXLT_ASSERT(memberIdx, 0, m_TargetObjects.Size());
271         m_TargetObjects[memberIdx] = object;
272     }
273 
274     //! 対象メンバのポインタを取得します。
GetTargetPtr(int memberIdx)275     void* GetTargetPtr(int memberIdx) const
276     {
277         NW_MINMAXLT_ASSERT(memberIdx, 0, m_TargetPtrs.Size());
278         return m_TargetPtrs[memberIdx];
279     }
280 
281     //! 対象メンバのポインタを設定します。
SetTargetPtr(int memberIdx,void * target)282     void SetTargetPtr(int memberIdx, void* target)
283     {
284         NW_MINMAXLT_ASSERT(memberIdx, 0, m_TargetPtrs.Size());
285         m_TargetPtrs[memberIdx] = target;
286     }
287 
288     //! メンバのオリジナル値を持っているかどうかを取得します。
HasOriginalValue()289     bool HasOriginalValue() const { return m_OriginalValues.Size() != 0; }
290 
291     //! メンバのオリジナル値を取得します。
GetOriginalValue(int memberIdx)292     const void* GetOriginalValue(int memberIdx) const
293     {
294         NW_MINMAXLT_ASSERT(memberIdx, 0, m_OriginalValues.Size());
295         return m_OriginalValues[memberIdx];
296     }
297 
298     //! メンバのオリジナル値を設定します。
SetOriginalValue(int memberIdx,const void * value)299     void SetOriginalValue(int memberIdx, const void* value)
300     {
301         NW_MINMAXLT_ASSERT(memberIdx, 0, m_OriginalValues.Size());
302         m_OriginalValues[memberIdx] = value;
303     }
304 
305     //! メンバの値のサイズをバイト数で取得します。
NW_DEPRECATED_FUNCTION(int GetMemberValueBytes (int memberIdx)const)306     NW_DEPRECATED_FUNCTION(int GetMemberValueBytes(int memberIdx) const)
307     {
308         return GetResAnimGroupMember(memberIdx).GetMemberSize();
309     }
310 
311     //! 評価前コールバック関数を取得します。
GetPreEvaluateCallback()312     PreEvaluateCallback GetPreEvaluateCallback() const { return m_PreEvaluateCallback; }
313 
314     //! 評価前コールバック関数を設定します。
SetPreEvaluateCallback(PreEvaluateCallback function)315     void SetPreEvaluateCallback(PreEvaluateCallback function) { m_PreEvaluateCallback = function; }
316 
317     //@}
318 
319 protected:
320     //----------------------------------------
321     //! @name コンストラクタ/デストラクタ
322     //@{
323 
324     //! コンストラクタです。
325     //!
326     //! :private
327     AnimGroup(
328         anim::ResAnimGroup resAnimGroup,
329         SceneNode* sceneNode,
330         os::IAllocator* allocator);
331 
332     //! デストラクタです。
333     //!
334     //! :private
~AnimGroup()335     virtual ~AnimGroup() {}
336 
337     //@}
338 
339     //! Initialize() の実行に必要なメモリサイズを取得します。
340     //!
341     //! :private
342     static void GetMemorySizeForInitialize(os::MemorySizeCalculator* pSize, const anim::ResAnimGroup resAnimGroup, bool useOriginalValue);
343 
344     //! メンバを初期化します。
345     //!
346     //! :private
347     Result Initialize(bool useOriginalValue);
348 
349 private:
350     anim::ResAnimGroup m_ResAnimGroup; //!< アニメーショングループのリソースです。
351     ut::MoveArray<anim::AnimBlendOp*> m_BlendOperations; //!< ブレンドオペレーションです。
352 
353     SceneNode* m_SceneNode; //!< 対象オブジェクトが属するシーンノードです。
354     ut::MoveArray<int> m_TargetObjectIndicies; //!< メンバごとの対象オブジェクトのインデックスです。
355     ut::MoveArray<void*> m_TargetObjects; //!< メンバごとの対象オブジェクトのポインタです。
356     ut::MoveArray<void*> m_TargetPtrs; //!< メンバごとの対象のポインタです。
357     ut::MoveArray<const void*> m_OriginalValues; //!< メンバごとのオリジナル値です。
358 
359     PreEvaluateCallback m_PreEvaluateCallback; //!< 評価前コールバック関数です。
360 };
361 
362 //---------------------------------------------------------------------------
363 //! @brief アニメーション評価を抽象化するクラスです。
364 //! 抽象クラスですのでインスタンス化して使用することはできません。
365 //!
366 //! フレームを進める、各フレームの値を取得する、などの動作を抽象化しています。
367 //! 単一のアニメーションを評価する AnimEvaluator, 複数のアニメーションをブレンドする AnimBlender などの派生クラスがあります。
368 //---------------------------------------------------------------------------
369 class AnimObject : public GfxObject
370 {
371 public:
372     //! @details :private
373     NW_UT_RUNTIME_TYPEINFO;
374 
375     //----------------------------------------
376     //! @name コンストラクタ/デストラクタ
377     //@{
378 
379     //! コンストラクタです。
AnimObject(os::IAllocator * allocator)380     AnimObject(os::IAllocator* allocator)
381     : GfxObject(allocator),
382       m_AnimGroup(NULL) {}
383 
384     //! デストラクタです。
~AnimObject()385     virtual ~AnimObject() {}
386 
387     //@}
388 
389     //----------------------------------------
390     //! @name 基本操作
391     //@{
392 
393     //! @brief アニメーションを関連付けます。
394     //!
395     //! @param[in] animGroup アニメーショングループです。
396     //!
397     //! @return バインドに成功したら true を返します。
398     //!
399     //! @sa TryBind
Bind(AnimGroup * animGroup)400     bool Bind(AnimGroup* animGroup)
401     {
402         return TryBind(animGroup).IsSuccess();
403     }
404 
405     //! @brief アニメーションを関連付けます。
406     //!
407     //! Bind() よりも詳細なバインド結果を得ることができます。
408     //!
409     //! @param[in] animGroup アニメーショングループです。
410     //!
411     //! @return バインドの結果を返します。
412     //!
413     //! @sa Bind
414     //! @sa BindResult
415     virtual Result TryBind(AnimGroup* animGroup) = 0;
416 
417     //! アニメーションの関連付けを解除します。
418     virtual void Release() = 0;
419 
420     //! フレームを更新します。
421     virtual void UpdateFrame() = 0;
422 
423     //@}
424 
425     //----------------------------------------
426     //! @name 評価
427     //@{
428 
429     //! @brief メンバ単位でアニメーション結果を取得します。
430     //!
431     //! @param[out] target アニメーション結果を書き込む対象です。
432     //! @param[in] memberIdx メンバインデックスです。
433     //!
434     //! @return アニメーション結果を返します。
435     //! ブレンドオペレーションを使用する場合は、返り値のアニメーション結果を使用してください。
436     //!
437     virtual const anim::AnimResult* GetResult(
438         void* target,
439         int memberIdx) const = 0;
440 
441     //@}
442 
443     //----------------------------------------
444     //! @name 取得/設定
445     //@{
446 
447     //! アニメーショングループを取得します。
GetAnimGroup()448     const AnimGroup* GetAnimGroup() const { return m_AnimGroup; }
449 
450     //! アニメーショングループを取得します。
GetAnimGroup()451     AnimGroup* GetAnimGroup() { return m_AnimGroup; }
452 
453     //! アニメーショングループを設定します。
SetAnimGroup(AnimGroup * group)454     void SetAnimGroup(AnimGroup* group) { m_AnimGroup = group; }
455 
456     //! @brief メンバに関連付けられたアニメーションが存在するかどうかを取得します。
457     //!
458     //! @param[in] memberIdx メンバインデックスです。
459     //!
460     //! @return アニメーションが存在すれば true を返します。
461     //!
462     virtual bool HasMemberAnim(int memberIdx) const = 0;
463 
464     //@}
465 
466     //----------------------------------------
467     //! @name キャッシュ
468     //@{
469 
470     //! アニメーション評価結果の内部キャッシュが古ければ更新します。
471     virtual void UpdateCache() = 0;
472 
473     //@}
474 
475 protected:
476     //! @details :private
477     AnimGroup* m_AnimGroup;
478 };
479 
480 //---------------------------------------------------------------------------
481 //! @brief アニメーションの関連付け情報のクラスです。
482 //!
483 //! AnimObject と AnimGroup を関連付けて、アニメーションの再生を行います。
484 //---------------------------------------------------------------------------
485 class AnimBinding : public GfxObject
486 {
487 public:
488 
489     //! アニメーショングループの MoveArray の定義です。
490     //!
491     //! :private
492     typedef ut::MoveArray<AnimGroup*> AnimGroupArray;
493 
494     //! アニメーションオブジェクトの MoveArray の定義です。
495     //!
496     //! :private
497     typedef ut::MoveArray<AnimObject*> AnimObjectArray;
498 
499     //----------------------------------------
500     //! @name 作成
501     //@{
502 
503     //! アニメーションバインディングを構築するクラスです。
504     class Builder
505     {
506     public:
507         //! コンストラクタです。
Builder()508         Builder()
509         :
510           m_MaxAnimGroups(1),
511           m_MaxAnimObjectsPerGroup(1) {}
512 
513         //! 最大アニメーショングループ数を設定します。
MaxAnimGroups(int maxAnimGroups)514         Builder& MaxAnimGroups(int maxAnimGroups)
515         {
516             NW_ASSERT(maxAnimGroups > 0);
517             m_MaxAnimGroups = maxAnimGroups;
518             return *this;
519         }
520 
521         //! @brief アニメーショングループ内での最大アニメーションオブジェクト数を設定します。
522         //!
523         //! @details 複数のアニメーショングループを持つ場合は、そのうち最大のものを指定してください。
MaxAnimObjectsPerGroup(int maxAnimObjects)524         Builder& MaxAnimObjectsPerGroup(int maxAnimObjects)
525         {
526             NW_ASSERT(maxAnimObjects > 0);
527             m_MaxAnimObjectsPerGroup = maxAnimObjects;
528             return *this;
529         }
530 
531         //! @brief 生成時に必要なメモリサイズを取得します。
532         //!
533         //! メモリサイズは Builder の設定によって変化します。
534         //! すべての設定が終わった後にこの関数を呼び出してください。
535         //!
536         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
537         {
538             os::MemorySizeCalculator size(alignment);
539 
540             GetMemorySizeInternal(&size);
541 
542             return size.GetSizeWithPadding(alignment);
543         }
544 
545         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)546         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
547         {
548             os::MemorySizeCalculator& size = *pSize;
549 
550             size += sizeof(AnimBinding);
551             AnimBinding::GetMemorySizeForInitialize(pSize, m_MaxAnimGroups, m_MaxAnimObjectsPerGroup);
552         }
553 
554         //! @brief アニメーションバインディングを生成します。
555         //!
556         //! @param[in] allocator アロケータです。
557         //!
558         //! @return 生成されたアニメーションバインディングです。
559         //!
Create(os::IAllocator * allocator)560         AnimBinding* Create(os::IAllocator* allocator)
561         {
562             void* buf = allocator->Alloc(sizeof(AnimBinding));
563 
564             if (buf == NULL)
565             {
566                 return NULL;
567             }
568 
569             AnimBinding* animBinding = new(buf) AnimBinding(allocator, m_MaxAnimObjectsPerGroup);
570 
571             Result result = animBinding->Initialize(m_MaxAnimGroups, m_MaxAnimObjectsPerGroup);
572 
573             if (result.IsSuccess())
574             {
575                 return animBinding;
576             }
577             else
578             {
579                 SafeDestroy(animBinding);
580                 return NULL;
581             }
582         }
583 
584     private:
585         int m_MaxAnimGroups;
586         int m_MaxAnimObjectsPerGroup;
587     };
588 
589     //@}
590 
591     //----------------------------------------
592     //! @name 基本操作
593     //@{
594 
595     //! @brief アニメーションを評価して対象に書き込みます。
596     //!
597     //! SceneUpdater::UpdateAll から自動的に呼び出されます。
598     //! 通常は、ユーザーが呼び出す必要はありません。
599     //!
600     //! @param[in] timing 評価タイミングです。
601     //!
602     void Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing);
603 
604     //! @brief 設定されたすべてのアニメーションオブジェクトのフレームを更新します。
605     //!
606     //! SceneUpdater::UpdateAll から自動的に呼び出されます。
607     //! 通常は、ユーザーが呼び出す必要はありません。
UpdateFrame()608     void UpdateFrame()
609     {
610         for (int animObjIdx = 0; animObjIdx < m_AnimObjects.Size(); ++animObjIdx)
611         {
612             if (m_AnimObjects[animObjIdx] != NULL)
613             {
614                 m_AnimObjects[animObjIdx]->UpdateFrame();
615             }
616         }
617     }
618 
619     //@}
620 
621     //----------------------------------------
622     //! @name 取得/設定
623     //@{
624 
625     //! アニメーショングループ数を取得します。
GetAnimGroupCount()626     int GetAnimGroupCount() const { return m_AnimGroups.Size(); }
627 
628     //! アニメーショングループを取得します。
GetAnimGroup(int groupIdx)629     const AnimGroup* GetAnimGroup(int groupIdx) const
630     {
631         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size());
632         return m_AnimGroups[groupIdx];
633     }
634 
635     //! アニメーショングループを取得します。
GetAnimGroup(int groupIdx)636     AnimGroup* GetAnimGroup(int groupIdx)
637     {
638         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size());
639         return m_AnimGroups[groupIdx];
640     }
641 
642     //! @brief アニメーショングループ名から、登録されているグループのインデックスを取得します。
643     //!
644     //! @param[in] animGroupName アニメーショングループ名です。
645     //!
646     //! @return アニメーショングループのインデックスです。
647     //! animGroupName に対応するアニメーショングループがない場合は -1 を返します。
648     //!
GetAnimGroupIndex(const char * animGroupName)649     int GetAnimGroupIndex(const char* animGroupName) const
650     {
651         for (int groupIdx = 0; groupIdx < m_AnimGroups.Size(); ++groupIdx)
652         {
653             if (m_AnimGroups[groupIdx] != NULL &&
654                 ::std::strcmp(m_AnimGroups[groupIdx]->GetName(), animGroupName) == 0)
655             {
656                 return groupIdx;
657             }
658         }
659         return -1;
660     }
661 
662     //! @brief アニメーショングループ名から、登録されているグループのインデックスを取得します。
663     //! @details より意味が明確な名称に変更される予定です。GetAnimGroupIndex(animGroupName)を使用してください。
NW_DEPRECATED_FUNCTION(int GetAnimBindingIndex (const char * animGroupName)const)664     NW_DEPRECATED_FUNCTION(int GetAnimBindingIndex(const char* animGroupName) const)
665     {
666         return GetAnimGroupIndex(animGroupName);
667     }
668 
669     //! アニメーショングループを設定します。
SetAnimGroup(int groupIdx,AnimGroup * animGroup)670     void SetAnimGroup(int groupIdx, AnimGroup* animGroup)
671     {
672         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size());
673         m_AnimGroups[groupIdx] = animGroup;
674     }
675 
676     //! アニメーションオブジェクトを取得します。
677     const AnimObject* GetAnimObject(int groupIdx, int objectIdx = 0) const
678     {
679         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimObjects.Size());
680         NW_MINMAXLT_ASSERT(objectIdx, 0, m_AnimObjectCountPerGroup);
681 
682         const int index = groupIdx * m_AnimObjectCountPerGroup + objectIdx;
683         return m_AnimObjects[index];
684     }
685 
686     //! アニメーションオブジェクトを取得します。
687     AnimObject* GetAnimObject(int groupIdx, int objectIdx = 0)
688     {
689         NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size());
690         NW_MINMAXLT_ASSERT(objectIdx, 0, m_AnimObjectCountPerGroup);
691 
692         const int index = groupIdx * m_AnimObjectCountPerGroup + objectIdx;
693         return m_AnimObjects[index];
694     }
695 
696     //! @brief アニメーションオブジェクトを設定します。
697     //! アニメーションオブジェクトにバインドされたアニメーショングループの名前から、
698     //! アニメーションバインディング中の設定先グループを決定します。
699     //!
700     //! @param[in] animObject アニメーションオブジェクトです。
701     //! アニメーショングループにバインドされている必要があります。
702     //! @param[in] objectIdx アニメーショングループについてのアニメーションオブジェクトのindexです。
703     //!                      複数個のアニメーションオブジェクトを一つのグループにバインドする際に指定します。
704     //!
705     //! @return 成功すれば true を返します。
706     //!
707     bool SetAnimObject(AnimObject* animObject, int objectIdx = 0)
708     {
709         const AnimGroup* animGroup = animObject->GetAnimGroup();
710         NW_NULL_ASSERT(animGroup);
711         return SetAnimObject(animGroup->GetName(), animObject, objectIdx);
712     }
713 
714     //! @brief アニメーションオブジェクトを設定します。
715     //!
716     //! @param[in] groupIdx アニメーションバインディング中の、バインド対象のグループのインデックスです。
717     //! @param[in] animObject アニメーションオブジェクトです。
718     //! @param[in] objectIdx アニメーショングループについてのアニメーションオブジェクトのindexです。
719     //!                      複数個のアニメーションオブジェクトを一つのグループにバインドする際に指定します。
720     //!
721     //! @return 成功すれば true を返します。
722     //!
723     bool SetAnimObject(int groupIdx, AnimObject* animObject, int objectIdx = 0)
724     {
725         // ここでgroupIdxに入っているのは、対象のグループのインデックス
726         if ((0 <= groupIdx && groupIdx < m_AnimGroups.Size()) &&
727             (0 <= objectIdx && objectIdx < m_AnimObjectCountPerGroup))
728         {
729             const int index = groupIdx * m_AnimObjectCountPerGroup + objectIdx;
730             m_AnimObjects[index] = animObject;
731             return true;
732         }
733         return false;
734     }
735 
736     //! @brief アニメーションオブジェクトを設定します。
737     //!
738     //! @param[in] animGroupName アニメーショングループ名です。
739     //! @param[in] animObject アニメーションオブジェクトです。
740     //! @param[in] objectIdx アニメーショングループについてのアニメーションオブジェクトのindexです。
741     //!                      複数個のアニメーションオブジェクトを一つのグループにバインドする際に指定します。
742     //!
743     //! @return 成功すれば true を返します。
744     //!
745     bool SetAnimObject(const char* animGroupName, AnimObject* animObject, int objectIdx = 0)
746     {
747         return SetAnimObject(GetAnimGroupIndex(animGroupName), animObject, objectIdx);
748     }
749 
750     //@}
751 
752 protected:
753     //----------------------------------------
754     //! @name コンストラクタ/デストラクタ
755     //@{
756 
757     //! コンストラクタです。
758     //!
759     //! :private
AnimBinding(os::IAllocator * allocator,int maxAnimObjects)760     AnimBinding(
761         os::IAllocator* allocator,
762         int maxAnimObjects)
763     : GfxObject(allocator)
764     , m_AnimObjectCountPerGroup(maxAnimObjects)
765     {
766     }
767 
768     //! デストラクタです。
769     //!
770     //! :private
~AnimBinding()771     virtual ~AnimBinding()
772     {
773         // AnimGroups, AnimObjects共に、中身は生成元で削除します。
774         // AnimBindingでは参照しているだけなので、何も行いません。
775     }
776 
777     //@}
778 
779     //! Initialize() の実行に必要なメモリサイズを取得します。
780     //!
781     //! :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,int maxAnimGroups,int maxAnimObjects)782     static void GetMemorySizeForInitialize(os::MemorySizeCalculator* pSize, int maxAnimGroups, int maxAnimObjects)
783     {
784         os::MemorySizeCalculator& size = *pSize;
785 
786         const int animObjectCount = maxAnimGroups * maxAnimObjects;
787 
788         size += sizeof(AnimGroup*) * maxAnimGroups;
789         size += sizeof(AnimObject*) * animObjectCount;
790     }
791 
792     //! メンバを初期化します。
793     //!
794     //! :private
Initialize(int maxAnimGroups,int maxAnimObjects)795     Result Initialize(int maxAnimGroups, int maxAnimObjects)
796     {
797         // AnimObjectの個数は、Builderで設定されたAnimObjectsの数 * Groupの数です。
798         const int animObjectCount = maxAnimGroups * maxAnimObjects;
799 
800         Result result = INITIALIZE_RESULT_OK;
801 
802         {
803             void* memory = GetAllocator().Alloc(sizeof(AnimGroup*) * maxAnimGroups);
804             if (memory == NULL)
805             {
806                 result |= Result::MASK_FAIL_BIT;
807             }
808             NW_ENSURE_AND_RETURN(result);
809 
810             m_AnimGroups = AnimGroupArray(memory, maxAnimGroups, &GetAllocator());
811         }
812         {
813             void* memory = GetAllocator().Alloc(sizeof(AnimObject*) * animObjectCount);
814             if (memory == NULL)
815             {
816                 result |= Result::MASK_FAIL_BIT;
817             }
818             NW_ENSURE_AND_RETURN(result);
819 
820             m_AnimObjects = AnimObjectArray(memory, animObjectCount, &GetAllocator());
821         }
822 
823         for (int animGroupIdx = 0; animGroupIdx < maxAnimGroups; ++animGroupIdx)
824         {
825             m_AnimGroups.PushBack(NULL);
826         }
827 
828         for (int animObjectIdx = 0; animObjectIdx < animObjectCount; ++animObjectIdx)
829         {
830             m_AnimObjects.PushBack(NULL);
831         }
832 
833         return result;
834     }
835 
836 private:
837     //----------------------------------------
838     // 評価
839 
840     // ブレンダを使用しない場合の評価処理です。
841     // 不要なループを省略し、高速に処理します。
842     NW_FORCE_INLINE void EvaluateSimple(AnimGroup* animGroup, AnimEvaluator* evaluator);
843     NW_FORCE_INLINE void EvaluateTransformSimple(AnimGroup* animGroup, TransformAnimEvaluator* evaluator);
844 
845     // ブレンダを使用する場合の評価処理です。
846     NW_FORCE_INLINE void EvaluateBlender(AnimGroup* animGroup, AnimObject* animObj);
847 
848     NW_FORCE_INLINE void EvaluateTransformMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj); //!< @details :private
849     NW_FORCE_INLINE void EvaluateTransformMemberFast(AnimGroup* animGroup, int memberIdx, TransformAnimEvaluator* evaluator); //!< @details :private
850     NW_FORCE_INLINE void EvaluateMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj, int& lastTargetObjIdx, bool& targetObjSkipFlag); //!< @details :private
851 
852     AnimGroupArray m_AnimGroups; //!< @details :private
853     AnimObjectArray m_AnimObjects; //!< @details :private
854     const int m_AnimObjectCountPerGroup; //!< @details :private
855 };
856 
857 //---------------------------------------------------------------------------
858 //! @brief アニメーション評価の基底クラスです。
859 //! 抽象クラスですのでインスタンス化して使用することはできません。
860 //---------------------------------------------------------------------------
861 class BaseAnimEvaluator : public AnimObject
862 {
863 public:
864     NW_UT_RUNTIME_TYPEINFO;
865 
866     //! 関連付け対象がない場合のインデックスです。
867     //!
868     //! :private
869     static const int NotFoundIndex;
870 
871     //----------------------------------------
872     //! @name コンストラクタ/デストラクタ
873     //@{
874 
875     //! コンストラクタです。
BaseAnimEvaluator(os::IAllocator * allocator)876     BaseAnimEvaluator(
877         os::IAllocator* allocator)
878     : AnimObject(allocator),
879       m_IsCacheDirty(true),
880       m_IsCacheExternal(false)
881     {
882     }
883 
884     //! デストラクタです。
~BaseAnimEvaluator()885     virtual ~BaseAnimEvaluator() {}
886 
887     //@}
888 
889     //----------------------------------------
890     //! @name 基本操作
891     //@{
892 
893     //! @brief アニメーションを関連付けます。
894     //!
895     //! Bind よりも詳細なバインド結果を得ることができます。
896     //!
897     //! @param[in] animGroup アニメーショングループです。
898     //!
899     //! @return バインドの結果を返します。
900     //!
901     //! @sa Bind
902     //! @sa TryBindResult
903     virtual Result TryBind(AnimGroup* animGroup);
904 
905     //! アニメーションの関連付けを解除します。
Release()906     virtual void Release()
907     {
908         m_AnimGroup = NULL;
909     }
910 
911     //! フレームを更新します。
UpdateFrame()912     virtual void UpdateFrame()
913     {
914         // 更新フレームが 0 の場合は、SetStepFrame() で
915         // キャッシュを更新済みです。
916         if (GetStepFrame() != 0.0f)
917         {
918             m_AnimFrameController.UpdateFrame();
919             m_IsCacheDirty = true;
920         }
921     }
922 
923     //! @brief アニメーションを変更します。
924     //!
925     //! AnimEvaluator::Bind の後でアニメーションを差し替える場合に使用します。
926     //! AnimEvaluator を破棄して再生成するより高速です。
927     //!
928     //! 再生フレームは 0.0f にリセットされます。
929     //!
930     //! @param animData アニメーションデータです。
ChangeAnim(const nw::anim::ResAnim animData)931     virtual void ChangeAnim(const nw::anim::ResAnim animData)
932     {
933         NW_NULL_ASSERT(m_AnimGroup);
934 
935         // このASSERTが失敗した場合は、Builder::MaxAnimMembers の値を大きくしてください
936         NW_ASSERT(animData.GetMemberAnimSetCount() <= m_ReverseBindIndexTable.Capacity());
937 
938         SetResAnim(animData);
939 
940         AnimGroup* animGroup = m_AnimGroup;
941         Release();
942         Bind(animGroup);
943     }
944 
945     //! @brief すべてのアニメーション対象メンバーを生成時の状態に戻します。
946     //!
947     //! マテリアルに対して行う場合、マテリアルのバッファを生成する必要があります。
948     //! SceneBuilder クラスでモデルを作成する際のオプションで、
949     //! SceneBuilder::MaterialBufferCount と SceneBuilder::BufferOption を設定してください。
950     //! BufferOption には、 Model::MULTI_FLAG_ANIMATABLE_MATERIAL の内容が最低限必要です。
Reset()951     void Reset()
952     {
953         for (int i = (m_AnimGroup->GetMemberCount() - 1); i >= 0; --i)
954         {
955             this->ResetMember(i);
956         }
957     }
958 
959     //! @brief 指定されたメンバーを生成時の状態に戻します。
960     //! @param memberIdx 対象のメンバーです。
961     void ResetMember(int memberIdx);
962 
963     //@}
964 
965     //----------------------------------------
966     //! @name フレーム制御
967     //@{
968 
969     //! フレームを取得します。
GetFrame()970     float GetFrame() const { return m_AnimFrameController.GetFrame(); }
971 
972     //! @brief フレームを設定します。
973     //!
974     //! @param[in] frame 設定するフレームです。
975     //!
SetFrame(float frame)976     void SetFrame(float frame)
977     {
978         m_AnimFrameController.SetFrame(frame);
979         m_IsCacheDirty = true;
980     }
981 
982     //! @brief フレームをリセットします。
983     //!
984     //! @param[in] frame 設定するフレームです。
985     //!
ResetFrame(f32 frame)986     void ResetFrame(f32 frame)
987     {
988         m_AnimFrameController.GetAnimFrame().ResetFrame(frame);
989         m_IsCacheDirty = true;
990     }
991 
992     //! @brief 更新フレームを取得します。
993     //! @sa SetStepFrame
GetStepFrame()994     float GetStepFrame() const { return m_AnimFrameController.GetStepFrame(); }
995 
996     //! @brief 更新フレームを設定します。
997     //!
998     //! UpdateFrame() を呼び出すと、現在のフレームに更新フレームが加算されます。
999     //! 例えば SetStepFrame(2.0f) とすると、2倍速再生になります。
1000     //!
1001     //! @param[in] stepFrame 更新フレームです。
SetStepFrame(float stepFrame)1002     void SetStepFrame(float stepFrame)
1003     {
1004         m_AnimFrameController.SetStepFrame(stepFrame);
1005         if (stepFrame == 0.0f)
1006         {
1007             m_IsCacheDirty = true;
1008             UpdateCache();
1009         }
1010     }
1011 
1012     //! @brief 開始フレームを取得します。
1013     //! @sa SetStartFrame
GetStartFrame()1014     float GetStartFrame() const { return m_AnimFrameController.GetStartFrame(); }
1015 
1016     //! @brief 開始フレームを設定します。
1017     //!
1018     //! 開始フレームを現在のフレームより後に設定した場合、
1019     //! 現在のフレームを開始フレームに移動します。
1020     //!
1021     //! @param[in] startFrame 開始フレームです。
SetStartFrame(float startFrame)1022     void SetStartFrame(float startFrame)
1023     {
1024         m_AnimFrameController.SetStartFrame(startFrame);
1025         if (startFrame > GetFrame())
1026         {
1027             SetFrame(startFrame);
1028         }
1029     }
1030 
1031     //! @brief 終了フレームを取得します。
1032     //! @sa SetEndFrame
GetEndFrame()1033     float GetEndFrame() const { return m_AnimFrameController.GetEndFrame(); }
1034 
1035     //! @brief 終了フレームを設定します。
1036     //!
1037     //! 終了フレームを現在のフレームより前に設定した場合、
1038     //! 現在のフレームを終了フレームに移動します。
1039     //!
1040     //! @param[in] endFrame 終了フレームです。
SetEndFrame(float endFrame)1041     void SetEndFrame(float endFrame)
1042     {
1043         m_AnimFrameController.SetEndFrame(endFrame);
1044         if (endFrame < GetFrame())
1045         {
1046             SetFrame(endFrame);
1047         }
1048     }
1049 
1050     //! アニメーション再生方法を取得します。
GetPlayPolicy()1051     nw::anim::AnimFrameController::PlayPolicy GetPlayPolicy() const
1052     {
1053         return m_AnimFrameController.GetPlayPolicy();
1054     }
1055 
1056     //! @brief アニメーション再生方法を設定します。
1057     //!
1058     //! @param[in] playPolicy 設定するアニメーション再生方法です。
1059     //! @sa nw::anim::AnimFrameController::SetPlayPolicy
SetPlayPolicy(nw::anim::AnimFrameController::PlayPolicy playPolicy)1060     void SetPlayPolicy(nw::anim::AnimFrameController::PlayPolicy playPolicy)
1061     {
1062         m_AnimFrameController.SetPlayPolicy(playPolicy);
1063         m_IsCacheDirty = true;
1064     }
1065 
1066     //! アニメーションフレーム制御情報を取得します。
AnimFrameController()1067     const nw::anim::AnimFrameController& AnimFrameController() const { return m_AnimFrameController; }
1068 
1069     //@}
1070 
1071     //----------------------------------------
1072     //! @name 取得/設定
1073     //@{
1074 
1075     //! ユーザーデータを取得します。
GetUserData()1076     const void* GetUserData() const { return m_AnimFrameController.GetUserData(); }
1077 
1078     //! ユーザーデータを取得します。
GetUserData()1079     void* GetUserData() { return m_AnimFrameController.GetUserData(); }
1080 
1081     //! @brief ユーザーデータを設定します。
1082     //!
1083     //! @param[in] userData 設定するユーザーデータです。
1084     //! @sa nw::anim::AnimFrameController::SetUserData
1085     //!
SetUserData(void * userData)1086     void SetUserData(void* userData) { m_AnimFrameController.SetUserData(userData); }
1087 
1088     //! ResAnimGroupMember のインデックスから ResMemberAnim のインデックスへの変換テーブルを取得します。
BindIndexTable()1089     const ut::MoveArray<int>& BindIndexTable() const { return m_BindIndexTable; }
1090 
1091     //! ResAnimGroupMember のインデックスから ResMemberAnim のインデックスへの変換テーブルを取得します。
BindIndexTable()1092     ut::MoveArray<int>& BindIndexTable() { return m_BindIndexTable; }
1093 
1094     //! ResMemberAnim のインデックスから ResAnimGroupMember のインデックスへの変換テーブルを取得します。
ReverseBindIndexTable()1095     const ut::MoveArray<int>& ReverseBindIndexTable() const { return m_ReverseBindIndexTable; }
1096 
1097     //! ResMemberAnim のインデックスから ResAnimGroupMember のインデックスへの変換テーブルを取得します。
ReverseBindIndexTable()1098     ut::MoveArray<int>& ReverseBindIndexTable() { return m_ReverseBindIndexTable; }
1099 
1100     //! アニメーションデータを取得します。
GetAnimData()1101     const nw::anim::ResAnim GetAnimData() const { return m_AnimData; }
1102 
1103     //@}
1104 
1105     //----------------------------------------
1106     //! @name キャッシュ
1107     //@{
1108 
1109     //! キャッシュバッファを取得します。
GetCacheBuffer()1110     virtual const void* GetCacheBuffer() const { return NULL; }
1111 
1112     //! キャッシュバッファに必要なサイズ(バイト数)を取得します。
GetCacheBufferSizeNeeded()1113     virtual int GetCacheBufferSizeNeeded() const { return 0; }
1114 
1115     //! @brief キャッシュバッファを設定します。
1116     //! この関数で指定したキャッシュバッファはデストラクタで解放されません。
1117     //!
1118     //! @param[in] buf キャッシュバッファ用のメモリの先頭アドレスです。
1119     //! NULL の場合、キャッシュが無効になります。
1120     //! @param[in] size キャッシュバッファのサイズ(バイト数)です。
1121     //!
SetCacheBuffer(void * buf,int size)1122     virtual void SetCacheBuffer(void* buf, int size)
1123     {
1124         (void)buf;
1125         (void)size;
1126     }
1127 
1128     //@}
1129 
1130 protected:
1131     //! Initialize() の実行に必要なメモリサイズを取得します。
1132     //!
1133     //! :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,const int maxMembers,const int maxAnimMembers)1134     static void GetMemorySizeForInitialize(
1135         os::MemorySizeCalculator* pSize,
1136         const int maxMembers,
1137         const int maxAnimMembers)
1138     {
1139         os::MemorySizeCalculator& size = *pSize;
1140 
1141         size += sizeof(int) * maxMembers;
1142         size += sizeof(int) * maxAnimMembers;
1143     }
1144 
1145     //! メンバを初期化します。
1146     //!
1147     //! :private
Initialize(const nw::anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers)1148     virtual Result Initialize(
1149         const nw::anim::ResAnim& animData,
1150         const int maxMembers,
1151         const int maxAnimMembers)
1152     {
1153         Result result = INITIALIZE_RESULT_OK;
1154 
1155         SetResAnim(animData);
1156 
1157         {
1158             void* memory = GetAllocator().Alloc(sizeof(int) * maxMembers);
1159             if (memory == NULL)
1160             {
1161                 result |= Result::MASK_FAIL_BIT;
1162             }
1163             NW_ENSURE_AND_RETURN(result);
1164 
1165             m_BindIndexTable = ut::MoveArray<int>(memory, maxMembers, &GetAllocator());
1166         }
1167 
1168         {
1169             void* memory = GetAllocator().Alloc(sizeof(int) * maxAnimMembers);
1170             if (memory == NULL)
1171             {
1172                 result |= Result::MASK_FAIL_BIT;
1173             }
1174             NW_ENSURE_AND_RETURN(result);
1175 
1176             m_ReverseBindIndexTable = ut::MoveArray<int>(memory, maxAnimMembers, &GetAllocator());
1177         }
1178 
1179         return result;
1180     }
1181 
1182     //! AnimGroupMemberのIndex -> MemberAnimのIndex
1183     //!
1184     //! :private
1185     ut::MoveArray<int> m_BindIndexTable;
1186 
1187     //! MemberAnimのIndex -> AnimGroupMemberのIndex
1188     //!
1189     //! :private
1190     ut::MoveArray<int> m_ReverseBindIndexTable;
1191 
1192     anim::AnimFrameController m_AnimFrameController; //!< @details :private
1193     anim::ResAnim m_AnimData; //!< @details :private
1194 
1195     //! キャッシュの内容が古ければ true
1196     //!
1197     //! :private
1198     bool m_IsCacheDirty;
1199 
1200     //! 外部から指定したキャッシュバッファなら true
1201     //!
1202     //! :private
1203     bool m_IsCacheExternal;
1204 
1205 private:
SetResAnim(const nw::anim::ResAnim animData)1206     void SetResAnim(const nw::anim::ResAnim animData)
1207     {
1208         m_AnimData = animData;
1209         m_AnimFrameController.SetStepFrame(1.0f);
1210         m_AnimFrameController.SetStartFrame(0.0f);
1211         m_AnimFrameController.SetEndFrame(animData.GetFrameSize());
1212         m_AnimFrameController.GetAnimFrame().ResetFrame(0.0f);
1213 
1214         switch (animData.GetLoopMode())
1215         {
1216             case nw::anim::ResAnimData::LOOP_MODE_ONETIME:
1217                 m_AnimFrameController.SetPlayPolicy(nw::anim::PlayPolicy_Onetime);
1218                 break;
1219 
1220             case nw::anim::ResAnimData::LOOP_MODE_LOOP:
1221                 m_AnimFrameController.SetPlayPolicy(nw::anim::PlayPolicy_Loop);
1222                 break;
1223 
1224             default:
1225                 NW_ASSERT(false);
1226         }
1227 
1228         m_IsCacheDirty = true;
1229     }
1230 };
1231 
1232 //---------------------------------------------------------------------------
1233 //! @brief 汎用アニメーションを評価するクラスです。
1234 //!
1235 //! アニメーションデータを保持し、ファンクションカーブの評価を行います。
1236 //---------------------------------------------------------------------------
1237 class AnimEvaluator : public BaseAnimEvaluator
1238 {
1239 public:
1240     NW_UT_RUNTIME_TYPEINFO;
1241 
1242     //----------------------------------------
1243     //! @name 作成
1244     //@{
1245 
1246     //! 汎用アニメーション評価を構築するクラスです。
1247     class Builder
1248     {
1249     public:
1250         //! コンストラクタです。
Builder()1251         Builder()
1252         : m_AnimData(NULL),
1253           m_MaxMembers(64),
1254           m_MaxAnimMembers(64),
1255           m_AllocCache(false) {}
1256 
1257         //! アニメーションデータを設定します。
AnimData(const nw::anim::ResAnim & animData)1258         Builder& AnimData(const nw::anim::ResAnim& animData) { m_AnimData = animData; return *this; }
1259 
1260         //! @brief アニメーション対象メンバの最大数を設定します。
1261         //!
1262         //! AnimEvaluator::Bind に渡す AnimGroup の AnimGroup::GetMemberCount の値を設定してください。
1263         //! 複数の AnimGroup に Bind する場合は、最大値を設定してください。
MaxMembers(int maxMembers)1264         Builder& MaxMembers(int maxMembers)
1265         {
1266             NW_ASSERT(maxMembers > 0);
1267             m_MaxMembers = maxMembers;
1268             return *this;
1269         }
1270 
1271         //! @brief 実際にアニメーションするメンバの最大数を設定します。
1272         //!
1273         //! AnimData() に渡す anim::res::ResAnim の anim::res::ResAnim::GetMemberAnimSetCount の値を設定してください。
1274         //! AnimEvaluator::ChangeAnim で複数の ResAnim を切り替える場合は、最大値を設定してください。
MaxAnimMembers(int maxAnimMembers)1275         Builder& MaxAnimMembers(int maxAnimMembers)
1276         {
1277             NW_ASSERT(maxAnimMembers > 0);
1278             m_MaxAnimMembers = maxAnimMembers;
1279             return *this;
1280         }
1281 
1282         //! キャッシュバッファを確保してキャッシュを有効にするかどうかを設定します。
AllocCache(bool allocCache)1283         Builder& AllocCache(bool allocCache) { m_AllocCache = allocCache; return *this; }
1284 
1285         //! @brief 生成時に必要なメモリサイズを取得します。
1286         //!
1287         //! メモリサイズは Builder の設定によって変化します。
1288         //! すべての設定が終わった後にこの関数を呼び出してください。
1289         //!
1290         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
1291         {
1292             os::MemorySizeCalculator size(alignment);
1293 
1294             GetMemorySizeInternal(&size);
1295 
1296             return size.GetSizeWithPadding(alignment);
1297         }
1298 
1299         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)1300         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
1301         {
1302             os::MemorySizeCalculator& size = *pSize;
1303 
1304             size += sizeof(AnimEvaluator);
1305             AnimEvaluator::GetMemorySizeForInitialize(pSize, m_AnimData, m_MaxMembers, m_MaxAnimMembers, m_AllocCache);
1306         }
1307 
1308         //! @brief 汎用アニメーション評価を生成します。
1309         //!
1310         //! @param[in] allocator アロケータです。
1311         //!
1312         //! @return 生成された汎用アニメーション評価です。
1313         //!
Create(os::IAllocator * allocator)1314         AnimEvaluator* Create(os::IAllocator* allocator)
1315         {
1316             void* buf = allocator->Alloc(sizeof(AnimEvaluator));
1317 
1318             if (buf == NULL)
1319             {
1320                 return NULL;
1321             }
1322 
1323             AnimEvaluator* animEvaluator = new(buf) AnimEvaluator(allocator);
1324 
1325             Result result = animEvaluator->Initialize(m_AnimData, m_MaxMembers, m_MaxAnimMembers, m_AllocCache);
1326             NW_ASSERT(result.IsSuccess());
1327 
1328             return animEvaluator;
1329         }
1330 
1331     private:
1332         nw::anim::ResAnim m_AnimData;
1333         int m_MaxMembers;
1334         int m_MaxAnimMembers;
1335         bool m_AllocCache;
1336     };
1337 
1338     //@}
1339 
1340     //----------------------------------------
1341     //! @name 基本操作
1342     //@{
1343 
1344     //! @brief アニメーションを変更します。
1345     //!
1346     //! GetCacheBufferSizeNeeded() の値が変化しますので、
1347     //! SetCacheBuffer() している場合はバッファの再設定が必要です。
1348     //!
1349     //! 内部で確保したキャッシュバッファは、自動的にサイズ変更されます。
1350     //!
1351     //! @param animData アニメーションデータです。
1352     //! @sa BaseAnimEvaluator::ChangeAnim
ChangeAnim(const nw::anim::ResAnim animData)1353     virtual void ChangeAnim(const nw::anim::ResAnim animData)
1354     {
1355         // キャッシュサイズを求めるのにm_AnimDataを参照するので、
1356         // 先に更新する必要がある
1357         BaseAnimEvaluator::ChangeAnim(animData);
1358 
1359         m_CachePtrs.Resize(animData.GetMemberAnimSetCount());
1360 
1361         if (!m_IsCacheExternal && m_CacheBuf != NULL)
1362         {
1363             os::SafeFree(m_CacheBuf, &GetAllocator());
1364 
1365             // サイズ0でのAllocを回避する
1366             // CreateEmpty~Anim()などを使用した場合に起こりうる
1367             if (animData.GetMemberAnimSetCount() != 0)
1368             {
1369                 m_CacheBuf = GetAllocator().Alloc(GetCacheBufferSizeNeeded());
1370                 NW_NULL_ASSERT(m_CacheBuf);
1371 
1372                 SetCacheBufferPointers();
1373             }
1374         }
1375     }
1376 
1377     //@}
1378 
1379     //----------------------------------------
1380     //! @name 評価
1381     //@{
1382 
1383     //! @brief メンバ単位でアニメーション結果を取得します。
1384     //!
1385     //! @param[out] target アニメーション結果を書き込む対象です。
1386     //! @param[in] memberIdx メンバインデックスです。
1387     //!
1388     //! @return アニメーション結果を返します。
1389     //! ブレンドオペレーションを使用する場合は、返り値のアニメーション結果を使用してください。
1390     //!
1391     virtual const anim::AnimResult* GetResult(
1392         void* target,
1393         int memberIdx) const;
1394 
1395     //@}
1396 
1397     //----------------------------------------
1398     //! @name 取得/設定
1399     //@{
1400 
1401     //! @brief メンバに関連付けられたアニメーションが存在するかどうかを取得します。
1402     //!
1403     //! @param[in] memberIdx メンバインデックスです。
1404     //!
1405     //! @return アニメーションが存在すれば true を返します。
1406     //!
HasMemberAnim(int memberIdx)1407     virtual bool HasMemberAnim(int memberIdx) const
1408     {
1409         NW_MINMAXLT_ASSERT(memberIdx, 0, m_BindIndexTable.Size());
1410         return m_BindIndexTable[memberIdx] != NotFoundIndex;
1411     }
1412 
1413     //@}
1414 
1415     //----------------------------------------
1416     //! @name キャッシュ
1417     //@{
1418 
1419     //! アニメーション評価結果の内部キャッシュが古ければ更新します。
1420     virtual void UpdateCache();
1421 
1422     //! キャッシュバッファに必要なサイズ(バイト数)を取得します。
1423     //! @return 必要なサイズ(バイト数)です。
1424     virtual int GetCacheBufferSizeNeeded() const;
1425 
1426     //! キャッシュバッファを取得します。
GetCacheBuffer()1427     virtual const void* GetCacheBuffer() const { return m_CacheBuf; }
1428 
1429     //! @brief キャッシュバッファを設定します。
1430     //! この関数で指定したキャッシュバッファはデストラクタで解放されません。
1431     //!
1432     //! @param[in] buf キャッシュバッファ用のメモリの先頭アドレスです。
1433     //! NULL の場合、キャッシュが無効になります。
1434     //! @param[in] size キャッシュバッファのサイズ(バイト数)です。
1435     //!
SetCacheBuffer(void * buf,int size)1436     virtual void SetCacheBuffer(void* buf, int size)
1437     {
1438         m_CacheBuf = buf;
1439         if (buf != NULL)
1440         {
1441             NW_ASSERT(size >= GetCacheBufferSizeNeeded());
1442             (void)size;
1443             m_IsCacheDirty = true;
1444             m_IsCacheExternal = true;
1445             SetCacheBufferPointers();
1446         }
1447     }
1448 
1449     //@}
1450 
1451 protected:
1452     //----------------------------------------
1453     //! @name コンストラクタ/デストラクタ
1454     //@{
1455 
1456     //! コンストラクタです。
1457     //!
1458     //! :private
1459     AnimEvaluator(
1460         os::IAllocator* allocator);
1461 
1462     //! デストラクタです。
1463     //!
1464     //! :private
~AnimEvaluator()1465     virtual ~AnimEvaluator()
1466     {
1467         if (!m_IsCacheExternal && m_CacheBuf != NULL)
1468         {
1469             GetAllocator().Free(m_CacheBuf);
1470         }
1471     }
1472 
1473     //@}
1474 
1475     //! Initialize() の実行に必要なメモリサイズを取得します。
1476     //!
1477     //! :private
1478     static void GetMemorySizeForInitialize(
1479         os::MemorySizeCalculator* pSize,
1480         const nw::anim::ResAnim& animData,
1481         const int maxMembers,
1482         const int maxAnimMembers,
1483         bool allocCache);
1484 
1485     //! @details :private
1486     virtual Result Initialize(
1487         const nw::anim::ResAnim& animData,
1488         const int maxMembers,
1489         const int maxAnimMembers,
1490         bool allocCache);
1491 
1492     //! キャッシュバッファに必要なサイズ(バイト数)を取得します。
1493     //!
1494     //! :private
1495     static int GetCacheBufferSizeNeeded(const anim::ResAnim& animData);
1496 
1497     //! 各メンバアニメのキャッシュバッファへのポインタを設定します。
1498     //!
1499     //! :private
1500     void SetCacheBufferPointers();
1501 
1502     //! AnimResult を実サイズで詰めたバッファ
1503     //!
1504     //! :private
1505     void* m_CacheBuf;
1506 
1507     //! 各メンバアニメの m_CacheBuf 中のポインタ
1508     //!
1509     //! :private
1510     ut::MoveArray<anim::AnimResult*> m_CachePtrs;
1511 };
1512 
1513 //---------------------------------------------------------------------------
1514 //! @brief 汎用アニメーションブレンドの基底クラスです。
1515 //! 抽象クラスですのでインスタンス化して使用することはできません。
1516 //!
1517 //! AnimBlender は複数の AnimEvaluator のアニメーション評価結果をブレンドします。
1518 //! AnimBlender で他の AnimBlender のアニメーション評価結果をブレンドすることも可能です。
1519 //---------------------------------------------------------------------------
1520 class AnimBlender : public AnimObject
1521 {
1522 public:
1523     NW_UT_RUNTIME_TYPEINFO;
1524 
1525     //! アニメーションオブジェクトの MoveArray の定義です。
1526     //!
1527     //! :private
1528     typedef ut::MoveArray<AnimObject*> AnimObjectArray;
1529 
1530     //----------------------------------------
1531     //! @name コンストラクタ/デストラクタ
1532     //@{
1533 
1534     //! コンストラクタです。
AnimBlender(os::IAllocator * allocator)1535     AnimBlender(
1536         os::IAllocator* allocator)
1537     : AnimObject(allocator)
1538     {
1539     }
1540 
1541     //! デストラクタです。
~AnimBlender()1542     virtual ~AnimBlender() {}
1543 
1544     //@}
1545 
1546     //----------------------------------------
1547     //! @name 基本操作
1548     //@{
1549 
1550     //! @brief アニメーションを関連付けます。
1551     //!
1552     //! Bind よりも詳細なバインド結果を得ることができます。
1553     //!
1554     //! @param[in] animGroup アニメーショングループです。
1555     //!
1556     //! @return バインドの結果を返します。
1557     //!
1558     //! @sa Bind
1559     //! @sa TryBindResult
TryBind(AnimGroup * animGroup)1560     virtual Result TryBind(AnimGroup* animGroup)
1561     {
1562         NW_NULL_ASSERT(animGroup);
1563         NW_ASSERT(m_AnimGroup == NULL);
1564         m_AnimGroup = animGroup;
1565         return Result(BIND_RESULT_OK);
1566     }
1567 
1568     //! アニメーションの関連付けを解除します。
Release()1569     virtual void Release()
1570     {
1571         m_AnimGroup = NULL;
1572     }
1573 
1574     //! フレームを更新します。
UpdateFrame()1575     virtual void UpdateFrame()
1576     {
1577         for (int animObjIdx = 0; animObjIdx < m_AnimObjects.Size(); ++animObjIdx)
1578         {
1579             if (m_AnimObjects[animObjIdx] != NULL)
1580             {
1581                 m_AnimObjects[animObjIdx]->UpdateFrame();
1582             }
1583         }
1584     }
1585 
1586     //@}
1587 
1588     //----------------------------------------
1589     //! @name 取得/設定
1590     //@{
1591 
1592     //! @brief メンバに関連付けられたアニメーションが存在するかどうかを取得します。
1593     //!
1594     //! @param[in] memberIdx メンバインデックスです。
1595     //!
1596     //! @return アニメーションが存在すれば true を返します。
1597     //!
HasMemberAnim(int memberIdx)1598     virtual bool HasMemberAnim(int memberIdx) const
1599     {
1600         for (int animObjIdx = 0; animObjIdx < m_AnimObjects.Size(); ++animObjIdx)
1601         {
1602             if (m_AnimObjects[animObjIdx] != NULL &&
1603                 m_AnimObjects[animObjIdx]->HasMemberAnim(memberIdx))
1604             {
1605                 return true;
1606             }
1607         }
1608         return false;
1609     }
1610 
1611     //@}
1612 
1613     //----------------------------------------
1614     //! @name アニメーションオブジェクト
1615     //@{
1616 
1617     //! @brief アニメーションオブジェクトを追加します。
1618     //!
1619     //! @param[in] animObj 追加するアニメーションオブジェクトです。
1620     //! NULL を指定しておいて、後で ReplaceAnimObject() で置き換えることも可能です。
1621     //!
AddAnimObject(AnimObject * animObj)1622     void AddAnimObject(AnimObject* animObj)
1623     {
1624         NW_ASSERT(m_AnimObjects.Size() < m_AnimObjects.Capacity());
1625         m_AnimObjects.PushBack(animObj);
1626     }
1627 
1628     //! @brief アニメーションオブジェクトを取得します。
1629     //!
1630     //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。
1631     //!
1632     //! @return アニメーションオブジェクトです。
1633     //!
GetAnimObject(int animObjIdx)1634     const AnimObject* GetAnimObject(int animObjIdx) const
1635     {
1636         NW_MINMAXLT_ASSERT(animObjIdx, 0, m_AnimObjects.Size());
1637         return m_AnimObjects[animObjIdx];
1638     }
1639 
1640     //! @brief アニメーションオブジェクトを取得します。
1641     //!
1642     //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。
1643     //!
1644     //! @return アニメーションオブジェクトです。
1645     //!
GetAnimObject(int animObjIdx)1646     AnimObject* GetAnimObject(int animObjIdx)
1647     {
1648         NW_MINMAXLT_ASSERT(animObjIdx, 0, m_AnimObjects.Size());
1649         return m_AnimObjects[animObjIdx];
1650     }
1651 
1652     //! @brief アニメーションオブジェクトを置き替えます。
1653     //!
1654     //! @param[in] animObjIdx 置き替えるアニメーションオブジェクトのインデックスです。
1655     //! @param[in] animObj アニメーションオブジェクトです。
1656     //! NULL を指定した場合、アニメーションオブジェクトがない状態になります。
1657     //!
1658     //! @return 置き替える前のアニメーションオブジェクトです。
1659     //!
ReplaceAnimObject(int animObjIdx,AnimObject * animObj)1660     AnimObject* ReplaceAnimObject(int animObjIdx, AnimObject* animObj)
1661     {
1662         NW_MINMAXLT_ASSERT(animObjIdx, 0, m_AnimObjects.Size());
1663         AnimObject* oldObj = m_AnimObjects[animObjIdx];
1664         m_AnimObjects[animObjIdx] = animObj;
1665         return oldObj;
1666     }
1667 
1668     //! アニメーションオブジェクトをクリアします。
ClearAnimObjects()1669     void ClearAnimObjects()
1670     {
1671         m_AnimObjects.Clear();
1672     }
1673 
1674     //! 追加されているアニメーションオブジェクト数を取得します。
GetAnimObjectCount()1675     int GetAnimObjectCount() const
1676     {
1677         return m_AnimObjects.Size();
1678     }
1679 
1680     //! アニメーションオブジェクトの最大数を取得します。
GetMaxAnimObjects()1681     int GetMaxAnimObjects() const
1682     {
1683         return m_AnimObjects.Capacity();
1684     }
1685 
1686     //@}
1687 
1688     //----------------------------------------
1689     //! @name キャッシュ
1690     //@{
1691 
1692     //! アニメーション評価結果の内部キャッシュが古ければ更新します。
UpdateCache()1693     virtual void UpdateCache()
1694     {
1695         for (int animObjIdx = 0; animObjIdx < m_AnimObjects.Size(); ++animObjIdx)
1696         {
1697             if (m_AnimObjects[animObjIdx] != NULL)
1698             {
1699                 m_AnimObjects[animObjIdx]->UpdateCache();
1700             }
1701         }
1702     }
1703 
1704     //@}
1705 
1706 protected:
1707     //! Initialize() の実行に必要なメモリサイズを取得します。
1708     //!
1709     //! :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,int maxAnimObjects)1710     static void GetMemorySizeForInitialize(os::MemorySizeCalculator* pSize, int maxAnimObjects)
1711     {
1712         os::MemorySizeCalculator& size = *pSize;
1713 
1714         size += sizeof(AnimObject*) * maxAnimObjects;
1715     }
1716 
1717     //! @details :private
Initialize(int maxAnimObjects)1718     virtual Result Initialize(int maxAnimObjects)
1719     {
1720         Result result = INITIALIZE_RESULT_OK;
1721 
1722         void* memory = GetAllocator().Alloc(sizeof(AnimObject*) * maxAnimObjects);
1723 
1724         if (memory == NULL)
1725         {
1726             result |= Result::MASK_FAIL_BIT;
1727         }
1728         NW_ENSURE_AND_RETURN(result);
1729 
1730         m_AnimObjects = AnimObjectArray(memory, maxAnimObjects, &GetAllocator());
1731 
1732         return result;
1733     }
1734 
1735     AnimObjectArray m_AnimObjects; //!< @details :private
1736 };
1737 
1738 //---------------------------------------------------------------------------
1739 //! @brief 汎用アニメーション評価結果を補間ブレンドするクラスです。
1740 //!
1741 //! 登録された全てのアニメーションオブジェクトの結果に重みをかけて、ブレンドした結果を採用します。
1742 //! アニメーションが無いメンバの場合は、モデルのロード時の状態(OriginalValue)をブレンド計算に使用します。
1743 //!
1744 //! デフォルトでは、ブレンドの重みは合計が 1.0 となるように正規化されてからブレンドされるので、重みの比率だけが意味を持ちます。
1745 //! 正規化が不要な場合は、 SetNormalizationEnabled() で無効化できます。
1746 //---------------------------------------------------------------------------
1747 class AnimInterpolator : public AnimBlender
1748 {
1749 public:
1750     NW_UT_RUNTIME_TYPEINFO;
1751 
1752     //----------------------------------------
1753     //! @name 作成
1754     //@{
1755 
1756     //! @brief 汎用アニメーション補間を構築するクラスです。
1757     //!
1758     //! バージョン 1.0.1 以前の補間法に戻すためには、IsOldMethod か IgnoreNoAnimMember に true を指定してください。
1759     //!
1760     //! 1.0.1 以前の補間方法と現在の補間方法の違いの詳細については、アニメーションのドキュメント(高度な機能)を参照ください。
1761     class Builder
1762     {
1763     public:
1764         //! コンストラクタです。
Builder()1765         Builder()
1766         : m_MaxAnimObjects(2),
1767           m_IgnoreNoAnimMember(false) {}
1768 
1769         //! 最大アニメーションオブジェクト数を設定します。
MaxAnimObjects(int maxAnimObjects)1770         Builder& MaxAnimObjects(int maxAnimObjects)
1771         {
1772             NW_ASSERT(maxAnimObjects > 0);
1773             m_MaxAnimObjects = maxAnimObjects;
1774             return *this;
1775         }
1776 
1777         //! @brief バージョン 1.0.1 以前の補間法に戻すかどうかを設定します。
1778         //!
1779         //! 1.0.1 以前の補間法は IgnoreNoAnimMember() に true を指定したときと同じであり、
1780         //! この関数は IgnoreNoAnimMember() のエイリアスです。
1781         //!
1782         //! この設定はバージョン 1.3.0 以降で削除されます。
1783         NW_DEPRECATED_FUNCTION_MSG(
1784             Builder& IsOldMethod(bool isOldMethod),
1785             "AnimIntepolator::IsOldMethod() is deprecated. Use IgnoreNoAnimMember()")
1786         {
1787             return IgnoreNoAnimMember(isOldMethod);
1788         }
1789         //! @brief アニメーションが存在しないメンバを無視するかどうかを設定します。
1790         //!
1791         //! デフォルトでは、アニメーションが存在しないメンバはバインド時の値がブレンドされます。
1792         //! IgnoreNoAnimMember に true を設定すると、
1793         //! 重みの正規化がメンバ毎に行なわれ、アニメーションが存在しないメンバは重み 0 としてブレンドされます。
1794         //!
1795         //! この挙動は バージョン 1.0.1 以前の補間法と同じです。
1796         //!
IgnoreNoAnimMember(bool ignoreNoAnimMember)1797         Builder& IgnoreNoAnimMember(bool ignoreNoAnimMember) { m_IgnoreNoAnimMember = ignoreNoAnimMember; return *this; }
1798 
1799         //! @brief 生成時に必要なメモリサイズを取得します。
1800         //!
1801         //! メモリサイズは Builder の設定によって変化します。
1802         //! すべての設定が終わった後にこの関数を呼び出してください。
1803         //!
1804         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
1805         {
1806             os::MemorySizeCalculator size(alignment);
1807 
1808             GetMemorySizeInternal(&size);
1809 
1810             return size.GetSizeWithPadding(alignment);
1811         }
1812 
1813         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)1814         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
1815         {
1816             os::MemorySizeCalculator& size = *pSize;
1817 
1818             size += sizeof(AnimInterpolator);
1819             AnimInterpolator::GetMemorySizeForInitialize(pSize, m_MaxAnimObjects);
1820         }
1821 
1822         //! @brief 汎用アニメーション補間を生成します。
1823         //!
1824         //! @param[in] allocator アロケータです。
1825         //!
1826         //! @return 生成された汎用アニメーション補間です。
1827         //!
Create(os::IAllocator * allocator)1828         AnimInterpolator* Create(os::IAllocator* allocator)
1829         {
1830             void* buf = allocator->Alloc(sizeof(AnimInterpolator));
1831 
1832             if (buf == NULL)
1833             {
1834                 return NULL;
1835             }
1836 
1837             AnimInterpolator* animInterpolator = new(buf) AnimInterpolator(allocator);
1838 
1839             Result result = animInterpolator->Initialize(m_MaxAnimObjects, m_IgnoreNoAnimMember);
1840             NW_ASSERT(result.IsSuccess());
1841 
1842             return animInterpolator;
1843         }
1844 
1845     private:
1846         int m_MaxAnimObjects;
1847         bool m_IgnoreNoAnimMember;
1848     };
1849 
1850     //@}
1851 
1852     //----------------------------------------
1853     //! @name 評価
1854     //@{
1855 
1856     //! @brief メンバ単位でアニメーション結果を取得します。
1857     //!
1858     //! @param[out] target アニメーション結果を書き込む対象です。
1859     //! @param[in] memberIdx メンバインデックスです。
1860     //!
1861     //! @return アニメーション結果を返します。
1862     //! ブレンドオペレーションを使用する場合は、返り値のアニメーション結果を使用してください。
1863     //!
1864     virtual const anim::AnimResult* GetResult(
1865         void* target,
1866         int memberIdx) const;
1867 
1868     //@}
1869 
1870     //----------------------------------------
1871     //! @name 取得/設定
1872     //@{
1873 
1874     //! @brief アニメーションのブレンド重みを取得します。
1875     //!
1876     //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。
1877     //!
1878     //! @return 重みです。
1879     //!
GetWeight(int animObjIdx)1880     float GetWeight(int animObjIdx) const
1881     {
1882         NW_MINMAXLT_ASSERT(animObjIdx, 0, m_Weights.Size());
1883         return m_Weights[animObjIdx];
1884     }
1885 
1886     //! @brief アニメーションのブレンド重みを設定します。
1887     //!
1888     //! ブレンド重みの解釈については、 SetNormalizationEnabled() を参照してください。
1889     //!
1890     //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。
1891     //! @param[in] weight 重みです。
1892     //! @sa SetNormalizationEnabled
1893     //!
SetWeight(int animObjIdx,float weight)1894     void SetWeight(int animObjIdx, float weight)
1895     {
1896         NW_MINMAXLT_ASSERT(animObjIdx, 0, m_Weights.Size());
1897         m_Weights[animObjIdx] = weight;
1898         m_NormalizedWeights[animObjIdx] = weight;
1899         m_IsWeightDirty = true;
1900     }
1901 
1902     //! @brief アニメーションのブレンド重みを正規化するかを設定します。
1903     //!
1904     //! true を指定すると、ブレンド重みが合計で 1 になるよう正規化してからブレンドを行います。
1905     //! false を指定すると、SetWeight() で指定された重みがそのままブレンドに使用されますので、
1906     //! 重みの設定に注意してください。
1907     //!
1908     //! 正規化処理は、 SetWeight() 実行後の最初のアニメーションブレンド時に 1 度だけ行われます。
1909     //!
1910     //! Builder::IsOldMethod で true を指定していると、この設定は無視されます。
1911     //!
1912     //! デフォルト値は true です。
SetNormalizationEnabled(bool enabled)1913     void SetNormalizationEnabled(bool enabled){ m_IsWeightNormalizationEnabled = enabled; }
1914 
1915     //! @brief アニメーションのブレンド重みを正規化するかの設定を取得します。
GetNormalizationEnabled()1916     bool GetNormalizationEnabled() const { return m_IsWeightNormalizationEnabled; }
1917 
1918     //@}
1919 
1920 protected:
1921     //----------------------------------------
1922     //! @name コンストラクタ/デストラクタ
1923     //@{
1924 
1925     //! コンストラクタです。
1926     //!
1927     //! :private
AnimInterpolator(os::IAllocator * allocator)1928     AnimInterpolator(
1929         os::IAllocator* allocator)
1930     : AnimBlender(allocator),
1931       m_IsOldMethod(false),
1932       m_IsWeightDirty(false),
1933       m_IsWeightNormalizationEnabled(true)
1934     {
1935     }
1936 
1937     //! デストラクタです。
1938     //!
1939     //! :private
~AnimInterpolator()1940     virtual ~AnimInterpolator() {}
1941 
1942     //@}
1943 
1944     //! Initialize() の実行に必要なメモリサイズを取得します。
1945     //!
1946     //! :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,int maxAnimObjects)1947     static void GetMemorySizeForInitialize(os::MemorySizeCalculator* pSize, int maxAnimObjects)
1948     {
1949         os::MemorySizeCalculator& size = *pSize;
1950 
1951         AnimBlender::GetMemorySizeForInitialize(pSize, maxAnimObjects);
1952         size += sizeof(float) * maxAnimObjects;
1953         size += sizeof(float) * maxAnimObjects;
1954     }
1955 
1956     //! @details :private
Initialize(int maxAnimObjects,bool ignoreNoAnimMember)1957     virtual Result Initialize(int maxAnimObjects, bool ignoreNoAnimMember)
1958     {
1959         Result result = AnimBlender::Initialize(maxAnimObjects);
1960         NW_ENSURE_AND_RETURN(result);
1961 
1962         {
1963             void* memory = GetAllocator().Alloc(sizeof(float) * maxAnimObjects);
1964             if (memory == NULL)
1965             {
1966                 result |= Result::MASK_FAIL_BIT;
1967             }
1968             NW_ENSURE_AND_RETURN(result);
1969 
1970             m_Weights = ut::MoveArray<float>(memory, maxAnimObjects, &GetAllocator());
1971             for (int animObjIdx = 0; animObjIdx < maxAnimObjects; ++animObjIdx)
1972             {
1973                 m_Weights.PushBack(animObjIdx == 0 ? 1.0f : 0.0f);
1974             }
1975         }
1976 
1977         {
1978             void* memory = GetAllocator().Alloc(sizeof(float) * maxAnimObjects);
1979             if (memory == NULL)
1980             {
1981                 result |= Result::MASK_FAIL_BIT;
1982             }
1983             NW_ENSURE_AND_RETURN(result);
1984 
1985             m_NormalizedWeights = ut::MoveArray<float>(memory, maxAnimObjects, &GetAllocator());
1986             for (int animObjIdx = 0; animObjIdx < maxAnimObjects; ++animObjIdx)
1987             {
1988                 m_NormalizedWeights.PushBack(animObjIdx == 0 ? 1.0f : 0.0f);
1989             }
1990         }
1991 
1992         // TODO: 変数名その他を変更。
1993         m_IsOldMethod = ignoreNoAnimMember;
1994 
1995         return result;
1996     }
1997 
1998     //! @brief ブレンド重みを正規化します。
1999     //!
2000     //! :private
NormalizeWeight()2001     void NormalizeWeight() const
2002     {
2003         float weightSum = 0.0f;
2004         float normalizeScale;
2005         for (int i = 0; i < m_Weights.Size(); ++i)
2006         {
2007             weightSum += m_Weights[i];
2008         }
2009         normalizeScale = GetAnimWeightNormalizeScale(weightSum);
2010         for (int i = 0; i < m_Weights.Size(); ++i)
2011         {
2012             m_NormalizedWeights[i] = m_Weights[i] * normalizeScale;
2013         }
2014         m_IsWeightDirty = false;
2015     }
2016 
2017     ut::MoveArray<float> m_Weights; //!< @details :private
2018     mutable ut::MoveArray<float> m_NormalizedWeights; //!< @details :private
2019 
2020     bool m_IsOldMethod; //!< @details :private
2021     mutable bool m_IsWeightDirty; //!< @details :private
2022     bool m_IsWeightNormalizationEnabled; //!< @details :private
2023 };
2024 
2025 //---------------------------------------------------------------------------
2026 //! @details :private
2027 //! @brief 汎用アニメーション評価結果を加算ブレンドするクラスです。
2028 //---------------------------------------------------------------------------
2029 class AnimAdder : public AnimBlender
2030 {
2031 public:
2032     NW_UT_RUNTIME_TYPEINFO;
2033 
2034     //----------------------------------------
2035     //! @name 作成
2036     //@{
2037 
2038     //! 汎用アニメーション補間を構築するクラスです。
2039     class Builder
2040     {
2041     public:
2042         //! コンストラクタです。
Builder()2043         Builder()
2044         : m_MaxAnimObjects(2) {}
2045 
2046         //! 最大アニメーションオブジェクト数を設定します。
MaxAnimObjects(int maxAnimObjects)2047         Builder& MaxAnimObjects(int maxAnimObjects)
2048         {
2049             NW_ASSERT(maxAnimObjects > 0);
2050             m_MaxAnimObjects = maxAnimObjects;
2051             return *this;
2052         }
2053 
2054         //! @brief 生成時に必要なメモリサイズを取得します。
2055         //!
2056         //! メモリサイズは Builder の設定によって変化します。
2057         //! すべての設定が終わった後にこの関数を呼び出してください。
2058         //!
2059         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
2060         {
2061             os::MemorySizeCalculator size(alignment);
2062 
2063             GetMemorySizeInternal(&size);
2064 
2065             return size.GetSizeWithPadding(alignment);
2066         }
2067 
2068         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)2069         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
2070         {
2071             os::MemorySizeCalculator& size = *pSize;
2072 
2073             size += sizeof(AnimAdder);
2074             AnimAdder::GetMemorySizeForInitialize(pSize, m_MaxAnimObjects);
2075         }
2076 
2077         //! @brief 汎用アニメーション補間を生成します。
2078         //!
2079         //! @param[in] allocator アロケータです。
2080         //!
2081         //! @return 生成された汎用アニメーション補間です。
2082         //!
Create(os::IAllocator * allocator)2083         AnimAdder* Create(os::IAllocator* allocator)
2084         {
2085             void* buf = allocator->Alloc(sizeof(AnimAdder));
2086 
2087             if (buf == NULL)
2088             {
2089                 return NULL;
2090             }
2091 
2092             AnimAdder* animAdder = new(buf) AnimAdder(allocator);
2093 
2094             Result result = animAdder->Initialize(m_MaxAnimObjects);
2095             NW_ASSERT(result.IsSuccess());
2096 
2097             return animAdder;
2098         }
2099 
2100     private:
2101         int m_MaxAnimObjects;
2102     };
2103 
2104     //@}
2105 
2106     //----------------------------------------
2107     //! @name 評価
2108     //@{
2109 
2110     //! @brief メンバ単位でアニメーション結果を取得します。
2111     //!
2112     //! @param[out] target アニメーション結果を書き込む対象です。
2113     //! @param[in] memberIdx メンバインデックスです。
2114     //!
2115     //! @return アニメーション結果を返します。
2116     //! ブレンドオペレーションを使用する場合は、返り値のアニメーション結果を使用してください。
2117     //!
2118     virtual const anim::AnimResult* GetResult(
2119         void* target,
2120         int memberIdx) const;
2121 
2122     //@}
2123 
2124     //----------------------------------------
2125     //! @name 取得/設定
2126     //@{
2127 
2128     //! @brief アニメーションのブレンド重みを取得します。
2129     //!
2130     //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。
2131     //!
2132     //! @return 重みです。
2133     //!
GetWeight(int animObjIdx)2134     float GetWeight(int animObjIdx) const
2135     {
2136         NW_MINMAXLT_ASSERT(animObjIdx, 0, m_Weights.Size());
2137         return m_Weights[animObjIdx];
2138     }
2139 
2140     //! @brief アニメーションのブレンド重みを設定します。
2141     //!
2142     //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。
2143     //! @param[in] weight 重みです。
2144     //!
SetWeight(int animObjIdx,float weight)2145     void SetWeight(int animObjIdx, float weight)
2146     {
2147         NW_MINMAXLT_ASSERT(animObjIdx, 0, m_Weights.Size());
2148         m_Weights[animObjIdx] = weight;
2149     }
2150 
2151     //@}
2152 
2153 protected:
2154     //----------------------------------------
2155     //! @name コンストラクタ/デストラクタ
2156     //@{
2157 
2158     //! コンストラクタです。
AnimAdder(os::IAllocator * allocator)2159     AnimAdder(
2160         os::IAllocator* allocator)
2161     : AnimBlender(allocator)
2162     {
2163     }
2164 
2165     //! デストラクタです。
~AnimAdder()2166     virtual ~AnimAdder() {}
2167 
2168     //@}
2169 
2170     //! Initialize() の実行に必要なメモリサイズを取得します。
2171     //!
2172     //! :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,int maxAnimObjects)2173     static void GetMemorySizeForInitialize(os::MemorySizeCalculator* pSize, int maxAnimObjects)
2174     {
2175         os::MemorySizeCalculator& size = *pSize;
2176 
2177         AnimBlender::GetMemorySizeForInitialize(pSize, maxAnimObjects);
2178         size += sizeof(float) * maxAnimObjects;
2179     }
2180 
Initialize(int maxAnimObjects)2181     virtual Result Initialize(int maxAnimObjects)
2182     {
2183         Result result = AnimBlender::Initialize(maxAnimObjects);
2184         NW_ENSURE_AND_RETURN(result);
2185 
2186         void* memory = GetAllocator().Alloc(sizeof(float) * maxAnimObjects);
2187         if (memory == NULL)
2188         {
2189             result |= Result::MASK_FAIL_BIT;
2190         }
2191         NW_ENSURE_AND_RETURN(result);
2192 
2193         m_Weights = ut::MoveArray<float>(memory, maxAnimObjects, &GetAllocator());
2194         for (int animObjIdx = 0; animObjIdx < maxAnimObjects; ++animObjIdx)
2195         {
2196             m_Weights.PushBack(1.0f);
2197         }
2198 
2199         return result;
2200     }
2201 
2202     ut::MoveArray<float> m_Weights;
2203 };
2204 
2205 //---------------------------------------------------------------------------
2206 //! @brief 汎用アニメーション評価結果を上書きブレンドするクラスです。
2207 //!
2208 //! AddAnimObject() で登録された順番にアニメーションオブジェクトを評価します。
2209 //! 同じメンバに複数のアニメーションがあった場合、後に登録されたアニメーションの結果で上書きされます。
2210 //! アニメーションを持っていないメンバについては、上書き処理は行われません。
2211 //---------------------------------------------------------------------------
2212 class AnimOverrider : public AnimBlender
2213 {
2214 public:
2215     NW_UT_RUNTIME_TYPEINFO;
2216 
2217     //----------------------------------------
2218     //! @name 作成
2219     //@{
2220 
2221     //! 汎用アニメーション補間を構築するクラスです。
2222     class Builder
2223     {
2224     public:
2225         //! コンストラクタです。
Builder()2226         Builder()
2227         : m_MaxAnimObjects(2) {}
2228 
2229         //! 最大アニメーションオブジェクト数を設定します。
MaxAnimObjects(int maxAnimObjects)2230         Builder& MaxAnimObjects(int maxAnimObjects)
2231         {
2232             NW_ASSERT(maxAnimObjects > 0);
2233             m_MaxAnimObjects = maxAnimObjects;
2234             return *this;
2235         }
2236 
2237         //! @brief 生成時に必要なメモリサイズを取得します。
2238         //!
2239         //! メモリサイズは Builder の設定によって変化します。
2240         //! すべての設定が終わった後にこの関数を呼び出してください。
2241         //!
2242         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
2243         {
2244             os::MemorySizeCalculator size(alignment);
2245 
2246             GetMemorySizeInternal(&size);
2247 
2248             return size.GetSizeWithPadding(alignment);
2249         }
2250 
2251         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)2252         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
2253         {
2254             os::MemorySizeCalculator& size = *pSize;
2255 
2256             size += sizeof(AnimOverrider);
2257             AnimOverrider::GetMemorySizeForInitialize(pSize, m_MaxAnimObjects);
2258         }
2259 
2260         //! @brief 汎用アニメーション補間を生成します。
2261         //!
2262         //! @param[in] allocator アロケータです。
2263         //!
2264         //! @return 生成された汎用アニメーション補間です。
2265         //!
Create(os::IAllocator * allocator)2266         AnimOverrider* Create(os::IAllocator* allocator)
2267         {
2268             void* buf = allocator->Alloc(sizeof(AnimOverrider));
2269 
2270             if (buf == NULL)
2271             {
2272                 return NULL;
2273             }
2274 
2275             AnimOverrider* animOverrider = new(buf) AnimOverrider(allocator);
2276 
2277             Result result = animOverrider->Initialize(m_MaxAnimObjects);
2278             NW_ASSERT(result.IsSuccess());
2279 
2280             return animOverrider;
2281         }
2282 
2283     private:
2284         int m_MaxAnimObjects;
2285     };
2286 
2287     //@}
2288 
2289     //----------------------------------------
2290     //! @name 評価
2291     //@{
2292 
2293     //! @brief メンバ単位でアニメーション結果を取得します。
2294     //!
2295     //! @param[out] target アニメーション結果を書き込む対象です。
2296     //! @param[in] memberIdx メンバインデックスです。
2297     //!
2298     //! @return アニメーション結果を返します。
2299     //! ブレンドオペレーションを使用する場合は、返り値のアニメーション結果を使用してください。
2300     //!
2301     virtual const anim::AnimResult* GetResult(
2302         void* target,
2303         int memberIdx) const;
2304 
2305     //@}
2306 
2307 protected:
2308     //----------------------------------------
2309     //! @name コンストラクタ/デストラクタ
2310     //@{
2311 
2312     //! コンストラクタです。
2313     //!
2314     //! :private
AnimOverrider(os::IAllocator * allocator)2315     AnimOverrider(
2316         os::IAllocator* allocator)
2317     : AnimBlender(allocator)
2318     {}
2319 
2320     //! デストラクタです。
2321     //!
2322     //! :private
~AnimOverrider()2323     virtual ~AnimOverrider() {}
2324 
2325     //@}
2326 };
2327 
2328 } // namespace gfx
2329 } // namespace nw
2330 
2331 #endif // NW_GFX_ANIMOBJECT_H_
2332