1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ParticleSet.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: 31829 $
16  *---------------------------------------------------------------------------*/
17 
18 #ifndef NW_GFX_PARTICLESET_H_
19 #define NW_GFX_PARTICLESET_H_
20 
21 #include <nw/gfx/gfx_TransformNode.h>
22 
23 #include <nw/gfx/gfx_ParticleModel.h>
24 #include <nw/gfx/res/gfx_ResParticleSet.h>
25 #include <nw/gfx/res/gfx_ResParticleAnimationOption.h>
26 #include <nw/gfx/gfx_ParticleRandom.h>
27 #include <nw/gfx/gfx_ParticleTime.h>
28 
29 namespace nw
30 {
31 namespace gfx
32 {
33 
34 class ParticleCollection;
35 class ParticleContext;
36 class ParticleShape;
37 
38 //---------------------------------------------------------------------------
39 //! @brief        パーティクル群を表すクラスです。
40 //---------------------------------------------------------------------------
41 class ParticleSet : public SceneNode
42 {
43 private:
44     NW_DISALLOW_COPY_AND_ASSIGN(ParticleSet);
45 
46 public:
47     NW_UT_RUNTIME_TYPEINFO;
48 
49     //! @brief 設定内容です。
50     struct Description : public SceneNode::Description
51     {
52         s32 maxInitializers;         //!< ParticleInitializerのバッファの数です。
53         s32 maxUpdaters;             //!< ParticleUpdaterのバッファの数です。
54 
55         //! @brief コンストラクタです。
DescriptionDescription56         Description() :
57             maxInitializers(0),
58             maxUpdaters(0)
59         {}
60     };
61 
62     //! @brief ランタイム用のイニシャライザの管理情報です。
63     struct Initializer
64     {
65         bool m_IsCopied; //!< コピーされたリソースであることを表すフラグです。
66         const ResParticleInitializerData *resource; //!< リソースへのポインタです。
67         u32 work; //!< ワークエリアです。
68 
69         // 高速化のためのキャッシュ
70         nw::ut::ResTypeInfo     m_Type;
71         void* m_TargetStreams[2]; //!< 変更対象のストリームへのポインタです。
72     };
73 
74     //! @brief ランタイム用のアップデータの管理情報です。
75     struct Updater
76     {
77         bool m_IsCopied; //!< コピーされたリソースであることを表すフラグです。
78         const ResParticleUpdaterData *resource; //!< リソースへのポインタです。
79         u32 work; //!< ワークエリアです。
80 
81         // 高速化のためのキャッシュ
82         nw::ut::ResTypeInfo     m_Type;
83         void* m_TargetStreams[2]; //!< 変更対象のストリームへのポインタです。
84 
85         u32                     m_Flags;        //!< フラグです。
86 
87         //! @brief アップデータの管理情報のフラグです。
88         enum Flag
89         {
90             FLAG_IS_HAS_CURVE_ANIM         = 0x1 << 0       //!< カーブアニメーションを保持しているかのフラグです。
91         };
92 
93         //! @brief 任意のフラグが有効になっているか取得します。
94         //! @param[in] flags 有効か調べるフラグです。
95         //! @return 有効な場合はtrueを返します。
IsEnabledFlagsUpdater96         inline bool IsEnabledFlags(bit32 flags) const
97         {
98             return ut::CheckFlag(m_Flags, flags);
99         }
100 
101         //! @brief 任意のフラグを有効に設定します。
102         //! @param[in] flags 有効にするフラグです。
EnableFlagsUpdater103         inline void EnableFlags(bit32 flags)
104         {
105             m_Flags = ut::EnableFlag(m_Flags, flags);
106         }
107     };
108 
109     //----------------------------------------
110     //! @name 作成/破棄
111     //@{
112 
113     //! @brief        リソースからパーティクルセットを生成します。
114     //!
115     //! @param[in]    parent 親のノードです。
116     //! @param[in]    resource リソースです。
117     //! @param[in]    description 設定内容です。
118     //! @param[in]    mainAllocator メインアロケータです。
119     //! @param[in]    deviceAllocator デバイスアロケータです。
120     //! @param[in]    shape シェイプです。
121     //!
122     //! @return       生成されたトランスフォームノードです。
123     //!
124     static ParticleSet* Create(
125         SceneNode* parent,
126         ResSceneObject resource,
127         const ParticleSet::Description& description,
128         os::IAllocator* mainAllocator,
129         os::IAllocator* deviceAllocator,
130         ParticleShape* shape);
131 
132     //! @brief        生成時に必要なメモリサイズを取得します。
133     //! @param[in]    resource リソースです。
134     //! @param[in]    description 設定内容です。
135     //! @param[in]    alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
136     //! @return       必要なメモリサイズです。
137     static size_t GetMemorySize(
138         ResParticleSet resource,
139         const ParticleSet::Description& description,
140         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
141     {
142         os::MemorySizeCalculator size(alignment);
143 
144         GetMemorySizeInternal(&size, resource, description);
145 
146         return size.GetSizeWithPadding(alignment);
147     }
148 
149     //! @details :private
150     static void GetMemorySizeInternal(
151         os::MemorySizeCalculator* pSize,
152         ResParticleSet resource,
153         const ParticleSet::Description& description);
154 
155     //! @brief        生成時に必要なデバイスメモリサイズを取得します。
156     //! @param[in]    resource リソースです。
157     //! @param[in]    alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
158     //! @return       必要なデバイスメモリサイズです。
159     static size_t GetDeviceMemorySize(
160         ResParticleSet resource,
161         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
162     {
163         os::MemorySizeCalculator size(alignment);
164 
165         GetDeviceMemorySizeInternal(&size, resource);
166 
167         return size.GetSizeWithPadding(alignment);
168     }
169 
170     //! @details :private
171     static void GetDeviceMemorySizeInternal(
172         os::MemorySizeCalculator* pSize,
173         ResParticleSet resource);
174 
175     //@}
176 
177     //----------------------------------------
178     //! @name 更新
179     //@{
180 
181     //! @brief        ビジターを受け付けます。
182     //!
183     //! @param[in]    visitor ビジターです。
184     //!
185     virtual void Accept(ISceneVisitor* visitor);
186 
187     //@}
188 
189     //----------------------------------------
190     //! @name リソース
191     //@{
192 
193     //! @brief リソースを取得します。
194     //! @return 設定されているリソースです。
GetResParticleSet()195     ResParticleSet GetResParticleSet()
196     {
197         return ResDynamicCast<ResParticleSet>( this->GetResSceneObject() );
198     }
199 
200     //! @brief リソースを取得します。
201     //! @return 設定されているリソースです。
GetResParticleSet()202     const ResParticleSet GetResParticleSet() const
203     {
204         return ResDynamicCast<ResParticleSet>( this->GetResSceneObject() );
205     }
206 
207     //@}
208 
209     //----------------------------------------
210     //! @name 取得/設定
211     //@{
212 
213     //! @brief パーティクルコレクションを設定します。
214     //! @param[in] node 設定するパーティクルコレクションです。
215     //! @return 既に設定されている場合は、falseを返します。
AttachParticleCollection(ParticleCollection * node)216     bool AttachParticleCollection(ParticleCollection* node)
217     {
218         if (this->m_ParticleCollection != NULL)
219         {
220             return false;
221         }
222 
223         this->m_ParticleCollection = node;
224         return true;
225     }
226 
227     //! @brief パーティクルコレクションを取得します。
228     //! @return 設定されているパーティクルコレクションです。
GetParticleCollection()229     ParticleCollection* GetParticleCollection()
230     {
231         return this->m_ParticleCollection;
232     }
233 
234     //! @brief パーティクルコレクションを取得します。
235     //! @return 設定されているパーティクルコレクションです。
GetParticleCollection()236     const ParticleCollection* GetParticleCollection() const
237     {
238         return this->m_ParticleCollection;
239     }
240 
241     //! @brief イニシャライザの配列を取得します。
242     //! @details 通常は生成時にサイズが決定されるため、生成後に追加削除することはできません。
243     //! @return イニシャライザの配列へのポインタを返します。
GetInitializers()244     ut::MoveArray<Initializer>* GetInitializers()
245     {
246         return &this->m_Initializers;
247     }
248 
249     //! @brief イニシャライザの配列を取得します。
250     //! @details 通常は生成時にサイズが決定されるため、生成後に追加削除することはできません。
251     //! @return イニシャライザの配列へのポインタを返します。
GetInitializers()252     const ut::MoveArray<Initializer>* GetInitializers() const
253     {
254         return &this->m_Initializers;
255     }
256 
257     //! @brief アップデータの配列を取得します。
258     //! @details 通常は生成時にサイズが決定されるため、生成後に追加削除することはできません。
259     //! @return アップデータの配列へのポインタを返します。
GetUpdaters()260     ut::MoveArray<Updater>* GetUpdaters()
261     {
262         return &this->m_Updaters;
263     }
264 
265     //! @brief アップデータの配列を取得します。
266     //! @details 通常は生成時にサイズが決定されるため、生成後に追加削除することはできません。
267     //! @return アップデータの配列へのポインタを返します。
GetUpdaters()268     const ut::MoveArray<Updater>* GetUpdaters() const
269     {
270         return &this->m_Updaters;
271     }
272 
273 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
274     //! @brief パーティクルを追加します。
275     //! @details :private
276     void AddParticles(
277         const nw::math::MTX34& emitterMatrix,
278         const nw::math::VEC3* const positions,
279         ParticleSet* parentParticleSet,
280         const u16* const parentIndices,
281         int count);
282 #else
283     //! @brief パーティクルを追加します。
284     //! @details :private
285     //! パーティクルコレクションに新しくパーティクル粒子を追加します。
286     //! パラメータは重要なもの以外は未初期化です。
287     //!
288     //! @param[in] count 追加する個数です。
289     //! @return 実際に追加できた個数です。
290     int AddParticles(int count);
291 #endif
292 
293     //! @brief パーティクルの更新処理を行います。
294     //! @param[in] particleContext パーティクルコンテキストです。
295     //! @param[in] enableSwapBuffer バッファをスワップするかを指定します。
296     void UpdateParticles(
297         ParticleContext* particleContext,
298         bool enableSwapBuffer = true);
299 
300     //! @brief        パーティクルコレクションを空にします。
301     //! @details パーティクルコレクションのClearを呼び出し、ストリームの状態を初期化します。
302     //!          この関数は描画中には使用できません。
303     //!          GPUからストリームへのアクセスがない状態で使用してください。
304     void ClearParticleCollection();
305 
306     //! @details :private
Srand(u32 seed)307     void Srand(u32 seed)
308     {
309         m_ParticleRandom.Srand(seed);
310     }
311 
312     //! @brief スケールのオフセット値を取得します。
313     //! @details 個々のパーティクルのスケールに乗算するオフセットを取得します。
314     //! @return スケールのオフセット値を返します。
GetScaleOffset()315     const nw::math::VEC3& GetScaleOffset() const
316     {
317         return this->m_ScaleOffset;
318     }
319 
320     //! @brief スケールのオフセット値を設定します。
321     //! @details 個々のパーティクルのスケールに乗算するオフセットを設定します。
322     //! @param[in] offset 新しいオフセット値
SetScaleOffset(const nw::math::VEC3 & offset)323     void SetScaleOffset(const nw::math::VEC3& offset)
324     {
325         this->m_ScaleOffset = offset;
326     }
327 
328     //! @brief 回転のオフセット値を取得します。
329     //! @details 個々のパーティクルの回転に加算するオフセットを取得します。
330     //! @return 回転のオフセット値を返します。
GetRotateOffset()331     const nw::math::VEC3& GetRotateOffset() const
332     {
333         return this->m_RotateOffset;
334     }
335 
336     //! @brief 回転のオフセット値を設定します。
337     //! @details 個々のパーティクルの回転に加算するオフセットを設定します。
338     //! @param[in] offset 新しいオフセット値
SetRotateOffset(const nw::math::VEC3 & offset)339     void SetRotateOffset(const nw::math::VEC3& offset)
340     {
341         this->m_RotateOffset = offset;
342     }
343 
344     //! @details :private
WorldMatrix()345     const nw::math::MTX34& WorldMatrix()
346     {
347         if (this->GetResParticleSet().GetIsForceWorld())
348         {
349             return nw::math::MTX34::Identity();
350         }
351         else
352         {
353             ParticleModel* model = static_cast<ParticleModel*>(this->GetParent());
354             return model->WorldMatrix();
355         }
356     }
357 
358     //! @details :private
InverseWorldMatrix()359     const nw::math::MTX34& InverseWorldMatrix()
360     {
361         if (this->GetResParticleSet().GetIsForceWorld())
362         {
363             return nw::math::MTX34::Identity();
364         }
365         else
366         {
367             ParticleModel* model = static_cast<ParticleModel*>(this->GetParent());
368             return model->InverseWorldMatrix();
369         }
370     }
371 
372     //! @brief 描画順を取得します。
373     //! @return 生成順の時にtrueを返します。
IsAscendingOrder()374     bool IsAscendingOrder() const
375     {
376         const ResParticleShapeBuilder& resShapeBuilder =
377             this->GetResParticleSet().GetParticleShapeBuilder();
378         return (resShapeBuilder.IsValid()) ? resShapeBuilder.IsAscendingOrder() : true;
379     }
380 
381     //! @brief 処理順序のヒント情報をリセットします。
382     //! @details :private
ResetDebugHint()383     void ResetDebugHint()
384     {
385 #ifdef NW_CHECK_PARTICLE_PROCESS
386         m_ProcessStep = STEP_NONE;
387 #endif
388     }
389 
390 #ifdef NW_CHECK_PARTICLE_PROCESS
391     //! @brief 描画の開始を宣言します。
392     //! @details :private
393     //! 処理順序の確認のためのヒント情報です。
BeginDraw()394     void BeginDraw()
395     {
396         // どの条件下でも描画可能
397         m_ProcessStep = STEP_DRAW;
398     }
399 
400     //! @brief アップデートの開始を宣言します。
401     //! @details :private
402     //! 処理順序の確認のためのヒント情報です。
BeginUpdate(bool enableSwapBuffer)403     void BeginUpdate(bool enableSwapBuffer)
404     {
405         if (enableSwapBuffer)
406         {
407             NW_WARNING(
408                 m_ProcessStep == STEP_NONE ||
409                 m_ProcessStep == STEP_DRAW,
410                 "detected an illegal order(Update with SwapBuffer Prev:%d)", m_ProcessStep);
411             m_ProcessStep = STEP_UPDATE1;
412         }
413         else
414         {
415             NW_WARNING(
416                 m_ProcessStep == STEP_UPDATE1 ||
417                 m_ProcessStep == STEP_UPDATE2,
418                 "detected an illegal order(Update without SwapBuffer Prev:%d)", m_ProcessStep);
419             m_ProcessStep = STEP_UPDATE2;
420         }
421     }
422 
423 #endif
424 
425     //@}
426 
427     //----------------------------------------
428     //! @name 初期化/更新
429     //@{
430 
431     //! @brief 新しく追加したパーティクルを初期化します。
432     //! @details :private
433     //!
434     //! @param[in] startIndex 初期化を開始するパーティクルのストリーム上のインデックスです。
435     //! @param[in] count      初期化するパーティクルの数です。
436     //! @param[in] incrIndex  インデックスの変化する方向を 1, または -1 で指定します。
437     //! @param[in] time       現在の時刻です。
438     void InitializeParticles(
439         int startIndex,
440         int count,
441         int incrIndex,
442         ParticleTime time);
443 
444     //@}
445 
446 protected:
447     //----------------------------------------
448     //! @name コンストラクタ/デストラクタ
449     //@{
450 
451     //! コンストラクタです。
452     ParticleSet(
453         os::IAllocator* allocator,
454         ResParticleSet resObj,
455         const ParticleSet::Description& description);
456 
457     //! デストラクタです。
458     virtual ~ParticleSet();
459 
460     //@}
461 
462 private:
463     ParticleCollection* m_ParticleCollection;
464 
465     ParticleRandom m_ParticleRandom;
466 
467     ut::MoveArray<Initializer> m_Initializers;
468     ut::MoveArray<Updater> m_Updaters;
469 
470     math::VEC3 m_ScaleOffset;
471     math::VEC3 m_RotateOffset;
472 
473     bool m_UsePrevTranslate;
474 
475 #ifdef NW_CHECK_PARTICLE_PROCESS
476     //! 処理の状態
477     enum ProcessStep
478     {
479         STEP_NONE,    //! 未定義
480         STEP_UPDATE1, //! アップデート1回目(swapあり)
481         STEP_UPDATE2, //! アップデート2回目(swapなし)
482         STEP_DRAW     //! 描画
483     } m_ProcessStep;
484 #endif
485 
486 };
487 
488 } // namespace gfx
489 } // namespace nw
490 
491 #endif // NW_GFX_PARTICLESET_H_
492