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