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