/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_ParticleCollection.h Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. 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. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_PARTICLECOLLECTION_H_ #define NW_GFX_PARTICLECOLLECTION_H_ #include #include #include #include #include namespace nw { namespace gfx { namespace internal { //! パーティクルで用いるショートベクタ演算の最大の処理単位です。 const int PARTICLE_SIMD_WIDTH_MAX = 8; } // namespace internal class ParticleSet; class ParticleCollection; //--------------------------------------------------------------------------- //! @brief パーティクルの粒子の情報を表すクラスです。 //--------------------------------------------------------------------------- class ParticleCollection : public GfxObject { private: NW_DISALLOW_COPY_AND_ASSIGN(ParticleCollection); public: NW_UT_RUNTIME_TYPEINFO; //! @brief パーティクルのための属性情報です。 //! @details :private struct ParticleAttribute { s32 m_Usage; bool m_IsStream; f32* m_Stream; }; //---------------------------------------- //! @name 作成/破棄 //@{ //! @brief リソースからParticleCollectionノードを生成します。 //! //! @param[in] parent 親のノードです。 //! @param[in] resource リソースです。 //! @param[in] mainAllocator メインアロケータです。 //! @param[in] deviceAllocator デバイスアロケータです。 //! @param[in] shape シェイプです。 //! //! @return 生成されたParticleCollectionノードです。 //! static ParticleCollection* Create( ParticleSet* parent, ResParticleCollection resource, os::IAllocator* mainAllocator, os::IAllocator* deviceAllocator, ParticleShape* shape); //! @brief 生成時に必要なメモリサイズを取得します。 //! @param[in] resource リソースです。 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 //! @return 必要なメモリサイズです。 static size_t GetMemorySize( ResParticleCollection resource, size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) { os::MemorySizeCalculator size(alignment); GetMemorySizeInternal(&size, resource); return size.GetSizeWithPadding(alignment); } //! @details :private static void GetMemorySizeInternal( os::MemorySizeCalculator* pSize, ResParticleCollection resource); //! @brief 生成時に必要なデバイスメモリサイズを取得します。 //! @param[in] resource リソースです。 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 //! @return 必要なデバイスメモリサイズです。 static size_t GetDeviceMemorySize( ResParticleCollection resource, size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) { os::MemorySizeCalculator size(alignment); GetDeviceMemorySizeInternal(&size, resource); return size.GetSizeWithPadding(alignment); } //! @details :private static void GetDeviceMemorySizeInternal( os::MemorySizeCalculator* pSize, ResParticleCollection resource); //@} //---------------------------------------- //! @name リソース //@{ //! @brief リソースを取得します。 //! @return リソースを返します。 ResParticleCollection GetResParticleCollection() { return this->m_ResParticleCollection; } //! @brief リソースを取得します。 //! @return リソースを返します。 const ResParticleCollection GetResParticleCollection() const { return this->m_ResParticleCollection; } //@} //---------------------------------------- //! @name 取得/設定 //@{ //! @brief パーティクル数の上限を取得します。 //! @return パーティクル数の上限を返します。 int GetCapacity() const { return this->m_Capacity; } //! @brief パーティクル数を取得します。 //! @return 現在のパーティクル数を返します。 int GetCount() const { return this->m_Count; } //! @brief パーティクル数を設定します。 //! @return 現在のパーティクル数を設定します。 //! @details :private void SetCount(int count) { this->m_Count = count; } //! @brief 有効なパーティクルのインデックスの最小値を取得します。 //! @details :private u16 GetMinActiveIndex() const { return this->m_MinActiveIndex; } //! @brief 有効なパーティクルのインデックスの最大値を取得します。 //! @details :private u16 GetMaxActiveIndex() const { return this->m_MaxActiveIndex; } //! @brief 有効なパーティクルのインデックスの最小値を設定します。 //! @details :private void SetMinActiveIndex(u16 minActiveIndex) { this->m_MinActiveIndex = minActiveIndex; } //! @brief 有効なパーティクルのインデックスの最大値を設定します。 //! @details :private void SetMaxActiveIndex(u16 maxActiveIndex) { this->m_MaxActiveIndex = maxActiveIndex; } //! @brief 指定された属性がストリームかどうかを調べます。 //! @param[in] usage 利用種別です。 //! @return ストリームの場合はtrueを返します。 bool IsStream(ParticleUsage usage) const { NW_ASSERT(usage >= 0 && usage < PARTICLEUSAGE_COUNT); return this->m_IsStream[usage]; } //! @details :private bool GetBufferSide() const { return this->m_BufferSide; } //! @details :private int GetLastBuffer() const { return this->m_LastBuffer; } //! @details :private void SetLastBuffer(int value) { this->m_LastBuffer = value; } //! @brief 指定された属性のストリームのポインタを取得します。 //! @param[in] usage 利用種別です。 //! @param[in] side バッファの使用目的です。 //! @return ストリームを返します。 void* GetStreamPtr(ParticleUsage usage, ParticleBuffer side) { NW_ASSERT(usage >= 0 && usage < PARTICLEUSAGE_COUNT); if (!this->m_IsStream[usage]) { return NULL; } if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } return this->m_StreamPtr[usage][side]; } //! @brief 指定された属性のストリームのポインタを取得します。 //! @param[in] usage 利用種別です。 //! @param[in] side バッファの使用目的です。 //! @return ストリームを返します。 const void* GetStreamPtr(ParticleUsage usage, ParticleBuffer side) const { NW_ASSERT(usage >= 0 && usage < PARTICLEUSAGE_COUNT); if (!this->m_IsStream[usage]) { return NULL; } if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } return this->m_StreamPtr[usage][side]; } //! @brief 指定された属性のパラメータへのポインタを取得します。 //! @param[in] usage 利用種別です。 //! @return パラメータへのポインタを返します。 const void* GetParameterPtr(ParticleUsage usage) const { NW_ASSERT(usage >= 0 && usage < PARTICLEUSAGE_COUNT); if (this->m_IsStream[usage]) { return NULL; } return this->m_StreamPtr[usage][0]; } //! @brief 指定された属性のパラメータを設定します。 //! @details :private //! @param[in] usage 利用種別です。 //! @param[in] side バッファの使用目的です。 //! @param[in] ptr 新しいパラメータへのポインタです。 void SetParameter(ParticleUsage usage, ParticleBuffer side, const f32* ptr); //! @brief PARTICLEUSAGE_LIFEのパラメータを設定します。 //! @details LIFEがストリームの場合は効果はありません。 //! @param[in] ptr 新しいパラメータへのポインタです。 void SetLifeParameter(const ParticleTime* ptr) { SetParameter(PARTICLEUSAGE_LIFE, PARTICLE_BUFFER_FRONT, (const f32*)ptr); } //! @brief 指定された属性のストリームまたはパラメータを取得します。 //! @details パラメータの場合には、streamにはNULLが格納されます。 //! @param[in] usage 利用種別です。 //! @param[out] stream ストリームの場合にポインタを格納するポインタです。 //! @param[out] param パラメータの場合にパラメータを格納するポインタです。 //! @param[in] side バッファの使用目的です。 //! @return ストリームの場合は、ストリームへのポインタを返します。パラメータの場合はパラメータを返します。 template NW_FORCE_INLINE bool GetStreamOrParameter(ParticleUsage usage, T** stream, T* param, ParticleBuffer side) { if (this->m_IsStream[usage]) { if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } *stream = (T*)this->m_StreamPtr[usage][side]; } else { *stream = NULL; if (param != NULL && m_StreamPtr[usage][0] != NULL) { memcpy(param, this->m_StreamPtr[usage][0], sizeof(T)); } } return true; } //! @brief 全てのストリームを初期化します。 //! @details ストリームの状態を初期化します。この関数は描画中には使用できません。 //! GPUからストリームへのアクセスがない状態で使用してください。 void Clear(); //! @brief 計算用と描画用の対象となるバッファを入れ替えます。 //! @details :private void SwapBuffer() { ParticleShape* shape = this->m_ParticleShape; ParticleBuffer side = PARTICLE_BUFFER_FRONT; if (this->m_BufferSide) { side = (ParticleBuffer)(1 - side); } this->m_BufferSide = !this->m_BufferSide; shape->SetBufferSide(this->m_BufferSide); int size = this->GetMaxActiveIndex() + 1; for (int usage = 0; usage < PARTICLEUSAGE_COUNT; ++usage) { void* src = this->m_StreamPtr[usage][side]; void* dst = this->m_StreamPtr[usage][(ParticleBuffer)(1 - side)]; if (usage != PARTICLEUSAGE_ACTIVEINDEX) { if (src != dst) { nw::os::MemCpy(dst, src, this->m_StreamStride[usage] * size); } } } this->m_LastBuffer = 1 - this->m_LastBuffer; } //! @brief 生成済み全てのパーティクル粒子を削除します。 //! @detail 次回の削除処理で実際に削除されます。 //! その前に、チャイルドパーティクルの放出処理があれば、終了時として扱われます。 void KillParticles() { NW_NULL_ASSERT(m_ParticleSet); ParticleModel* model = static_cast(m_ParticleSet->GetParent()); NW_NULL_ASSERT(model); ParticleTime time = model->ParticleAnimFrameController().GetFrame(); u16* activeIndex = (u16*)this->GetStreamPtr( nw::gfx::PARTICLEUSAGE_ACTIVEINDEX,nw::gfx::PARTICLE_BUFFER_FRONT); NW_NULL_ASSERT(activeIndex); #ifdef NW_GFX_PARTICLE_COMPAT_1_1 ParticleTime* negtime = (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_NEG_TIMELIMIT, PARTICLE_BUFFER_FRONT); NW_NULL_ASSERT(negtime); for (s32 i = 0; i < m_Count; ++i) { int convertedIndex = activeIndex[i]; // -timeで消えるが念のためマージンを設ける negtime[convertedIndex] = -time + 1.0f; } #else ParticleTime* birth = (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT); NW_NULL_ASSERT(birth); ParticleTime lifeParam; if (this->IsStream(PARTICLEUSAGE_LIFE)) { ParticleTime* life = (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_LIFE, PARTICLE_BUFFER_FRONT); for (s32 i = 0; i < m_Count; ++i) { int convertedIndex = activeIndex[i]; lifeParam = life[convertedIndex]; birth[convertedIndex] = time - lifeParam - 1; } } else { lifeParam = *(ParticleTime*)this->GetParameterPtr(PARTICLEUSAGE_LIFE); for (s32 i = 0; i < m_Count; ++i) { int convertedIndex = activeIndex[i]; birth[convertedIndex] = time - lifeParam - 1; } } #endif } //! @brief 指定したインデックスのパーティクル粒子を削除します。 //! @detail 次回の削除処理で実際に削除されます。 //! その前に、チャイルドパーティクルの放出処理があれば、終了時として扱われます。 //! @param[in] index ACTIVEINDEXが指し示すインデックスです。 void KillParticle(int index) { NW_NULL_ASSERT(m_ParticleSet); ParticleModel* model = static_cast(m_ParticleSet->GetParent()); NW_NULL_ASSERT(model); ParticleTime time = model->ParticleAnimFrameController().GetFrame(); #ifdef NW_GFX_PARTICLE_COMPAT_1_1 ParticleTime* negtime = (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_NEG_TIMELIMIT, PARTICLE_BUFFER_FRONT); NW_NULL_ASSERT(negtime); negtime[index] = -time + 1.0f; // -timeで消えるが念のためマージンを設ける #else ParticleTime* birth = (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT); NW_NULL_ASSERT(birth); ParticleTime lifeParam; if (this->IsStream(PARTICLEUSAGE_LIFE)) { ParticleTime* life = (ParticleTime*)this->GetStreamPtr(PARTICLEUSAGE_LIFE, PARTICLE_BUFFER_FRONT); lifeParam = life[index]; } else { lifeParam = *(ParticleTime*)this->GetParameterPtr(PARTICLEUSAGE_LIFE); } birth[index] = time - lifeParam - 1; #endif } //@} protected: //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! @brief コンストラクタです。 ParticleCollection( os::IAllocator* allocator, os::IAllocator* deviceAllocator, void* deviceMemory, ResParticleCollection resObj); //! @brief デストラクタです。 virtual ~ParticleCollection(); //@} private: ParticleAttribute m_ParticleAttribute[PARTICLEUSAGE_COUNT]; int m_Capacity; int m_Count; bool m_BufferSide; bool m_IsStream[PARTICLEUSAGE_COUNT]; void* m_StreamPtr[PARTICLEUSAGE_COUNT][2]; int m_StreamStride[PARTICLEUSAGE_COUNT]; u16 m_MinActiveIndex; u16 m_MaxActiveIndex; ResParticleCollection m_ResParticleCollection; ParticleShape* m_ParticleShape; ParticleSet* m_ParticleSet; os::IAllocator* m_DeviceAllocator; void* m_DeviceMemory; int m_LastBuffer; }; } // namespace gfx } // namespace nw #endif // NW_GFX_PARTICLECOLLECTION_H_