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