/*---------------------------------------------------------------------------* Project: NintendoWare File: UserRenderNodeDemo.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 #include #include "GrRenderer.h" namespace { class GrUserRenderCommand; //---------------------------------------- // メモリ関係 // デバイスメモリを確保するためのアロケータです。 nw::demo::DemoAllocator s_DeviceAllocator; //---------------------------------------- // ファイル名の定義です。 const wchar_t* SKY_SPHERE_FILE_NAME = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl"); const wchar_t* MODEL_RESOURCE_FILES[] = { NW_DEMO_FILE_PATH(L"Male.bcmdl"), NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"), NW_DEMO_FILE_PATH(L"FragmentLight.bcenv") }; const wchar_t* GR_SHADER_FILE = NW_DEMO_FILE_PATH(L"UserRenderCommandShader.shbin"); //---------------------------------------- // 描画関係 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; static nw::demo::GraphicsDrawing s_GraphicsDrawing; //---------------------------------------- // リソース関係 nw::demo::ResourceArray s_Resources; //---------------------------------------- // シーン関係 const int SCENE_NODE_COUNT = 8; 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 s32 s_BaseCameraIndex = 0; //---------------------------------------- // シーン環境関係 const s32 ENVIRONMENT_SETTINGS_COUNT = 1; typedef nw::ut::FixedSizeArray SceneEnvironmentSettingArray; SceneEnvironmentSettingArray s_SceneEnvironmentSettings; //---------------------------------------- // ユーザ定義の描画ノードによる描画関係 nw::gfx::UserRenderNode* s_UserRenderNode = NULL; GrUserRenderCommand* s_GrUserRenderCommand = NULL; GrPrimitiveRenderer s_GrPrimitiveRenderer; /*!--------------------------------------------------------------------------* @brief GR で描画するためののレンダーコマンドです。 *---------------------------------------------------------------------------*/ class GrUserRenderCommand : public nw::gfx::UserRenderCommand { public: //! @brief コマンドを呼び出します。 virtual void Invoke(nw::gfx::RenderContext* renderContext) { // UserRenderCommand が設定されている UserRenderNode を取得 nw::gfx::UserRenderNode* userRenderNode = GetUserRenderNode(); NW_NULL_ASSERT( userRenderNode ); nw::math::MTX34& worldMatrix = userRenderNode->WorldMatrix(); // 描画コマンドバッファのポインタを取得 u32* command = NULL; nngxGetCmdlistParameteri( NN_GX_CMDLIST_CURRENT_BUFADDR, reinterpret_cast(&command)); // 最後にポインタを進めるため、現在のコマンドリストの先頭アドレスを保存 const u32* start_addr = command; command = s_GrPrimitiveRenderer.MakeSceneBeginCommand(command); command = s_GrPrimitiveRenderer.MakeDrawBoxCommand(command, worldMatrix); command = s_GrPrimitiveRenderer.MakeSceneEndCommand(command); // コマンドリストのポインタを進める nngxMoveCommandbufferPointer((command - start_addr) * sizeof(u32)); // GR で描画するためにシェーダーを切り替えているので、 // レンダーコンテキストをリセットする。 renderContext->ResetState( nw::gfx::RenderContext::RESETSTATEMODE_SHADER_PROGRAM | nw::gfx::RenderContext::RESETSTATEMODE_MATERIAL_CACHE ,0); } public: //! コンストラクタです。 GrUserRenderCommand(){} //! デストラクタです。 virtual ~GrUserRenderCommand() {} }; /*!--------------------------------------------------------------------------* @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; // maxUserRenderNodes はデフォルト値が 0 になっているので、ここで値を設定します。 sceneDescription.maxUserRenderNodes = 1; s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription); // デモ用の最遠景モデルをレンダリングシステムに設定します。 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME); s_GrPrimitiveRenderer.Initialize( &s_DeviceAllocator, GR_SHADER_FILE ); NW_GL_ASSERT(); } /*!--------------------------------------------------------------------------* @brief グラフィックス関連の後始末をします。 *---------------------------------------------------------------------------*/ void TerminateGraphics() { s_GrPrimitiveRenderer.Finalize(); nw::gfx::SafeDestroy(s_LeftCamera); nw::gfx::SafeDestroy(s_RightCamera); nw::gfx::SafeDestroy(s_SceneSystem); nw::gfx::SafeDestroyAll(s_RenderTargets); s_GraphicsDrawing.Finalize(); nw::gfx::SafeDestroy(s_RenderSystem); NW_GL_ASSERT(); } /*!--------------------------------------------------------------------------* @brief ユーザ定義の描画ノード関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildUserRenderNode() { // ユーザ定義の描画コマンドを生成します void* userCommandMemory = s_DeviceAllocator.Alloc(sizeof(GrUserRenderCommand)); NW_NULL_ASSERT(userCommandMemory); s_GrUserRenderCommand = new(userCommandMemory) GrUserRenderCommand(); // ユーザ定義の描画ノードを生成します NW_ASSERT(s_UserRenderNode == NULL); s_UserRenderNode = nw::gfx::UserRenderNode::DynamicBuilder() .IsFixedSizeMemory(false) .Create(&s_DeviceAllocator); NW_NULL_ASSERT(s_UserRenderNode); // UserRenderNode は Z ソートされないので // 描画優先度とレイヤー ID のみによってのみ描画順が制御できます。 s_UserRenderNode->SetPriority( 0 ); s_UserRenderNode->SetLayerId( 0 ); // ユーザ定義の描画ノードに描画コマンドを設定します s_UserRenderNode->SetUserRenderCommand(s_GrUserRenderCommand); // ユーザ定義の描画ノードをアタッチします s_SceneRoot->AttachChild(s_UserRenderNode); s_UserRenderNode->Transform().SetTranslate(nw::math::VEC3(-5.0f, 5.0f, 0.0f)); } /*!--------------------------------------------------------------------------* @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(23.0f, 20.0f, 21.0f), nw::math::VEC3(0.0f, 8.0f, 0.0f) ); s_SceneRoot->AttachChild(s_BaseCamera); s_SceneSystem->GetCameraController()->Register(s_BaseCamera); } /*!--------------------------------------------------------------------------* @brief リソース関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildResources(nw::demo::ResourceSet* resourceSet) { 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)); 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::Model* model = nw::ut::DynamicCast(node); model->Transform().SetTranslate(nw::math::VEC3(5.0f, 0.0f, 0.0f)); } 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); } // 親子付け参照関係を解決 nw::gfx::SceneHelper::ResolveReference(sceneNodeArray); nw::gfx::SceneHelper::ForeachRootNodes( sceneNodeArray.Begin(), sceneNodeArray.End(), nw::gfx::AttachNode(s_SceneRoot) ); 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(); BuildUserRenderNode(); BuildCameras(); NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES) { BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator)); } // シーンツリーを巡回して初期化を行います。 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_BaseCamera); nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]); NW_GL_ASSERT(); s_FrameCount = 0; } /*!--------------------------------------------------------------------------* @brief シーン関連の後始末をします。 *---------------------------------------------------------------------------*/ void TerminateScenes() { s_DeviceAllocator.Free(s_GrUserRenderCommand); nw::gfx::SafeDestroyBranch(s_UserRenderNode); nw::gfx::SafeDestroyBranch(s_SceneRoot); nw::demo::SafeCleanupResources(s_Resources); nw::gfx::SafeDestroyAll(s_SceneEnvironmentSettings); NW_GL_ASSERT(); s_Resources.clear(); } /*!--------------------------------------------------------------------------* @brief シーンを更新します。 *---------------------------------------------------------------------------*/ void UpdateScene() { s_SceneSystem->GetCameraController()->Update(); s_SceneSystem->UpdateScene(); s_BaseCamera->UpdateCameraMatrix(); nw::gfx::ResCameraProjectionUpdater resProjectionUpdater = s_BaseCamera->GetProjectionUpdater()->GetResource(); int near = resProjectionUpdater.GetNear(); s_RenderSystem->CalcStereoCamera( s_LeftCamera, s_RightCamera, s_BaseCamera, near + 5.0f); ++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()); InitializeScenes(); nw::demo::DebugUtility::PostInitializeScenes(); bool isContinuing = true; nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext(); while ( isContinuing ) { nw::demo::DebugUtility::AdvanceAutoTestFrame(); nw::demo::PadFactory::GetPad()->Update(); 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(); 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; } } nw::demo::DebugUtility::PreTerminateScenes(); TerminateScenes(); } } // namespace /*!--------------------------------------------------------------------------* @brief メイン関数です。 *---------------------------------------------------------------------------*/ void nnMain() { nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator); nw::demo::PadFactory::Initialize(&s_DeviceAllocator); NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem) { InitializeGraphics(); DemoScene(); TerminateGraphics(); } nw::demo::PadFactory::Finalize(); nw::demo::FinalizeGraphicsSystem(); }