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