1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: demo_Particle.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: 25938 $ 14 *---------------------------------------------------------------------------*/ 15 16 #ifndef NW_DEMO_PARTICLE_H_ 17 #define NW_DEMO_PARTICLE_H_ 18 19 #include <nw/gfx.h> 20 #include <nw/ut.h> 21 22 namespace nw 23 { 24 25 namespace demo 26 { 27 28 //! @brief パーティクル管理用のクラスです。 29 //! Transformノードに管理用の情報を付加しています。 30 class ParticleNode : public gfx::TransformNode 31 { 32 private: 33 NW_DISALLOW_COPY_AND_ASSIGN(ParticleNode); 34 35 public: 36 NW_UT_RUNTIME_TYPEINFO; 37 38 //---------------------------------------- 39 //! @name 作成/破棄 40 //@{ 41 42 //! @brief シーンノードを動的に構築するためのクラスです。 43 //! 44 //! IsFixedSizeMemory の初期値は true です。false に変更すると、各種最大数の設定は無視されます。 45 class DynamicBuilder 46 { 47 public: 48 //! コンストラクタです。 DynamicBuilder()49 DynamicBuilder() {} 50 //! デストラクタです。 ~DynamicBuilder()51 ~DynamicBuilder() {} 52 53 //! @brief 生成時以外にもメモリを確保するかどうかのフラグを設定します。 54 //! 55 //! true を指定すると、生成時のみ固定サイズのメモリ確保を行います。 56 //! 57 //! false を指定すると、生成時以外にも必要に応じて動的にメモリ確保が行われます。 IsFixedSizeMemory(bool isFixedSizeMemory)58 DynamicBuilder& IsFixedSizeMemory(bool isFixedSizeMemory) 59 { 60 m_Description.isFixedSizeMemory = isFixedSizeMemory; 61 return *this; 62 } 63 64 //! 子の最大数を設定します。 MaxChildren(int maxChildren)65 DynamicBuilder& MaxChildren(int maxChildren) 66 { 67 m_Description.maxChildren = maxChildren; 68 return *this; 69 } 70 71 //! 管理できるコールバックの最大数を設定します。 MaxCallbacks(int maxCallbacks)72 DynamicBuilder& MaxCallbacks(int maxCallbacks) 73 { 74 m_Description.maxCallbacks = maxCallbacks; 75 return *this; 76 } 77 78 //! @brief シーンノードを生成します。 79 //! 80 //! @param[in] allocator アロケータです。 81 //! 82 //! @return 生成したシーンノードを返します。 83 //! 84 ParticleNode* Create(os::IAllocator* allocator); 85 86 private: 87 gfx::TransformNode::Description m_Description; 88 }; 89 90 //! @brief IDを取得します。 91 //! 92 //! @return IDです。 GetID()93 int GetID() const 94 { 95 return m_Id; 96 } 97 98 //! @brief IDを設定します。 99 //! 100 //! @param[in] id 設定するIDです。 SetID(int id)101 void SetID(int id) 102 { 103 m_Id = id; 104 } 105 106 //! @brief 位置を設定します。 107 //! 108 //! @param[in] x 設定する位置Xです。 109 //! @param[in] y 設定する位置Yです。 110 //! @param[in] z 設定する位置Zです。 SetTranslate(f32 x,f32 y,f32 z)111 void SetTranslate(f32 x, f32 y, f32 z) 112 { 113 this->Transform().SetTranslate(x, y, z); 114 } 115 116 //! @brief 位置を設定します。 117 //! 118 //! @param[in] translate 設定する位置です。 SetTranslate(const nw::math::VEC3 & translate)119 void SetTranslate(const nw::math::VEC3& translate) 120 { 121 this->Transform().SetTranslate(translate); 122 } 123 124 //! @brief 位置を取得します。 GetTranslate(nw::math::VEC3 * translate)125 void GetTranslate(nw::math::VEC3* translate) const 126 { 127 this->Transform().GetTranslate(translate); 128 } 129 130 //! @brief 回転を設定します。 131 //! 132 //! @param[in] x 設定する回転値X(ラジアン)です。 133 //! @param[in] y 設定する回転値Y(ラジアン)です。 134 //! @param[in] z 設定する回転値Z(ラジアン)です。 SetRotate(f32 radX,f32 radY,f32 radZ)135 void SetRotate(f32 radX, f32 radY, f32 radZ) 136 { 137 this->Transform().SetRotateXYZ(radX, radY, radZ ); 138 } 139 140 //! @brief 拡縮を設定します。 141 //! 142 //! @param[in] x 設定する拡縮値Xです。 143 //! @param[in] y 設定する拡縮値Yです。 144 //! @param[in] z 設定する拡縮値Zです。 SetScale(f32 x,f32 y,f32 z)145 void SetScale(f32 x, f32 y, f32 z) 146 { 147 this->Transform().SetScale(x, y, z); 148 } 149 150 //! @brief ステップフレームを設定します。 151 //! 152 //! @param[in] 設定するステップフレームです。 SetStepFrame(f32 stepFrame)153 void SetStepFrame(f32 stepFrame) 154 { 155 u32 emitterNum = this->GetParticleEmitterSize(); 156 for (u32 i = 0; i < emitterNum; ++i) 157 { 158 nw::gfx::ParticleEmitter* emitter = this->GetParticleEmitter(i); 159 emitter->ParticleAnimFrameController().SetStepFrame(stepFrame); 160 } 161 162 u32 modelNum = this->GetParticleModelSize(); 163 164 for (u32 i = 0; i < modelNum; ++i) 165 { 166 nw::gfx::ParticleModel* model = this->GetParticleModel(i); 167 model->ParticleAnimFrameController().SetStepFrame(stepFrame); 168 } 169 } 170 171 //! @brief フレームを設定します。 172 //! 173 //! @param[in] 設定するフレームです。 SetFrame(f32 frame)174 void SetFrame(f32 frame) 175 { 176 u32 emitterNum = this->GetParticleEmitterSize(); 177 for (u32 i = 0; i < emitterNum; ++i) 178 { 179 nw::gfx::ParticleEmitter* emitter = this->GetParticleEmitter(i); 180 emitter->ParticleAnimFrameController().SetFrame(frame); 181 } 182 183 u32 modelNum = this->GetParticleModelSize(); 184 185 for (u32 i = 0; i < modelNum; ++i) 186 { 187 nw::gfx::ParticleModel* model = this->GetParticleModel(i); 188 model->ParticleAnimFrameController().SetFrame(frame); 189 } 190 } 191 192 //! @brief リセットします。 193 //! GPU処理中はコールできません。 194 //! 195 //! @param[in] リセットを行い、初期状態に戻します。 Reset()196 void Reset() 197 { 198 u32 emitterNum = this->GetParticleEmitterSize(); 199 for (u32 i = 0; i < emitterNum; ++i) 200 { 201 nw::gfx::ParticleEmitter* emitter = this->GetParticleEmitter(i); 202 emitter->Reset(); 203 } 204 205 u32 modelNum = this->GetParticleModelSize(); 206 207 for (u32 i = 0; i < modelNum; ++i) 208 { 209 nw::gfx::ParticleModel* model = this->GetParticleModel(i); 210 model->ForeachParticleSet(nw::gfx::ParticleSetsClear()); 211 model->ParticleAnimFrameController().SetFrame(0.f); 212 } 213 } 214 215 //! @brief 放出量をセットします。 216 //! 217 //! @param[in] ratio 設定する放出量です。 SetEmissionRatio(f32 ratio)218 void SetEmissionRatio(f32 ratio) 219 { 220 u32 emitterNum = this->GetParticleEmitterSize(); 221 for (u32 i = 0; i < emitterNum; ++i) 222 { 223 nw::gfx::ParticleEmitter* emitter = this->GetParticleEmitter(i); 224 nw::gfx::ResParticleEmitterParameter resParameter = emitter->GetResParticleEmitterParameterCopy(); 225 NW_ASSERT(resParameter.IsValid()); 226 227 resParameter.SetEmissionRatio(ratio); 228 } 229 } 230 231 //! @brief 現在のパーティクルの個数を取得します。 232 //! 233 //! @return 現在のパーティクルの個数です。 GetParticleSize()234 u32 GetParticleSize() 235 { 236 u32 particleNum = 0; 237 238 u32 modelNum = this->GetParticleModelSize(); 239 240 for (u32 i = 0; i < modelNum; ++i) 241 { 242 nw::gfx::ParticleModel* model = this->GetParticleModel(i); 243 for (u32 j = 0; j < model->GetParticleSetsCount(); ++j ) 244 { 245 nw::gfx::ParticleSet* particleSet = model->GetParticleSets(j); 246 particleNum += particleSet->GetParticleCollection()->GetCount(); 247 } 248 } 249 250 return particleNum; 251 } 252 253 //! @brief 終了状態かどうかを取得します。 254 //! 255 //! @return 終了状態であれば、trueが返ります。 IsDone()256 bool IsDone() 257 { 258 bool isDone = true; 259 260 u32 emitterNum = this->GetParticleEmitterSize(); 261 for (u32 i = 0; i < emitterNum; ++i) 262 { 263 nw::gfx::ParticleEmitter* emitter = this->GetParticleEmitter(i); 264 if (emitter->IsAlive()) 265 { 266 isDone = false; 267 } 268 } 269 270 u32 modelNum = this->GetParticleModelSize(); 271 272 for (u32 i = 0; i < modelNum; ++i) 273 { 274 nw::gfx::ParticleModel* model = this->GetParticleModel(i); 275 if (model->HasParticle()) 276 { 277 isDone = false; 278 } 279 } 280 281 return isDone; 282 } 283 284 285 //! @brief 粒子のスケールのオフセット値設定します。 286 //! 287 //! @param[in] particleOffset 設定する粒子のスケールのオフセットです。 SetParticleScaleOffset(f32 particleOffset)288 void SetParticleScaleOffset( f32 particleOffset ) 289 { 290 u32 modelNum = this->GetParticleModelSize(); 291 292 for (u32 i = 0; i < modelNum; ++i) 293 { 294 nw::gfx::ParticleModel* model = this->GetParticleModel(i); 295 296 for (int j = 0; j < (int)model->GetParticleSetsCount(); ++j) 297 { 298 nw::gfx::ParticleSet* particleSet = model->GetParticleSets(j); 299 particleSet->SetScaleOffset(nw::math::VEC3(particleOffset, particleOffset, particleOffset)); 300 } 301 } 302 } 303 304 //! @brief 粒子のスケールのオフセット値設定します。 305 //! 306 //! @param[in] particleOffsetX 設定する粒子のスケールのオフセットXです。 307 //! @param[in] particleOffsetY 設定する粒子のスケールのオフセットYです。 308 //! @param[in] particleOffsetZ 設定する粒子のスケールのオフセットZです。 309 void SetParticleScaleOffset( f32 particleOffsetX, f32 particleOffsetY, f32 particleOffsetZ = 1.f ) 310 { 311 u32 modelNum = this->GetParticleModelSize(); 312 313 for (u32 i = 0; i < modelNum; ++i) 314 { 315 nw::gfx::ParticleModel* model = this->GetParticleModel(i); 316 317 for (int j = 0; j < (int)model->GetParticleSetsCount(); ++j) 318 { 319 nw::gfx::ParticleSet* particleSet = model->GetParticleSets(j); 320 particleSet->SetScaleOffset(nw::math::VEC3(particleOffsetX, particleOffsetY, particleOffsetZ)); 321 } 322 } 323 } 324 325 //! @brief パーティクルモデルのインスタンスを登録します。 326 //! 327 //! @param[in] 登録するパーティクルモデルのインスタンスです。 RegisterParticleModel(nw::gfx::ParticleModel * model)328 void RegisterParticleModel( nw::gfx::ParticleModel* model ) 329 { 330 m_ModelInstances.PushBack(model); 331 } 332 333 //! @brief パーティクルエミッタのインスタンスを登録します。 334 //! 335 //! @param[in] 登録するパーティクルエミッタのインスタンスです。 RegisterParticleEmitter(nw::gfx::ParticleEmitter * emitter)336 void RegisterParticleEmitter( nw::gfx::ParticleEmitter* emitter ) 337 { 338 m_EmitterInstances.PushBack(emitter); 339 } 340 341 342 //! @brief 保持しているパーティクルモデル数を取得します。 343 //! 344 //! @return 保持しているパーティクルモデル数です。 GetParticleModelSize()345 u32 GetParticleModelSize() const 346 { 347 return m_ModelInstances.size(); 348 } 349 350 //! @brief 保持しているパーティクルエミッタ数を取得します。 351 //! 352 //! @return 保持しているパーティクルエミッタ数です。 GetParticleEmitterSize()353 u32 GetParticleEmitterSize() const 354 { 355 return m_EmitterInstances.size(); 356 } 357 358 //! @brief 保持しているパーティクルモデルインスタンスを取得します。 359 //! 360 //! @return パーティクルモデルのインスタンスです。 GetParticleModel(u32 index)361 nw::gfx::ParticleModel* GetParticleModel(u32 index) 362 { 363 if (this->GetParticleModelSize() > index) 364 { 365 return m_ModelInstances[index]; 366 } 367 return NULL; 368 } 369 370 //! @brief 保持しているパーティクルエミッタインスタンスを取得します。 371 //! 372 //! @return パーティクルエミッタのインスタンスです。 GetParticleEmitter(u32 index)373 nw::gfx::ParticleEmitter* GetParticleEmitter(u32 index) 374 { 375 if (this->GetParticleEmitterSize() > index) 376 { 377 return m_EmitterInstances[index]; 378 } 379 return NULL; 380 } 381 382 protected: 383 //---------------------------------------- 384 //! @name コンストラクタ/デストラクタ 385 //@{ 386 387 //! コンストラクタです。 388 ParticleNode( 389 os::IAllocator* allocator, 390 gfx::ResTransformNode resObj, 391 const gfx::TransformNode::Description& description); 392 393 //! デストラクタです。 ~ParticleNode()394 virtual ~ParticleNode() 395 { 396 397 } 398 399 //@} 400 401 private: 402 int m_Id; 403 ut::MoveArray<nw::gfx::ParticleModel*> m_ModelInstances; 404 ut::MoveArray<nw::gfx::ParticleEmitter*> m_EmitterInstances; 405 }; 406 407 408 409 410 //! @brief 一表現のためのパーティクル一式です 411 // パーティクルを管理する機能はアプリケーション毎の実装になります。 412 // このクラスは参考のための実装例です。 413 // パフォーマンスよりも簡便性を重視した実装です。 414 class ParticleEffect 415 { 416 public: 417 //---------------------------------------- 418 //! @name 初期化・終了処理 419 //@{ 420 421 //! @brief ParticleEffectクラスを生成します。 422 //! 423 //! @return 生成したParticleEffectクラスを返します。 424 //! 425 static ParticleEffect* Create(os::IAllocator* mainAllocator, 426 os::IAllocator* deviceAllocator, 427 bool autoAlocate, 428 gfx::ParticleContext* particleContext); 429 430 //! @brief ParticleEffectクラスを破棄します。 431 //! 432 void Destroy(); 433 434 private: 435 //! @brief コンストラクタです。 436 //! 437 //! @param[in] mainAllocator メインメモリのアロケータです。 438 //! @param[in] deviceAllocator デバイスメモリのアロケータです。 439 //! @param[in] autoAlocate 足りない時に自動でアロケートすることを許可するフラグです。 440 //! @param[in] particleContext パーティクルコンテキストです。 441 //! ParticleEffect(os::IAllocator * mainAllocator,os::IAllocator * deviceAllocator,bool autoAlocate,gfx::ParticleContext * particleContext)442 ParticleEffect( 443 os::IAllocator* mainAllocator, 444 os::IAllocator* deviceAllocator, 445 bool autoAlocate, 446 gfx::ParticleContext* particleContext 447 ) 448 : m_NextId(0), 449 m_MainAllocator(mainAllocator), 450 m_DeviceAllocator(deviceAllocator), 451 m_AutoAlocate(autoAlocate), 452 m_ResModels(mainAllocator), 453 m_ResEmitters(mainAllocator), 454 m_FreeInstances(mainAllocator), 455 m_ActiveInstances(mainAllocator), 456 m_ParticleContext(particleContext) 457 { 458 } 459 460 //! デストラクタです。 ~ParticleEffect()461 ~ParticleEffect() 462 { 463 NW_ASSERT(this->GetActiveSize() == 0); 464 this->FreePool(); 465 } 466 public: 467 //! @brief リソースのセットアップを行います。 468 //! 469 //! @param[in] useParticleMaterial パーティクルマテリアルを使用する場合はtrueを指定します。 470 void Setup(gfx::ResGraphicsFile resource, bool useParticleMaterial = false); 471 472 //! @brief リソースから指定された名前のノードを管理対象として登録します。 473 //! 474 //! @param[in] resource グラフィックスリソースです。 475 //! @param[in] nodeNames 登録するノード一覧です。 476 void Register(gfx::ResGraphicsFile resource, const char** nodeNames); 477 478 //! @brief 全てのリソースを管理対象として登録します。 479 //! 480 //! @param[in] resource グラフィックスリソースです。 481 void Register(gfx::ResGraphicsFile resource); 482 483 //@} 484 485 //---------------------------------------- 486 //! @name 生成・破棄 487 //@{ 488 489 //! @brief ノードを生成します。 490 //! @return 生成したノードをまとめるトップノード(demo::ParticleNode)を返します。 LeaseInstance()491 ParticleNode* LeaseInstance() 492 { 493 if (this->GetFreeSize() == 0) 494 { 495 if (this->m_AutoAlocate) 496 { 497 this->AddPool(1); 498 } 499 else 500 { 501 return NULL; 502 } 503 } 504 505 ParticleNode* node = this->m_FreeInstances.Back(); 506 this->m_FreeInstances.PopBack(); 507 this->m_ActiveInstances.PushBack(node); 508 509 this->ResetParticle(node); 510 511 return node; 512 } 513 514 //! @brief ノードを解放します。 515 //! @param[in] node 開放するトップノードです。 ReleaseInstance(gfx::SceneNode * node)516 void ReleaseInstance(gfx::SceneNode* node) 517 { 518 ParticleNode* topNode = ut::DynamicCast<ParticleNode*>(node); 519 520 if (topNode != NULL) 521 { 522 int activeCount = this->GetActiveSize(); 523 this->m_ActiveInstances.EraseFind(topNode); 524 NW_ASSERT(this->GetActiveSize() == activeCount - 1); 525 526 this->m_FreeInstances.PushBack(topNode); 527 } 528 } 529 530 //@} 531 532 //---------------------------------------- 533 //! @name 取得 534 //@{ 535 536 //! @brief インデックスでリース中のエフェクトを取得します。 537 //! @param[in] index インデックスです。 538 //! @return 該当するトップノードです。 GetActiveEffect(int index)539 ParticleNode* GetActiveEffect(int index) 540 { 541 if (index < 0 || index >= this->GetActiveSize()) 542 { 543 return NULL; 544 } 545 546 return this->m_ActiveInstances[index]; 547 } 548 549 //! @brief ノードを初期化します。 550 //! @param[in] topNode 初期化するエフェクトをトップノードで指定します。 ResetParticle(nw::gfx::SceneNode * topNode)551 void ResetParticle(nw::gfx::SceneNode* topNode) 552 { 553 if (nw::ut::IsTypeOf<nw::gfx::ParticleModel>(topNode)) 554 { 555 nw::gfx::ParticleModel* particleModel = 556 nw::ut::DynamicCast<nw::gfx::ParticleModel*>(topNode); 557 558 particleModel->ForeachParticleSet(nw::gfx::ParticleSetsClear()); 559 particleModel->ParticleAnimFrameController().SetFrame(0); 560 } 561 else if (nw::ut::IsTypeOf<nw::gfx::ParticleEmitter>(topNode)) 562 { 563 nw::gfx::ParticleEmitter* emitter = 564 nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(topNode); 565 566 emitter->Reset(); 567 } 568 569 nw::gfx::SceneNodeChildren::iterator end = topNode->GetChildEnd(); 570 for (nw::gfx::SceneNodeChildren::iterator child = topNode->GetChildBegin(); 571 child != end; 572 ++child) 573 { 574 ResetParticle(*child); 575 } 576 } 577 578 //@} 579 580 //---------------------------------------- 581 //! @name インスタンスプール 582 //@{ 583 584 //! @brief リース中を含む確保済みのインスタンスの総数を取得します。 GetPoolSize()585 int GetPoolSize() const 586 { 587 return this->GetFreeSize() + this->GetActiveSize(); 588 } 589 590 //! @brief リース中のでないフリーのインスタンスの数を取得します。 GetFreeSize()591 int GetFreeSize() const 592 { 593 return this->m_FreeInstances.Size(); 594 } 595 596 //! @brief リース中のインスタンスの数を取得します。 GetActiveSize()597 int GetActiveSize() const 598 { 599 return this->m_ActiveInstances.Size(); 600 } 601 602 //! @brief 指定数のインスタンスを新しくプールします。 AddPool(int num)603 void AddPool(int num) 604 { 605 for (int i = 0 ; i < num ; ++i) 606 { 607 ParticleNode* node = this->Allocate(); 608 this->m_FreeInstances.push_back(node); 609 } 610 } 611 612 //! @brief リース中以外の全てのインスタンスを破棄します。 FreePool()613 void FreePool() 614 { 615 while (this->m_FreeInstances.Size() > 0) 616 { 617 ParticleNode* node = this->m_FreeInstances.Back(); 618 this->m_FreeInstances.PopBack(); 619 DestroyParticleNode(node); 620 } 621 } 622 623 //@} 624 625 private: 626 //! @details :private 627 ParticleNode* Allocate(); 628 629 //! @details :private 630 void DestroyParticleNode(ParticleNode* node); 631 632 int m_NextId; 633 634 os::IAllocator* m_MainAllocator; 635 os::IAllocator* m_DeviceAllocator; 636 637 bool m_AutoAlocate; 638 639 ut::MoveArray<gfx::ResParticleModel> m_ResModels; 640 ut::MoveArray<gfx::ResParticleEmitter> m_ResEmitters; 641 642 ut::MoveArray<ParticleNode*> m_FreeInstances; 643 ut::MoveArray<ParticleNode*> m_ActiveInstances; 644 645 gfx::ParticleContext* m_ParticleContext; 646 }; 647 648 649 } // namespace demo 650 651 } // namespace nw 652 653 #endif // NW_DEMO_PARTICLE_H_ 654