1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ParticleCollection.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_PARTICLECOLLECTION_H_
19 #define NW_GFX_PARTICLECOLLECTION_H_
20 
21 #include <nw/gfx/gfx_GfxObject.h>
22 #include <nw/gfx/gfx_ParticleSet.h>
23 #include <nw/gfx/gfx_ParticleShape.h>
24 
25 #include <nw/gfx/res/gfx_ResParticleCollection.h>
26 
27 #include <nw/os.h>
28 
29 namespace nw
30 {
31 namespace gfx
32 {
33 
34 namespace internal
35 {
36 //! パーティクルで用いるショートベクタ演算の最大の処理単位です。
37 const int PARTICLE_SIMD_WIDTH_MAX = 8;
38 } // namespace internal
39 
40 class ParticleSet;
41 class ParticleCollection;
42 
43 //---------------------------------------------------------------------------
44 //! @brief        パーティクルの粒子の情報を表すクラスです。
45 //---------------------------------------------------------------------------
46 class ParticleCollection : public GfxObject
47 {
48 private:
49     NW_DISALLOW_COPY_AND_ASSIGN(ParticleCollection);
50 
51 public:
52     NW_UT_RUNTIME_TYPEINFO;
53 
54     //! @brief パーティクルのための属性情報です。
55     //! @details :private
56     struct ParticleAttribute
57     {
58         s32 m_Usage;
59         bool m_IsStream;
60         f32* m_Stream;
61     };
62 
63     //----------------------------------------
64     //! @name 作成/破棄
65     //@{
66 
67     //! @brief        リソースからParticleCollectionノードを生成します。
68     //!
69     //! @param[in]    parent 親のノードです。
70     //! @param[in]    resource リソースです。
71     //! @param[in]    mainAllocator メインアロケータです。
72     //! @param[in]    deviceAllocator デバイスアロケータです。
73     //! @param[in]    shape シェイプです。
74     //!
75     //! @return       生成されたParticleCollectionノードです。
76     //!
77     static ParticleCollection* Create(
78         ParticleSet* parent,
79         ResParticleCollection resource,
80         os::IAllocator* mainAllocator,
81         os::IAllocator* deviceAllocator,
82         ParticleShape* shape);
83 
84     //! @brief        生成時に必要なメモリサイズを取得します。
85     //! @param[in]    resource リソースです。
86     //! @param[in]    alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
87     //! @return       必要なメモリサイズです。
88     static size_t GetMemorySize(
89         ResParticleCollection resource,
90         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
91     {
92         os::MemorySizeCalculator size(alignment);
93 
94         GetMemorySizeInternal(&size, resource);
95 
96         return size.GetSizeWithPadding(alignment);
97     }
98 
99     //! @details :private
100     static void GetMemorySizeInternal(
101         os::MemorySizeCalculator* pSize,
102         ResParticleCollection resource);
103 
104     //! @brief        生成時に必要なデバイスメモリサイズを取得します。
105     //! @param[in]    resource リソースです。
106     //! @param[in]    alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
107     //! @return       必要なデバイスメモリサイズです。
108     static size_t GetDeviceMemorySize(
109         ResParticleCollection resource,
110         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
111     {
112         os::MemorySizeCalculator size(alignment);
113 
114         GetDeviceMemorySizeInternal(&size, resource);
115 
116         return size.GetSizeWithPadding(alignment);
117     }
118 
119     //! @details :private
120     static void GetDeviceMemorySizeInternal(
121         os::MemorySizeCalculator* pSize,
122         ResParticleCollection resource);
123 
124     //@}
125 
126     //----------------------------------------
127     //! @name リソース
128     //@{
129 
130     //! @brief リソースを取得します。
131     //! @return リソースを返します。
GetResParticleCollection()132     ResParticleCollection GetResParticleCollection()
133     {
134         return this->m_ResParticleCollection;
135     }
136 
137     //! @brief リソースを取得します。
138     //! @return リソースを返します。
GetResParticleCollection()139     const ResParticleCollection GetResParticleCollection() const
140     {
141         return this->m_ResParticleCollection;
142     }
143 
144     //@}
145 
146     //----------------------------------------
147     //! @name 取得/設定
148     //@{
149 
150     //! @brief パーティクル数の上限を取得します。
151     //! @return パーティクル数の上限を返します。
GetCapacity()152     int GetCapacity() const
153     {
154         return this->m_Capacity;
155     }
156 
157     //! @brief パーティクル数を取得します。
158     //! @return 現在のパーティクル数を返します。
GetCount()159     int GetCount() const
160     {
161         return this->m_Count;
162     }
163 
164     //! @brief パーティクル数を設定します。
165     //! @return 現在のパーティクル数を設定します。
166     //! @details :private
SetCount(int count)167     void SetCount(int count)
168     {
169         this->m_Count = count;
170     }
171 
172     //! @brief 有効なパーティクルのインデックスの最小値を取得します。
173     //! @details :private
GetMinActiveIndex()174     u16 GetMinActiveIndex() const
175     {
176         return this->m_MinActiveIndex;
177     }
178 
179     //! @brief 有効なパーティクルのインデックスの最大値を取得します。
180     //! @details :private
GetMaxActiveIndex()181     u16 GetMaxActiveIndex() const
182     {
183         return this->m_MaxActiveIndex;
184     }
185 
186     //! @brief 有効なパーティクルのインデックスの最小値を設定します。
187     //! @details :private
SetMinActiveIndex(u16 minActiveIndex)188     void SetMinActiveIndex(u16 minActiveIndex)
189     {
190         this->m_MinActiveIndex = minActiveIndex;
191     }
192 
193     //! @brief 有効なパーティクルのインデックスの最大値を設定します。
194     //! @details :private
SetMaxActiveIndex(u16 maxActiveIndex)195     void SetMaxActiveIndex(u16 maxActiveIndex)
196     {
197         this->m_MaxActiveIndex = maxActiveIndex;
198     }
199 
200     //! @brief 指定された属性がストリームかどうかを調べます。
201     //! @param[in] usage 利用種別です。
202     //! @return ストリームの場合はtrueを返します。
IsStream(ParticleUsage usage)203     bool IsStream(ParticleUsage usage) const
204     {
205         NW_ASSERT(usage >= 0 && usage < PARTICLEUSAGE_COUNT);
206 
207         return this->m_IsStream[usage];
208     }
209 
210     //! @details :private
GetBufferSide()211     bool GetBufferSide() const
212     {
213         return this->m_BufferSide;
214     }
215 
216     //! @details :private
GetLastBuffer()217     int GetLastBuffer() const
218     {
219         return this->m_LastBuffer;
220     }
221 
222     //! @details :private
SetLastBuffer(int value)223     void SetLastBuffer(int value)
224     {
225         this->m_LastBuffer = value;
226     }
227 
228     //! @brief 指定された属性のストリームのポインタを取得します。
229     //! @param[in] usage 利用種別です。
230     //! @param[in] side バッファの使用目的です。
231     //! @return ストリームを返します。
GetStreamPtr(ParticleUsage usage,ParticleBuffer side)232     void* GetStreamPtr(ParticleUsage usage, ParticleBuffer side)
233     {
234         NW_ASSERT(usage >= 0 && usage < PARTICLEUSAGE_COUNT);
235 
236         if (!this->m_IsStream[usage])
237         {
238             return NULL;
239         }
240 
241         if (this->m_BufferSide)
242         {
243             side = (ParticleBuffer)(1 - side);
244         }
245 
246         return this->m_StreamPtr[usage][side];
247     }
248 
249     //! @brief 指定された属性のストリームのポインタを取得します。
250     //! @param[in] usage 利用種別です。
251     //! @param[in] side バッファの使用目的です。
252     //! @return ストリームを返します。
GetStreamPtr(ParticleUsage usage,ParticleBuffer side)253     const void* GetStreamPtr(ParticleUsage usage, ParticleBuffer side) const
254     {
255         NW_ASSERT(usage >= 0 && usage < PARTICLEUSAGE_COUNT);
256 
257         if (!this->m_IsStream[usage])
258         {
259             return NULL;
260         }
261 
262         if (this->m_BufferSide)
263         {
264             side = (ParticleBuffer)(1 - side);
265         }
266 
267         return this->m_StreamPtr[usage][side];
268     }
269 
270     //! @brief 指定された属性のパラメータへのポインタを取得します。
271     //! @param[in] usage 利用種別です。
272     //! @return パラメータへのポインタを返します。
GetParameterPtr(ParticleUsage usage)273     const void* GetParameterPtr(ParticleUsage usage) const
274     {
275         NW_ASSERT(usage >= 0 && usage < PARTICLEUSAGE_COUNT);
276 
277         if (this->m_IsStream[usage])
278         {
279             return NULL;
280         }
281 
282         return this->m_StreamPtr[usage][0];
283     }
284 
285     //! @brief 指定された属性のパラメータを設定します。
286     //! @details :private
287     //! @param[in] usage 利用種別です。
288     //! @param[in] side バッファの使用目的です。
289     //! @param[in] ptr 新しいパラメータへのポインタです。
290     void SetParameter(ParticleUsage usage, ParticleBuffer side, const f32* ptr);
291 
292     //! @brief PARTICLEUSAGE_LIFEのパラメータを設定します。
293     //! @details LIFEがストリームの場合は効果はありません。
294     //! @param[in] ptr 新しいパラメータへのポインタです。
SetLifeParameter(const ParticleTime * ptr)295     void SetLifeParameter(const ParticleTime* ptr)
296     {
297         SetParameter(PARTICLEUSAGE_LIFE, PARTICLE_BUFFER_FRONT, (const f32*)ptr);
298     }
299 
300     //! @brief 指定された属性のストリームまたはパラメータを取得します。
301     //! @details パラメータの場合には、streamにはNULLが格納されます。
302     //! @param[in] usage 利用種別です。
303     //! @param[out] stream ストリームの場合にポインタを格納するポインタです。
304     //! @param[out] param パラメータの場合にパラメータを格納するポインタです。
305     //! @param[in] side バッファの使用目的です。
306     //! @return ストリームの場合は、ストリームへのポインタを返します。パラメータの場合はパラメータを返します。
307     template <class T>
GetStreamOrParameter(ParticleUsage usage,T ** stream,T * param,ParticleBuffer side)308     NW_FORCE_INLINE bool GetStreamOrParameter(ParticleUsage usage, T** stream, T* param, ParticleBuffer side)
309     {
310         if (this->m_IsStream[usage])
311         {
312             if (this->m_BufferSide)
313             {
314                 side = (ParticleBuffer)(1 - side);
315             }
316 
317             *stream = (T*)this->m_StreamPtr[usage][side];
318         }
319         else
320         {
321             *stream = NULL;
322             if (param != NULL && m_StreamPtr[usage][0] != NULL)
323             {
324                 memcpy(param, this->m_StreamPtr[usage][0], sizeof(T));
325             }
326         }
327         return true;
328     }
329 
330     //! @brief 全てのストリームを初期化します。
331     //! @details ストリームの状態を初期化します。この関数は描画中には使用できません。
332     //!          GPUからストリームへのアクセスがない状態で使用してください。
333     void Clear();
334 
335     //! @brief 計算用と描画用の対象となるバッファを入れ替えます。
336     //! @details :private
SwapBuffer()337     void SwapBuffer()
338     {
339         ParticleShape* shape = this->m_ParticleShape;
340 
341         ParticleBuffer side = PARTICLE_BUFFER_FRONT;
342         if (this->m_BufferSide)
343         {
344             side = (ParticleBuffer)(1 - side);
345         }
346 
347         this->m_BufferSide = !this->m_BufferSide;
348         shape->SetBufferSide(this->m_BufferSide);
349 
350         int size = this->GetMaxActiveIndex() + 1;
351         for (int usage = 0; usage < PARTICLEUSAGE_COUNT; ++usage)
352         {
353             void* src = this->m_StreamPtr[usage][side];
354             void* dst = this->m_StreamPtr[usage][(ParticleBuffer)(1 - side)];
355 
356             if (usage != PARTICLEUSAGE_ACTIVEINDEX)
357             {
358                 if (src != dst)
359                 {
360                     nw::os::MemCpy(dst, src, this->m_StreamStride[usage] * size);
361                 }
362             }
363         }
364 
365         this->m_LastBuffer = 1 - this->m_LastBuffer;
366     }
367 
368     //! @brief 生成済み全てのパーティクル粒子を削除します。
369     //! @detail 次回の削除処理で実際に削除されます。
370     //! その前に、チャイルドパーティクルの放出処理があれば、終了時として扱われます。
KillParticles()371     void KillParticles()
372     {
373         NW_NULL_ASSERT(m_ParticleSet);
374         ParticleModel* model = static_cast<ParticleModel*>(m_ParticleSet->GetParent());
375         NW_NULL_ASSERT(model);
376         ParticleTime time = model->ParticleAnimFrameController().GetFrame();
377 
378         u16* activeIndex = (u16*)this->GetStreamPtr(
379             nw::gfx::PARTICLEUSAGE_ACTIVEINDEX,nw::gfx::PARTICLE_BUFFER_FRONT);
380         NW_NULL_ASSERT(activeIndex);
381 
382 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
383         ParticleTime* negtime =
384             (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_NEG_TIMELIMIT, PARTICLE_BUFFER_FRONT);
385         NW_NULL_ASSERT(negtime);
386 
387         for (s32 i = 0; i < m_Count; ++i)
388         {
389             int convertedIndex = activeIndex[i];
390 
391             // -timeで消えるが念のためマージンを設ける
392             negtime[convertedIndex] = -time + 1.0f;
393         }
394 #else
395         ParticleTime* birth =
396             (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
397         NW_NULL_ASSERT(birth);
398 
399         ParticleTime lifeParam;
400         if (this->IsStream(PARTICLEUSAGE_LIFE))
401         {
402             ParticleTime* life =
403                 (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_LIFE, PARTICLE_BUFFER_FRONT);
404 
405             for (s32 i = 0; i < m_Count; ++i)
406             {
407                 int convertedIndex = activeIndex[i];
408                 lifeParam = life[convertedIndex];
409                 birth[convertedIndex] = time - lifeParam - 1;
410             }
411         }
412         else
413         {
414             lifeParam = *(ParticleTime*)this->GetParameterPtr(PARTICLEUSAGE_LIFE);
415             for (s32 i = 0; i < m_Count; ++i)
416             {
417                 int convertedIndex = activeIndex[i];
418                 birth[convertedIndex] = time - lifeParam - 1;
419             }
420         }
421 #endif
422     }
423 
424     //! @brief 指定したインデックスのパーティクル粒子を削除します。
425     //! @detail 次回の削除処理で実際に削除されます。
426     //! その前に、チャイルドパーティクルの放出処理があれば、終了時として扱われます。
427     //! @param[in] index ACTIVEINDEXが指し示すインデックスです。
KillParticle(int index)428     void KillParticle(int index)
429     {
430         NW_NULL_ASSERT(m_ParticleSet);
431         ParticleModel* model = static_cast<ParticleModel*>(m_ParticleSet->GetParent());
432         NW_NULL_ASSERT(model);
433         ParticleTime time = model->ParticleAnimFrameController().GetFrame();
434 
435 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
436         ParticleTime* negtime =
437             (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_NEG_TIMELIMIT, PARTICLE_BUFFER_FRONT);
438         NW_NULL_ASSERT(negtime);
439 
440         negtime[index] = -time + 1.0f; // -timeで消えるが念のためマージンを設ける
441 #else
442         ParticleTime* birth =
443             (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
444         NW_NULL_ASSERT(birth);
445 
446         ParticleTime lifeParam;
447         if (this->IsStream(PARTICLEUSAGE_LIFE))
448         {
449             ParticleTime* life =
450                 (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_LIFE, PARTICLE_BUFFER_FRONT);
451             lifeParam = life[index];
452         }
453         else
454         {
455             lifeParam = *(ParticleTime*)this->GetParameterPtr(PARTICLEUSAGE_LIFE);
456         }
457 
458         birth[index] = time - lifeParam - 1;
459 #endif
460     }
461 
462     //@}
463 
464 protected:
465     //----------------------------------------
466     //! @name コンストラクタ/デストラクタ
467     //@{
468 
469     //! @brief コンストラクタです。
470     ParticleCollection(
471         os::IAllocator* allocator,
472         os::IAllocator* deviceAllocator,
473         void* deviceMemory,
474         ResParticleCollection resObj);
475 
476     //! @brief デストラクタです。
477     virtual ~ParticleCollection();
478 
479     //@}
480 private:
481     ParticleAttribute m_ParticleAttribute[PARTICLEUSAGE_COUNT];
482     int m_Capacity;
483     int m_Count;
484     bool m_BufferSide;
485     bool m_IsStream[PARTICLEUSAGE_COUNT];
486     void* m_StreamPtr[PARTICLEUSAGE_COUNT][2];
487     int m_StreamStride[PARTICLEUSAGE_COUNT];
488 
489     u16 m_MinActiveIndex;
490     u16 m_MaxActiveIndex;
491 
492     ResParticleCollection m_ResParticleCollection;
493     ParticleShape* m_ParticleShape;
494     ParticleSet* m_ParticleSet;
495 
496     os::IAllocator* m_DeviceAllocator;
497     void* m_DeviceMemory;
498 
499     int m_LastBuffer;
500 };
501 
502 } // namespace gfx
503 } // namespace nw
504 
505 #endif // NW_GFX_PARTICLECOLLECTION_H_
506