1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ParticleDropFrameDemo.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     sceneDescription.maxSceneNodes = 128;
128     sceneDescription.maxParticleSets = 64;
129     sceneDescription.maxParticleEmitters = 64;
130     sceneDescription.maxParticleModels = 64;
131     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
132 
133     // ParticleContextを生成します。
134     s_ParticleContext = nw::gfx::ParticleContext::Builder()
135         .MaxEmission(1000)
136         .MaxStreamLength(1000)
137         .UseDoubleBuffer(true)
138         .Create(&s_DeviceAllocator);
139 
140     // ParticleSceneUpdaterを生成します。
141     s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
142         .Create(&s_DeviceAllocator);
143 
144     // デモ用の最遠景モデルをレンダリングシステムに設定します。
145     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
146     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
147 
148     NW_GL_ASSERT();
149 }
150 
151 /*!--------------------------------------------------------------------------*
152   @brief        グラフィックス関連の後始末をします。
153  *---------------------------------------------------------------------------*/
154 void
TerminateGraphics()155 TerminateGraphics()
156 {
157     nw::gfx::SafeDestroy(s_LeftCamera);
158 
159     nw::gfx::SafeDestroy(s_RightCamera);
160 
161     nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
162 
163     nw::gfx::SafeDestroy(s_ParticleContext);
164 
165     nw::gfx::SafeDestroy(s_SceneSystem);
166 
167     nw::gfx::SafeDestroyAll(s_RenderTargets);
168 
169     s_GraphicsDrawing.Finalize();
170 
171     nw::gfx::SafeDestroy(s_RenderSystem);
172 
173     NW_GL_ASSERT();
174 }
175 
176 /*!--------------------------------------------------------------------------*
177   @brief        再生ステップを設定します。
178 
179   @param[in]    再生ステップです。
180  *---------------------------------------------------------------------------*/
181 void
SetStepFrame(f32 stepFrame)182 SetStepFrame(f32 stepFrame)
183 {
184     nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext();
185 
186     nw::gfx::SceneNodeArray::iterator end = sceneContext->GetSceneNodesEnd();
187     for (nw::gfx::SceneNodeArray::iterator i = sceneContext->GetSceneNodesBegin(); i != end; ++i)
188     {
189         nw::gfx::ParticleEmitter* emitter = nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(*i);
190         if (emitter != NULL)
191         {
192             emitter->ParticleAnimFrameController().SetStepFrame(stepFrame);
193         }
194         else
195         {
196             nw::gfx::ParticleModel* model = nw::ut::DynamicCast<nw::gfx::ParticleModel*>(*i);
197             if (model != NULL)
198             {
199                 model->ParticleAnimFrameController().SetStepFrame(stepFrame);
200             }
201         }
202     }
203 }
204 
205 /*!--------------------------------------------------------------------------*
206   @brief        ルートノード関連の構築をします。
207  *---------------------------------------------------------------------------*/
208 void
BuildRootNodes()209 BuildRootNodes()
210 {
211     NW_ASSERT(s_SceneRoot == NULL);
212     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
213         .MaxChildren(128)
214         .Create(&s_DeviceAllocator);
215     NW_NULL_ASSERT(s_SceneRoot);
216 }
217 
218 /*!--------------------------------------------------------------------------*
219   @brief        カメラ関連の構築をします。
220  *---------------------------------------------------------------------------*/
221 void
BuildCameras()222 BuildCameras()
223 {
224     nw::demo::Utility::CreateStereoCameras(
225         &s_BaseCamera,
226         &s_LeftCamera,
227         &s_RightCamera,
228         &s_DeviceAllocator,
229         nw::math::VEC3(28.0f, 22.0f, 28.0f),
230         nw::math::VEC3(0.0f, 0.0f, 0.0f),
231         s_fNearPlane
232     );
233 
234     s_SceneRoot->AttachChild(s_BaseCamera);
235     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
236 }
237 
238 /*!--------------------------------------------------------------------------*
239   @brief        リソース関連の構築をします。
240  *---------------------------------------------------------------------------*/
241 void
BuildResources(nw::demo::ResourceSet * resourceSet)242 BuildResources(nw::demo::ResourceSet* resourceSet)
243 {
244     // テクスチャリソースをVRAMに配置します。
245     resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
246 
247     // リソースのセットアップを行います。
248     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
249 
250     if (result.IsFailure())
251     {
252         NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
253     }
254 
255     for (int i = 0; i < 10; ++i)
256     {
257         // 生成したノードを格納する配列です。
258         nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(SCENE_NODE_COUNT, &s_DeviceAllocator);
259 
260         // ResModelArray から ParticleModel インスタンスを生成します。
261         nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
262         nw::gfx::ResModelArray::iterator modelsEnd = models.end();
263         for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
264             modelResource != modelsEnd; ++modelResource)
265         {
266             nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
267                 &s_ParticleAllocator,
268                 (*modelResource)
269                 );
270             if (node != NULL)
271             {
272                 sceneNodeArray.push_back(node);
273                 s_ModelCount++;
274             }
275         }
276 
277         // ResEmitterArray から ParticleEmitter インスタンスを生成します。
278         nw::gfx::ResEmitterArray emitters = resourceSet->resource.GetEmitters();
279         for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin();
280             emitterResource != emitters.end(); ++emitterResource)
281         {
282             nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
283                 &s_ParticleAllocator,
284                 (*emitterResource)
285                 );
286             if (node != NULL)
287             {
288                 sceneNodeArray.push_back(node);
289                 s_EmitterCount++;
290             }
291         }
292 
293         // 親子付け参照関係を解決します。
294         nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
295 
296         // パーティクル独自の初期設定を行います。
297         nw::gfx::ParticleUtil::SetupParticleObject(&sceneNodeArray, s_ParticleContext);
298 
299         // モデルとエミッタをシーンツリーに追加します。
300         nw::gfx::SceneHelper::ForeachRootNodes(
301             sceneNodeArray.Begin(),
302             sceneNodeArray.End(),
303             nw::gfx::AttachNode(s_SceneRoot)
304             );
305     }
306 }
307 
308 /*!--------------------------------------------------------------------------*
309   @brief        シーンを初期化します。
310  *---------------------------------------------------------------------------*/
311 void
InitializeScenes()312 InitializeScenes()
313 {
314     BuildRootNodes();
315 
316     BuildCameras();
317 
318     // リソースをロードして、セットアップを行います。
319     NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
320     {
321         BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
322     }
323     NW_ASSERT(s_ModelCount > 0);
324     NW_ASSERT(s_EmitterCount > 0);
325 
326     // シーンツリーを巡回して初期化を行います。
327     s_SceneSystem->InitializeScene(s_SceneRoot);
328     s_SceneSystem->UpdateScene();
329 
330     // シーン環境の参照解決を行い設定します。
331     s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
332 
333     // カメラを設定します。
334     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
335     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
336     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
337 
338     NW_GL_ASSERT();
339 
340     s_FrameCount = 0;
341 }
342 
343 /*!--------------------------------------------------------------------------*
344   @brief        シーン関連の後始末をします。
345  *---------------------------------------------------------------------------*/
346 void
TerminateScenes()347 TerminateScenes()
348 {
349     nw::gfx::SafeDestroyBranch(s_SceneRoot);
350     nw::demo::SafeCleanupResources(s_Resources);
351     nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
352 
353     NW_GL_ASSERT();
354 
355     s_Resources.clear();
356     s_SceneEnvironmentSettings.clear();
357 }
358 
359 /*!--------------------------------------------------------------------------*
360   @brief        シーンを更新します。
361  *---------------------------------------------------------------------------*/
362 void
UpdateScene(bool particleSwapBuffer=true)363 UpdateScene(bool particleSwapBuffer = true)
364 {
365     NW_ASSERT(0 < s_RenderTargets.size());
366 
367     s_SceneSystem->GetCameraController()->Update();
368 
369     s_SceneSystem->UpdateScene();
370 
371     s_BaseCamera->UpdateCameraMatrix();
372 
373     NW_NULL_ASSERT(s_ParticleSceneUpdater);
374     s_ParticleSceneUpdater->UpdateNode(
375         s_SceneSystem->GetSceneContext(),
376         s_ParticleContext,
377         particleSwapBuffer);
378 
379     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
380 
381     s_FrameCount++;
382 
383     s_FlushCache->Execute();
384 }
385 
386 /*!--------------------------------------------------------------------------*
387   @brief        負荷表示やテスト機能の処理をおこないます。
388  *---------------------------------------------------------------------------*/
389 void
ReportDemo()390 ReportDemo()
391 {
392     NW_PROFILE("ReportDemo");
393 
394     // 負荷表示からはこれらの負荷は除きます。
395     s_RenderSystem->SuspendLoadMeter();
396 
397     nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
398 
399     s_GraphicsDrawing.BeginDrawingShape();
400 
401     nw::demo::DebugUtility::DrawLoadMeter(
402         s_RenderSystem,
403         &s_GraphicsDrawing
404     );
405 
406     s_GraphicsDrawing.EndDrawingShape();
407 
408     s_GraphicsDrawing.BeginDrawingString();
409 
410     nw::demo::DebugUtility::DrawLoadMeterText(
411         s_RenderSystem,
412         &s_GraphicsDrawing
413     );
414 
415     s_GraphicsDrawing.EndDrawingString();
416 
417     s_RenderSystem->ResumeLoadMeter();
418 }
419 
420 /*!--------------------------------------------------------------------------*
421   @brief        シーンをデモンストレーションします。
422  *---------------------------------------------------------------------------*/
423 void
DemoScene()424 DemoScene()
425 {
426     NW_ASSERT(!s_RenderTargets.empty());
427 
428     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
429 
430     InitializeScenes();
431 
432     nw::demo::DebugUtility::PostInitializeScenes();
433 
434     bool isContinuing = true;
435     bool isFirst = true;
436     int currentVsyncCount = nngxCheckVSync(NN_GX_DISPLAY0);
437     int prevVsyncCount = currentVsyncCount - 1; // 最初の処理用に-1
438 
439     while ( isContinuing )
440     {
441         const s32 screenKind = nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN;
442 
443         nw::demo::DebugUtility::AdvanceAutoTestFrame();
444 
445         nw::demo::PadFactory::GetPad()->Update();
446 
447         // 効率的なダブルバッファの処理ではなく、
448         // サンプルとしてのわかりやすさを重視しています。
449 #if 0
450         // 再生レートを上げてまとめて処理する
451         // 利点:処理が高速
452         // 欠点:1フレーム毎の処理と結果が多少異なる
453         SetStepFrame(currentVsyncCount - prevVsyncCount);
454         UpdateScene();
455 #else
456         // コマ落ち分の処理を繰り返し行う
457         // 利点:コマ落ちでないときと結果が一致することが保証される
458         // 欠点:繰り返し分のCPU処理がかかる
459         for (int i = 0; i < currentVsyncCount - prevVsyncCount; ++i)
460         {
461             //SetStepFrame(1.0f);
462             UpdateScene(i == 0);
463         }
464 #endif
465 
466         prevVsyncCount = currentVsyncCount;
467 
468         renderContext->SetActiveCamera(s_BaseCameraIndex);
469         s_RenderSystem->SubmitView(s_SceneSystem);
470 
471         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
472         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
473 
474         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
475         ReportDemo();
476         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
477 
478         //s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
479         s_RenderSystem->WaitCommandList();
480         s_RenderSystem->SwapBuffer(screenKind);
481         s_RenderSystem->WaitVSync(screenKind);
482         currentVsyncCount = nngxCheckVSync(NN_GX_DISPLAY0);
483         s_RenderSystem->RunCommandList();
484         s_RenderSystem->SwapCommandList();
485 
486         renderContext->ResetState();
487 
488         if (nw::demo::Utility::IsTerminating())
489         {
490             isContinuing = false;
491         }
492     }
493 
494     nw::demo::DebugUtility::PreTerminateScenes();
495 
496     TerminateScenes();
497 }
498 
499 } // namespace
500 
501 /*!--------------------------------------------------------------------------*
502   @brief        メイン関数です。
503  *---------------------------------------------------------------------------*/
504 void
nnMain()505 nnMain()
506 {
507     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
508     nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
509 
510     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
511 
512     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
513     {
514         InitializeGraphics();
515 
516         // キャッシュフラッシュ用のクラスを生成(通常のアプリでは必要ありません)
517         s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
518 
519         DemoScene();
520 
521         // キャッシュフラッシュ用のクラスを破棄
522         nw::ut::SafeDestroy(s_FlushCache);
523 
524         TerminateGraphics();
525     }
526 
527     nw::demo::PadFactory::Finalize();
528 
529     nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
530 
531     nw::demo::FinalizeGraphicsSystem();
532 }
533