/*---------------------------------------------------------------------------* Project: NintendoWare File: SimpleDemo.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: 31311 $ *---------------------------------------------------------------------------*/ #define NW_DEBUG_CHECK_MEMORY_LEAK #include #include #include #include #include #include #include namespace { //---------------------------------------- // メモリ関係 // デバイスメモリを確保するためのアロケータです。 nw::demo::DemoAllocator s_DeviceAllocator; //---------------------------------------- // ファイル名の定義です。 const wchar_t* SKY_SPHERE_FILE_NAME = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl"); static const wchar_t* MODEL_RESOURCE_FILES[] = { NW_DEMO_FILE_PATH(L"Cube.bcmdl"), NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"), NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"), }; //---------------------------------------- // 描画関係 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::demo::GraphicsDrawing s_GraphicsDrawing; //---------------------------------------- // リソース関係 nw::demo::ResourceArray s_Resources; //---------------------------------------- // シーン関係 const int SCENE_NODE_COUNT = 4; nw::gfx::SceneNode* s_SceneRoot = NULL; nw::gfx::Camera* s_Camera = NULL; s32 s_FrameCount = 0; //---------------------------------------- // シーン環境関係 const s32 ENVIRONMENT_SETTINGS_COUNT = 1; typedef nw::ut::FixedSizeArray SceneEnvironmentSettingArray; SceneEnvironmentSettingArray s_SceneEnvironmentSettings; const s32 s_BaseCameraIndex = 0; /*!--------------------------------------------------------------------------* @brief グラフィックス関連の初期化を行います。 *---------------------------------------------------------------------------*/ void InitializeGraphics() { // コマンドキャッシュを動的に確保するためにアロケータを渡します。 // gfx のライブラリを使う前に必ずアロケータを設定する必要があります。 nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator ); // デモ用のレンダリングシステムのインスタンスを生成します。 // 生成の設定である構造体 renderDescription への標準的な値の設定は // 構造体のコンストラクタで行われています。 nw::demo::RenderSystem::Description renderDescription; s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription); // デバッグ表示用の GraphicsDrawing を初期化します。 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()); // デモ用のシーンシステムのインスタンスを生成します。 // 生成の設定である構造体 sceneDescription への標準的な値の設定は // 構造体のコンストラクタで行われています。 nw::demo::SceneSystem::Description sceneDescription; sceneDescription.isFixedSizeMemory = true; s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription); // デモ用の最遠景モデルをレンダリングシステムに設定します。 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME); NW_GL_ASSERT(); } /*!--------------------------------------------------------------------------* @brief グラフィックス関連の後始末をします。 *---------------------------------------------------------------------------*/ void TerminateGraphics() { 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() .Create(&s_DeviceAllocator); NW_NULL_ASSERT(s_SceneRoot); } /*!--------------------------------------------------------------------------* @brief カメラ関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildCameras() { s_Camera = nw::demo::Utility::CreateCamera( &s_DeviceAllocator, nw::math::VEC3(7.0f, 3.5f, -5.0f) ); s_SceneRoot->AttachChild(s_Camera); s_SceneSystem->GetCameraController()->Register(s_Camera); } /*!--------------------------------------------------------------------------* @brief リソース関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildResources(nw::demo::ResourceSet* resourceSet) { // ForeachTexture, ForeachIndexStream, ForeachVertexStream で // ResGraphicsFile 内の ResTexture, ResIndexStream, ResVertexStream に関数オブジェクトを設定します。 // 関数オブジェクトは SetLocationFlag でメモリの配置場所を指定します。 // ここでは VRAMA と VRAMB にテクスチャと頂点データを配置します。 // resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP)); resourceSet->resource.ForeachIndexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP)); resourceSet->resource.ForeachVertexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP)); // リソースのセットアップを行います。リソースのセットアップでは以下のような処理を行います。 // ・シェーダーやテクスチャの参照解決 // ・テクスチャや頂点のVRAM転送 // ・マテリアルのコマンド生成 // // Setup の戻り値 Result は ResourceResult であり、参照解決エラーなどを返します。 // エラーコードが返ってきた場合は引数に必要な ResGraphicsFile を与えて再度 Setup することでエラーを解消できます。 // Setup を行ったリソースは Cleanup を呼び出して内部で確保したメモリなどを破棄する必要があります。 // nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator); if (result.IsFailure()) { NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode()); } nw::ut::MoveArray sceneNodeArray(SCENE_NODE_COUNT, &s_DeviceAllocator); // モデルのインスタンスを生成します。 nw::gfx::ResModelArray models = resourceSet->resource.GetModels(); nw::gfx::ResModelArray::iterator modelsEnd = models.end(); for (nw::gfx::ResModelArray::iterator modelResource = models.begin(); modelResource != modelsEnd; ++modelResource) { nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode( &s_DeviceAllocator, (*modelResource), false ); NW_NULL_ASSERT(node); sceneNodeArray.push_back(node); } // ライトのインスタンスを生成します。 nw::gfx::ResLightArray lights = resourceSet->resource.GetLights(); nw::gfx::ResLightArray::iterator lightsEnd = lights.end(); for (nw::gfx::ResLightArray::iterator lightResource = lights.begin(); lightResource != lightsEnd; ++lightResource) { nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode( &s_DeviceAllocator, (*lightResource) ); NW_NULL_ASSERT(node); sceneNodeArray.push_back(node); } // ファイル内に含まれる SceneNode 継承クラスをすべて渡すことで、 // ResSceneNode の親子階層を SceneNode で構築します。 nw::gfx::SceneHelper::ResolveReference(sceneNodeArray); // SceneNode 継承クラスをシーンルートに追加します。 nw::gfx::SceneHelper::ForeachRootNodes( sceneNodeArray.Begin(), sceneNodeArray.End(), nw::gfx::AttachNode(s_SceneRoot) ); // シーン環境設定のインスタンスを生成します。 // シーン環境はライトセット、カメラ、フォグをマテリアルごとに切り替えるために必要となります。 // SimpleDemo ではライトセットのみ利用しています。 nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings(); nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end(); for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin(); settingResource != settingsEnd; ++settingResource) { nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder() .Resource(*settingResource) .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator); nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting = nw::ut::DynamicCast(sceneObject); NW_NULL_ASSERT(sceneEnvironmentSetting); s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting); } } /*!--------------------------------------------------------------------------* @brief シーンを初期化します。 *---------------------------------------------------------------------------*/ void InitializeScenes() { BuildRootNodes(); BuildCameras(); // ファイルからモデル、ライト、シーン環境のインスタンスを作成して、シーンルートに追加します。 NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES) { BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator)); } // SceneInitializer でマテリアルソートの順序を決定する MaterialId を設定します。 // SceneTraverser でシーンノードの収集と直列化をして SceneContext に追加を行います。 s_SceneSystem->InitializeScene(s_SceneRoot); // カメラ位置を世界座標にするために一度更新しておきます。 s_SceneSystem->UpdateScene(); // シーン環境の参照解決を行い設定します。 s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings); // カメラを設定します。 nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment(); sceneEnvironment.SetCamera(s_BaseCameraIndex, s_Camera); nw::demo::Utility::SetCameraAspectRatio(s_Camera, s_RenderTargets[0]); NW_GL_ASSERT(); s_FrameCount = 0; } /*!--------------------------------------------------------------------------* @brief シーン関連の後始末をします。 *---------------------------------------------------------------------------*/ void TerminateScenes() { nw::gfx::SafeDestroyBranch(s_SceneRoot); nw::demo::SafeCleanupResources(s_Resources); nw::gfx::SafeDestroyAll(s_SceneEnvironmentSettings); NW_GL_ASSERT(); s_Resources.clear(); s_SceneEnvironmentSettings.clear(); } /*!--------------------------------------------------------------------------* @brief シーンを更新します。 *---------------------------------------------------------------------------*/ void UpdateScene() { s_SceneSystem->GetCameraController()->Update(); s_SceneSystem->UpdateScene(); s_Camera->UpdateCameraMatrix(); ++s_FrameCount; } /*!--------------------------------------------------------------------------* @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(); } /*!--------------------------------------------------------------------------* @brief シーンをデモンストレーションします。 *---------------------------------------------------------------------------*/ void DemoScene() { NW_ASSERT(!s_RenderTargets.empty()); nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext(); InitializeScenes(); nw::demo::DebugUtility::PostInitializeScenes(); bool isContinuing = true; while ( isContinuing ) { // テスト用フレームワークの更新を行います。 nw::demo::DebugUtility::AdvanceAutoTestFrame(); // パッドの更新を行います。 nw::demo::PadFactory::GetPad()->Update(); // ここでの処理順序については // ドキュメント『処理フロー』の『グラフィックス描画シーケンス』を参照してください。 // アニメーション、ノード、スケルトン、カメラの更新処理を行います。 UpdateScene(); // ライト、環境マップ、WScale 用のカメラを設定します。 // ActiveCamera は RenderContext::ResetState でリセットされますので、 // 毎フレーム描画前に設定を行う必要があります。 renderContext->SetActiveCamera(s_BaseCameraIndex); // 視点に依存する更新処理と RenderQueue の構築を行います。 s_RenderSystem->SubmitView(s_SceneSystem); // 上画面を描画します。 s_RenderSystem->SetRenderTarget(s_RenderTargets[0]); s_RenderSystem->RenderScene(s_Camera, nw::demo::UPPER_SCREEN); // 下画面をクリアします。 s_RenderSystem->ClearBySkyModel(s_Camera); // 下画面にフォントで描画します。 ReportDemo(); s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN); // 描画されたバッファを表示します。 // PresentBuffer 関数は内部でVSync待ちやコマンドリストの処理を行っています。 // 詳しくは PresentBuffer 関数を参照してください。 s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN); // gfx ライブラリでの描画後に ResetState を呼び出すことで描画に用いたステートをリセットします。 renderContext->ResetState(); if (nw::demo::Utility::IsTerminating()) { isContinuing = false; } } nw::demo::DebugUtility::PreTerminateScenes(); TerminateScenes(); } } // namespace /*!--------------------------------------------------------------------------* @brief メイン関数です。 *---------------------------------------------------------------------------*/ void nnMain() { // SDKとデバイスメモリの初期化処理を行います。 nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator); nw::demo::PadFactory::Initialize(&s_DeviceAllocator); // NW_DEMO_TEST_LOOP はプロファイラなどの初期化を行うマクロです。 // NW_DEBUG_CHECK_MEMORY_LEAK マクロが有効であれば、メモリリークチェックが有効になり、以下のブロックはループになります。 // このとき、パッドの START ボタンを押すと nw::demo::Utility::IsTerminating() が true になるため、 // DemoScene() 内のループから抜けます。 // そして以下のループが繰り返されるときにメモリリークのチェックを行います。 NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem) { InitializeGraphics(); DemoScene(); TerminateGraphics(); } nw::demo::PadFactory::Finalize(); // デバイスメモリの終了処理を行います。 nw::demo::FinalizeGraphicsSystem(); }