1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ParticleShape.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_PARTICLESHAPE_H_
17 #define NW_GFX_PARTICLESHAPE_H_
18 
19 #include <nw/gfx/gfx_SceneObject.h>
20 #include <nw/gfx/res/gfx_ResParticleShape.h>
21 #include <nw/gfx/res/gfx_ResParticleUpdater.h>
22 
23 namespace nw
24 {
25 namespace gfx
26 {
27 class ParticleShape;
28 class ParticleSet;
29 
30 //! @brief パーティクルのバッファの種別です。
31 enum ParticleBuffer
32 {
33     PARTICLE_BUFFER_FRONT = 0, //!< 計算用バッファです。
34     PARTICLE_BUFFER_BACK      //!< 描画用バッファです。
35 };
36 
37 //---------------------------------------------------------------------------
38 //! @brief        パーティクルのためのシェイプを表すクラスです。
39 //! @details      ParticleCollectionを使い、このクラスは利用しないようにしてください。
40 //---------------------------------------------------------------------------
41 class ParticleShape : public SceneObject
42 {
43 private:
44     NW_DISALLOW_COPY_AND_ASSIGN(ParticleShape);
45 
46 public:
47     NW_UT_RUNTIME_TYPEINFO;
48 
49     //! @brief パーティクルのための頂点バッファ情報です。
50     //! @details :private
51     struct VertexAttribute
52     {
53         s32 m_Usage;
54         u32 m_FormatType;
55         u8 m_Dimension;
56         bool m_IsStream;
57         u8* m_Stream[2];
58         void* m_CommandPtr[2]; //< コマンド上でのこのデータの先頭アドレス
59     };
60 
61     //----------------------------------------
62     //! @name 作成
63     //@{
64 
65     //! @brief        リソースからパーティクルシェイプノードを生成します。
66     //!
67     //! @param[in]    resource リソースです。
68     //! @param[in]    capacity 最大頂点数です。
69     //! @param[in]    mainAllocator メインメモリのアロケータです。
70     //! @param[in]    deviceAllocator デバイスメモリのアロケータです。
71     //!
72     //! @return       生成されたトランスフォームノードです。
73     //!
74     static ParticleShape* Create(
75         ResSceneObject resource,
76         int capacity,
77         os::IAllocator* mainAllocator,
78         os::IAllocator* deviceAllocator);
79 
80     //! @brief        生成時に必要なメモリサイズを取得します。
81     //! @param[in]    capacity 最大頂点数です。
82     //! @param[in]    alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
83     //! @return       必要なメモリサイズです。
84     static size_t GetMemorySize(
85         int capacity,
86         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
87     {
88         os::MemorySizeCalculator size(alignment);
89 
90         GetMemorySizeInternal(&size, capacity);
91 
92         return size.GetSizeWithPadding(alignment);
93     }
94 
95     //! @details :private
96     static void GetMemorySizeInternal(
97         os::MemorySizeCalculator* pSize,
98         int capacity);
99 
100     //! @brief        生成時に必要なデバイスメモリサイズを取得します。
101     //! @param[in]    capacity 最大頂点数です。
102     //! @param[in]    alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
103     //! @return       必要なデバイスメモリサイズです。
104     static size_t GetDeviceMemorySize(
105         int capacity,
106         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
107     {
108         os::MemorySizeCalculator size(alignment);
109 
110         GetDeviceMemorySizeInternal(&size, capacity);
111 
112         return size.GetSizeWithPadding(alignment);
113     }
114 
115     //! @details :private
116     static void GetDeviceMemorySizeInternal(
117         os::MemorySizeCalculator* pSize,
118         int capacity);
119 
120     //! @details :private
121     static int AddVertexStreamSize(
122         u32 formatType,
123         int dimension,
124         int capacity,
125         int prevSize);
126 
127     //! @details :private
128     static int AddVertexParamSize(
129         u32 formatType,
130         int dimension,
131         int prevSize);
132 
133     //! @details :private
134     VertexAttribute* AddVertexStream(
135         s32 usage,
136         u32 formatType,
137         int dimension,
138         int capacity,
139         u8** memory);
140 
141     //! @details :private
142     VertexAttribute* AddVertexParam(
143         s32 usage,
144         u32 formatType,
145         int dimension,
146         f32* parameters,
147         u8** memory);
148 
149     //@}
150 
151     //----------------------------------------
152     //! @name 取得/設定
153     //@{
154 
155     //! @brief リソースを取得します。
156     //! @return パーティクルシェイプのリソースです。
GetResParticleShape()157     ResParticleShape GetResParticleShape()
158     {
159         return ResDynamicCast<ResParticleShape>( this->GetResSceneObject() );
160     }
161 
162     //! @brief リソースを取得します。
163     //! @return パーティクルシェイプのリソースです。
GetResParticleShape()164     const ResParticleShape GetResParticleShape() const
165     {
166         return ResDynamicCast<ResParticleShape>( this->GetResSceneObject() );
167     }
168 
169     //! @brief 頂点アトリビュートの個数を取得します。
170     //! @return 頂点アトリビュートの個数です。
GetVertexAttributesCount()171     int GetVertexAttributesCount() const
172     {
173         return this->m_ResVertexAttributeDataCount;
174     }
175 
176     //! @brief 頂点アトリビュートがストリームかどうかを調べます。
177     //! @param[in] index インデックスです。
178     //! @return 頂点アトリビュートがストリームの場合はtrueを返します。
IsVertexStream(int index)179     bool IsVertexStream(int index)
180     {
181         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
182         return this->m_VertexAttribute[index].m_IsStream;
183     }
184 
185     //! @brief 頂点アトリビュートの利用種別を取得します。
186     //! @param[in] index インデックスです。
187     //! @return 頂点アトリビュートの利用種別です。
GetVertexAttributeUsage(int index)188     s32 GetVertexAttributeUsage(int index)
189     {
190         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
191         return this->m_VertexAttribute[index].m_Usage;
192     }
193 
194     //! @brief 頂点アトリビュートのフォーマットを取得します。
195     //! @param[in] index インデックスです。
196     //! @return 頂点アトリビュートのフォーマットです。
GetVertexAttributeFormatType(int index)197     u32 GetVertexAttributeFormatType(int index)
198     {
199         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
200         return this->m_VertexAttribute[index].m_FormatType;
201     }
202 
203     //! @brief 頂点アトリビュートの次元を取得します。
204     //! @param[in] index インデックスです。
205     //! @return 頂点アトリビュートの次元です。
GetVertexAttributeDimension(int index)206     u8 GetVertexAttributeDimension(int index)
207     {
208         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
209         return this->m_VertexAttribute[index].m_Dimension;
210     }
211 
212     //! @brief 頂点アトリビュートのストリームのポインタを取得します。
213     //! @param[in] index インデックスです。
214     //! @param[in] side バッファの使用目的です。
215     //! @return 頂点アトリビュートのストリームへのポインタです。
GetVertexStreamPtr(int index,ParticleBuffer side)216     u8* GetVertexStreamPtr(int index, ParticleBuffer side)
217     {
218         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
219         NW_ASSERT(side >= 0 && side <= 1);
220         if (!this->m_VertexAttribute[index].m_IsStream)
221         {
222             return NULL;
223         }
224 
225         if (this->m_BufferSide)
226         {
227             side = (ParticleBuffer)(1 - side);
228         }
229 
230         return this->m_VertexAttribute[index].m_Stream[side];
231     }
232 
233     //! @brief 頂点アトリビュートのストリームのポインタを取得します。
234     //! @param[in] index インデックスです。
235     //! @param[in] side バッファの使用目的です。
236     //! @return 頂点アトリビュートのストリームへのポインタです。
GetVertexStreamPtr(int index,ParticleBuffer side)237     const u8* GetVertexStreamPtr(int index, ParticleBuffer side) const
238     {
239         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
240         NW_ASSERT(side >= 0 && side <= 1);
241         if (!this->m_VertexAttribute[index].m_IsStream)
242         {
243             return NULL;
244         }
245 
246         if (this->m_BufferSide)
247         {
248             side = (ParticleBuffer)(1 - side);
249         }
250 
251         return this->m_VertexAttribute[index].m_Stream[side];
252     }
253 
254     //! @brief 頂点アトリビュートのパラメータを取得します。
255     //! @param[in] index インデックスです。
256     //! @return 頂点アトリビュートのストリームへのポインタです。
GetVertexParameter(int index)257     f32* GetVertexParameter(int index)
258     {
259         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
260         if (this->m_VertexAttribute[index].m_IsStream)
261         {
262             return NULL;
263         }
264 
265         return reinterpret_cast<f32*>(this->m_VertexAttribute[index].m_Stream[0]);
266     }
267 
268     //! @brief 頂点アトリビュートのパラメータを取得します。
269     //! @param[in] index インデックスです。
270     //! @return 頂点アトリビュートのストリームへのポインタです。
GetVertexParameter(int index)271     const f32* GetVertexParameter(int index) const
272     {
273         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
274         if (this->m_VertexAttribute[index].m_IsStream)
275         {
276             return NULL;
277         }
278 
279         return reinterpret_cast<const f32*>(this->m_VertexAttribute[index].m_Stream[0]);
280     }
281 
282     //! @brief 頂点アトリビュートのパラメータを設定します。
283     //! @details :private
284     //! @param[in] index インデックスです。
285     //! @param[in] side バッファの使用目的です。
286     //! @param[in] ptr 新しいパラメータへのポインタです。
SetVertexParameter(int index,ParticleBuffer side,const f32 * ptr)287     void SetVertexParameter(int index, ParticleBuffer side, const f32* ptr)
288     {
289         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
290         NW_ASSERT(side >= 0 && side <= 1);
291         if (this->m_VertexAttribute[index].m_IsStream)
292         {
293             return;
294         }
295 
296         if (this->m_BufferSide)
297         {
298             side = (ParticleBuffer)(1 - side);
299         }
300 
301         int count = this->GetVertexAttributeDimension(index);
302         f32* fdata = this->GetVertexParameter(index);
303 
304         u32 data[4] = { 0, 0, 0, 0 };
305 
306         for (int j = 0; j < count; ++j)
307         {
308             fdata[j] = ptr[j];
309             data[j] = ut::Float24::Float32ToBits24(fdata[j]);
310         }
311 
312         u32* target = reinterpret_cast<u32*>(
313             this->m_VertexAttribute[index].m_CommandPtr[side]);
314 
315         *target++ = (data[3] <<  8) | (data[2] >> 16);
316         *target++ = (data[2] << 16) | (data[1] >> 8);
317         *target = (data[1] << 24) | (data[0]);
318     }
319 
320     //! :private
SetVertexAttributeCommandPtr(int index,int side,void * ptr)321     void* SetVertexAttributeCommandPtr(int index, int side, void* ptr)
322     {
323         NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount);
324         NW_ASSERT(side >= 0 && side <= 1);
325         return this->m_VertexAttribute[index].m_CommandPtr[side] = ptr;
326     }
327 
328     //! @brief プリミティブのストリームのポインタを取得します。
329     //! @param[in] side バッファの使用目的です。
330     //! @return プリミティブのストリームへのポインタです。
GetPrimitiveStreamPtr(ParticleBuffer side)331     u8* GetPrimitiveStreamPtr(ParticleBuffer side)
332     {
333         NW_ASSERT(side >= 0 && side <= 1);
334         if (this->m_BufferSide)
335         {
336             side = (ParticleBuffer)(1 - side);
337         }
338         return this->m_PrimitiveBuffer[side];
339     }
340 
341     //! @brief プリミティブのストリームのポインタを取得します。
342     //! @param[in] side バッファの使用目的です。
343     //! @return プリミティブのストリームへのポインタです。
GetPrimitiveStreamPtr(ParticleBuffer side)344     const u8* GetPrimitiveStreamPtr(ParticleBuffer side) const
345     {
346         NW_ASSERT(side >= 0 && side <= 1);
347         if (this->m_BufferSide)
348         {
349             side = (ParticleBuffer)(1 - side);
350         }
351         return this->m_PrimitiveBuffer[side];
352     }
353 
354     //! @brief GPUコマンド発行のためのプリミティブのストリームのオフセットを取得します。
355     //! @details :private
356     //! @param[in] side バッファの使用目的です。
357     //! @return プリミティブのストリームへのポインタです。
GetPrimitiveStreamOffset(ParticleBuffer side)358     u32 GetPrimitiveStreamOffset(ParticleBuffer side) const
359     {
360         NW_ASSERT(side >= 0 && side <= 1);
361         if (this->m_BufferSide)
362         {
363             side = (ParticleBuffer)(1 - side);
364         }
365         return this->m_PrimitiveBufferOffset[side];
366     }
367 
368     //! @brief 各ストリームに格納できるパーティクル数の上限を取得します。
369     //! @return パーティクル数の上限です。
GetVertexCapacity()370     int GetVertexCapacity() const
371     {
372         return m_Capacity;
373     }
374 
375     //! @brief 計算用と描画用の対象となるバッファを入れ替えます。
SetBufferSide(bool swap)376     void SetBufferSide(bool swap)
377     {
378         this->m_BufferSide = swap;
379     }
380 
381     //! @brief 表面のバッファ番号を取得します。
382     //! @return 表面のバッファ番号です。
GetBufferSide()383     int GetBufferSide() const
384     {
385         return this->m_BufferSide ? 1 : 0;
386     }
387 
388     //! @brief コマンドキャッシュを生成します。
389     //! @details :private
390     void CreateCommandCache(ParticleSet* particleSet);
391 
392     //! @brief バッファをフラッシュします。
393     //! @details :private
394     void FlushBuffer();
395 
396     //@}
397 
398     void* m_CommandCache[2];
399     s32   m_CommandCacheSize[2];
400 
401     void* m_DeactivateVertexCommandCache;
402     s32   m_DeactivateVertexCommandCacheSize;
403 
404     void* m_PrimitiveCommandCache;
405     s32   m_PrimitiveCommandCacheSize;
406 
407 protected:
408     //----------------------------------------
409     //! @name コンストラクタ/デストラクタ
410     //@{
411 
412     //! コンストラクタです。
413     ParticleShape(
414         int capacity,
415         os::IAllocator* allocator,
416         os::IAllocator* deviceAllocator,
417         void* deviceMemory,
418         ResParticleShape resObj);
419 
420     //! デストラクタです。
421     virtual ~ParticleShape();
422 
423     //@}
424 
425 private:
426     //! @brief アトリビュートを追加します。
427     //! @details :private
AddVertexAttribute(s32 usage,u32 formatType,u8 dimension,bool isStream,u8 * stream0,u8 * stream1)428     VertexAttribute* AddVertexAttribute(
429         s32 usage,
430         u32 formatType,
431         u8 dimension,
432         bool isStream,
433         u8* stream0,
434         u8* stream1)
435     {
436         this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_Usage = usage;
437         this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_FormatType = formatType;
438         this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_Dimension = dimension;
439         this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_IsStream = isStream;
440         this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_Stream[0] = stream0;
441         this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_Stream[1] = stream1;
442         this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_CommandPtr[0] = NULL;
443         this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_CommandPtr[1] = NULL;
444         ++this->m_ResVertexAttributeDataCount;
445         return &this->m_VertexAttribute[this->m_ResVertexAttributeDataCount - 1];
446     }
447 
448     static const int bufferAlignment = 4; // ストリームに必要なアライメント
449     int m_Capacity;
450     bool m_BufferSide;
451 
452     int m_ResVertexAttributeDataCount;
453     VertexAttribute m_VertexAttribute[PARTICLEUSAGE_COUNT];
454 
455     u8* m_PrimitiveBuffer[2];
456     u32 m_PrimitiveBufferOffset[2];
457 
458     os::IAllocator* m_DeviceAllocator;
459     void* m_DeviceMemory;
460 };
461 
462 } // namespace gfx
463 } // namespace nw
464 
465 #endif // NW_GFX_PARTICLESET_H_
466