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