/*---------------------------------------------------------------------------* Project: NintendoWare File: FastCreateDemo.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: $ *---------------------------------------------------------------------------*/ // FastCreateDemo はフレームヒープアロケータを使用して、 // 高速にオブジェクトの生成と破棄を行なうデモです。 // // 詳しくはドキュメント、および // PrepareBuilder(), BuildLattices(), DestroyLattices() などの実装を // 参照してください。 #define NW_DEBUG_CHECK_MEMORY_LEAK // オブジェクトの生成にフレームヒープアロケータを使用します。 #define USE_FRAME_HEAP #include #include #include #include #include #include #include namespace { //---------------------------------------- // メモリ関係 // デバイスメモリを確保するためのアロケータです。 nw::demo::DemoAllocator s_DeviceAllocator; // フレームヒープアロケータです。 nw::demo::FrameHeapAllocator s_FrameHeapAllocator; //---------------------------------------- // ファイル名の定義です。 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"Beam.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; static nw::demo::GraphicsDrawing s_GraphicsDrawing; //---------------------------------------- // リソース関係 nw::demo::ResourceArray s_Resources; //---------------------------------------- // シーン関係 nw::gfx::TransformNode* s_SceneRoot = NULL; nw::gfx::TransformNode* s_ModelRoot = 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; //---------------------------------------- // シーン環境関係 const s32 ENVIRONMENT_SETTINGS_COUNT = 1; typedef nw::ut::FixedSizeArray SceneEnvironmentSettingArray; SceneEnvironmentSettingArray s_SceneEnvironmentSettings; //---------------------------------------- // モデル関係 const int LATTICE_WIDTH = 2; const int LATTICE_COUNT = (LATTICE_WIDTH * 2) * (LATTICE_WIDTH * 2) * (LATTICE_WIDTH * 2); const f32 LATTICE_SIZE = 14.0f; const int MODEL_PER_LATTICE = 3; const int NODE_PER_LATTICE = MODEL_PER_LATTICE + 1; nw::gfx::ResSceneNode s_ResBeam; nw::gfx::SceneBuilder s_BeamBuilder; nw::gfx::TransformNode::DynamicBuilder s_LatticeRootBuilder; size_t s_SizeOfLattice; struct Lattice { nw::gfx::TransformNode* root; nw::math::VEC3 position; }; typedef nw::ut::FixedSizeArray LatticeArray; LatticeArray s_Lattices; f32 s_PhaseAxis = 0.0f; f32 s_PhaseRot = 0.0f; f32 s_PhaseScale = 0.0f; const f32 STEP_PHASE_AXIS = 0.012f; const f32 STEP_PHASE_ROT = 0.14f; const f32 STEP_PHASE_SCALE = 0.004f; /*!--------------------------------------------------------------------------* @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; sceneDescription.maxSceneNodes = NODE_PER_LATTICE * LATTICE_COUNT + 4; sceneDescription.maxModels = MODEL_PER_LATTICE * LATTICE_COUNT; sceneDescription.maxMaterials = MODEL_PER_LATTICE * LATTICE_COUNT; 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_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 BuildRootNodes() { NW_ASSERT(s_SceneRoot == NULL); s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder() .Create(&s_DeviceAllocator); NW_NULL_ASSERT(s_SceneRoot); NW_ASSERT(s_ModelRoot == NULL); s_ModelRoot = nw::gfx::TransformNode::DynamicBuilder() .MaxChildren(LATTICE_COUNT) .Create(&s_DeviceAllocator); s_SceneRoot->AttachChild(s_ModelRoot); NW_NULL_ASSERT(s_ModelRoot); } /*!--------------------------------------------------------------------------* @brief カメラ関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildCameras() { nw::demo::Utility::CreateStereoCameras( &s_BaseCamera, &s_LeftCamera, &s_RightCamera, &s_DeviceAllocator, nw::math::VEC3(60.0f, 40.0f, 45.0f), nw::math::VEC3(0.0f, 0.0f, 0.0f), s_fNearPlane ); 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(&s_DeviceAllocator); nw::gfx::ResModelArray models = resourceSet->resource.GetModels(); if (models.size() > 0) { // モデルのリソースを記憶しておきます。 s_ResBeam = models[0]; } 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 BuildLattices() { nw::os::IAllocator* allocator; #ifdef USE_FRAME_HEAP // 必要なサイズのメモリをまとめて確保し、 // フレームヒープアロケータにそのメモリを渡して初期化します。 size_t memorySize = s_SizeOfLattice * LATTICE_COUNT; void* memory = s_DeviceAllocator.Alloc(memorySize); s_FrameHeapAllocator.Initialize(reinterpret_cast(memory), memorySize); allocator = &s_FrameHeapAllocator; #else allocator = &s_DeviceAllocator; #endif for (int x = -LATTICE_WIDTH ; x < LATTICE_WIDTH ; ++x) { for (int y = -LATTICE_WIDTH ; y < LATTICE_WIDTH ; ++y) { for (int z = -LATTICE_WIDTH ; z < LATTICE_WIDTH ; ++z) { nw::gfx::TransformNode* root = s_LatticeRootBuilder.Create(allocator); Lattice lattice; lattice.position = nw::math::VEC3( LATTICE_SIZE * x + LATTICE_SIZE * 0.5f, LATTICE_SIZE * y + LATTICE_SIZE * 0.5f, LATTICE_SIZE * z + LATTICE_SIZE * 0.5f); lattice.root = root; for (int i = 0 ; i < 3 ; ++i) { nw::gfx::SceneObject* sceneObject = s_BeamBuilder.CreateObject(allocator, allocator); nw::gfx::Model* beam = reinterpret_cast(sceneObject); beam->Transform().SetRotateXYZ( (i == 1 ? nn::math::F_PI * 0.5f : 0.0f), (i == 2 ? nn::math::F_PI * 0.5f : 0.0f), 0.0f); root->AttachChild(beam); } s_Lattices.push_back(lattice); s_ModelRoot->AttachChild(root); } } } } /*!--------------------------------------------------------------------------* @brief すべてのモデルを破棄します。 *---------------------------------------------------------------------------*/ void DestroyLattices() { s_ModelRoot->DetachAllChildren(); #ifdef USE_FRAME_HEAP // フレームヒープを使用してモデルを作成した場合、 // 確保したメモリをまとめて破棄することで、 // Destroy の呼び出しを省略することができます。 void* memory = reinterpret_cast(s_FrameHeapAllocator.GetStartAddress()); s_FrameHeapAllocator.Finalize(); s_DeviceAllocator.Free(memory); #else // 拡張ヒープを使用してモデルを作成した場合、 // それぞれ Destroy を呼んで、 // 適切にメモリを解放する必要があります。 LatticeArray::iterator end = s_Lattices.end(); for (LatticeArray::iterator model = s_Lattices.begin(); model != end; ++model) { (*model).root->DestroyBranch(); } #endif s_Lattices.clear(); } /*!--------------------------------------------------------------------------* @brief モデルの位置を更新し、また再作成を行ないます。 *---------------------------------------------------------------------------*/ void UpdateLattices() { DestroyLattices(); BuildLattices(); // 各格子の位置を計算します。 f32 scale = -nw::math::CosRad(s_PhaseScale) * 0.5f + 0.5f; nw::math::VEC3 axis(0.0f, 0.0f, 0.0f); nw::math::SinCosRad(&axis.x, &axis.y, s_PhaseAxis); nw::math::MTX34 mat; nw::math::MTX34RotAxisDeg(&mat, &axis, s_PhaseRot); LatticeArray::iterator end = s_Lattices.end(); for (LatticeArray::iterator model = s_Lattices.begin(); model != end; ++model) { nw::math::VEC3 pos = (*model).position * scale; VEC3TransformNormal(&pos, &mat, &pos); (*model).root->Transform().SetTranslate(pos); } s_PhaseAxis += STEP_PHASE_AXIS; s_PhaseRot += STEP_PHASE_ROT; s_PhaseScale += STEP_PHASE_SCALE; } /*!--------------------------------------------------------------------------* @brief ノードの Builder の準備を行ないます。 *---------------------------------------------------------------------------*/ void PrepareBuilder() { NW_ASSERT(s_ResBeam.IsValid()); // 各 Builder を設定します。 s_BeamBuilder .Resource(s_ResBeam) .MaxCallbacks(0) .MaxChildren(0) .BufferOption(nw::gfx::Model::FLAG_BUFFER_NOT_USE) .IsAnimationEnabled(false); s_LatticeRootBuilder .MaxCallbacks(0) .MaxChildren(3); // 1つの格子を生成するために必要なメモリサイズを計算します。 s_SizeOfLattice = s_BeamBuilder.GetMemorySize() * 3 + s_LatticeRootBuilder.GetMemorySize(); } /*!--------------------------------------------------------------------------* @brief シーンを初期化します。 *---------------------------------------------------------------------------*/ void InitializeScenes() { BuildRootNodes(); BuildCameras(); NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES) { BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator)); } PrepareBuilder(); BuildLattices(); // シーンツリーを巡回して初期化を行います。 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; s_PhaseAxis = 0.0f; s_PhaseRot = 0.0f; s_PhaseScale = 0.0f; } /*!--------------------------------------------------------------------------* @brief シーン関連の後始末をします。 *---------------------------------------------------------------------------*/ void TerminateScenes() { DestroyLattices(); nw::gfx::SafeDestroyBranch(s_SceneRoot); nw::demo::SafeCleanupResources(s_Resources); nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings); NW_GL_ASSERT(); s_Resources.clear(); s_SceneEnvironmentSettings.clear(); s_Lattices.clear(); s_ModelRoot = NULL; } /*!--------------------------------------------------------------------------* @brief シーンを更新します。 *---------------------------------------------------------------------------*/ void UpdateScene() { UpdateLattices(); 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()); 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(); 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(); }