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: 25401 $
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* FONT_SHADER_FILE_NAME = NW_DEMO_FILE_PATH(L"nwfont_RectDrawerShader.shbin");
40 const wchar_t* FONT_FILE_NAME        = NW_DEMO_FILE_PATH(L"Font.bcfnt");
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 NW_LOAD_METER_INTERVAL = 60;
53 
54 //----------------------------------------
55 // 描画関係
56 const int RENDER_TARGET_COUNT = 1;
57 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
58 
59 RenderTargetArray s_RenderTargets;
60 nw::demo::SceneSystem*  s_SceneSystem = NULL;
61 nw::demo::RenderSystem* s_RenderSystem = NULL;
62 nw::gfx::ParticleContext* s_ParticleContext = NULL;
63 
64 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
65 
66 //----------------------------------------
67 // リソース関係
68 nw::demo::ResourceArray s_Resources;
69 
70 int s_ModelCount = 0;
71 int s_EmitterCount = 0;
72 
73 //----------------------------------------
74 // シーン関係
75 const int SCENE_NODE_COUNT = 4;
76 nw::gfx::SceneNode* s_SceneRoot = NULL;
77 s32 s_FrameCount = 0;
78 nw::gfx::Camera* s_BaseCamera = NULL;
79 nw::gfx::Camera* s_LeftCamera = NULL;
80 nw::gfx::Camera* s_RightCamera = NULL;
81 const f32 s_fNearPlane = 0.1f;
82 
83 //----------------------------------------
84 // シーン環境関係
85 const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
86 
87 typedef nw::ut::FixedSizeArray<nw::gfx::SceneEnvironmentSetting*, ENVIRONMENT_SETTINGS_COUNT> SceneEnvironmentSettingArray;
88 SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
89 
90 const s32 s_BaseCameraIndex = 0;
91 
92 //----------------------------------------
93 // パーティクル関係
94 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
95 
96 nw::demo::FlushCache* s_FlushCache;
97 
98 /*!--------------------------------------------------------------------------*
99   @brief        グラフィックス関連の初期化を行います。
100  *---------------------------------------------------------------------------*/
101 void
InitializeGraphics()102 InitializeGraphics()
103 {
104     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
105 
106     // renderDescriptionへステレオの設定を行います。
107     nw::demo::RenderSystem::Description renderDescription;
108 
109     renderDescription.reusableCommandBufferSize = 0x100000;
110     renderDescription.reusableCommandRequestCount      = 512;
111     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
112 
113     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
114 
115     s_GraphicsDrawing.SetScreenSize(
116         renderDescription.lowerScreenDescription.width,
117         renderDescription.lowerScreenDescription.height
118     );
119     bool result = s_GraphicsDrawing.InitializeFont(&s_DeviceAllocator, FONT_SHADER_FILE_NAME, FONT_FILE_NAME);
120 
121     NN_ASSERTMSG(result, "Fail to load Font.");
122 
123     s_RenderTargets.push_back(
124         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
125     );
126     NW_ASSERT(!s_RenderTargets.empty());
127     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
128 
129     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
130     nw::demo::SceneSystem::Description sceneDescription;
131     sceneDescription.isFixedSizeMemory = true;
132     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
133 
134     s_ParticleContext = nw::gfx::ParticleContext::Builder()
135         .MaxEmission(1000)
136         .Create(&s_DeviceAllocator);
137 
138     s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
139         .Create(&s_DeviceAllocator);
140 
141     // デモ用の最遠景モデルをレンダリングシステムに設定します。
142     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
143     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
144 
145     NW_GL_ASSERT();
146 }
147 
148 /*!--------------------------------------------------------------------------*
149   @brief        グラフィックス関連の後始末をします。
150  *---------------------------------------------------------------------------*/
151 void
TerminateGraphics()152 TerminateGraphics()
153 {
154     nw::gfx::SafeDestroy(s_LeftCamera);
155 
156     nw::gfx::SafeDestroy(s_RightCamera);
157 
158     nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
159 
160     nw::gfx::SafeDestroy(s_ParticleContext);
161 
162     nw::gfx::SafeDestroy(s_SceneSystem);
163 
164     nw::gfx::SafeDestroyAll(s_RenderTargets);
165 
166     s_GraphicsDrawing.Finalize();
167 
168     nw::gfx::SafeDestroy(s_RenderSystem);
169 
170     NW_GL_ASSERT();
171 }
172 
173 /*!--------------------------------------------------------------------------*
174   @brief        再生ステップを設定します。
175 
176   @param[in]    再生ステップです。
177  *---------------------------------------------------------------------------*/
178 void
SetStepFrame(f32 stepFrame)179 SetStepFrame(f32 stepFrame)
180 {
181     nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext();
182 
183     nw::gfx::SceneNodeArray::iterator end = sceneContext->GetSceneNodesEnd();
184     for (nw::gfx::SceneNodeArray::iterator i = sceneContext->GetSceneNodesBegin(); i != end; ++i)
185     {
186         nw::gfx::ParticleEmitter* emitter = nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(*i);
187         if (emitter != NULL)
188         {
189             emitter->ParticleAnimFrameController().SetStepFrame(stepFrame);
190         }
191         else
192         {
193             nw::gfx::ParticleModel* model = nw::ut::DynamicCast<nw::gfx::ParticleModel*>(*i);
194             if (model != NULL)
195             {
196                 model->ParticleAnimFrameController().SetStepFrame(stepFrame);
197             }
198         }
199     }
200 }
201 
202 /*!--------------------------------------------------------------------------*
203   @brief        ルートノード関連の構築をします。
204  *---------------------------------------------------------------------------*/
205 void
BuildRootNodes()206 BuildRootNodes()
207 {
208     NW_ASSERT(s_SceneRoot == NULL);
209     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
210         .Create(&s_DeviceAllocator);
211     NW_NULL_ASSERT(s_SceneRoot);
212 }
213 
214 /*!--------------------------------------------------------------------------*
215   @brief        カメラ関連の構築をします。
216  *---------------------------------------------------------------------------*/
217 void
BuildCameras()218 BuildCameras()
219 {
220     nw::demo::Utility::CreateStereoCameras(
221         &s_BaseCamera,
222         &s_LeftCamera,
223         &s_RightCamera,
224         &s_DeviceAllocator,
225         nw::math::VEC3(28.0f, 22.0f, 28.0f),
226         nw::math::VEC3(0.0f, 0.0f, 0.0f),
227         s_fNearPlane
228     );
229 
230     s_SceneRoot->AttachChild(s_BaseCamera);
231     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
232 }
233 
234 /*!--------------------------------------------------------------------------*
235   @brief        リソース関連の構築をします。
236  *---------------------------------------------------------------------------*/
237 void
BuildResources(nw::demo::ResourceSet * resourceSet)238 BuildResources(nw::demo::ResourceSet* resourceSet)
239 {
240     resourceSet->resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
241     resourceSet->resource.ForeachIndexStream(nw::gfx::IndexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
242     resourceSet->resource.ForeachVertexStream(nw::gfx::VertexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
243 
244     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
245 
246     if (result.IsFailure())
247     {
248         NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
249     }
250 
251     nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(SCENE_NODE_COUNT, &s_DeviceAllocator);
252 
253     nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
254     nw::gfx::ResModelArray::iterator modelsEnd = models.end();
255     for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
256          modelResource != modelsEnd; ++modelResource)
257     {
258         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
259             &s_ParticleAllocator,
260             (*modelResource)
261         );
262         if (node != NULL)
263         {
264             sceneNodeArray.push_back(node);
265             s_ModelCount++;
266         }
267     }
268 
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     nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
285     for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
286          lightResource != lights.end(); ++lightResource)
287     {
288         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
289             &s_DeviceAllocator,
290             (*lightResource)
291         );
292         NW_NULL_ASSERT(node);
293         sceneNodeArray.push_back(node);
294     }
295 
296     // 親子付け参照関係を解決
297     nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
298 
299     nw::gfx::ParticleUtil::SetupParticleObject(&sceneNodeArray, s_ParticleContext);
300 
301     // モデルとエミッタをシーンに追加
302     nw::gfx::SceneHelper::ForeachRootNodes(
303         sceneNodeArray.Begin(),
304         sceneNodeArray.End(),
305         nw::gfx::AttachNode(s_SceneRoot)
306     );
307 
308     nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
309     nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
310     for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
311         settingResource != settingsEnd; ++settingResource)
312     {
313         nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
314             .Resource(*settingResource)
315             .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
316 
317         nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
318             nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
319 
320         NW_NULL_ASSERT(sceneEnvironmentSetting);
321         s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
322     }
323 }
324 
325 /*!--------------------------------------------------------------------------*
326   @brief        シーンを初期化します。
327  *---------------------------------------------------------------------------*/
328 void
InitializeScenes()329 InitializeScenes()
330 {
331     BuildRootNodes();
332 
333     BuildCameras();
334 
335     NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
336     {
337         BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
338     }
339     NW_ASSERT(s_ModelCount > 0);
340     NW_ASSERT(s_EmitterCount > 0);
341 
342     // シーンツリーを巡回して初期化を行います。
343     s_SceneSystem->InitializeScene(s_SceneRoot);
344     s_SceneSystem->UpdateScene();
345 
346     // シーン環境の参照解決を行い設定します。
347     s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
348 
349     // カメラを設定します。
350     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
351     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
352     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
353 
354     NW_GL_ASSERT();
355 
356     s_FrameCount = 0;
357 }
358 
359 /*!--------------------------------------------------------------------------*
360   @brief        シーン関連の後始末をします。
361  *---------------------------------------------------------------------------*/
362 void
TerminateScenes()363 TerminateScenes()
364 {
365     nw::gfx::SafeDestroyBranch(s_SceneRoot);
366     nw::demo::SafeCleanupResources(s_Resources);
367     nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
368 
369     NW_GL_ASSERT();
370 
371     s_Resources.clear();
372     s_SceneEnvironmentSettings.clear();
373 }
374 
375 /*!--------------------------------------------------------------------------*
376   @brief        シーンを更新します。
377  *---------------------------------------------------------------------------*/
378 void
UpdateScene()379 UpdateScene()
380 {
381     NW_ASSERT(0 < s_RenderTargets.size());
382 
383     s_SceneSystem->GetCameraController()->Update();
384 
385     s_SceneSystem->UpdateScene();
386 
387     s_BaseCamera->UpdateCameraMatrix();
388 
389     NW_NULL_ASSERT(s_ParticleSceneUpdater);
390     s_ParticleSceneUpdater->UpdateNode(
391         s_SceneSystem->GetSceneContext(),
392         s_ParticleContext);
393 
394     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
395 
396     s_FrameCount++;
397 
398     s_FlushCache->Execute();
399 }
400 
401 /*!--------------------------------------------------------------------------*
402   @brief        負荷表示やテスト機能の処理をおこないます。
403  *---------------------------------------------------------------------------*/
404 void
ReportDemo()405 ReportDemo()
406 {
407     NW_PROFILE("ReportDemo");
408 
409     // 負荷表示からはこれらの負荷は除きます。
410     s_RenderSystem->SuspendLoadMeter();
411 
412     s_GraphicsDrawing.BeginDrawingString();
413 
414     nw::demo::DebugUtility::DrawLoadMeter(
415         s_RenderSystem,
416         &s_GraphicsDrawing,
417         (s_FrameCount % NW_LOAD_METER_INTERVAL == 0)
418     );
419 
420     s_GraphicsDrawing.FlushDrawing();
421 
422     s_RenderSystem->ResumeLoadMeter();
423 }
424 
425 /*!--------------------------------------------------------------------------*
426   @brief        シーンをデモンストレーションします。
427  *---------------------------------------------------------------------------*/
428 void
DemoScene()429 DemoScene()
430 {
431     NW_ASSERT(!s_RenderTargets.empty());
432 
433     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
434 
435     InitializeScenes();
436 
437     bool isContinuing = true;
438 
439     while ( isContinuing )
440     {
441         nw::demo::DebugUtility::AdvanceAutoTestFrame();
442 
443         nw::demo::PadFactory::GetPad()->Update();
444 
445         SetStepFrame(1.0f);
446         UpdateScene();
447 
448         renderContext->SetActiveCamera(s_BaseCameraIndex);
449         s_RenderSystem->SubmitView(s_SceneSystem);
450 
451         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
452         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
453 
454         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
455         ReportDemo();
456         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
457 
458         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
459 
460         renderContext->ResetState();
461 
462         if (nw::demo::Utility::IsTerminating())
463         {
464             isContinuing = false;
465         }
466     }
467 
468     TerminateScenes();
469 }
470 
471 } // namespace
472 
473 /*!--------------------------------------------------------------------------*
474   @brief        メイン関数です。
475  *---------------------------------------------------------------------------*/
476 void
nnMain()477 nnMain()
478 {
479     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
480     nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
481 
482     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
483 
484     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
485     {
486         InitializeGraphics();
487 
488         // キャッシュフラッシュ用のクラスを生成(通常のアプリでは必要ありません)
489         s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
490 
491         DemoScene();
492 
493         // キャッシュフラッシュ用のクラスを破棄
494         nw::ut::SafeDestroy(s_FlushCache);
495 
496         TerminateGraphics();
497     }
498 
499     nw::demo::PadFactory::Finalize();
500 
501     nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
502 
503     nw::demo::FinalizeGraphicsSystem();
504 }
505