1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ParticleEmitter.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_PARTICLEEMITTER_H_
17 #define NW_GFX_PARTICLEEMITTER_H_
18 
19 #include <nw/gfx/gfx_TransformNode.h>
20 
21 #include <nw/gfx/res/gfx_ResParticleEmitter.h>
22 #include <nw/gfx/gfx_ParticleCollection.h>
23 #include <nw/gfx/gfx_ParticleRandom.h>
24 #include <nw/anim/anim_AnimFrameController.h>
25 
26 namespace nw
27 {
28 namespace gfx
29 {
30 class ParticleEmitter;
31 
32 //---------------------------------------------------------------------------
33 //! @brief        パーティクルエミッタを表すクラスです。
34 //---------------------------------------------------------------------------
35 class ParticleEmitter : public TransformNode
36 {
37 private:
38     NW_DISALLOW_COPY_AND_ASSIGN(ParticleEmitter);
39 
40 public:
41     NW_UT_RUNTIME_TYPEINFO;
42 
43     //! @brief 設定内容です。
44     struct Description : public TransformNode::Description
45     {
46         //! @brief コンストラクタです。
DescriptionDescription47         Description()
48         {}
49     };
50 
51     //----------------------------------------
52     //! @name 作成/破棄
53     //@{
54 
55     //! @brief        リソースからParticleEmitterノードを生成します。
56     //!
57     //! @param[in]    parent 親のノードです。
58     //! @param[in]    resource リソースです。
59     //! @param[in]    description 設定内容です。
60     //! @param[in]    allocator アロケータです。
61     //!
62     //! @return       生成されたParticleEmitterノードです。
63     //!
64     static ParticleEmitter* Create(
65         SceneNode* parent,
66         ResSceneObject resource,
67         const ParticleEmitter::Description& description,
68         os::IAllocator* allocator);
69 
70     //! @brief        生成時に必要なデバイスメモリサイズを取得します。
71     //! @param[in]    resource リソースです。
72     //! @param[in]    description 設定内容です。
73     //! @param[in]    alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
74     //! @return       必要なデバイスメモリサイズです。
75     static size_t GetMemorySize(
76         ResParticleEmitter resource,
77         const ParticleEmitter::Description& description,
78         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
79     {
80         os::MemorySizeCalculator size(alignment);
81 
82         GetMemorySizeInternal(&size, resource, description);
83 
84         return size.GetSizeWithPadding(alignment);
85     }
86 
87     //! @details :private
88     static void GetMemorySizeInternal(
89         os::MemorySizeCalculator* pSize,
90         ResParticleEmitter resource,
91         const ParticleEmitter::Description& description);
92 
93     //@}
94 
95     //----------------------------------------
96     //! @name 更新
97     //@{
98 
99     //! @brief        ビジターを受け付けます。
100     //!
101     //! @param[in]    visitor ビジターです。
102     //!
103     virtual void Accept(ISceneVisitor* visitor);
104 
105     //! フレームを更新します。
UpdateParticleFrame()106     void UpdateParticleFrame()
107     {
108         m_ParticleAnimFrameController.UpdateFrame();
109     }
110 
111     //! エミッタを初期状態に戻します。
Reset()112     void Reset()
113     {
114         m_IsFirstEmission = true;
115         m_EmissionCount = 0;
116         m_NextEmissionTime = 0;
117 
118         // フレームコントローラはFrameを0にするだけです。
119         m_ParticleAnimFrameController.SetFrame(0);
120     }
121 
122     //@}
123 
124     //----------------------------------------
125     //! @name 取得/設定
126     //@{
127 
128     //! @brief 放出量を計算します。
129     //!
130     //! @param[in]    prevTime 前回の時刻です。
131     //! @param[in]    time 現在の時刻です。
132     //!
133     //! @return       放出量を返します。
134     int GetEmissionCount(f32 prevTime, f32 time);
135 
136     //! @brief リソースを取得します。
137     //! @return リソースを返します。
GetResParticleEmitter()138     ResParticleEmitter GetResParticleEmitter()
139     {
140         return ResDynamicCast<ResParticleEmitter>( this->GetResSceneObject() );
141     }
142 
143     //! @brief リソースを取得します。
144     //! @return リソースを返します。
GetResParticleEmitter()145     const ResParticleEmitter GetResParticleEmitter() const
146     {
147         return ResDynamicCast<ResParticleEmitter>( this->GetResSceneObject() );
148     }
149 
150     //! @brief 放出先のParticleSetを設定します。
151     //!
152     //! @param[in]    particleSet 放出先のParticleSetです。
153     //!
SetParticleSet(ParticleSet * particleSet)154     void SetParticleSet(ParticleSet* particleSet)
155     {
156         this->m_ParticleSet = particleSet;
157     }
158 
159     //! @brief 放出先のParticleSetを取得します。
160     //! @return 放出先のParticleSetを返します。
GetParticleSet()161     ParticleSet* GetParticleSet()
162     {
163         return this->m_ParticleSet;
164     }
165 
166     //! @brief 放出先のParticleSetを取得します。
167     //! @return 放出先のParticleSetを返します。
GetParticleSet()168     const ParticleSet* GetParticleSet() const
169     {
170         return this->m_ParticleSet;
171     }
172 
173     //! @brief アニメーションフレーム制御情報を取得します。
174     //! @return アニメーションフレームコントローラを返します。
ParticleAnimFrameController()175     anim::AnimFrameController& ParticleAnimFrameController()
176     {
177         return m_ParticleAnimFrameController;
178     }
179 
180     //! @brief アニメーションフレーム制御情報を取得します。
181     //! @return アニメーションフレームコントローラを返します。
ParticleAnimFrameController()182     const anim::AnimFrameController& ParticleAnimFrameController() const
183     {
184         return m_ParticleAnimFrameController;
185     }
186 
187     //! @brief 放出パラメータのリソースを取得します。
188     // ここで取得したリソースは保持しないでください。
189     //! @param[in] copyOnly 複製の場合のみ取得します。
190     //! @return リソースを返します。
191     ResParticleEmitterParameter GetResParticleEmitterParameterCopy(bool copyOnly = false)
192     {
193         if (m_ResParameter.IsValid())
194         {
195             return m_ResParameter;
196         }
197 
198         if (!copyOnly && this->GetResParticleEmitter().IsValid())
199         {
200             return ResParticleEmitterParameter(&this->GetResParticleEmitter().ptr()->m_IsResourceCopyEnabled);
201         }
202 
203         return m_ResParameter; // invalid
204     }
205 
206     //! @brief 放出パラメータのリソースを取得します。
207     // ここで取得したリソースは保持しないでください。
208     //! @param[in] copyOnly 複製の場合のみ取得します。
209     //! @return リソースを返します。
210     const ResParticleEmitterParameter GetResParticleEmitterParameterCopy(bool copyOnly = false) const
211     {
212         if (m_ResParameter.IsValid())
213         {
214             return m_ResParameter;
215         }
216 
217         if (!copyOnly && this->GetResParticleEmitter().IsValid())
218         {
219             return ResParticleEmitterParameter(&this->GetResParticleEmitter().ptr()->m_IsResourceCopyEnabled);
220         }
221 
222         return m_ResParameter; // invalid
223     }
224 
225     //! @brief 形状のリソースを取得します。
226     // ここで取得したリソースは保持しないでください。
227     //! @param[in] copyOnly 複製の場合のみ取得します。
228     //! @return リソースを返します。
229     ResParticleForm GetResParticleFormCopy(bool copyOnly = false)
230     {
231         if (m_ResForm.IsValid())
232         {
233             return m_ResForm;
234         }
235 
236         if (!copyOnly && this->GetResParticleEmitter().IsValid())
237         {
238             return this->GetResParticleEmitter().GetParticleForm();
239         }
240 
241         return m_ResForm; // invalid
242     }
243 
244     //! @brief 形状のリソースを取得します。
245     // ここで取得したリソースは保持しないでください。
246     //! @param[in] copyOnly 複製の場合のみ取得します。
247     //! @return リソースを返します。
248     const ResParticleForm GetResParticleFormCopy(bool copyOnly = false) const
249     {
250         if (m_ResForm.IsValid())
251         {
252             return m_ResForm;
253         }
254 
255         if (!copyOnly && this->GetResParticleEmitter().IsValid())
256         {
257             return this->GetResParticleEmitter().GetParticleForm();
258         }
259 
260         return m_ResForm; // invalid
261     }
262 
263     //! @details :private
Srand(u32 seed)264     void Srand(u32 seed)
265     {
266         m_ParticleRandom.Srand(seed);
267     }
268 
269     //! @brief パーティクルの放出時間が終了していないことを調べます。
270     //! @return 放出が終了していなければtrueを返します。
IsAlive()271     bool IsAlive() const
272     {
273         const ResParticleEmitterParameter resource = this->GetResParticleEmitterParameterCopy(false);
274         if (!resource.IsValid())
275         {
276             return false;
277         }
278 
279         if (resource.GetEmissionRatio() == 0)
280         {
281             return false;
282         }
283 
284         if (resource.GetEmissionSpanInfinity())
285         {
286             return true;
287         }
288 
289         f32 time = m_ParticleAnimFrameController.GetFrame();
290         f32 cookedTime = time - resource.GetEmissionStart() - 1;
291         if (cookedTime >= resource.GetEmissionSpan())
292         {
293             return false;
294         }
295 
296         return true;
297     }
298 
299     //@}
300 
301     //----------------------------------------
302     //! @name 放出
303     //@{
304 
305     //! @brief 放出処理を行います。
306     //! @param[in]    particleContext パーティクルコンテキストです。
307     //!
308     //! @return       放出量を返します。
309     int Emission(ParticleContext* particleContext);
310 
311     //@}
312 
313     //----------------------------------------
314     //! @name エミッタ形状
315     //@{
316 
317 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
318     //! @details :private
319     static void CalcCubeForm(
320         const ResParticleCubeForm& cubeForm,
321         int emissionCount,
322         ParticleRandom* random,
323         nw::math::VEC3* positions);
324 
325     //! @details :private
326     static void CalcCylinderForm(
327         const ResParticleCylinderForm& cylinderForm,
328         int emissionCount,
329         ParticleRandom* random,
330         nw::math::VEC3* positions);
331 
332     //! @details :private
333     static void CalcDiscForm(
334         const ResParticleDiscForm& discForm,
335         int emissionCount,
336         ParticleRandom* random,
337         nw::math::VEC3* positions);
338 
339     //! @details :private
340     static void CalcPointForm(
341         const ResParticlePointForm& pointForm,
342         int emissionCount,
343         ParticleRandom* random,
344         nw::math::VEC3* positions);
345 
346     //! @details :private
347     static void CalcSphereForm(
348         const ResParticleSphereForm& sphereForm,
349         int emissionCount,
350         ParticleRandom* random,
351         nw::math::VEC3* positions);
352 
353     //! @details :private
354     static void CalcRectangleForm(
355         const ResParticleRectangleForm& rectangleForm,
356         int emissionCount,
357         ParticleRandom* random,
358         nw::math::VEC3* positions);
359 #else
360     //! @details :private
361     static void CalcCubeForm(
362         const ResParticleCubeForm& cubeForm,
363         int emissionCount,
364         ParticleRandom* random,
365         u16* activeIndex,
366         int incrIndex,
367         nw::math::VEC3* targetTranslate);
368 
369     //! @details :private
370     static void CalcCylinderForm(
371         const ResParticleCylinderForm& cylinderForm,
372         int emissionCount,
373         ParticleRandom* random,
374         u16* activeIndex,
375         int incrIndex,
376         nw::math::VEC3* targetTranslate);
377 
378     //! @details :private
379     static void CalcDiscForm(
380         const ResParticleDiscForm& discForm,
381         int emissionCount,
382         ParticleRandom* random,
383         u16* activeIndex,
384         int incrIndex,
385         nw::math::VEC3* targetTranslate);
386 
387     //! @details :private
388     static void CalcPointForm(
389         const ResParticlePointForm& pointForm,
390         int emissionCount,
391         ParticleRandom* random,
392         u16* activeIndex,
393         int incrIndex,
394         nw::math::VEC3* targetTranslate);
395 
396     //! @details :private
397     static void CalcSphereForm(
398         const ResParticleSphereForm& sphereForm,
399         int emissionCount,
400         ParticleRandom* random,
401         u16* activeIndex,
402         int incrIndex,
403         nw::math::VEC3* targetTranslate);
404 
405     //! @details :private
406     static void CalcRectangleForm(
407         const ResParticleRectangleForm& rectangleForm,
408         int emissionCount,
409         ParticleRandom* random,
410         u16* activeIndex,
411         int incrIndex,
412         nw::math::VEC3* targetTranslate);
413 #endif
414 
415     //@}
416 
417 protected:
418     //----------------------------------------
419     //! @name コンストラクタ/デストラクタ
420     //@{
421 
422     //! @brief コンストラクタです。
423     //! @param[in] allocator メモリアロケータです。
424     //! @param[in] resObj エミッタのリソースです。
425     //! @param[in] description ディスクリプションです。
426     //! @param[in] resParameterObj エミッタパラメータのリソースです。
427     //! @param[in] resFormObj 形状のリソースです。
428     ParticleEmitter(
429         os::IAllocator* allocator,
430         ResParticleEmitter resObj,
431         const ParticleEmitter::Description& description,
432         ResParticleEmitterParameter resParameterObj,
433         ResParticleForm resFormObj);
434 
435     //! @brief デストラクタです。
436     virtual ~ParticleEmitter();
437 
438     //@}
439 
440 private:
441     bool m_IsFirstEmission;
442     f32 m_EmissionCount;
443     s32 m_NextEmissionTime;
444     ParticleSet* m_ParticleSet;
445 
446     ParticleRandom m_ParticleRandom;
447     anim::AnimFrameController m_ParticleAnimFrameController;
448 
449     ResParticleEmitterParameter m_ResParameter;
450     ResParticleForm m_ResForm;
451 };
452 
453 } // namespace gfx
454 } // namespace nw
455 
456 #endif // NW_GFX_PARTICLEEMITTER_H_
457