/*---------------------------------------------------------------------------* Project: NintendoWare File: SceneTreeDemo.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"); const wchar_t* MODEL_RESOURCE_FILES[] = { NW_DEMO_FILE_PATH(L"SceneTree.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; static nw::demo::GraphicsDrawing s_GraphicsDrawing; //---------------------------------------- // リソース関係 nw::demo::ResourceArray s_Resources; //---------------------------------------- // シーン関係 nw::gfx::TransformNode* s_SceneRoot = NULL; nw::gfx::TransformNode* s_ModelRoot = NULL; nw::gfx::TransformNode* s_CameraRoot = NULL; nw::gfx::TransformNode* s_LightRoot = NULL; nw::gfx::TransformNode* s_FogRoot = 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; /*!--------------------------------------------------------------------------* @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); // デモ用の最遠景モデルをレンダリングシステムに設定します。 // 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() .IsFixedSizeMemory(false) .Create(&s_DeviceAllocator); NW_NULL_ASSERT(s_SceneRoot); NW_ASSERT(s_ModelRoot == NULL); s_ModelRoot = nw::gfx::TransformNode::DynamicBuilder() .IsFixedSizeMemory(false) .Create(&s_DeviceAllocator); s_SceneRoot->AttachChild(s_ModelRoot); NW_NULL_ASSERT(s_ModelRoot); NW_ASSERT(s_CameraRoot == NULL); s_CameraRoot = nw::gfx::TransformNode::DynamicBuilder() .IsFixedSizeMemory(false) .Create(&s_DeviceAllocator); s_SceneRoot->AttachChild(s_CameraRoot); NW_NULL_ASSERT(s_CameraRoot); NW_ASSERT(s_LightRoot == NULL); s_LightRoot = nw::gfx::TransformNode::DynamicBuilder() .IsFixedSizeMemory(false) .Create(&s_DeviceAllocator); s_SceneRoot->AttachChild(s_LightRoot); NW_NULL_ASSERT(s_LightRoot); NW_ASSERT(s_FogRoot == NULL); s_FogRoot = nw::gfx::TransformNode::DynamicBuilder() .IsFixedSizeMemory(false) .Create(&s_DeviceAllocator); s_SceneRoot->AttachChild(s_FogRoot); NW_NULL_ASSERT(s_FogRoot); // テスト用にノードを生成して追加します。 s_SceneRoot->AttachChild(nw::gfx::SceneNode::DynamicBuilder() .MaxChildren(4) .Create(&s_DeviceAllocator)); } /*!--------------------------------------------------------------------------* @brief カメラ関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildCameras() { // シーンツリーを構築します。 // カメラを生成します。 // カメラルートはシーンルートの子ノードになり親のトランスフォームの影響を受けます。 nw::demo::Utility::CreateStereoCameras( &s_BaseCamera, &s_LeftCamera, &s_RightCamera, &s_DeviceAllocator, nw::math::VEC3(45.0f, 30.0f, 45.0f), nw::math::VEC3(-45.0f, -15.0f, -45.0f), s_fNearPlane ); // ビューアップデータがカメラのトランスフォームの影響を受けるようにします。 nw::gfx::ResCameraViewUpdater resViewUpdater = s_BaseCamera->GetViewUpdater()->GetResource(); nw::gfx::ResLookAtTargetViewUpdater resLookAtTargetViewUpdater = nw::gfx::ResDynamicCast(resViewUpdater); resLookAtTargetViewUpdater.SetFlags( nw::gfx::ResLookAtTargetViewUpdaterData::FLAG_INHERITING_TARGET_ROTATE | nw::gfx::ResLookAtTargetViewUpdaterData::FLAG_INHERITING_TARGET_TRANSLATE | nw::gfx::ResLookAtTargetViewUpdaterData::FLAG_INHERITING_UP_ROTATE); s_CameraRoot->AttachChild(s_BaseCamera); s_SceneSystem->GetCameraController()->Register(s_BaseCamera); } /*!--------------------------------------------------------------------------* @brief ライト関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildLights() { // ライトを生成します。 nw::gfx::AmbientLight* ambientLight = nw::gfx::AmbientLight::DynamicBuilder() .MaxCallbacks(0) .MaxChildren(0) .Create(&s_DeviceAllocator); s_LightRoot->AttachChild(ambientLight); nw::gfx::ResAmbientLight resAmbientLight(ambientLight->GetResAmbientLight()); resAmbientLight.SetAmbient(0.2f, 0.2f, 0.2f); nw::gfx::HemiSphereLight* hemiSphereLight = nw::gfx::HemiSphereLight::DynamicBuilder() .MaxCallbacks(0) .MaxChildren(0) .Create(&s_DeviceAllocator); s_LightRoot->AttachChild(hemiSphereLight); nw::gfx::ResHemiSphereLight resHemiSphereLight(hemiSphereLight->GetResHemiSphereLight()); resHemiSphereLight.SetSkyColor(0.9f, 0.9f, 1.0f); resHemiSphereLight.SetGroundColor(0.1f, 0.0f, 0.0f); resHemiSphereLight.SetDirection(0.0f, 1.0f, 0.0f); resHemiSphereLight.SetLerpFactor(0.5f); nw::gfx::VertexLight* vertexLight = nw::gfx::VertexLight::DynamicBuilder() .MaxCallbacks(0) .MaxChildren(0) .Create(&s_DeviceAllocator); s_LightRoot->AttachChild(vertexLight); nw::gfx::ResVertexLight resVertexLight(vertexLight->GetResVertexLight()); resVertexLight.SetLightKind(nw::gfx::ResVertexLight::KIND_SPOT); resVertexLight.GetTransform().translate.Set(0.0f, 15.0f, 5.0f); resVertexLight.SetAmbient(0.2f, 0.2f, 0.2f); resVertexLight.SetDiffuse(1.0f, 1.0f, 1.0f); resVertexLight.SetDistanceAttenuation(0.01f, 0.001f, 0.0001f); resVertexLight.SetDistanceAttenuationEnabled(true); resVertexLight.SetSpotFactor(1.0f, NW_MATH_DEG_TO_RAD(90.0f)); nw::math::VEC3 vertexLightDirection(0.0f, 0.0f, -1.0f); vertexLightDirection.Normalize(); resVertexLight.SetDirection(vertexLightDirection); nw::gfx::FragmentLight* fragmentLight = nw::gfx::FragmentLight::DynamicBuilder() .MaxCallbacks(0) .MaxChildren(0) .Create(&s_DeviceAllocator); s_LightRoot->AttachChild(fragmentLight); nw::gfx::ResFragmentLight resFragmentLight(fragmentLight->GetResFragmentLight()); resFragmentLight.SetLightKind(nw::gfx::ResFragmentLight::KIND_DIRECTIONAL); nw::math::VEC3 fragmentLightDirection(-0.5f, -1.0f, -0.5f); fragmentLightDirection.Normalize(); resFragmentLight.SetDirection(fragmentLightDirection); resFragmentLight.SetAmbient(0.2f, 0.2f, 0.2f); resFragmentLight.SetDiffuse(1.0f, 1.0f, 1.0f); resFragmentLight.SetSpecular0(0.8f, 0.8f, 0.8f); resFragmentLight.SetSpecular1(0.8f, 0.8f, 0.8f); } /*!--------------------------------------------------------------------------* @brief フォグ関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildFogs() { // フォグを生成します。 nw::gfx::Fog* fog = nw::gfx::Fog::DynamicBuilder() .MaxCallbacks(0) .MaxChildren(0) .Create(&s_DeviceAllocator); s_FogRoot->AttachChild(fog); nw::gfx::ResFog resFog(fog->GetResFog()); resFog.SetColor(0.3f, 0.3f, 0.5f); nw::gfx::ResFogUpdater resFogUpdater = resFog.GetFogUpdater(); resFogUpdater.SetFogUpdaterType(nw::gfx::ResFogUpdater::FOG_UPDATER_TYPE_EXPONENT_SQUARE); resFogUpdater.SetDensity(10.0f); resFogUpdater.SetMinFogDepth(10.0f); resFogUpdater.SetMaxFogDepth(500.0f); } /*!--------------------------------------------------------------------------* @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 %x", result.GetCode()); } nw::ut::MoveArray sceneNodeArray(&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::gfx::Model::MULTI_FLAG_BUFFER_MATERIAL ); NW_NULL_ASSERT(node); sceneNodeArray.push_back(node); if (nw::ut::IsTypeOf(node)) { nw::gfx::SkeletalModel* skeletalModel = static_cast(node); nw::gfx::Skeleton* skeleton = skeletalModel->GetSkeleton(); NW_NULL_ASSERT(skeleton); nw::gfx::ResSkeleton resSkeleton = skeleton->GetResSkeleton(); NW_ASSERT(resSkeleton.IsValid()); } } // モデルをシーンに追加 nw::gfx::SceneHelper::ForeachRootNodes( sceneNodeArray.Begin(), sceneNodeArray.End(), nw::gfx::AttachNode(s_ModelRoot) ); } /*!--------------------------------------------------------------------------* @brief シーンを初期化します。 *---------------------------------------------------------------------------*/ void InitializeScenes() { BuildRootNodes(); BuildCameras(); BuildLights(); BuildFogs(); 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(); // カメラを設定します。 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(); s_ModelRoot = NULL; s_CameraRoot = NULL; s_LightRoot = NULL; s_FogRoot = NULL; } /*!--------------------------------------------------------------------------* @brief シーンを更新します。 *---------------------------------------------------------------------------*/ void UpdateScene() { float radian = static_cast((s_FrameCount * 5) % (314 * 2)) * 0.01f; // カメラルートがY軸中心に回転します。 nw::gfx::TransformNode* cameraNode = nw::ut::DynamicCast(s_CameraRoot); NW_NULL_ASSERT(cameraNode); cameraNode->Transform().SetRotateXYZ(0.0f, radian, 0.0f); // モデルルートがY軸に沿って上下します。 nw::gfx::TransformNode* modelNode = nw::ut::DynamicCast(s_ModelRoot); NW_NULL_ASSERT(modelNode); modelNode->Transform().SetTranslate(0.0f, nw::math::SinRad(radian) * 10.0f, 0.0f); nw::gfx::SceneNodeArray::iterator end = modelNode->GetChildEnd(); for (nw::gfx::SceneNodeArray::iterator node = modelNode->GetChildBegin(); node != end; ++node) { // Model クラスの Transform を変更します。 if (nw::ut::IsTypeOf(*node)) { nw::gfx::Model* model = static_cast(*node); model->Transform().SetScale(radian, radian, radian); model->Transform().SetRotateXYZ(radian, 0.0f, 0.0f); } } s_SceneSystem->GetCameraController()->Update(); s_SceneSystem->UpdateScene(); s_BaseCamera->UpdateCameraMatrix(); s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 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(); // SceneTreeDemo は SceneEnvironmentSetting を読み込まず // SceneEnvironment に直接ライト、フォグを設定しています。 s_RenderSystem->SetEnvironment(s_SceneSystem); 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(); }