/*---------------------------------------------------------------------------* Project: NintendoWare File: ParticleCombinationNodeDemo.cpp 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: $ *---------------------------------------------------------------------------*/ #define NW_DEBUG_CHECK_MEMORY_LEAK #include #include #include #include #include #include #include namespace { //---------------------------------------- // メモリ関係 // デバイスメモリを確保するためのアロケータです。 nw::demo::DemoAllocator s_DeviceAllocator; nw::demo::DemoAllocator s_ParticleAllocator; //---------------------------------------- // ファイル名の定義です。 const wchar_t* SKY_SPHERE_FILE_NAME = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl"); //---------------------------------------- // 描画関係 const int RENDER_TARGET_COUNT = 1; typedef nw::ut::FixedSizeArray RenderTargetArray; RenderTargetArray s_RenderTargets; nw::demo::SceneSystem* s_SceneSystem = NULL; nw::demo::RenderSystem* s_RenderSystem = NULL; nw::gfx::ParticleContext* s_ParticleContext = NULL; nw::demo::GraphicsDrawing s_GraphicsDrawing; //---------------------------------------- // リソース関係 nw::demo::ResourceArray s_Resources; //---------------------------------------- // シーン関係 nw::gfx::SceneNode* s_SceneRoot = NULL; s32 s_FrameCount = 0; nw::gfx::Camera* s_BaseCamera = NULL; nw::gfx::Camera* s_LeftCamera = NULL; nw::gfx::Camera* s_RightCamera = NULL; const f32 s_fNearPlane = 0.1f; const s32 s_BaseCameraIndex = 0; //---------------------------------------- // パーティクル関係 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL; nw::demo::FlushCache* s_FlushCache; /*!--------------------------------------------------------------------------* @brief グラフィックス関連の初期化を行います。 *---------------------------------------------------------------------------*/ void InitializeGraphics() { nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator ); // renderDescriptionへステレオの設定を行います。 nw::demo::RenderSystem::Description renderDescription; renderDescription.reusableCommandBufferSize = 0x100000; renderDescription.reusableCommandRequestCount = 512; renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO; s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription); s_GraphicsDrawing.SetScreenSize( renderDescription.lowerScreenDescription.width, renderDescription.lowerScreenDescription.height ); nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing); s_RenderTargets.push_back( nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription) ); NW_ASSERT(!s_RenderTargets.empty()); s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front()); // sceneDescriptionへの標準的な設定はコンストラクタで行われています。 nw::demo::SceneSystem::Description sceneDescription; s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription); s_ParticleContext = nw::gfx::ParticleContext::Builder() .MaxEmission(1000) .Create(&s_DeviceAllocator); s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder() .Create(&s_DeviceAllocator); // デモ用の最遠景モデルをレンダリングシステムに設定します。 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME); NW_GL_ASSERT(); } /*!--------------------------------------------------------------------------* @brief グラフィックス関連の後始末をします。 *---------------------------------------------------------------------------*/ void TerminateGraphics() { nw::gfx::SafeDestroy(s_LeftCamera); nw::gfx::SafeDestroy(s_RightCamera); nw::gfx::SafeDestroy(s_ParticleSceneUpdater); nw::gfx::SafeDestroy(s_ParticleContext); nw::gfx::SafeDestroy(s_SceneSystem); nw::gfx::SafeDestroyAll(s_RenderTargets); s_GraphicsDrawing.Finalize(); nw::gfx::SafeDestroy(s_RenderSystem); NW_GL_ASSERT(); } /*!--------------------------------------------------------------------------* @brief ルートノード関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildRootNodes() { NW_ASSERT(s_SceneRoot == NULL); s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder() .IsFixedSizeMemory(false) .Create(&s_DeviceAllocator); NW_NULL_ASSERT(s_SceneRoot); } /*!--------------------------------------------------------------------------* @brief カメラ関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildCameras() { nw::demo::Utility::CreateStereoCameras( &s_BaseCamera, &s_LeftCamera, &s_RightCamera, &s_DeviceAllocator, nw::math::VEC3(0.0f, 13.0f, 70.f), nw::math::VEC3(0.0f, 13.0f, 0.0f), s_fNearPlane ); s_SceneRoot->AttachChild(s_BaseCamera); s_SceneSystem->GetCameraController()->Register(s_BaseCamera); } /*!--------------------------------------------------------------------------* @brief シーンを初期化します。 *---------------------------------------------------------------------------*/ void InitializeScenes() { BuildRootNodes(); BuildCameras(); // シーンツリーを巡回して初期化を行います。 s_SceneSystem->InitializeScene(s_SceneRoot); s_SceneSystem->UpdateScene(); // カメラを設定します。 nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment(); sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera); nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]); NW_GL_ASSERT(); s_FrameCount = 0; } /*!--------------------------------------------------------------------------* @brief シーン関連の後始末をします。 *---------------------------------------------------------------------------*/ void TerminateScenes() { nw::gfx::SafeDestroyBranch(s_SceneRoot); nw::demo::SafeCleanupResources(s_Resources); NW_GL_ASSERT(); s_Resources.clear(); } /*!--------------------------------------------------------------------------* @brief シーンを更新します。 *---------------------------------------------------------------------------*/ void UpdateScene() { NW_ASSERT(0 < s_RenderTargets.size()); s_SceneSystem->GetCameraController()->Update(); s_SceneSystem->UpdateScene(); s_BaseCamera->UpdateCameraMatrix(); NW_NULL_ASSERT(s_ParticleSceneUpdater); s_ParticleSceneUpdater->UpdateNode( s_SceneSystem->GetSceneContext(), s_ParticleContext); s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f); s_FrameCount++; s_FlushCache->Execute(); } /*!--------------------------------------------------------------------------* @brief 負荷表示やテスト機能の処理をおこないます。 *---------------------------------------------------------------------------*/ void ReportDemo() { NW_PROFILE("ReportDemo"); // 負荷表示からはこれらの負荷は除きます。 s_RenderSystem->SuspendLoadMeter(); nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem); s_GraphicsDrawing.BeginDrawingShape(); nw::demo::DebugUtility::DrawLoadMeter( s_RenderSystem, &s_GraphicsDrawing ); s_GraphicsDrawing.EndDrawingShape(); s_GraphicsDrawing.BeginDrawingString(); nw::demo::DebugUtility::DrawLoadMeterText( s_RenderSystem, &s_GraphicsDrawing ); s_GraphicsDrawing.EndDrawingString(); s_RenderSystem->ResumeLoadMeter(); } //---------------------------------------- // デモ固有の変数 // パーティクルエフェクトクラス nw::demo::ParticleEffect* s_ParticleEffect = NULL; // 配置数 #define DEMO_FIRE_DRAW_NUM (5) // パーティクルハンドルクラス nw::demo::ParticleHandle* s_PaticleHandle5M5E[DEMO_FIRE_DRAW_NUM]; nw::demo::ParticleHandle* s_PaticleHandle1M5E = NULL; nw::demo::ParticleHandle* s_PaticleHandle1M1E = NULL; // カウンタ u32 s_Count = 0; // アニメーションステート enum { DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER = 0, DEMO_ASSORTMENT_STATE_1MODEL_5EMITTER = 1, DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER = 2, DEMO_ASSORTMENT_STATE_MAX = 3 }; u32 s_AnimationState = DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER; // ロードするエフェクトファイル const wchar_t* EFFECT_RESOURCE_FILE = NW_DEMO_FILE_PATH(L"fire_particle_mem5.bcptl"); // ロードするエフェクトシェーダファイル const wchar_t* SHADER_RESOURCE_FILE_NAME = NW_DEMO_FILE_PATH(L"nwgfx_ParticleDefaultShader.bcsdr"); /*!--------------------------------------------------------------------------* @brief ParticleNodeCombinationDemoの初期化を行います。 *---------------------------------------------------------------------------*/ void InitializeParticleNodeCombinationDemo() { // 以下のパーティクルモデル/エミッタ組み合わせを用いて、 // 炎エフェクトを画面に5つ表示するデモです。 // 5 ParticleModel - 5 ParticleEmitter(5M5E) // 配置等の扱いは容易ですが、メモリ・処理速度面で不利です。 // // 1 ParticleModel - 5 ParticleEmitter(1M5E) // 自由度が低くなりますが、処理速度やメモリ使用量で有利です。 // // 1 ParticleModel - 1 ParticleEmitter(1M1E) // 自由度が低くなりますが、処理速度やメモリ使用量で有利です。 // また、この手法は放出間隔が1フレームのデータにしか適用できません。 // メモリ面では(1M1E)、速度面では(1M5E)の方が有利です。 s_AnimationState = DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER; s_Count = 0; s_ParticleEffect = NULL; // シェーダバイナリをロードします。 nw::demo::ParticleEffect::InitializeShaderBinary(SHADER_RESOURCE_FILE_NAME, &s_DeviceAllocator); // パーティクルエフェクトクラスを生成します。 s_ParticleEffect = nw::demo::ParticleEffect::Create(&s_DeviceAllocator, &s_DeviceAllocator, false, s_ParticleContext); // エフェクトデータをロードしてセットアップします。 nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, EFFECT_RESOURCE_FILE, &s_DeviceAllocator); // リソースのセットアップを行います。 s_ParticleEffect->Setup(resourceSet->resource, false); // ParticleEffectにリソースをセットします。 s_ParticleEffect->Register(resourceSet->resource); s_ParticleEffect->AddPool(6); // (5M5E)の準備を行います。 for (s32 i = 0; i < DEMO_FIRE_DRAW_NUM; ++i) { s_PaticleHandle5M5E[i] = s_ParticleEffect->LeaseInstance(); if (s_PaticleHandle5M5E[i]) { s_PaticleHandle5M5E[i]->SetTranslate(10.0f * (i - 2), 0.f, 0.f); } // シーンに追加します。 s_SceneRoot->AttachChild(s_PaticleHandle5M5E[i]); } // (1M5E)の準備を行います。 s_PaticleHandle1M5E = s_ParticleEffect->CreateMultiEmitterParticleHandle( DEMO_FIRE_DRAW_NUM ); if (s_PaticleHandle1M5E) { for (s32 i = 0; i < s_PaticleHandle1M5E->GetParticleEmitterSize(); ++i) { s_PaticleHandle1M5E->GetParticleEmitter(i)->Transform().SetTranslate(10.0f * (i - 2), 0.f, 0.f); } } // (1M1E)の準備を行います。 s_PaticleHandle1M1E = s_ParticleEffect->LeaseInstance(); s_PaticleHandle1M1E->SetTranslate(0.f, 0.f, 0.f); s_SceneRoot->AttachChild(s_PaticleHandle1M1E); // シーンを更新します。 s_SceneSystem->InitializeScene(s_SceneRoot); s_SceneSystem->UpdateScene(); } /*!--------------------------------------------------------------------------* @brief ParticleNodeCombinationDemoの定期処理です。 *---------------------------------------------------------------------------*/ void UpdateParticleNodeCombinationDemo() { ++s_Count; // 600フレームごとに組み合わせパターンを変更します。 if ( s_Count%600 == 0 ) { s_Count = 0; switch(s_AnimationState) { case DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER: { // (5M5E)ノードをデタッチします。 for (u32 i = 0; i < DEMO_FIRE_DRAW_NUM; ++i) { s_SceneRoot->DetachChild(s_PaticleHandle5M5E[i]); } // (1M5E)ノードをアタッチします。 s_SceneRoot->AttachChild(s_PaticleHandle1M5E); // シーンを更新します。 s_SceneSystem->InitializeScene(s_SceneRoot); s_SceneSystem->UpdateScene(); s_AnimationState = DEMO_ASSORTMENT_STATE_1MODEL_5EMITTER; } break; case DEMO_ASSORTMENT_STATE_1MODEL_5EMITTER: { // (1M5E)ノードをデタッチします。 s_SceneRoot->DetachChild(s_PaticleHandle1M5E); // (1M1E)ノードをアタッチします。 s_SceneRoot->AttachChild(s_PaticleHandle1M1E); // シーンを更新します。 s_SceneSystem->InitializeScene(s_SceneRoot); s_SceneSystem->UpdateScene(); s_AnimationState = DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER; } break; case DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER: { // (1M1E)ノードをデタッチします。 s_SceneRoot->DetachChild(s_PaticleHandle1M1E); // (5M5E)ノードをアタッチします。 for (u32 i = 0; i < DEMO_FIRE_DRAW_NUM; ++i) { s_SceneRoot->AttachChild(s_PaticleHandle5M5E[i]); } // シーンを更新します。 s_SceneSystem->InitializeScene(s_SceneRoot); s_SceneSystem->UpdateScene(); s_AnimationState = DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER; } break; default: break; } } // (1M1E)の場合は、毎フレーム放出位置の変更と放出処理を行う必要があります。 // 放出処理の後、Reset処理を行うので、放出間隔1フレーム以外の値を // 指定しているデータにおいても、毎フレーム放出を行ってしまうので注意が必要です。 if( s_AnimationState == DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER ) { nw::gfx::ParticleEmitter* emitter = s_PaticleHandle1M1E->GetParticleEmitter(0); if (emitter) { for (s32 i = 0; i < DEMO_FIRE_DRAW_NUM; ++i) { // 放出位置を設定します。 emitter->WorldMatrix().SetupTranslate(nn::math::VEC3(nw::math::VEC3(10.0f * (i - 2), 0.f, 0.f))); // 放出処理を行い、リセットを行います。 emitter->UpdateParticleFrame(); emitter->Emission(s_ParticleContext); emitter->Reset(); } } } } /*!--------------------------------------------------------------------------* @brief ParticleNodeCombinationDemoのスクリーンデバッグ表示です。 *---------------------------------------------------------------------------*/ void ReportParticleNodeCombinationDemo() { s_GraphicsDrawing.DrawString(10, 10, "Counter : %d\n", (600 - s_Count) ); switch(s_AnimationState) { case DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER: { s_GraphicsDrawing.DrawString(10, 22, "Particle Model Num : 5\n" ); s_GraphicsDrawing.DrawString(10, 34, "Particle Emitter Num : 5\n" ); } break; case DEMO_ASSORTMENT_STATE_1MODEL_5EMITTER: { s_GraphicsDrawing.DrawString(10, 22, "Particle Model Num : 1\n" ); s_GraphicsDrawing.DrawString(10, 34, "Particle Emitter Num : 5\n" ); } break; case DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER: { s_GraphicsDrawing.DrawString(10, 22, "Particle Model Num : 1\n" ); s_GraphicsDrawing.DrawString(10, 34, "Particle Emitter Num : 1\n" ); } break; } } /*!--------------------------------------------------------------------------* @brief ParticleNodeCombinationDemoの終了処理を行います。 *---------------------------------------------------------------------------*/ void TerminateParticleNodeCombinationDemo() { // s_ParticleEffect->DestroyParticleHandle(s_PaticleHandle1M1E); nw::demo::ParticleNode* prevTarget = s_ParticleEffect->GetActiveEffect(0); while (prevTarget != NULL) { s_ParticleEffect->ReleaseInstance(prevTarget); prevTarget = s_ParticleEffect->GetActiveEffect(0); } // CreateMultiEmitterParticleHandle で生成したので、ハンドルの破棄が必要です。 s_ParticleEffect->DestroyParticleHandle(s_PaticleHandle1M5E); s_ParticleEffect->FreePool(); nw::ut::SafeDestroy(s_ParticleEffect); // ロードしたパーティクルシェーダを破棄します。 nw::demo::ParticleEffect::FinalizeShaderBinary(); } /*!--------------------------------------------------------------------------* @brief シーンをデモンストレーションします。 *---------------------------------------------------------------------------*/ void DemoScene() { NW_ASSERT(!s_RenderTargets.empty()); nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext(); InitializeScenes(); // ParticleNodeCombinationDemoの初期化処理です。 InitializeParticleNodeCombinationDemo(); bool isContinuing = true; while ( isContinuing ) { nw::demo::DebugUtility::AdvanceAutoTestFrame(); nw::demo::PadFactory::GetPad()->Update(); // ParticleNodeCombinationDemoの定期処理です。 UpdateParticleNodeCombinationDemo(); UpdateScene(); renderContext->SetActiveCamera(s_BaseCameraIndex); s_RenderSystem->SubmitView(s_SceneSystem); s_RenderSystem->SetRenderTarget(s_RenderTargets[0]); s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera); s_RenderSystem->ClearBySkyModel(s_BaseCamera); ReportDemo(); // ParticleNodeCombinationDemoのレポートを表示します。 ReportParticleNodeCombinationDemo(); s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN); s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN); renderContext->ResetState(); if (nw::demo::Utility::IsTerminating()) { isContinuing = false; } } // ParticleNodeCombinationDemoの終了処理です。 TerminateParticleNodeCombinationDemo(); TerminateScenes(); } } // namespace /*!--------------------------------------------------------------------------* @brief メイン関数です。 *---------------------------------------------------------------------------*/ void nnMain() { nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator); nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE); nw::demo::PadFactory::Initialize(&s_DeviceAllocator); NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem) { InitializeGraphics(); s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator); DemoScene(); nw::ut::SafeDestroy(s_FlushCache); TerminateGraphics(); } nw::demo::PadFactory::Finalize(); nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator); nw::demo::FinalizeGraphicsSystem(); }