1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ParticleDemo.cpp
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 28172 $
14  *---------------------------------------------------------------------------*/
15 
16 #define NW_DEBUG_CHECK_MEMORY_LEAK
17 
18 #include <nn/os.h>
19 #include <nn/fs.h>
20 
21 #include <nw/types.h>
22 #include <nw/demo.h>
23 #include <nw/dev.h>
24 #include <nw/gfx.h>
25 #include <nw/ut.h>
26 
27 namespace
28 {
29 
30 //----------------------------------------
31 // メモリ関係
32 
33 // デバイスメモリを確保するためのアロケータです。
34 nw::demo::DemoAllocator s_DeviceAllocator;
35 nw::demo::DemoAllocator s_ParticleAllocator;
36 
37 //----------------------------------------
38 // ファイル名の定義です。
39 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
40 
41 const wchar_t* MODEL_RESOURCE_FILES[] =
42 {
43     NW_DEMO_FILE_PATH(L"fountain_particle_all.bcptl"),
44     NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
45     NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"),
46 };
47 
48 //----------------------------------------
49 // 描画関係
50 const int RENDER_TARGET_COUNT = 1;
51 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
52 
53 RenderTargetArray s_RenderTargets;
54 nw::demo::SceneSystem*  s_SceneSystem = NULL;
55 nw::demo::RenderSystem* s_RenderSystem = NULL;
56 nw::gfx::ParticleContext* s_ParticleContext = NULL;
57 
58 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
59 
60 //----------------------------------------
61 // リソース関係
62 nw::demo::ResourceArray s_Resources;
63 
64 int s_ModelCount = 0;
65 int s_EmitterCount = 0;
66 
67 //----------------------------------------
68 // シーン関係
69 const int SCENE_NODE_COUNT = 4;
70 nw::gfx::SceneNode* s_SceneRoot = NULL;
71 s32 s_FrameCount = 0;
72 nw::gfx::Camera* s_BaseCamera = NULL;
73 nw::gfx::Camera* s_LeftCamera = NULL;
74 nw::gfx::Camera* s_RightCamera = NULL;
75 const f32 s_fNearPlane = 0.1f;
76 
77 //----------------------------------------
78 // シーン環境関係
79 const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
80 
81 typedef nw::ut::FixedSizeArray<nw::gfx::SceneEnvironmentSetting*, ENVIRONMENT_SETTINGS_COUNT> SceneEnvironmentSettingArray;
82 SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
83 
84 const s32 s_BaseCameraIndex = 0;
85 
86 //----------------------------------------
87 // パーティクル関係
88 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
89 
90 nw::demo::FlushCache* s_FlushCache;
91 
92 /*!--------------------------------------------------------------------------*
93   @brief        グラフィックス関連の初期化を行います。
94  *---------------------------------------------------------------------------*/
95 void
InitializeGraphics()96 InitializeGraphics()
97 {
98     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
99 
100     // renderDescriptionへステレオの設定を行います。
101     nw::demo::RenderSystem::Description renderDescription;
102 
103     renderDescription.reusableCommandBufferSize = 0x100000;
104     renderDescription.reusableCommandRequestCount      = 512;
105     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
106 
107     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
108 
109     s_GraphicsDrawing.SetScreenSize(
110         renderDescription.lowerScreenDescription.width,
111         renderDescription.lowerScreenDescription.height
112     );
113 
114     nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
115 
116     s_RenderTargets.push_back(
117         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
118     );
119     NW_ASSERT(!s_RenderTargets.empty());
120     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
121 
122     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
123     nw::demo::SceneSystem::Description sceneDescription;
124     sceneDescription.isFixedSizeMemory = true;
125     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
126 
127     // ParticleContextを生成します。
128     s_ParticleContext = nw::gfx::ParticleContext::Builder()
129         .MaxEmission(1000)
130         .Create(&s_DeviceAllocator);
131 
132     // ParticleSceneUpdaterを生成します。
133     s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
134         .Create(&s_DeviceAllocator);
135 
136     // デモ用の最遠景モデルをレンダリングシステムに設定します。
137     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
138     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
139 
140     NW_GL_ASSERT();
141 }
142 
143 /*!--------------------------------------------------------------------------*
144   @brief        グラフィックス関連の後始末をします。
145  *---------------------------------------------------------------------------*/
146 void
TerminateGraphics()147 TerminateGraphics()
148 {
149     nw::gfx::SafeDestroy(s_LeftCamera);
150 
151     nw::gfx::SafeDestroy(s_RightCamera);
152 
153     nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
154 
155     nw::gfx::SafeDestroy(s_ParticleContext);
156 
157     nw::gfx::SafeDestroy(s_SceneSystem);
158 
159     nw::gfx::SafeDestroyAll(s_RenderTargets);
160 
161     s_GraphicsDrawing.Finalize();
162 
163     nw::gfx::SafeDestroy(s_RenderSystem);
164 
165     NW_GL_ASSERT();
166 }
167 
168 /*!--------------------------------------------------------------------------*
169   @brief        再生ステップを設定します。
170 
171   @param[in]    再生ステップです。
172  *---------------------------------------------------------------------------*/
173 void
SetStepFrame(f32 stepFrame)174 SetStepFrame(f32 stepFrame)
175 {
176     nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext();
177 
178     nw::gfx::SceneNodeArray::iterator end = sceneContext->GetSceneNodesEnd();
179     for (nw::gfx::SceneNodeArray::iterator i = sceneContext->GetSceneNodesBegin(); i != end; ++i)
180     {
181         nw::gfx::ParticleEmitter* emitter = nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(*i);
182         if (emitter != NULL)
183         {
184             emitter->ParticleAnimFrameController().SetStepFrame(stepFrame);
185         }
186         else
187         {
188             nw::gfx::ParticleModel* model = nw::ut::DynamicCast<nw::gfx::ParticleModel*>(*i);
189             if (model != NULL)
190             {
191                 model->ParticleAnimFrameController().SetStepFrame(stepFrame);
192             }
193         }
194     }
195 }
196 
197 /*!--------------------------------------------------------------------------*
198   @brief        ルートノード関連の構築をします。
199  *---------------------------------------------------------------------------*/
200 void
BuildRootNodes()201 BuildRootNodes()
202 {
203     NW_ASSERT(s_SceneRoot == NULL);
204     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
205         .Create(&s_DeviceAllocator);
206     NW_NULL_ASSERT(s_SceneRoot);
207 }
208 
209 /*!--------------------------------------------------------------------------*
210   @brief        カメラ関連の構築をします。
211  *---------------------------------------------------------------------------*/
212 void
BuildCameras()213 BuildCameras()
214 {
215     nw::demo::Utility::CreateStereoCameras(
216         &s_BaseCamera,
217         &s_LeftCamera,
218         &s_RightCamera,
219         &s_DeviceAllocator,
220         nw::math::VEC3(28.0f, 22.0f, 28.0f),
221         nw::math::VEC3(0.0f, 0.0f, 0.0f),
222         s_fNearPlane
223     );
224 
225     s_SceneRoot->AttachChild(s_BaseCamera);
226     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
227 }
228 
229 /*!--------------------------------------------------------------------------*
230   @brief        リソース関連の構築をします。
231  *---------------------------------------------------------------------------*/
232 void
BuildResources(nw::demo::ResourceSet * resourceSet)233 BuildResources(nw::demo::ResourceSet* resourceSet)
234 {
235     // テクスチャリソースをVRAMに配置します。
236     resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
237 
238     // リソースのセットアップを行います。
239     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
240 
241     if (result.IsFailure())
242     {
243         NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
244     }
245 
246     // 生成したノードを格納する配列です。
247     nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(SCENE_NODE_COUNT, &s_DeviceAllocator);
248 
249     // ResModelArray から ParticleModel インスタンスを生成します。
250     nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
251     nw::gfx::ResModelArray::iterator modelsEnd = models.end();
252     for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
253          modelResource != modelsEnd; ++modelResource)
254     {
255         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
256             &s_ParticleAllocator,
257             (*modelResource)
258         );
259         if (node != NULL)
260         {
261             sceneNodeArray.push_back(node);
262             s_ModelCount++;
263         }
264     }
265 
266     // ResEmitterArray から ParticleEmitter インスタンスを生成します。
267     nw::gfx::ResEmitterArray emitters = resourceSet->resource.GetEmitters();
268     for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin();
269          emitterResource != emitters.end(); ++emitterResource)
270     {
271         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
272             &s_ParticleAllocator,
273             (*emitterResource)
274         );
275         if (node != NULL)
276         {
277             sceneNodeArray.push_back(node);
278             s_EmitterCount++;
279         }
280     }
281 
282     // 親子付け参照関係を解決します。
283     nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
284 
285     // パーティクル独自の初期設定を行います。
286     nw::gfx::ParticleUtil::SetupParticleObject(&sceneNodeArray, s_ParticleContext);
287 
288     // モデルとエミッタをシーンツリーに追加します。
289     nw::gfx::SceneHelper::ForeachRootNodes(
290         sceneNodeArray.Begin(),
291         sceneNodeArray.End(),
292         nw::gfx::AttachNode(s_SceneRoot)
293     );
294 }
295 
296 /*!--------------------------------------------------------------------------*
297   @brief        シーンを初期化します。
298  *---------------------------------------------------------------------------*/
299 void
InitializeScenes()300 InitializeScenes()
301 {
302     BuildRootNodes();
303 
304     BuildCameras();
305 
306     // リソースをロードして、セットアップを行います。
307     NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
308     {
309         BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
310     }
311     NW_ASSERT(s_ModelCount > 0);
312     NW_ASSERT(s_EmitterCount > 0);
313 
314     // シーンツリーを巡回して初期化を行います。
315     s_SceneSystem->InitializeScene(s_SceneRoot);
316     s_SceneSystem->UpdateScene();
317 
318     // シーン環境の参照解決を行い設定します。
319     s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
320 
321     // カメラを設定します。
322     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
323     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
324     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
325 
326     NW_GL_ASSERT();
327 
328     s_FrameCount = 0;
329 }
330 
331 /*!--------------------------------------------------------------------------*
332   @brief        シーン関連の後始末をします。
333  *---------------------------------------------------------------------------*/
334 void
TerminateScenes()335 TerminateScenes()
336 {
337     nw::gfx::SafeDestroyBranch(s_SceneRoot);
338     nw::demo::SafeCleanupResources(s_Resources);
339     nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
340 
341     NW_GL_ASSERT();
342 
343     s_Resources.clear();
344     s_SceneEnvironmentSettings.clear();
345 }
346 
347 /*!--------------------------------------------------------------------------*
348   @brief        シーンを更新します。
349  *---------------------------------------------------------------------------*/
350 void
UpdateScene()351 UpdateScene()
352 {
353     NW_ASSERT(0 < s_RenderTargets.size());
354 
355     s_SceneSystem->GetCameraController()->Update();
356 
357     s_SceneSystem->UpdateScene();
358 
359     s_BaseCamera->UpdateCameraMatrix();
360 
361     NW_NULL_ASSERT(s_ParticleSceneUpdater);
362     s_ParticleSceneUpdater->UpdateNode(
363         s_SceneSystem->GetSceneContext(),
364         s_ParticleContext);
365 
366     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
367 
368     s_FrameCount++;
369 
370     s_FlushCache->Execute();
371 }
372 
373 /*!--------------------------------------------------------------------------*
374   @brief        負荷表示やテスト機能の処理をおこないます。
375  *---------------------------------------------------------------------------*/
376 void
ReportDemo()377 ReportDemo()
378 {
379     NW_PROFILE("ReportDemo");
380 
381     // 負荷表示からはこれらの負荷は除きます。
382     s_RenderSystem->SuspendLoadMeter();
383 
384     nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
385 
386     s_GraphicsDrawing.BeginDrawingShape();
387 
388     nw::demo::DebugUtility::DrawLoadMeter(
389         s_RenderSystem,
390         &s_GraphicsDrawing
391     );
392 
393     s_GraphicsDrawing.EndDrawingShape();
394 
395     s_GraphicsDrawing.BeginDrawingString();
396 
397     nw::demo::DebugUtility::DrawLoadMeterText(
398         s_RenderSystem,
399         &s_GraphicsDrawing
400     );
401 
402     s_GraphicsDrawing.EndDrawingString();
403 
404     s_RenderSystem->ResumeLoadMeter();
405 }
406 
407 /*!--------------------------------------------------------------------------*
408   @brief        シーンをデモンストレーションします。
409  *---------------------------------------------------------------------------*/
410 void
DemoScene()411 DemoScene()
412 {
413     NW_ASSERT(!s_RenderTargets.empty());
414 
415     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
416 
417     InitializeScenes();
418 
419     nw::demo::DebugUtility::PostInitializeScenes();
420 
421     bool isContinuing = true;
422 
423     while ( isContinuing )
424     {
425         nw::demo::DebugUtility::AdvanceAutoTestFrame();
426 
427         nw::demo::PadFactory::GetPad()->Update();
428 
429         SetStepFrame(1.0f);
430         UpdateScene();
431 
432         renderContext->SetActiveCamera(s_BaseCameraIndex);
433         s_RenderSystem->SubmitView(s_SceneSystem);
434 
435         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
436         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
437 
438         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
439         ReportDemo();
440         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
441 
442         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
443 
444         renderContext->ResetState();
445 
446         if (nw::demo::Utility::IsTerminating())
447         {
448             isContinuing = false;
449         }
450     }
451 
452     nw::demo::DebugUtility::PreTerminateScenes();
453 
454     TerminateScenes();
455 }
456 
457 } // namespace
458 
459 /*!--------------------------------------------------------------------------*
460   @brief        メイン関数です。
461  *---------------------------------------------------------------------------*/
462 void
nnMain()463 nnMain()
464 {
465     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
466     nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
467 
468     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
469 
470     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
471     {
472         InitializeGraphics();
473 
474         // キャッシュフラッシュ用のクラスを生成(通常のアプリでは必要ありません)
475         s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
476 
477         DemoScene();
478 
479         // キャッシュフラッシュ用のクラスを破棄
480         nw::ut::SafeDestroy(s_FlushCache);
481 
482         TerminateGraphics();
483     }
484 
485     nw::demo::PadFactory::Finalize();
486 
487     nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
488 
489     nw::demo::FinalizeGraphicsSystem();
490 }
491