1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: gfx_ParticleSet.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: 31829 $ 16 *---------------------------------------------------------------------------*/ 17 18 #ifndef NW_GFX_PARTICLESET_H_ 19 #define NW_GFX_PARTICLESET_H_ 20 21 #include <nw/gfx/gfx_TransformNode.h> 22 23 #include <nw/gfx/gfx_ParticleModel.h> 24 #include <nw/gfx/res/gfx_ResParticleSet.h> 25 #include <nw/gfx/res/gfx_ResParticleAnimationOption.h> 26 #include <nw/gfx/gfx_ParticleRandom.h> 27 #include <nw/gfx/gfx_ParticleTime.h> 28 29 namespace nw 30 { 31 namespace gfx 32 { 33 34 class ParticleCollection; 35 class ParticleContext; 36 class ParticleShape; 37 38 //--------------------------------------------------------------------------- 39 //! @brief パーティクル群を表すクラスです。 40 //--------------------------------------------------------------------------- 41 class ParticleSet : public SceneNode 42 { 43 private: 44 NW_DISALLOW_COPY_AND_ASSIGN(ParticleSet); 45 46 public: 47 NW_UT_RUNTIME_TYPEINFO; 48 49 //! @brief 設定内容です。 50 struct Description : public SceneNode::Description 51 { 52 s32 maxInitializers; //!< ParticleInitializerのバッファの数です。 53 s32 maxUpdaters; //!< ParticleUpdaterのバッファの数です。 54 55 //! @brief コンストラクタです。 DescriptionDescription56 Description() : 57 maxInitializers(0), 58 maxUpdaters(0) 59 {} 60 }; 61 62 //! @brief ランタイム用のイニシャライザの管理情報です。 63 struct Initializer 64 { 65 bool m_IsCopied; //!< コピーされたリソースであることを表すフラグです。 66 const ResParticleInitializerData *resource; //!< リソースへのポインタです。 67 u32 work; //!< ワークエリアです。 68 69 // 高速化のためのキャッシュ 70 nw::ut::ResTypeInfo m_Type; 71 void* m_TargetStreams[2]; //!< 変更対象のストリームへのポインタです。 72 }; 73 74 //! @brief ランタイム用のアップデータの管理情報です。 75 struct Updater 76 { 77 bool m_IsCopied; //!< コピーされたリソースであることを表すフラグです。 78 const ResParticleUpdaterData *resource; //!< リソースへのポインタです。 79 u32 work; //!< ワークエリアです。 80 81 // 高速化のためのキャッシュ 82 nw::ut::ResTypeInfo m_Type; 83 void* m_TargetStreams[2]; //!< 変更対象のストリームへのポインタです。 84 85 u32 m_Flags; //!< フラグです。 86 87 //! @brief アップデータの管理情報のフラグです。 88 enum Flag 89 { 90 FLAG_IS_HAS_CURVE_ANIM = 0x1 << 0 //!< カーブアニメーションを保持しているかのフラグです。 91 }; 92 93 //! @brief 任意のフラグが有効になっているか取得します。 94 //! @param[in] flags 有効か調べるフラグです。 95 //! @return 有効な場合はtrueを返します。 IsEnabledFlagsUpdater96 inline bool IsEnabledFlags(bit32 flags) const 97 { 98 return ut::CheckFlag(m_Flags, flags); 99 } 100 101 //! @brief 任意のフラグを有効に設定します。 102 //! @param[in] flags 有効にするフラグです。 EnableFlagsUpdater103 inline void EnableFlags(bit32 flags) 104 { 105 m_Flags = ut::EnableFlag(m_Flags, flags); 106 } 107 }; 108 109 //---------------------------------------- 110 //! @name 作成/破棄 111 //@{ 112 113 //! @brief リソースからパーティクルセットを生成します。 114 //! 115 //! @param[in] parent 親のノードです。 116 //! @param[in] resource リソースです。 117 //! @param[in] description 設定内容です。 118 //! @param[in] mainAllocator メインアロケータです。 119 //! @param[in] deviceAllocator デバイスアロケータです。 120 //! @param[in] shape シェイプです。 121 //! 122 //! @return 生成されたトランスフォームノードです。 123 //! 124 static ParticleSet* Create( 125 SceneNode* parent, 126 ResSceneObject resource, 127 const ParticleSet::Description& description, 128 os::IAllocator* mainAllocator, 129 os::IAllocator* deviceAllocator, 130 ParticleShape* shape); 131 132 //! @brief 生成時に必要なメモリサイズを取得します。 133 //! @param[in] resource リソースです。 134 //! @param[in] description 設定内容です。 135 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 136 //! @return 必要なメモリサイズです。 137 static size_t GetMemorySize( 138 ResParticleSet resource, 139 const ParticleSet::Description& description, 140 size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) 141 { 142 os::MemorySizeCalculator size(alignment); 143 144 GetMemorySizeInternal(&size, resource, description); 145 146 return size.GetSizeWithPadding(alignment); 147 } 148 149 //! @details :private 150 static void GetMemorySizeInternal( 151 os::MemorySizeCalculator* pSize, 152 ResParticleSet resource, 153 const ParticleSet::Description& description); 154 155 //! @brief 生成時に必要なデバイスメモリサイズを取得します。 156 //! @param[in] resource リソースです。 157 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 158 //! @return 必要なデバイスメモリサイズです。 159 static size_t GetDeviceMemorySize( 160 ResParticleSet resource, 161 size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) 162 { 163 os::MemorySizeCalculator size(alignment); 164 165 GetDeviceMemorySizeInternal(&size, resource); 166 167 return size.GetSizeWithPadding(alignment); 168 } 169 170 //! @details :private 171 static void GetDeviceMemorySizeInternal( 172 os::MemorySizeCalculator* pSize, 173 ResParticleSet resource); 174 175 //@} 176 177 //---------------------------------------- 178 //! @name 更新 179 //@{ 180 181 //! @brief ビジターを受け付けます。 182 //! 183 //! @param[in] visitor ビジターです。 184 //! 185 virtual void Accept(ISceneVisitor* visitor); 186 187 //@} 188 189 //---------------------------------------- 190 //! @name リソース 191 //@{ 192 193 //! @brief リソースを取得します。 194 //! @return 設定されているリソースです。 GetResParticleSet()195 ResParticleSet GetResParticleSet() 196 { 197 return ResDynamicCast<ResParticleSet>( this->GetResSceneObject() ); 198 } 199 200 //! @brief リソースを取得します。 201 //! @return 設定されているリソースです。 GetResParticleSet()202 const ResParticleSet GetResParticleSet() const 203 { 204 return ResDynamicCast<ResParticleSet>( this->GetResSceneObject() ); 205 } 206 207 //@} 208 209 //---------------------------------------- 210 //! @name 取得/設定 211 //@{ 212 213 //! @brief パーティクルコレクションを設定します。 214 //! @param[in] node 設定するパーティクルコレクションです。 215 //! @return 既に設定されている場合は、falseを返します。 AttachParticleCollection(ParticleCollection * node)216 bool AttachParticleCollection(ParticleCollection* node) 217 { 218 if (this->m_ParticleCollection != NULL) 219 { 220 return false; 221 } 222 223 this->m_ParticleCollection = node; 224 return true; 225 } 226 227 //! @brief パーティクルコレクションを取得します。 228 //! @return 設定されているパーティクルコレクションです。 GetParticleCollection()229 ParticleCollection* GetParticleCollection() 230 { 231 return this->m_ParticleCollection; 232 } 233 234 //! @brief パーティクルコレクションを取得します。 235 //! @return 設定されているパーティクルコレクションです。 GetParticleCollection()236 const ParticleCollection* GetParticleCollection() const 237 { 238 return this->m_ParticleCollection; 239 } 240 241 //! @brief イニシャライザの配列を取得します。 242 //! @details 通常は生成時にサイズが決定されるため、生成後に追加削除することはできません。 243 //! @return イニシャライザの配列へのポインタを返します。 GetInitializers()244 ut::MoveArray<Initializer>* GetInitializers() 245 { 246 return &this->m_Initializers; 247 } 248 249 //! @brief イニシャライザの配列を取得します。 250 //! @details 通常は生成時にサイズが決定されるため、生成後に追加削除することはできません。 251 //! @return イニシャライザの配列へのポインタを返します。 GetInitializers()252 const ut::MoveArray<Initializer>* GetInitializers() const 253 { 254 return &this->m_Initializers; 255 } 256 257 //! @brief アップデータの配列を取得します。 258 //! @details 通常は生成時にサイズが決定されるため、生成後に追加削除することはできません。 259 //! @return アップデータの配列へのポインタを返します。 GetUpdaters()260 ut::MoveArray<Updater>* GetUpdaters() 261 { 262 return &this->m_Updaters; 263 } 264 265 //! @brief アップデータの配列を取得します。 266 //! @details 通常は生成時にサイズが決定されるため、生成後に追加削除することはできません。 267 //! @return アップデータの配列へのポインタを返します。 GetUpdaters()268 const ut::MoveArray<Updater>* GetUpdaters() const 269 { 270 return &this->m_Updaters; 271 } 272 273 #ifdef NW_GFX_PARTICLE_COMPAT_1_1 274 //! @brief パーティクルを追加します。 275 //! @details :private 276 void AddParticles( 277 const nw::math::MTX34& emitterMatrix, 278 const nw::math::VEC3* const positions, 279 ParticleSet* parentParticleSet, 280 const u16* const parentIndices, 281 int count); 282 #else 283 //! @brief パーティクルを追加します。 284 //! @details :private 285 //! パーティクルコレクションに新しくパーティクル粒子を追加します。 286 //! パラメータは重要なもの以外は未初期化です。 287 //! 288 //! @param[in] count 追加する個数です。 289 //! @return 実際に追加できた個数です。 290 int AddParticles(int count); 291 #endif 292 293 //! @brief パーティクルの更新処理を行います。 294 //! @param[in] particleContext パーティクルコンテキストです。 295 //! @param[in] enableSwapBuffer バッファをスワップするかを指定します。 296 void UpdateParticles( 297 ParticleContext* particleContext, 298 bool enableSwapBuffer = true); 299 300 //! @brief パーティクルコレクションを空にします。 301 //! @details パーティクルコレクションのClearを呼び出し、ストリームの状態を初期化します。 302 //! この関数は描画中には使用できません。 303 //! GPUからストリームへのアクセスがない状態で使用してください。 304 void ClearParticleCollection(); 305 306 //! @details :private Srand(u32 seed)307 void Srand(u32 seed) 308 { 309 m_ParticleRandom.Srand(seed); 310 } 311 312 //! @brief スケールのオフセット値を取得します。 313 //! @details 個々のパーティクルのスケールに乗算するオフセットを取得します。 314 //! @return スケールのオフセット値を返します。 GetScaleOffset()315 const nw::math::VEC3& GetScaleOffset() const 316 { 317 return this->m_ScaleOffset; 318 } 319 320 //! @brief スケールのオフセット値を設定します。 321 //! @details 個々のパーティクルのスケールに乗算するオフセットを設定します。 322 //! @param[in] offset 新しいオフセット値 SetScaleOffset(const nw::math::VEC3 & offset)323 void SetScaleOffset(const nw::math::VEC3& offset) 324 { 325 this->m_ScaleOffset = offset; 326 } 327 328 //! @brief 回転のオフセット値を取得します。 329 //! @details 個々のパーティクルの回転に加算するオフセットを取得します。 330 //! @return 回転のオフセット値を返します。 GetRotateOffset()331 const nw::math::VEC3& GetRotateOffset() const 332 { 333 return this->m_RotateOffset; 334 } 335 336 //! @brief 回転のオフセット値を設定します。 337 //! @details 個々のパーティクルの回転に加算するオフセットを設定します。 338 //! @param[in] offset 新しいオフセット値 SetRotateOffset(const nw::math::VEC3 & offset)339 void SetRotateOffset(const nw::math::VEC3& offset) 340 { 341 this->m_RotateOffset = offset; 342 } 343 344 //! @details :private WorldMatrix()345 const nw::math::MTX34& WorldMatrix() 346 { 347 if (this->GetResParticleSet().GetIsForceWorld()) 348 { 349 return nw::math::MTX34::Identity(); 350 } 351 else 352 { 353 ParticleModel* model = static_cast<ParticleModel*>(this->GetParent()); 354 return model->WorldMatrix(); 355 } 356 } 357 358 //! @details :private InverseWorldMatrix()359 const nw::math::MTX34& InverseWorldMatrix() 360 { 361 if (this->GetResParticleSet().GetIsForceWorld()) 362 { 363 return nw::math::MTX34::Identity(); 364 } 365 else 366 { 367 ParticleModel* model = static_cast<ParticleModel*>(this->GetParent()); 368 return model->InverseWorldMatrix(); 369 } 370 } 371 372 //! @brief 描画順を取得します。 373 //! @return 生成順の時にtrueを返します。 IsAscendingOrder()374 bool IsAscendingOrder() const 375 { 376 const ResParticleShapeBuilder& resShapeBuilder = 377 this->GetResParticleSet().GetParticleShapeBuilder(); 378 return (resShapeBuilder.IsValid()) ? resShapeBuilder.IsAscendingOrder() : true; 379 } 380 381 //! @brief 処理順序のヒント情報をリセットします。 382 //! @details :private ResetDebugHint()383 void ResetDebugHint() 384 { 385 #ifdef NW_CHECK_PARTICLE_PROCESS 386 m_ProcessStep = STEP_NONE; 387 #endif 388 } 389 390 #ifdef NW_CHECK_PARTICLE_PROCESS 391 //! @brief 描画の開始を宣言します。 392 //! @details :private 393 //! 処理順序の確認のためのヒント情報です。 BeginDraw()394 void BeginDraw() 395 { 396 // どの条件下でも描画可能 397 m_ProcessStep = STEP_DRAW; 398 } 399 400 //! @brief アップデートの開始を宣言します。 401 //! @details :private 402 //! 処理順序の確認のためのヒント情報です。 BeginUpdate(bool enableSwapBuffer)403 void BeginUpdate(bool enableSwapBuffer) 404 { 405 if (enableSwapBuffer) 406 { 407 NW_WARNING( 408 m_ProcessStep == STEP_NONE || 409 m_ProcessStep == STEP_DRAW, 410 "detected an illegal order(Update with SwapBuffer Prev:%d)", m_ProcessStep); 411 m_ProcessStep = STEP_UPDATE1; 412 } 413 else 414 { 415 NW_WARNING( 416 m_ProcessStep == STEP_UPDATE1 || 417 m_ProcessStep == STEP_UPDATE2, 418 "detected an illegal order(Update without SwapBuffer Prev:%d)", m_ProcessStep); 419 m_ProcessStep = STEP_UPDATE2; 420 } 421 } 422 423 #endif 424 425 //@} 426 427 //---------------------------------------- 428 //! @name 初期化/更新 429 //@{ 430 431 //! @brief 新しく追加したパーティクルを初期化します。 432 //! @details :private 433 //! 434 //! @param[in] startIndex 初期化を開始するパーティクルのストリーム上のインデックスです。 435 //! @param[in] count 初期化するパーティクルの数です。 436 //! @param[in] incrIndex インデックスの変化する方向を 1, または -1 で指定します。 437 //! @param[in] time 現在の時刻です。 438 void InitializeParticles( 439 int startIndex, 440 int count, 441 int incrIndex, 442 ParticleTime time); 443 444 //@} 445 446 protected: 447 //---------------------------------------- 448 //! @name コンストラクタ/デストラクタ 449 //@{ 450 451 //! コンストラクタです。 452 ParticleSet( 453 os::IAllocator* allocator, 454 ResParticleSet resObj, 455 const ParticleSet::Description& description); 456 457 //! デストラクタです。 458 virtual ~ParticleSet(); 459 460 //@} 461 462 private: 463 ParticleCollection* m_ParticleCollection; 464 465 ParticleRandom m_ParticleRandom; 466 467 ut::MoveArray<Initializer> m_Initializers; 468 ut::MoveArray<Updater> m_Updaters; 469 470 math::VEC3 m_ScaleOffset; 471 math::VEC3 m_RotateOffset; 472 473 bool m_UsePrevTranslate; 474 475 #ifdef NW_CHECK_PARTICLE_PROCESS 476 //! 処理の状態 477 enum ProcessStep 478 { 479 STEP_NONE, //! 未定義 480 STEP_UPDATE1, //! アップデート1回目(swapあり) 481 STEP_UPDATE2, //! アップデート2回目(swapなし) 482 STEP_DRAW //! 描画 483 } m_ProcessStep; 484 #endif 485 486 }; 487 488 } // namespace gfx 489 } // namespace nw 490 491 #endif // NW_GFX_PARTICLESET_H_ 492