1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ParticleMultiModelDemo.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 エミッタとモデルのセットを複数配置するデモです。
17 ParticleMultiEmitterとの速度比較のためのデモです。
18 */
19 
20 #define NW_DEBUG_CHECK_MEMORY_LEAK
21 
22 #include <nn/os.h>
23 #include <nn/fs.h>
24 
25 #include <nw/types.h>
26 #include <nw/demo.h>
27 #include <nw/dev.h>
28 #include <nw/gfx.h>
29 #include <nw/ut.h>
30 
31 namespace
32 {
33 
34 //----------------------------------------
35 // メモリ関係
36 
37 // デバイスメモリを確保するためのアロケータです。
38 nw::demo::DemoAllocator s_DeviceAllocator;
39 nw::demo::DemoAllocator s_ParticleAllocator;
40 
41 //----------------------------------------
42 // ファイル名の定義です。
43 const wchar_t* FONT_SHADER_FILE_NAME = NW_DEMO_FILE_PATH(L"nwfont_RectDrawerShader.shbin");
44 const wchar_t* FONT_FILE_NAME        = NW_DEMO_FILE_PATH(L"Font.bcfnt");
45 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
46 
47 const wchar_t* MODEL_RESOURCE_FILES[] =
48 {
49     NW_DEMO_FILE_PATH(L"fire_particle_all.bcptl"),
50     NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
51     NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"),
52 };
53 
54 //----------------------------------------
55 // プロファイル関係
56 const int NW_LOAD_METER_INTERVAL = 60;
57 
58 //----------------------------------------
59 // 描画関係
60 const int RENDER_TARGET_COUNT = 1;
61 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
62 
63 RenderTargetArray s_RenderTargets;
64 nw::demo::SceneSystem*  s_SceneSystem = NULL;
65 nw::demo::RenderSystem* s_RenderSystem = NULL;
66 nw::gfx::ParticleContext* s_ParticleContext = NULL;
67 
68 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
69 
70 //----------------------------------------
71 // リソース関係
72 nw::demo::ResourceArray s_Resources;
73 
74 //----------------------------------------
75 // シーン関係
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 
120     bool result = s_GraphicsDrawing.InitializeFont(&s_DeviceAllocator, FONT_SHADER_FILE_NAME, FONT_FILE_NAME);
121 
122     NN_ASSERTMSG(result, "Fail to load Font.");
123 
124     s_RenderTargets.push_back(
125         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
126     );
127     NW_ASSERT(!s_RenderTargets.empty());
128     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
129 
130     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
131     nw::demo::SceneSystem::Description sceneDescription;
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         .IsFixedSizeMemory(false)
211         .Create(&s_DeviceAllocator);
212     NW_NULL_ASSERT(s_SceneRoot);
213 }
214 
215 /*!--------------------------------------------------------------------------*
216   @brief        カメラ関連の構築をします。
217  *---------------------------------------------------------------------------*/
218 void
BuildCameras()219 BuildCameras()
220 {
221     nw::demo::Utility::CreateStereoCameras(
222         &s_BaseCamera,
223         &s_LeftCamera,
224         &s_RightCamera,
225         &s_DeviceAllocator,
226         nw::math::VEC3(28.0f, 22.0f, 28.0f),
227         nw::math::VEC3(0.0f, 0.0f, 0.0f),
228         s_fNearPlane
229     );
230 
231     s_SceneRoot->AttachChild(s_BaseCamera);
232     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
233 }
234 
235 /*!--------------------------------------------------------------------------*
236   @brief        リソース関連の構築をします。
237  *---------------------------------------------------------------------------*/
238 void
BuildResources(nw::demo::ResourceSet * resourceSet)239 BuildResources(nw::demo::ResourceSet* resourceSet)
240 {
241     resourceSet->resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
242     resourceSet->resource.ForeachIndexStream(nw::gfx::IndexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
243     resourceSet->resource.ForeachVertexStream(nw::gfx::VertexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
244 
245     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
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     for (int i = 0; i < 5; ++i)
252     {
253         nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(&s_DeviceAllocator);
254 
255         nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
256         nw::gfx::ResModelArray::iterator modelsEnd = models.end();
257         for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
258             modelResource != modelsEnd; ++modelResource)
259         {
260             nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
261                 &s_ParticleAllocator,
262                 (*modelResource)
263                 );
264 
265             if (node != NULL)
266             {
267                 nw::gfx::ParticleModel* model = nw::ut::DynamicCast<nw::gfx::ParticleModel*>(node);
268                 if (model != NULL)
269                 {
270                     model->Transform().SetTranslate(5.0f * (i - 2), 0, 0);
271                 }
272                 sceneNodeArray.push_back(node);
273             }
274         }
275 
276         nw::gfx::ResEmitterArray emitters = resourceSet->resource.GetEmitters();
277         for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin();
278             emitterResource != emitters.end(); ++emitterResource)
279         {
280             nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
281                 &s_ParticleAllocator,
282                 (*emitterResource)
283                 );
284 
285             if (node != NULL)
286             {
287                 nw::gfx::ParticleEmitter* emitter = nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(node);
288                 if (emitter != NULL)
289                 {
290                     emitter->Transform().SetTranslate(5.0f * (i - 2), 0, 0);
291                 }
292                 sceneNodeArray.push_back(node);
293             }
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 
309     {
310         nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(&s_DeviceAllocator);
311 
312         nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
313         for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
314             lightResource != lights.end(); ++lightResource)
315         {
316             nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
317                 &s_DeviceAllocator,
318                 (*lightResource)
319                 );
320             NW_NULL_ASSERT(node);
321             sceneNodeArray.push_back(node);
322         }
323 
324         nw::gfx::SceneHelper::ForeachRootNodes(
325             sceneNodeArray.Begin(),
326             sceneNodeArray.End(),
327             nw::gfx::AttachNode(s_SceneRoot)
328             );
329     }
330 
331     nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
332     nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
333     for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
334         settingResource != settingsEnd; ++settingResource)
335     {
336         nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
337             .Resource(*settingResource)
338             .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
339 
340         nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
341             nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
342 
343         NW_NULL_ASSERT(sceneEnvironmentSetting);
344         s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
345     }
346 }
347 
348 /*!--------------------------------------------------------------------------*
349   @brief        シーンを初期化します。
350  *---------------------------------------------------------------------------*/
351 void
InitializeScenes()352 InitializeScenes()
353 {
354     BuildRootNodes();
355 
356     BuildCameras();
357 
358     NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
359     {
360         BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
361     }
362 
363     // シーンツリーを巡回して初期化を行います。
364     s_SceneSystem->InitializeScene(s_SceneRoot);
365     s_SceneSystem->UpdateScene();
366 
367     // シーン環境の参照解決を行い設定します。
368     s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
369 
370     // カメラを設定します。
371     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
372     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
373     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
374 
375     NW_GL_ASSERT();
376 
377     s_FrameCount = 0;
378 }
379 
380 /*!--------------------------------------------------------------------------*
381   @brief        シーン関連の後始末をします。
382  *---------------------------------------------------------------------------*/
383 void
TerminateScenes()384 TerminateScenes()
385 {
386     nw::gfx::SafeDestroyBranch(s_SceneRoot);
387     nw::demo::SafeCleanupResources(s_Resources);
388     nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
389 
390     NW_GL_ASSERT();
391 
392     s_Resources.clear();
393     s_SceneEnvironmentSettings.clear();
394 }
395 
396 /*!--------------------------------------------------------------------------*
397   @brief        シーンを更新します。
398  *---------------------------------------------------------------------------*/
399 void
UpdateScene()400 UpdateScene()
401 {
402     NW_ASSERT(0 < s_RenderTargets.size());
403 
404     s_SceneSystem->GetCameraController()->Update();
405 
406     s_SceneSystem->UpdateScene();
407 
408     s_BaseCamera->UpdateCameraMatrix();
409 
410     NW_NULL_ASSERT(s_ParticleSceneUpdater);
411     s_ParticleSceneUpdater->UpdateNode(
412         s_SceneSystem->GetSceneContext(),
413         s_ParticleContext);
414 
415     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
416 
417     s_FrameCount++;
418 
419     s_FlushCache->Execute();
420 }
421 
422 /*!--------------------------------------------------------------------------*
423   @brief        負荷表示やテスト機能の処理をおこないます。
424  *---------------------------------------------------------------------------*/
425 void
ReportDemo()426 ReportDemo()
427 {
428     NW_PROFILE("ReportDemo");
429 
430     // 負荷表示からはこれらの負荷は除きます。
431     s_RenderSystem->SuspendLoadMeter();
432 
433     s_GraphicsDrawing.BeginDrawingString();
434 
435     nw::demo::DebugUtility::DrawLoadMeter(
436         s_RenderSystem,
437         &s_GraphicsDrawing,
438         (s_FrameCount % NW_LOAD_METER_INTERVAL == 0)
439     );
440 
441     s_GraphicsDrawing.FlushDrawing();
442 
443     s_RenderSystem->ResumeLoadMeter();
444 }
445 
446 /*!--------------------------------------------------------------------------*
447   @brief        シーンをデモンストレーションします。
448  *---------------------------------------------------------------------------*/
449 void
DemoScene()450 DemoScene()
451 {
452     NW_ASSERT(!s_RenderTargets.empty());
453 
454     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
455 
456     InitializeScenes();
457 
458     bool isContinuing = true;
459 
460     while ( isContinuing )
461     {
462         nw::demo::DebugUtility::AdvanceAutoTestFrame();
463 
464         nw::demo::PadFactory::GetPad()->Update();
465 
466         SetStepFrame(1.0f);
467         UpdateScene();
468 
469         renderContext->SetActiveCamera(s_BaseCameraIndex);
470         s_RenderSystem->SubmitView(s_SceneSystem);
471 
472         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
473         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
474 
475         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
476         ReportDemo();
477         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
478 
479         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
480 
481         renderContext->ResetState();
482 
483         if (nw::demo::Utility::IsTerminating())
484         {
485             isContinuing = false;
486         }
487     }
488 
489     TerminateScenes();
490 }
491 
492 } // namespace
493 
494 /*!--------------------------------------------------------------------------*
495   @brief        メイン関数です。
496  *---------------------------------------------------------------------------*/
497 void
nnMain()498 nnMain()
499 {
500     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
501     nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
502 
503     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
504 
505     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
506     {
507         InitializeGraphics();
508 
509         s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
510 
511         DemoScene();
512 
513         nw::ut::SafeDestroy(s_FlushCache);
514 
515         TerminateGraphics();
516     }
517 
518     nw::demo::PadFactory::Finalize();
519 
520     nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
521 
522     nw::demo::FinalizeGraphicsSystem();
523 }
524