/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_ParticleShape.h Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 25986 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_PARTICLESHAPE_H_ #define NW_GFX_PARTICLESHAPE_H_ #include #include #include namespace nw { namespace gfx { class ParticleShape; class ParticleSet; //! @brief パーティクルのバッファの種別です。 enum ParticleBuffer { PARTICLE_BUFFER_FRONT = 0, //!< 計算用バッファです。 PARTICLE_BUFFER_BACK //!< 描画用バッファです。 }; //--------------------------------------------------------------------------- //! @brief パーティクルのためのシェイプを表すクラスです。 //! @details ParticleCollectionを使い、このクラスは利用しないようにしてください。 //--------------------------------------------------------------------------- class ParticleShape : public SceneObject { private: NW_DISALLOW_COPY_AND_ASSIGN(ParticleShape); public: NW_UT_RUNTIME_TYPEINFO; //! @brief パーティクルのための頂点バッファ情報です。 //! @details :private struct VertexAttribute { s32 m_Usage; u32 m_FormatType; u8 m_Dimension; bool m_IsStream; u8* m_Stream[2]; void* m_CommandPtr[2]; //< コマンド上でのこのデータの先頭アドレス }; //---------------------------------------- //! @name 作成 //@{ //! @brief リソースからパーティクルシェイプノードを生成します。 //! //! @param[in] resource リソースです。 //! @param[in] capacity 最大頂点数です。 //! @param[in] mainAllocator メインメモリのアロケータです。 //! @param[in] deviceAllocator デバイスメモリのアロケータです。 //! //! @return 生成されたトランスフォームノードです。 //! static ParticleShape* Create( ResSceneObject resource, int capacity, os::IAllocator* mainAllocator, os::IAllocator* deviceAllocator); //! @brief 生成時に必要なメモリサイズを取得します。 //! @param[in] capacity 最大頂点数です。 //! @param[in] alignment アロケータのメモリアライメントです。 //! @return 必要なメモリサイズです。 static size_t GetMemorySize( int capacity, size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) { os::MemorySizeCalculator size(alignment); GetMemorySizeInternal(&size, capacity); return size.GetSizeWithPadding(alignment); } //! @details :private static void GetMemorySizeInternal( os::MemorySizeCalculator* pSize, int capacity); //! @brief 生成時に必要なデバイスメモリサイズを取得します。 //! @param[in] capacity 最大頂点数です。 //! @param[in] alignment アロケータのメモリアライメントです。 //! @return 必要なデバイスメモリサイズです。 static size_t GetDeviceMemorySize( int capacity, size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) { os::MemorySizeCalculator size(alignment); GetDeviceMemorySizeInternal(&size, capacity); return size.GetSizeWithPadding(alignment); } //! @details :private static void GetDeviceMemorySizeInternal( os::MemorySizeCalculator* pSize, int capacity); //! @details :private static int AddVertexStreamSize( u32 formatType, int dimension, int capacity, int prevSize); //! @details :private static int AddVertexParamSize( u32 formatType, int dimension, int prevSize); //! @details :private VertexAttribute* AddVertexStream( s32 usage, u32 formatType, int dimension, int capacity, u8** memory); //! @details :private VertexAttribute* AddVertexParam( s32 usage, u32 formatType, int dimension, f32* parameters, u8** memory); //@} //---------------------------------------- //! @name 取得/設定 //@{ //! @brief リソースを取得します。 //! @return パーティクルシェイプのリソースです。 ResParticleShape GetResParticleShape() { return ResDynamicCast( this->GetResSceneObject() ); } //! @brief リソースを取得します。 //! @return パーティクルシェイプのリソースです。 const ResParticleShape GetResParticleShape() const { return ResDynamicCast( this->GetResSceneObject() ); } //! @brief 頂点アトリビュートの個数を取得します。 //! @return 頂点アトリビュートの個数です。 int GetVertexAttributesCount() const { return this->m_ResVertexAttributeDataCount; } //! @brief 頂点アトリビュートがストリームかどうかを調べます。 //! @param[in] index インデックスです。 //! @return 頂点アトリビュートがストリームの場合はtrueを返します。 bool IsVertexStream(int index) { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); return this->m_VertexAttribute[index].m_IsStream; } //! @brief 頂点アトリビュートの利用種別を取得します。 //! @param[in] index インデックスです。 //! @return 頂点アトリビュートの利用種別です。 s32 GetVertexAttributeUsage(int index) { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); return this->m_VertexAttribute[index].m_Usage; } //! @brief 頂点アトリビュートのフォーマットを取得します。 //! @param[in] index インデックスです。 //! @return 頂点アトリビュートのフォーマットです。 u32 GetVertexAttributeFormatType(int index) { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); return this->m_VertexAttribute[index].m_FormatType; } //! @brief 頂点アトリビュートの次元を取得します。 //! @param[in] index インデックスです。 //! @return 頂点アトリビュートの次元です。 u8 GetVertexAttributeDimension(int index) { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); return this->m_VertexAttribute[index].m_Dimension; } //! @brief 頂点アトリビュートのストリームのポインタを取得します。 //! @param[in] index インデックスです。 //! @param[in] side バッファの使用目的です。 //! @return 頂点アトリビュートのストリームへのポインタです。 u8* GetVertexStreamPtr(int index, ParticleBuffer side) { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); NW_ASSERT(side >= 0 && side <= 1); if (!this->m_VertexAttribute[index].m_IsStream) { return NULL; } if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } return this->m_VertexAttribute[index].m_Stream[side]; } //! @brief 頂点アトリビュートのストリームのポインタを取得します。 //! @param[in] index インデックスです。 //! @param[in] side バッファの使用目的です。 //! @return 頂点アトリビュートのストリームへのポインタです。 const u8* GetVertexStreamPtr(int index, ParticleBuffer side) const { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); NW_ASSERT(side >= 0 && side <= 1); if (!this->m_VertexAttribute[index].m_IsStream) { return NULL; } if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } return this->m_VertexAttribute[index].m_Stream[side]; } //! @brief 頂点アトリビュートのパラメータを取得します。 //! @param[in] index インデックスです。 //! @return 頂点アトリビュートのストリームへのポインタです。 f32* GetVertexParameter(int index) { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); if (this->m_VertexAttribute[index].m_IsStream) { return NULL; } return reinterpret_cast(this->m_VertexAttribute[index].m_Stream[0]); } //! @brief 頂点アトリビュートのパラメータを取得します。 //! @param[in] index インデックスです。 //! @return 頂点アトリビュートのストリームへのポインタです。 const f32* GetVertexParameter(int index) const { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); if (this->m_VertexAttribute[index].m_IsStream) { return NULL; } return reinterpret_cast(this->m_VertexAttribute[index].m_Stream[0]); } //! @brief 頂点アトリビュートのパラメータを設定します。 //! @details :private //! @param[in] index インデックスです。 //! @param[in] side バッファの使用目的です。 //! @param[in] ptr 新しいパラメータへのポインタです。 void SetVertexParameter(int index, ParticleBuffer side, const f32* ptr) { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); NW_ASSERT(side >= 0 && side <= 1); if (this->m_VertexAttribute[index].m_IsStream) { return; } if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } int count = this->GetVertexAttributeDimension(index); f32* fdata = this->GetVertexParameter(index); u32 data[4] = { 0, 0, 0, 0 }; for (int j = 0; j < count; ++j) { fdata[j] = ptr[j]; data[j] = ut::Float24::Float32ToBits24(fdata[j]); } u32* target = reinterpret_cast( this->m_VertexAttribute[index].m_CommandPtr[side]); *target++ = (data[3] << 8) | (data[2] >> 16); *target++ = (data[2] << 16) | (data[1] >> 8); *target = (data[1] << 24) | (data[0]); } //! :private void* SetVertexAttributeCommandPtr(int index, int side, void* ptr) { NW_ASSERT(index >= 0 && index < this->m_ResVertexAttributeDataCount); NW_ASSERT(side >= 0 && side <= 1); return this->m_VertexAttribute[index].m_CommandPtr[side] = ptr; } //! @brief プリミティブのストリームのポインタを取得します。 //! @param[in] side バッファの使用目的です。 //! @return プリミティブのストリームへのポインタです。 u8* GetPrimitiveStreamPtr(ParticleBuffer side) { NW_ASSERT(side >= 0 && side <= 1); if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } return this->m_PrimitiveBuffer[side]; } //! @brief プリミティブのストリームのポインタを取得します。 //! @param[in] side バッファの使用目的です。 //! @return プリミティブのストリームへのポインタです。 const u8* GetPrimitiveStreamPtr(ParticleBuffer side) const { NW_ASSERT(side >= 0 && side <= 1); if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } return this->m_PrimitiveBuffer[side]; } //! @brief GPUコマンド発行のためのプリミティブのストリームのオフセットを取得します。 //! @details :private //! @param[in] side バッファの使用目的です。 //! @return プリミティブのストリームへのポインタです。 u32 GetPrimitiveStreamOffset(ParticleBuffer side) const { NW_ASSERT(side >= 0 && side <= 1); if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } return this->m_PrimitiveBufferOffset[side]; } //! @brief 各ストリームに格納できるパーティクル数の上限を取得します。 //! @return パーティクル数の上限です。 int GetVertexCapacity() const { return m_Capacity; } //! @brief 計算用と描画用の対象となるバッファを入れ替えます。 void SetBufferSide(bool swap) { this->m_BufferSide = swap; } //! @brief 表面のバッファ番号を取得します。 //! @return 表面のバッファ番号です。 int GetBufferSide() const { return this->m_BufferSide ? 1 : 0; } //! @brief コマンドキャッシュを生成します。 //! @details :private void CreateCommandCache(ParticleSet* particleSet); //! @brief バッファをフラッシュします。 //! @details :private void FlushBuffer(); //@} void* m_CommandCache[2]; s32 m_CommandCacheSize[2]; void* m_DeactivateVertexCommandCache; s32 m_DeactivateVertexCommandCacheSize; void* m_PrimitiveCommandCache; s32 m_PrimitiveCommandCacheSize; protected: //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 ParticleShape( int capacity, os::IAllocator* allocator, os::IAllocator* deviceAllocator, void* deviceMemory, ResParticleShape resObj); //! デストラクタです。 virtual ~ParticleShape(); //@} private: //! @brief アトリビュートを追加します。 //! @details :private VertexAttribute* AddVertexAttribute( s32 usage, u32 formatType, u8 dimension, bool isStream, u8* stream0, u8* stream1) { this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_Usage = usage; this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_FormatType = formatType; this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_Dimension = dimension; this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_IsStream = isStream; this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_Stream[0] = stream0; this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_Stream[1] = stream1; this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_CommandPtr[0] = NULL; this->m_VertexAttribute[this->m_ResVertexAttributeDataCount].m_CommandPtr[1] = NULL; ++this->m_ResVertexAttributeDataCount; return &this->m_VertexAttribute[this->m_ResVertexAttributeDataCount - 1]; } static const int bufferAlignment = 4; // ストリームに必要なアライメント int m_Capacity; bool m_BufferSide; int m_ResVertexAttributeDataCount; VertexAttribute m_VertexAttribute[PARTICLEUSAGE_COUNT]; u8* m_PrimitiveBuffer[2]; u32 m_PrimitiveBufferOffset[2]; os::IAllocator* m_DeviceAllocator; void* m_DeviceMemory; }; } // namespace gfx } // namespace nw #endif // NW_GFX_PARTICLESET_H_