1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_RenderQueue.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: 28041 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_GFX_RENDERQUEUE_H_
17 #define NW_GFX_RENDERQUEUE_H_
18 
19 #include <nw/gfx/gfx_RenderElement.h>
20 
21 #include <nw/ut/ut_MoveArray.h>
22 #include <nw/ut/ut_Preprocessor.h>
23 #include <nw/ut/ut_TypeTraits.h>
24 #include <nw/gfx/gfx_Camera.h>
25 #include <nw/gfx/gfx_Model.h>
26 #include <nw/gfx/gfx_SkeletalModel.h>
27 #include <nw/gfx/gfx_SceneHelper.h>
28 
29 namespace nw
30 {
31 namespace gfx
32 {
33 
34 //---------------------------------------------------------------------------
35 //! @brief        描画要素を格納するキュークラスです。
36 //!
37 //! @tparam       TElement 描画単位となるクラスです。
38 //! @tparam       TElementList 描画単位のクラスを格納するためのコンテナです。
39 //! @tparam       TElementKeyFactory 描画単位をソートするためのキーを作成するクラスです。
40 //---------------------------------------------------------------------------
41 template<
42     typename TElement,
43     typename TElementList,
44     typename TElementKeyFactory = BasicRenderKeyFactory<typename TElement::KeyType>
45 >
46 class BasicRenderQueue  : public GfxObject
47 {
48 private:
49     NW_DISALLOW_COPY_AND_ASSIGN(BasicRenderQueue);
50     NW_STATIC_ASSERT(!ut::IsArray<TElement>::value);
51 
52 public:
53     NW_UT_RUNTIME_TYPEINFO;
54 
55     static const u8 PRIORITY_END = 0xff; //!< プライオリティの最後(最大値)を表す定義です。
56 
57     typedef TElement ElementType;
58     typedef TElementList ElementListType;
59     typedef TElementKeyFactory ElementKeyFactoryType;
60     typedef typename TElement::KeyType ElementKeyType;
61 
62     typedef typename TElementList::reference reference;
63     typedef typename TElementList::difference_type difference_type;
64     typedef typename TElementList::value_type value_type;
65     typedef typename TElementList::iterator iterator;
66     typedef typename TElementList::const_iterator const_iterator;
67 
68 #if defined(_MSC_VER) && _MSC_VER <= 1201
69     typedef std::reverse_iterator<iterator, TElement> reverse_iterator;
70     typedef std::reverse_iterator<const_iterator, TElement> const_reverse_iterator;
71 #else
72     typedef std::reverse_iterator<iterator> reverse_iterator;
73     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
74 #endif
75 
76     //---------------------------------------------------------------------------
77     //! @brief 描画レイヤーが1(半透明用)のときのみ深度計算を行うための関数オブジェクトです。
78     //---------------------------------------------------------------------------
79     struct IsCalculatingOnlyLayer1Functor
80     {
IsCalculatingOnlyLayer1FunctorIsCalculatingOnlyLayer1Functor81         IsCalculatingOnlyLayer1Functor(Model* model, ResMesh mesh)
82         {
83             isCalculating =
84                 model->GetRenderLayerId(mesh) == ResMaterial::TRANSLUCENCY_KIND_LAYER1;
85         }
86 
IsCalculatingOnlyLayer1FunctorIsCalculatingOnlyLayer1Functor87         IsCalculatingOnlyLayer1Functor(ResMaterial::TranslucencyKind renderLayer)
88         {
89             isCalculating = renderLayer ==  ResMaterial::TRANSLUCENCY_KIND_LAYER1;
90         }
91 
operatorIsCalculatingOnlyLayer1Functor92         bool operator ()() const
93         {
94             return isCalculating;
95         }
96 
97         bool isCalculating;
98     };
99 
100     //---------------------------------------------------------------------------
101     //! @brief 常に深度計算を行うための関数オブジェクトです。
102     //---------------------------------------------------------------------------
103     struct AlwaysCalculatingFunctor
104     {
AlwaysCalculatingFunctorAlwaysCalculatingFunctor105         AlwaysCalculatingFunctor(Model* model, ResMesh mesh)
106         { NW_UNUSED_VARIABLE(model); NW_UNUSED_VARIABLE(mesh); }
107 
AlwaysCalculatingFunctorAlwaysCalculatingFunctor108         AlwaysCalculatingFunctor(ResMaterial::TranslucencyKind renderLayer)
109         { NW_UNUSED_VARIABLE(renderLayer); }
110 
operatorAlwaysCalculatingFunctor111         bool operator ()() const
112         {
113             return true;
114         }
115     };
116 
117     //---------------------------------------------------------------------------
118     //! @brief クリップ座標系での深度を計算する関数オブジェクトです。
119     //---------------------------------------------------------------------------
120     struct CalculateDepthFunctor
121     {
122         typedef Model ModelType;
123 
CalculateDepthFunctorCalculateDepthFunctor124         CalculateDepthFunctor(ModelType* model)
125         : model(model)
126         {
127             NW_NULL_ASSERT(model);
128             this->resModel = model->GetResModel();
129             NW_ASSERT(resModel.IsValid());
130         }
131 
132         template<typename IsCalculating>
operatorCalculateDepthFunctor133         float operator ()(ResMesh mesh, const Camera& camera, IsCalculating isCalculating) const
134         {
135             if (isCalculating())
136             {
137                 ResShape shape = resModel.GetShapes(mesh.GetShapeIndex());
138                 NW_ASSERT(shape.IsValid());
139 
140                 return SceneHelper::CalculateDepth(
141                     shape.GetCenterPosition(), model->WorldMatrix(), camera);
142             }
143             else
144             {
145                 return 0.0f;
146             }
147         }
148 
149         ModelType* model;
150         ResModel resModel;
151     };
152 
153     //---------------------------------------------------------------------------
154     //! @brief スケルタルモデル用のクリップ座標系での深度を計算する関数オブジェクトです。
155     //---------------------------------------------------------------------------
156     struct CalculateDepthOfSkeletalModelFunctor
157     {
158         typedef SkeletalModel ModelType;
159 
CalculateDepthOfSkeletalModelFunctorCalculateDepthOfSkeletalModelFunctor160         CalculateDepthOfSkeletalModelFunctor(ModelType* model)
161         : model(model)
162         {
163             NW_NULL_ASSERT(model);
164             this->resModel = model->GetResModel();
165             NW_ASSERT(resModel.IsValid());
166         }
167 
168         template<typename IsCalculating>
operatorCalculateDepthOfSkeletalModelFunctor169         float operator ()(ResMesh mesh, const Camera& camera, IsCalculating isCalculating) const
170         {
171             if (isCalculating())
172             {
173                 float depth;
174                 ResShape shape = resModel.GetShapes(mesh.GetShapeIndex());
175                 NW_ASSERT(shape.IsValid());
176 
177                 // プリミティブが1つの場合はボーンのマトリクスを使用する
178                 if (shape.GetPrimitiveSetsCount() == 1)
179                 {
180                     ResPrimitiveSet primitiveSet = shape.GetPrimitiveSets(0);
181                     s32 boneIndex = primitiveSet.GetBoneIndexTable(0);
182                     Skeleton::MatrixPose& pose = this->model->GetSkeleton()->WorldMatrixPose();
183                     depth = SceneHelper::CalculateDepth(
184                         shape.GetCenterPosition(), *pose.GetMatrix(boneIndex), camera);
185                 }
186                 else
187                 {
188                     depth = SceneHelper::CalculateDepth(
189                         shape.GetCenterPosition(), model->WorldMatrix(), camera);
190                 }
191 
192                 return depth;
193             }
194             else
195             {
196                 return 0.0f;
197             }
198         }
199 
200         ModelType* model;
201         ResModel resModel;
202     };
203 
204     //---------------------------------------------------------------------------
205     //! @brief  モデルをレンダーキューに追加するための関数オブジェクトです。
206     //---------------------------------------------------------------------------
207     template<typename ModelType, typename CalculateDepth, typename IsCalculating>
208     struct BasicEnqueueModelFunctor : public std::unary_function<ResMesh, void>
209     {
BasicEnqueueModelFunctorBasicEnqueueModelFunctor210         BasicEnqueueModelFunctor(
211             BasicRenderQueue* renderQueue,
212             ModelType* model,
213             u8 layerId,
214             const Camera& camera)
215         : calculateDepth(model),
216           renderQueue(renderQueue),
217           camera(camera),
218           layerId(layerId) {}
219 
operatorBasicEnqueueModelFunctor220         result_type operator()(argument_type mesh)
221         {
222             NW_ASSERT(mesh.IsValid());
223             if (calculateDepth.model->IsMeshVisible(mesh))
224             {
225                 float depth = calculateDepth(mesh, camera, IsCalculating(calculateDepth.model, mesh));
226                 renderQueue->EnqueueMesh(mesh, calculateDepth.model, depth, layerId);
227             }
228         }
229 
230         CalculateDepth calculateDepth;
231         BasicRenderQueue* renderQueue;
232         const Camera& camera;
233         u8 layerId;
234     };
235 
236     //! @brief モデルをレンダーキューに追加するための関数オブジェクトです。
237     typedef BasicEnqueueModelFunctor<Model, CalculateDepthFunctor, AlwaysCalculatingFunctor>
238         EnqueueModelFunctor;
239 
240     //! @brief スケルタルモデルをレンダーキューに追加するための関数オブジェクトです。
241     typedef BasicEnqueueModelFunctor<SkeletalModel, CalculateDepthOfSkeletalModelFunctor, AlwaysCalculatingFunctor>
242         EnqueueSkeletalModelFunctor;
243 
244     //! @brief モデルをレンダーキューに追加するための関数オブジェクトです。
245     //!        描画レイヤーが1(半透明用)のときのみ深度計算を行います。
246     typedef BasicEnqueueModelFunctor<Model, CalculateDepthFunctor, IsCalculatingOnlyLayer1Functor>
247         FastEnqueueModelFunctor;
248 
249     //! @brief スケルタルモデルをレンダーキューに追加するための関数オブジェクトです。
250     //!        描画レイヤーが1(半透明用)のときのみ深度計算を行います。
251     typedef BasicEnqueueModelFunctor<SkeletalModel, CalculateDepthOfSkeletalModelFunctor, IsCalculatingOnlyLayer1Functor>
252         FastEnqueueSkeletalModelFunctor;
253 
254     //---------------------------------------------------------------------------
255     //! @brief  モデルをレンダーキューに追加するための関数オブジェクトです。
256     //!
257     //! 半透明系のメッシュの深度をモデル単位にしてキーを作成します。
258     //---------------------------------------------------------------------------
259     template<typename ModelType, typename CalculateDepth, typename IsCalculating>
260     struct BasicEnqueueModelTranslucentModelBaseFunctor : public std::unary_function<ResMesh, void>
261     {
BasicEnqueueModelTranslucentModelBaseFunctorBasicEnqueueModelTranslucentModelBaseFunctor262         BasicEnqueueModelTranslucentModelBaseFunctor(
263             BasicRenderQueue* renderQueue,
264             ModelType* model,
265             u8 layerId,
266             const Camera& camera)
267         : calculateDepth(model),
268           renderQueue(renderQueue),
269           camera(camera),
270           layerId(layerId)
271         {
272             NW_NULL_ASSERT(renderQueue);
273 
274             modelDepth = SceneHelper::CalculateDepth(model->WorldMatrix(), camera);
275         }
276 
operatorBasicEnqueueModelTranslucentModelBaseFunctor277         result_type operator()(argument_type mesh)
278         {
279             NW_ASSERT(mesh.IsValid());
280             if (calculateDepth.model->IsMeshVisible(mesh))
281             {
282                 ResMaterial::TranslucencyKind translucencyKind =
283                     calculateDepth.model->GetRenderLayerId(mesh);
284 
285                 float depth = (translucencyKind == ResMaterial::TRANSLUCENCY_KIND_OPAQUE)
286                     ? calculateDepth(mesh, camera, IsCalculating(translucencyKind))
287                     : modelDepth;
288 
289                 renderQueue->EnqueueElement(
290                     ElementType(mesh, calculateDepth.model), translucencyKind, depth, layerId);
291             }
292         }
293 
294         CalculateDepth calculateDepth;
295         BasicRenderQueue* renderQueue;
296         const Camera& camera;
297         float modelDepth;
298         u8 layerId;
299     };
300 
301     //! @brief モデルをレンダーキューに追加するための関数オブジェクトです。
302     typedef BasicEnqueueModelTranslucentModelBaseFunctor<Model, CalculateDepthFunctor, AlwaysCalculatingFunctor>
303         EnqueueModelTranslucentModelBaseFunctor;
304 
305     //! @brief スケルタルモデルをレンダーキューに追加するための関数オブジェクトです。
306     typedef BasicEnqueueModelTranslucentModelBaseFunctor<SkeletalModel, CalculateDepthOfSkeletalModelFunctor, AlwaysCalculatingFunctor>
307         EnqueueSkeletalModelTranslucentModelBaseFunctor;
308 
309     //! @brief モデルをレンダーキューに追加するための関数オブジェクトです。
310     //!        描画レイヤーが1(半透明用)のときのみ深度計算を行います。
311     typedef BasicEnqueueModelTranslucentModelBaseFunctor<Model, CalculateDepthFunctor, IsCalculatingOnlyLayer1Functor>
312         FastEnqueueModelTranslucentModelBaseFunctor;
313 
314     //! @brief スケルタルモデルをレンダーキューに追加するための関数オブジェクトです。
315     //!        描画レイヤーが1(半透明用)のときのみ深度計算を行います。
316     typedef BasicEnqueueModelTranslucentModelBaseFunctor<SkeletalModel, CalculateDepthOfSkeletalModelFunctor, IsCalculatingOnlyLayer1Functor>
317         FastEnqueueSkeletalModelTranslucentModelBaseFunctor;
318 
319     //----------------------------------------
320     //! @name デバッグユーティリティ
321     //@{
322 
323     //! @brief レンダーキューの状態をログ出力にレポートするための関数オブジェクトです。
324     struct ReportFunctor : public std::unary_function<void, reference>
325     {
ReportFunctorReportFunctor326         ReportFunctor() : count(0) {}
327 
328         //! @brief ログ出力にレポートします。
operatorReportFunctor329         void operator() (reference element)
330         {
331 #ifdef NW_RELEASE
332             NW_UNUSED_VARIABLE(element);
333 #else
334             if (element.IsCommand())
335             {
336                 NW_DEV_LOG("%3d : Command(%x)\n",
337                     count,
338                     reinterpret_cast<u32>(element.GetCommand()));
339             }
340             else
341             {
342                 const ResMesh mesh = element.GetMesh();
343                 const ResModel model = element.GetModel()->GetResModel();
344                 const ResMaterial material =
345                     element.GetModel()->GetMaterial(mesh.GetMaterialIndex())->GetOriginal();
346                 NW_DEV_LOG("%3d : Model(%s), Mesh(%s), Material(%s)\n",
347                     count,
348                     model.GetName(),
349                     mesh.GetName(),
350                     material.GetName());
351             }
352 
353             ++count;
354 #endif
355         }
356 
357         int count;
358     };
359 
360     //@}
361 
362     //----------------------------------------
363     //! @name 作成
364     //@{
365 
366     //! @brief BasicRenderQueue を作成するためのクラスです。
367     //!
368     //! IsFixedSizeMemory の初期値は true です。false に変更すると、各種最大数の設定は無視されます。
369     class Builder
370     {
371     public:
372         //! @brief コンストラクタです。
Builder()373         Builder() : m_IsFixedSizeMemory(true), m_MaxRenderElements(64) {}
374 
375         //! @brief デストラクタです。
~Builder()376         ~Builder() {}
377 
378         //! @brief 生成時以外にもメモリを確保するかどうかのフラグを設定します。
379         //!
380         //!        true を指定すると、生成時のみ固定サイズのメモリ確保を行います。
381         //!
382         //!        false を指定すると、生成時以外にも必要に応じて動的にメモリ確保が行われます。
IsFixedSizeMemory(bool isFixedSizeMemory)383         Builder& IsFixedSizeMemory(bool isFixedSizeMemory)
384         {
385             m_IsFixedSizeMemory = isFixedSizeMemory;
386             return *this;
387         }
388 
389         //! @brief キューに積む描画要素の最大数を設定します。
MaxRenderElements(int max)390         Builder& MaxRenderElements(int max) { m_MaxRenderElements = max; return *this; }
391 
392         //! @brief レンダーキューを生成します。
393         //!
394         //! @param[in]    allocator アロケータです。
395         //!
396         //! @return       生成したレンダーキューを返します。
397         //!
Create(os::IAllocator * allocator)398         BasicRenderQueue* Create(os::IAllocator* allocator)
399         {
400             void* queueMemory = allocator->Alloc<BasicRenderQueue>(1);
401             NW_NULL_ASSERT(queueMemory);
402             BasicRenderQueue* queue;
403             if (m_IsFixedSizeMemory)
404             {
405                 queue = new(queueMemory) BasicRenderQueue(allocator, m_MaxRenderElements);
406             }
407             else
408             {
409                 queue = new(queueMemory) BasicRenderQueue(allocator);
410             }
411             return queue;
412         }
413 
414     private:
415         bool m_IsFixedSizeMemory;
416         int m_MaxRenderElements;
417     };
418 
419     //@}
420 
421     //----------------------------------------
422     //! @name キュー操作
423     //@{
424 
425     //! @brief キューに描画要素を追加します。
426     //!
427     //! @param[in]    element 追加する描画要素です。
428     //! @param[in]    translucencyKind 透明性の種類です。
429     //! @param[in]    depth スクリーン座標系におけるメッシュの深度です。(0.0 ~ 1.0)
430     //! @param[in]    layerId 描画要素のソート時に最優先に区分される ID です。レイヤーやビューポートの描画を制御するのに用います。
431     //!
432     //! @return       追加された描画要素を返します。追加できなかった場合は NULL が返ります。
433     //!
EnqueueElement(const ElementType & element,ResMaterial::TranslucencyKind translucencyKind,float depth,u8 layerId)434     ElementType* EnqueueElement(
435         const ElementType& element,
436         ResMaterial::TranslucencyKind translucencyKind,
437         float depth,
438         u8 layerId)
439     {
440         bool pushed = this->m_List.push_back(element);
441         if (!pushed)
442         {
443             return NULL;
444         }
445 
446         ElementType* back = &m_List.back();
447 
448         if (this->m_KeyCachingState == UNUSE_CACHED_KEY ||
449             translucencyKind == ResMaterial::TRANSLUCENCY_KIND_LAYER1)
450         {
451             RenderKeyFactory* keyFactory = this->GetKeyFactory(translucencyKind);
452             back->Key() = keyFactory->CreateRenderKey(*back, depth, layerId);
453         }
454         else
455         {
456             if (ut::CheckFlag<u32, u32>(back->GetMesh().GetFlags(), ResMesh::FLAG_VALID_RENDER_KEY_CACHE))
457             {
458                 // キャッシュしたキーを利用します。
459                 back->Key() = back->GetMesh().GetRenderKeyCache();
460             }
461             else
462             {
463                 // キーを作成して、キャッシュします。
464                 RenderKeyFactory* keyFactory = this->GetKeyFactory(translucencyKind);
465                 back->Key() = keyFactory->CreateRenderKey(*back, depth, layerId);
466 
467                 back->GetMesh().SetRenderKeyCache(back->Key());
468                 back->GetMesh().SetFlags(ut::EnableFlag<u32, u32>(
469                     back->GetMesh().GetFlags(), ResMesh::FLAG_VALID_RENDER_KEY_CACHE));
470             }
471         }
472 
473         return back;
474     }
475 
476     //! @brief キューにメッシュ要素を追加します。
477     //!
478     //! @param[in]    mesh メッシュです。
479     //! @param[in]    model メッシュの所有者となるモデルです。
480     //! @param[in]    depth スクリーン座標系におけるメッシュの深度です。(0.0 ~ 1.0)
481     //! @param[in]    layerId 描画要素のソート時に最優先に区分される ID です。レイヤーやビューポートの描画を制御するのに用います。
482     //!
EnqueueMesh(ResMesh mesh,Model * model,float depth,u8 layerId)483     ElementType* EnqueueMesh(
484         ResMesh mesh,
485         Model* model,
486         float depth,
487         u8 layerId)
488     {
489         NW_ASSERT(mesh.IsValid());
490         NW_NULL_ASSERT(model);
491 
492         return EnqueueElement(
493             ElementType(mesh, model), model->GetRenderLayerId(mesh), depth, layerId);
494     }
495 
496     //! @brief キューにモデルに含まれるメッシュ要素を追加します。
497     //!
498     //! @param[in]    model メッシュの所有者となるモデルです。
499     //! @param[in]    layerId 描画要素のソート時に最優先に区分される ID です。レイヤーやビューポートの描画を制御するのに用います。
500     //! @param[in]    camera メッシュの深度を計算するのに用いるカメラです。
501     //!
EnqueueModel(Model * model,u8 layerId,const Camera & camera)502     void EnqueueModel(
503         Model* model,
504         u8 layerId,
505         const Camera& camera)
506     {
507         NW_NULL_ASSERT(model);
508         gfx::ResMeshArray meshs = model->GetResMeshes();
509         std::for_each(
510             meshs.begin(),
511             meshs.end(),
512             EnqueueModelFunctor(this, model, layerId, camera));
513     }
514 
515     //! @brief キューにスケルタルモデルに含まれるメッシュ要素を追加します。
516     //!
517     //! @param[in]    model メッシュの所有者となるモデルです。
518     //! @param[in]    layerId 描画要素のソート時に最優先に区分される ID です。レイヤーやビューポートの描画を制御するのに用います。
519     //! @param[in]    camera メッシュの深度を計算するのに用いるカメラです。
520     //!
EnqueueSkeletalModel(SkeletalModel * model,u8 layerId,const Camera & camera)521     void EnqueueSkeletalModel(
522         SkeletalModel* model,
523         u8 layerId,
524         const Camera& camera)
525     {
526         NW_NULL_ASSERT(model);
527         gfx::ResMeshArray meshs = model->GetResMeshes();
528         std::for_each(
529             meshs.begin(),
530             meshs.end(),
531             EnqueueSkeletalModelFunctor(this, model, layerId, camera));
532     }
533 
534     //! @brief キューにコマンド要素を追加します。
535     //!
536     //! ここで設定するコマンドは描画時に呼び出されるので、
537     //! コマンドのインスタンスは描画時まで保持されるようにしてください。
538     //! ローカル変数等を使用して、描画前にデストラクトされると
539     //! 不正な関数呼び出しが行われてしまいます。
540     //!
541     //! @param[in]    command 描画時に呼び出されるコマンドです。
542     //! @param[in]    translucencyKind 透明性の種類です。
543     //! @param[in]    priority メッシュの描画優先度です。
544     //! @param[in]    layerId 描画要素のソート時に最優先に区分される ID です。レイヤーやビューポートの描画を制御するのに用います。
545     //!
546     //! @return       追加されたコマンド要素を返します。追加できなかった場合は NULL が返ります。
547     //!
EnqueueCommand(RenderCommand * command,ResMaterial::TranslucencyKind translucencyKind,u8 priority,u8 layerId)548     ElementType* EnqueueCommand(
549         RenderCommand* command,
550         ResMaterial::TranslucencyKind translucencyKind,
551         u8 priority,
552         u8 layerId)
553     {
554         RenderKeyFactory* keyFactory = this->GetKeyFactory(translucencyKind);
555 
556         bool pushed = this->m_List.push_back(
557             ElementType(keyFactory->CreateCommandRenderKey(
558                 command, translucencyKind, priority, layerId)));
559 
560         if (pushed)
561         {
562             return &this->m_List.back();
563         }
564         else
565         {
566             return NULL;
567         }
568     }
569 
570     //! @brief キューの全ての要素を削除します。
571     //!
572     //! @param[in] cacheEnabled true を指定するとキャッシュ機能を有効にします。
573     //!
574     void Reset(bool cacheEnabled = false)
575     {
576         this->m_List.clear();
577         this->m_KeyCachingState = (cacheEnabled) ? USE_CACHED_KEY : UNUSE_CACHED_KEY;
578     }
579 
580     //! @brief キューの全ての要素を削除して、キーファクトリの設定を行います。
581     //!
582     //! 各キーファクトリに NULL を設定すると、ファクトリの変更を行いません。
583     //!
584     //! @param[in] opacityKeyFactory 不透明メッシュのキーファクトリです。
585     //! @param[in] translucentKeyFactory 半透明メッシュのキーファクトリです。
586     //! @param[in] additiveKeyFactory 加算合成メッシュのキーファクトリです。
587     //! @param[in] subtractionKeyFactory 減算合成メッシュのキーファクトリです。
588     //! @param[in] cacheEnabled true を指定するとキャッシュ機能を有効にします。
589     //!
590     //! @sa nw::gfx::CreatePriorMaterialRenderKeyFactory
591     //! @sa nw::gfx::CreatePriorMaterialReverseDepthRenderKeyFactory
592     //! @sa nw::gfx::CreatePriorMaterialAndZeroDepthRenderKeyFactory
593     //! @sa nw::gfx::CreatePriorDepthRenderKeyFactory
594     //! @sa nw::gfx::CreatePriorDepthReverseDepthRenderKeyFactory
595     //! @sa nw::gfx::CreateTopPriorDepthRenderKeyFactory
596     //! @sa nw::gfx::CreateTopPriorDepthReverseDepthRenderKeyFactory
597     //!
598     void Reset(
599         ElementKeyFactoryType* opacityKeyFactory,
600         ElementKeyFactoryType* translucentKeyFactory,
601         ElementKeyFactoryType* additiveKeyFactory,
602         ElementKeyFactoryType* subtractionKeyFactory,
603         bool cacheEnabled = false)
604     {
605         this->Reset(cacheEnabled);
606 
607         if (opacityKeyFactory != NULL)
608         {
609             this->m_OpacityKeyFactory = opacityKeyFactory;
610         }
611         if (translucentKeyFactory != NULL)
612         {
613             this->m_TranslucentKeyFactory = translucentKeyFactory;
614         }
615         if (additiveKeyFactory != NULL)
616         {
617             this->m_AdditiveKeyFactory = additiveKeyFactory;
618         }
619         if (subtractionKeyFactory != NULL)
620         {
621             this->m_SubtractionKeyFactory = subtractionKeyFactory;
622         }
623     }
624 
625     //@}
626 
627     //----------------------------------------
628     //! @name 取得/設定
629     //@{
630 
631     //! @brief 要素数を取得します。
Size()632     int Size() const
633     {
634         return m_List.size();
635     }
636 
637     //! @brief 要素が1つもない場合は true を返します。
Empty()638     bool Empty() const
639     {
640         return m_List.empty();
641     }
642 
643     //! @brief 先頭の要素を参照します。
Peek()644     ElementType& Peek()
645     {
646         return m_List.front();
647     }
648 
649     //! @brief 先頭の要素を参照します。
Peek()650     const ElementType& Peek() const
651     {
652         return m_List.front();
653     }
654 
655     //! @brief 先頭のイテレータを取得します。
Begin()656     iterator Begin()
657     {
658         return m_List.begin();
659     }
660 
661     //! @brief 先頭のイテレータを取得します。
Begin()662     const_iterator Begin() const
663     {
664         return m_List.begin();
665     }
666 
667     //! @brief 末尾のイテレータを取得します。
End()668     iterator End()
669     {
670         return m_List.end();
671     }
672 
673     //! @brief 末尾のイテレータを取得します。
End()674     const_iterator End() const
675     {
676         return m_List.end();
677     }
678 
679     //! @brief 先頭のリバースイテレータを取得します。
ReverseBegin()680     reverse_iterator ReverseBegin()
681     {
682         return m_List.rbegin();
683     }
684 
685     //! @brief 先頭のリバースイテレータを取得します。
ReverseBegin()686     const_reverse_iterator ReverseBegin() const
687     {
688         return m_List.rbegin();
689     }
690 
691     //! @brief 末尾のリバースイテレータを取得します。
ReverseEnd()692     reverse_iterator ReverseEnd()
693     {
694         return m_List.rend();
695     }
696 
697     //! @brief 末尾のリバースイテレータを取得します。
ReverseEnd()698     const_reverse_iterator ReverseEnd() const
699     {
700         return m_List.rend();
701     }
702 
703     //@}
704 
705 private:
BasicRenderQueue(os::IAllocator * allocator)706     explicit BasicRenderQueue(os::IAllocator* allocator)
707     : GfxObject(allocator),
708       m_List(allocator),
709       m_OpacityKeyFactory(NULL),
710       m_TranslucentKeyFactory(NULL),
711       m_AdditiveKeyFactory(NULL),
712       m_SubtractionKeyFactory(NULL),
713       m_KeyCachingState(UNUSE_CACHED_KEY) {}
714 
BasicRenderQueue(os::IAllocator * allocator,int maxRenderElements)715     BasicRenderQueue(os::IAllocator* allocator, int maxRenderElements)
716     : GfxObject(allocator),
717       m_List(maxRenderElements, allocator),
718       m_OpacityKeyFactory(NULL),
719       m_TranslucentKeyFactory(NULL),
720       m_AdditiveKeyFactory(NULL),
721       m_SubtractionKeyFactory(NULL),
722       m_KeyCachingState(UNUSE_CACHED_KEY) {}
723 
~BasicRenderQueue()724     virtual ~BasicRenderQueue() {}
725 
GetKeyFactory(ResMaterial::TranslucencyKind translucencyKind)726     ElementKeyFactoryType* GetKeyFactory(ResMaterial::TranslucencyKind translucencyKind)
727     {
728         ElementKeyFactoryType* keyFactory = NULL;
729         switch (translucencyKind)
730         {
731         case ResMaterial::TRANSLUCENCY_KIND_LAYER0:
732             keyFactory = this->m_OpacityKeyFactory;
733             break;
734         case ResMaterial::TRANSLUCENCY_KIND_LAYER1:
735             keyFactory = this->m_TranslucentKeyFactory;
736             break;
737         case ResMaterial::TRANSLUCENCY_KIND_LAYER2:
738             keyFactory = this->m_SubtractionKeyFactory;
739             break;
740         case ResMaterial::TRANSLUCENCY_KIND_LAYER3:
741             keyFactory = this->m_AdditiveKeyFactory;
742             break;
743         default: NW_FAILSAFE_IF(false) { keyFactory = this->m_OpacityKeyFactory; } break;
744         }
745         NW_NULL_ASSERT(keyFactory);
746         return keyFactory;
747     }
748 
749     TElementList m_List;
750     ElementKeyFactoryType* m_OpacityKeyFactory;
751     ElementKeyFactoryType* m_TranslucentKeyFactory;
752     ElementKeyFactoryType* m_AdditiveKeyFactory;
753     ElementKeyFactoryType* m_SubtractionKeyFactory;
754 
755     enum KeyCachingState
756     {
757         UNUSE_CACHED_KEY,
758         USE_CACHED_KEY
759     };
760 
761     KeyCachingState m_KeyCachingState;
762 };
763 
764 //! @brief 標準のレンダーキューの定義です。
765 typedef BasicRenderQueue<
766     BasicRenderElement<RenderKeyType>,
767     ut::MoveArray<BasicRenderElement<RenderKeyType> > >
768         RenderQueue;
769 
770 //---------------------------------------------------------------------------
771 //! @brief        ソート比較用関数オブジェクトです。
772 //---------------------------------------------------------------------------
773 struct RenderElementCompare
774 : public std::binary_function<RenderElement, RenderElement, bool>
775 {
operatorRenderElementCompare776     bool operator() (
777         const RenderElement& lhs,
778         const RenderElement& rhs)
779     {
780         return lhs.Key() < rhs.Key();
781     }
782 };
783 
784 } // namespace gfx
785 } // namespace nw
786 
787 #endif // NW_GFX_RENDERQUEUE_H_
788