1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_SceneNode.h
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #ifndef NW_GFX_SCENENODE_H_
19 #define NW_GFX_SCENENODE_H_
20 
21 #include <nw/gfx/gfx_SceneObject.h>
22 #include <nw/gfx/gfx_AnimObject.h>
23 #include <nw/gfx/gfx_AnimBinding.h>
24 #include <nw/gfx/gfx_CalculatedTransform.h>
25 
26 #include <nw/ut/ut_Children.h>
27 #include <nw/ut/ut_Foreach.h>
28 #include <nw/ut/ut_Signal.h>
29 
30 namespace nw
31 {
32 namespace gfx
33 {
34 
35 class ISceneVisitor;
36 class SceneContext;
37 class WorldMatrixUpdater;
38 
39 //---------------------------------------------------------------------------
40 //! @brief        シーンツリーを構成するための節となるクラスです。
41 //!               複数の子を持つことができます。
42 //---------------------------------------------------------------------------
43 class SceneNode : public SceneObject
44 {
45 private:
46     NW_DISALLOW_COPY_AND_ASSIGN(SceneNode);
47     NW_CHILD_DECLARE_PARENT(SceneNode);
48 
49     static const size_t CHILDREN_MEMORY_ALIGNMENT = os::IAllocator::CACHE_LINE_ALIGNMENT;
50 
51 public:
52     NW_UT_RUNTIME_TYPEINFO;
53 
54     //! @brief  トラバースの結果を表すビットフラグの定義です。
55     enum TraversalResults
56     {
57         //! @details :private
58         FLAG_IS_VISIBLE_SHIFT = 0,
59         //! @details :private
60         FLAG_IS_DIRTY_SHIFT                           = 1,
61 
62         //! 描画を行うのであれば、1になります。
63         FLAG_IS_VISIBLE                               = 0x1 << FLAG_IS_VISIBLE_SHIFT,
64 
65         //! ワールドマトリクスの計算処理を行うのであれば、1になります。
66         FLAG_IS_DIRTY                                 = 0x1 << FLAG_IS_DIRTY_SHIFT,
67 
68         //! トラバースの結果の初期値です。
69         FLAG_DEFAULT = FLAG_IS_VISIBLE | FLAG_IS_DIRTY
70     };
71 
72     //! @brief 更新時に呼ばれるコールバック用シグナルの定義です。
73     //!
74     //! @sa PreUpdateSignal
75     typedef ut::Signal2<void, SceneNode*, SceneContext*> UpdateSignal;
76 
77     //! @brief 更新時に呼ばれるコールバック用スロットの定義です。
78     typedef UpdateSignal::SlotType UpdateSlot;
79 
80     //! @brief 設定内容です。
81     struct Description
82     {
83         bool isFixedSizeMemory; //!< 最初に固定サイズのメモリを確保するフラグです。
84         bool isAnimationEnabled; //!< アニメーション可能かのフラグです。
85         s32 maxCallbacks;       //!< 管理できるコールバックの最大数です。
86         s32 maxChildren;        //!< 子の最大数です。
87         s32 maxAnimObjectsPerGroup; //!< AnimBindingが持つ、AnimGroupごとのAnimObjectの最大数です。
88 
89         //! @brief コンストラクタです。
DescriptionDescription90         Description()
91          : isFixedSizeMemory(true),
92            isAnimationEnabled(true),
93            maxCallbacks(DEFAULT_MAX_CALLBACKS),
94            maxChildren(DEFAULT_MAX_CHILDREN),
95            maxAnimObjectsPerGroup(DEFAULT_MAX_ANIMOBJECTS)
96         {}
97     };
98 
99     //----------------------------------------
100     //! @name 作成/破棄
101     //@{
102 
103     //! @brief シーンノードを動的に構築するためのクラスです。
104     //!
105     //! IsFixedSizeMemory の初期値は true です。false に変更すると、各種最大数の設定は一部を除いて無視されます。
106     class DynamicBuilder
107     {
108     public:
109         //! コンストラクタです。
DynamicBuilder()110         DynamicBuilder() {}
111         //! デストラクタです。
~DynamicBuilder()112         ~DynamicBuilder() {}
113 
114         //! @brief 生成時以外にもメモリを確保するかどうかのフラグを設定します。
115         //!
116         //!        true を指定すると、生成時のみ固定サイズのメモリ確保を行います。
117         //!
118         //!        false を指定すると、生成時以外にも必要に応じて動的にメモリ確保が行われます。
IsFixedSizeMemory(bool isFixedSizeMemory)119         DynamicBuilder& IsFixedSizeMemory(bool isFixedSizeMemory)
120         {
121             m_Description.isFixedSizeMemory = isFixedSizeMemory;
122             return *this;
123         }
124 
125         //! 子の最大数を設定します。
MaxChildren(int maxChildren)126         DynamicBuilder& MaxChildren(int maxChildren)
127         {
128             m_Description.maxChildren = maxChildren;
129             return *this;
130         }
131 
132         //! 管理できるコールバックの最大数を設定します。
MaxCallbacks(int maxCallbacks)133         DynamicBuilder& MaxCallbacks(int maxCallbacks)
134         {
135             m_Description.maxCallbacks = maxCallbacks;
136             return *this;
137         }
138 
139         //! @brief AnimBindingが持てるAnimGroupごとのAnimObjectの最大数を設定します。
140         //!
141         //!        MaxAnimObjectsPerGroup の指定は IsFixedSizeMemory が false でも有効になります。
MaxAnimObjectsPerGroup(s32 maxAnimObjects)142         DynamicBuilder& MaxAnimObjectsPerGroup(s32 maxAnimObjects)
143         {
144             m_Description.maxAnimObjectsPerGroup = maxAnimObjects;
145             return *this;
146         }
147 
148         //! @brief アニメーション可能かを設定します。
149         //!
150         //!        false を指定すると AnimBinding の生成を行いません。
151         //!        そのためアニメーションのバインドができなくなりますが、
152         //!        アニメーション更新の処理が行われなくなるため、
153         //!        シーンアップデートのパフォーマンスが向上します。
IsAnimationEnabled(bool isAnimationEnabled)154         DynamicBuilder& IsAnimationEnabled(bool isAnimationEnabled)
155         {
156             m_Description.isAnimationEnabled = isAnimationEnabled;
157             return *this;
158         }
159 
160         //! @brief        シーンノードを生成します。
161         //!
162         //! @param[in]    allocator アロケータです。
163         //!
164         //! @return       生成したシーンノードを返します。
165         //!
166         SceneNode* Create(os::IAllocator* allocator);
167 
168         //! @brief 生成時に必要なメモリサイズを取得します。
169         //!
170         //! メモリサイズは Builder の設定によって変化します。
171         //! すべての設定が終わった後にこの関数を呼び出してください。
172         //!
173         //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
174         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
175         {
176             os::MemorySizeCalculator size(alignment);
177 
178             size += sizeof(SceneNode);
179             GetMemorySizeForInitialize(&size, ResSceneNode(), m_Description);
180 
181             return size.GetSizeWithPadding(alignment);
182         }
183 
184     private:
185         SceneNode::Description m_Description;
186     };
187 
188     //! @brief        シーンノードを生成します。
189     //!
190     //! @param[in]    parent 親のノードです。
191     //! @param[in]    resource リソースです。
192     //! @param[in]    description 設定内容です。
193     //! @param[in]    allocator アロケータです。
194     //!
195     //! @return       生成されたシーンノードです。
196     //!
197     static SceneNode* Create(
198         SceneNode* parent,
199         ResSceneObject resource,
200         const SceneNode::Description& description,
201         os::IAllocator* allocator);
202 
203     //! @brief        生成時に必要なメモリサイズを取得します。
204     //!
205     //! @param[in]    resSceneNode リソースです。
206     //! @param[in]    description 設定内容です。
207     //! @param[in]    alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
208     static size_t GetMemorySize(
209         ResSceneNode resSceneNode,
210         Description description,
211         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
212     {
213         os::MemorySizeCalculator size(alignment);
214 
215         GetMemorySizeInternal(&size, resSceneNode, description);
216 
217         return size.GetSizeWithPadding(alignment);
218     }
219 
220     //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize,ResSceneNode resSceneNode,Description description)221     static void GetMemorySizeInternal(
222         os::MemorySizeCalculator* pSize,
223         ResSceneNode resSceneNode,
224         Description description)
225     {
226         os::MemorySizeCalculator& size = *pSize;
227 
228         size += sizeof(SceneNode);
229         GetMemorySizeForInitialize(pSize, resSceneNode, description);
230     }
231 
232     //! @brief 自ノードを含むブランチ以下のノードを全て破棄します。
DestroyBranch()233     void DestroyBranch()
234     {
235         SceneNodeChildren::iterator end = this->m_Children.end();
236         for (SceneNodeChildren::iterator child = this->m_Children.begin(); child != end; ++child)
237         {
238             if (*child)
239             {
240                 (*child)->SetParent(NULL);
241                 (*child)->DestroyBranch();
242                 *child = NULL;
243             }
244         }
245         this->Destroy();
246     }
247 
248     //! @brief        生成時に必要なデバイスメモリサイズを取得します。
249     //!
250     //! @param[in]    resource リソースです。
251     //! @param[in]    description 設定内容です。
252     //!
253     //! @details :private
254     static size_t GetDeviceMemorySize(
255         ResSceneObject,
256         Description,
257         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
258     {
259         NW_UNUSED_VARIABLE(alignment);
260 
261         return 0;
262     }
263 
264     //! @details :private
GetDeviceMemorySizeInternal(os::MemorySizeCalculator *,ResSceneObject,Description)265     static void GetDeviceMemorySizeInternal(
266         os::MemorySizeCalculator*,
267         ResSceneObject,
268         Description)
269     {
270     }
271 
272     //@}
273 
274     //----------------------------------------
275     //! @name リソース
276     //@{
277 
278     //! @brief シーンノードのリソースを取得します。
GetResSceneNode()279     ResSceneNode GetResSceneNode()
280     {
281         return ResStaticCast<ResSceneNode>( this->GetResSceneObject() );
282     }
283 
284     //! @brief シーンノードのリソースを取得します。
GetResSceneNode()285     const ResSceneNode GetResSceneNode() const
286     {
287         return ResStaticCast<ResSceneNode>( this->GetResSceneObject() );
288     }
289 
290     //@}
291 
292     //----------------------------------------
293     //! @name トランスフォーム
294     //@{
295 
296     //! @brief        変換情報に関する更新を行います。
297     //!
298     //! @param[in]    worldMatrixUpdater ワールドマトリクス更新クラスです。
299     //! @param[in]    sceneContext シーンコンテキストです。
300     //!
UpdateTransform(WorldMatrixUpdater * worldMatrixUpdater,SceneContext * sceneContext)301     virtual void UpdateTransform(
302         WorldMatrixUpdater* worldMatrixUpdater,
303         SceneContext* sceneContext)
304     {
305         NW_UNUSED_VARIABLE(worldMatrixUpdater);
306         NW_UNUSED_VARIABLE(sceneContext);
307     }
308 
309     //@}
310 
311     //----------------------------------------
312     //! @name シーンツリー
313     //@{
314 
315     //! @brief        子を取り付けます。
316     //!
317     //! @param[in] child   子となるシーンノードです。
318     //!
319     //! @return       追加できなかった場合は、false が返ります。
320     //!
AttachChild(SceneNode * child)321     bool AttachChild(SceneNode* child)
322     {
323         if (IsCircularReference(child))
324         {
325             return false;
326         }
327 
328         return m_Children.Attach(child);
329     }
330 
331     //! @brief        子を取り外します。
332     //!
333     //! @param[in] child   子となるシーンノードです。
334     //!
DetachChild(SceneNode * child)335     void DetachChild(SceneNode* child)
336     {
337         NW_NULL_ASSERT(child);
338         NW_ASSERT(child->GetParent() == this);
339 
340         m_Children.Detach(child);
341     }
342 
343     //! @brief 子の先頭を取得します。
GetChildBegin()344     SceneNodeChildren::iterator GetChildBegin() { return m_Children.begin(); }
345 
346     //! @brief 子の先頭を取得します。
GetChildBegin()347     SceneNodeChildren::const_iterator GetChildBegin() const { return m_Children.begin(); }
348 
349     //! @brief 子の末尾を取得します。
GetChildEnd()350     SceneNodeChildren::iterator GetChildEnd() { return m_Children.end(); }
351 
352     //! @brief 子の末尾を取得します。
GetChildEnd()353     SceneNodeChildren::const_iterator GetChildEnd() const { return m_Children.end(); }
354 
355     //! @brief 全ての子を取り外します。
DetachAllChildren()356     void DetachAllChildren() { m_Children.clear(); }
357 
358     //! @brief        ビジターを受け付けます。
359     //!
360     //! @param[in]    visitor ビジターです。
361     //!
362     virtual void Accept(ISceneVisitor* visitor);
363 
364     //! @brief 親ノードをたどりワールドマトリクスを取得します。
TrackbackWorldMatrix()365     virtual const math::MTX34& TrackbackWorldMatrix() const
366     {
367         const SceneNode* parent = this->GetParent();
368         if (parent == NULL)
369         {
370             return nw::math::MTX34::Identity();
371         }
372 
373         return parent->TrackbackWorldMatrix();
374     }
375 
376     //! @brief 親ノードをたどりワールドトランスフォームを取得します。
TrackbackWorldTransform()377     virtual const CalculatedTransform& TrackbackWorldTransform() const
378     {
379         const SceneNode* parent = this->GetParent();
380         if (parent == NULL)
381         {
382             return CalculatedTransform::Identity();
383         }
384 
385         return parent->TrackbackWorldTransform();
386     }
387 
388     //! @brief 親ノードをたどりローカルトランスフォームを取得します。
TrackbackLocalTransform()389     virtual const CalculatedTransform& TrackbackLocalTransform() const
390     {
391         const SceneNode* parent = this->GetParent();
392         if (parent == NULL)
393         {
394             return CalculatedTransform::Identity();
395         }
396 
397         return parent->TrackbackLocalTransform();
398     }
399 
400     //@}
401 
402     //----------------------------------------
403     //! @name コールバック
404     //@{
405 
406     //! @brief シーンノード更新前のシグナルを取得します。
407     //!
408     //! TransformNode クラスまたはそのサブクラスでは、ノードのワールドマトリクス計算前の
409     //! シグナルとなります。
410     //!
411     //! @sa UpdateSignal
PreUpdateSignal()412     UpdateSignal& PreUpdateSignal() { return *m_PreUpdateSignal; }
413 
414     //! @brief シーンノード更新前のシグナルを取得します。
415     //!
416     //! TransformNode クラスまたはそのサブクラスでは、ノードのワールドマトリクス計算前の
417     //! シグナルとなります。
418     //!
419     //! @sa UpdateSignal
PreUpdateSignal()420     const UpdateSignal& PreUpdateSignal() const { return *m_PreUpdateSignal; }
421 
422     //@}
423 
424     //----------------------------------------
425     //! @name アニメーション
426     //@{
427 
428     //! @brief アニメーションバインディングを取得します。
GetAnimBinding()429     const AnimBinding* GetAnimBinding() const { return m_AnimBinding.Get(); }
430 
431     //! @brief アニメーションバインディングを取得します。
GetAnimBinding()432     AnimBinding* GetAnimBinding() { return m_AnimBinding.Get(); }
433 
434     //! @brief アニメーションバインディングを設定します。
SetAnimBinding(AnimBinding * animBinding)435     void SetAnimBinding(AnimBinding* animBinding) { m_AnimBinding = GfxPtr<AnimBinding>(animBinding); }
436 
437     //! @brief 設定されたすべてのアニメーションオブジェクトのフレームを更新します。
UpdateFrame()438     void UpdateFrame()
439     {
440         AnimBinding* animBinding = GetAnimBinding();
441         if (animBinding != NULL)
442         {
443             animBinding->UpdateFrame();
444         }
445     }
446 
447     //@}
448 
449     //----------------------------------------
450     //! @name トラバース
451     //@{
452 
453     //! @brief トラバースの結果を取得します。
GetTraversalResults()454     bit32 GetTraversalResults() const
455     {
456         return this->m_TraversalResults;
457     }
458 
459     //! @brief トラバースの結果を設定します。
SetTraversalResults(bit32 results)460     void SetTraversalResults(bit32 results)
461     {
462         this->m_TraversalResults = results;
463     }
464 
465     //! @brief 任意のトラバースの結果が有効であるか取得します。
IsEnabledResults(bit32 results)466     bool IsEnabledResults(bit32 results) const
467     {
468         return ut::CheckFlag(m_TraversalResults, results);
469     }
470 
471     //! @brief トラバースの結果を有効にします。
EnableTraversalResults(bit32 results)472     void EnableTraversalResults(bit32 results)
473     {
474         this->m_TraversalResults = ut::EnableFlag(this->m_TraversalResults, results);
475     }
476 
477     //! @brief トラバースの結果を無効にします。
DisableTraversalResults(bit32 results)478     void DisableTraversalResults(bit32 results)
479     {
480         this->m_TraversalResults = ut::DisableFlag(this->m_TraversalResults, results);
481     }
482 
483     //! @brief ノードからトラバースの結果をコピーします。
ResetTraversalResults()484     void ResetTraversalResults()
485     {
486         this->m_TraversalResults = FLAG_DEFAULT;
487     }
488 
489     //! @brief ノードからトラバースの結果をコピーします。
CopyTraversalResults(const SceneNode * node)490     void CopyTraversalResults(const SceneNode* node)
491     {
492         if (node != NULL)
493         {
494             this->m_TraversalResults = node->GetTraversalResults();
495         }
496     }
497 
498     //! @brief 親ノードからの変換情報を継承します。
499     NW_INLINE virtual void InheritTraversalResults();
500 
501     //! @brief ノード以下で描画を行うためのフラグを設定します。
502     //!
503     //! falseにするとノード以下の描画が無効になります。
504     //!
505     //! @param[in] isBranchVisible ノード以下で描画を行うためのフラグです。
506     //!
SetBranchVisible(bool isBranchVisible)507     void SetBranchVisible(bool isBranchVisible)
508     {
509         m_BranchVisible = isBranchVisible;
510     }
511 
512     //! @brief ノード以下で描画を行うためのフラグを取得します。
513     //!
514     //! @return ノード以下で描画を行うためのフラグです。
515     //!
IsBranchVisible()516     bool IsBranchVisible() const
517     {
518         return m_BranchVisible;
519     }
520     //@}
521 
522     //! @brief   Initialize() の実行に必要なメモリサイズを取得します。
523     //!
524     //! @details :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,ResSceneNode resSceneNode,Description description)525     static void GetMemorySizeForInitialize(
526         os::MemorySizeCalculator* pSize,
527         ResSceneNode resSceneNode,
528         Description description)
529     {
530         NW_ASSERT(description.isFixedSizeMemory);
531 
532         // SceneNode::Initialize
533         os::MemorySizeCalculator& size = *pSize;
534 
535         // SceneNode::CreateChildren
536         size.Add(sizeof(SceneNode*) * description.maxChildren, CHILDREN_MEMORY_ALIGNMENT);
537 
538         // SceneNode::CreateCallbacks
539         if (description.maxCallbacks == 0)
540         {
541             UpdateSignal::GetMemorySizeForInvalidateSignalInternal(pSize);
542         }
543         else
544         {
545             UpdateSignal::GetMemorySizeForFixedSizedSignalInternal(pSize, description.maxCallbacks);
546         }
547 
548         // SceneNode::CreateAnimBinding
549         if (description.isAnimationEnabled && resSceneNode.IsValid())
550         {
551             const int animGroupCount = resSceneNode.GetAnimGroupsCount();
552             if (animGroupCount)
553             {
554                 AnimBinding::Builder()
555                     .MaxAnimGroups(animGroupCount)
556                     .MaxAnimObjectsPerGroup(description.maxAnimObjectsPerGroup)
557                     .GetMemorySizeInternal(pSize);
558             }
559         }
560     }
561 
562 protected:
563     //----------------------------------------
564     //! @name コンストラクタ/デストラクタ
565     //@{
566 
567     //! @brief コンストラクタです。
SceneNode(os::IAllocator * allocator,ResSceneNode resObj,const SceneNode::Description & description)568     SceneNode(
569         os::IAllocator* allocator,
570         ResSceneNode resObj,
571         const SceneNode::Description& description)
572     : SceneObject(allocator, resObj),
573       m_BranchVisible(true),
574       m_PreUpdateSignal(NULL),
575       m_TraversalResults(FLAG_DEFAULT),
576       m_Description(description)
577     {
578         this->SetParent(NULL);
579         if (resObj.IsValid())
580         {
581             m_BranchVisible = resObj.IsBranchVisible();
582         }
583     }
584 
585     //! @brief デストラクタです。
~SceneNode()586     virtual ~SceneNode()
587     {
588         SceneNode* parent = this->GetParent();
589         if (parent)
590         {
591             parent->DetachChild(this);
592         }
593 
594         SafeDestroy(m_PreUpdateSignal);
595     }
596 
597     //@}
598 
599     //! @brief        循環参照ならば true を返します。
600     //!
601     //! @param[in]    child 対象となる子です。
602     //!
IsCircularReference(const SceneNode * child)603     bool IsCircularReference(const SceneNode* child) const
604     {
605         const SceneNode* parent = this->GetParent();
606         if (parent == 0)
607         {
608             return false;
609         }
610 
611         if (parent != child)
612         {
613             return parent->IsCircularReference(child);
614         }
615 
616         return true;
617     }
618 
619     //! @brief        全ての子にビジターを受け付けさせます。
620     //!
621     //! @param[in]    visitor ビジターです。
622     //!
AcceptChildren(ISceneVisitor * visitor)623     void AcceptChildren(ISceneVisitor* visitor)
624     {
625         NW_FOREACH(SceneNode* child, m_Children)
626         {
627             child->Accept(visitor);
628         }
629     }
630 
631     //! @brief メンバのメモリ確保と初期化を行います。
632     //!
633     //! コンストラクタではメモリの確保を行わず、こちらでメモリ確保を行います。
634     //! メモリ確保に失敗した場合は Result でエラーコードが返りますので、Destroy を呼び出してクラスを削除します。
635     virtual Result Initialize(os::IAllocator* allocator);
636 
637     //! @brief 子のノードです。
638     SceneNodeChildren m_Children;
639     //! @brief アニメーションとの関連付けです。
640     GfxPtr<AnimBinding> m_AnimBinding;
641     //! @brief ブランチ以下のビジビリティです。
642     bool m_BranchVisible;
643 
644 private:
645     //! 子を作成します。
646     Result CreateChildren(os::IAllocator* allocator);
647 
648     //! コールバック関数を生成します。
649     Result CreateCallbacks(os::IAllocator* allocator);
650 
651     //! アニメーションバインディングを生成します。
652     Result CreateAnimBinding(os::IAllocator* allocator);
653 
654     //!< 標準のAnimBindingの持つGroupに対するAnimObjectsの最大数です。
655     static const int DEFAULT_MAX_ANIMOBJECTS = 1;
656 
657     UpdateSignal* m_PreUpdateSignal;
658     bit32 m_TraversalResults;
659     Description m_Description;
660 };
661 
662 //---------------------------------------------------------------------------
663 //! @brief        ブランチ以下を削除後に0を設定するためのインライン関数です。
664 //!
665 //! @tparam       TNode 削除するオブジェクトの型です。
666 //!
667 //! @param[in]    node 削除するオブジェクトです。
668 //---------------------------------------------------------------------------
669 template<typename TNode>
670 NW_INLINE void
SafeDestroyBranch(TNode * & node)671 SafeDestroyBranch(
672     TNode*& node
673 )
674 {
675     if (node == NULL) { return; }
676     node->DestroyBranch();
677     node = NULL;
678 }
679 
680 //---------------------------------------------------------------------------
681 //! @brief        SafeDestroyBranch でオブジェクトを破棄するための関数オブジェクトです。
682 //!
683 //! @tparam       TObject 削除するオブジェクトの型です。
684 //---------------------------------------------------------------------------
685 template<typename TNode>
686 struct SafeBranchDestroyer : public std::unary_function<TNode&, void>
687 {
688     //! @brief オブジェクトを破棄します。
operatorSafeBranchDestroyer689     void operator()(TNode& node) const
690     {
691         SafeDestroyBranch(node);
692     }
693 };
694 
695 //---------------------------------------------------------------------------
696 //! @brief        SafeBranchDestroy でコンテナ要素の全てのオブジェクトを破棄するための関数です。
697 //!
698 //! @tparam       TArray 削除するオブジェクトの型です。
699 //!
700 //! @param[in]    nodes 削除するオブジェクトの配列です。
701 //---------------------------------------------------------------------------
702 template<typename TArray>
703 NW_INLINE void
SafeDestroyBranchAll(TArray & nodes)704 SafeDestroyBranchAll(
705     TArray& nodes
706 )
707 {
708     std::for_each(nodes.begin(), nodes.end(), SafeBranchDestroyer<typename TArray::value_type>());
709     nodes.clear();
710 }
711 
712 //----------------------------------------
713 NW_INLINE void
InheritTraversalResults()714 SceneNode::InheritTraversalResults()
715 {
716     bit32 results = this->GetTraversalResults();
717     SceneNode* parent = this->GetParent();
718 
719     bool isVisible = this->IsBranchVisible();
720 
721     if (parent != NULL && !(parent->IsEnabledResults(SceneNode::FLAG_IS_VISIBLE)))
722     {
723         isVisible = false;
724     }
725 
726     if (isVisible)
727     {
728         results = ut::EnableFlag(results, SceneNode::FLAG_IS_VISIBLE);
729     }
730     else
731     {
732         results = ut::DisableFlag(results, SceneNode::FLAG_IS_VISIBLE);
733     }
734 
735     this->SetTraversalResults(results);
736 }
737 
738 
739 } // namespace gfx
740 } // namespace nw
741 
742 #endif // NW_GFX_SCENENODE_H_
743