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