1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: ParticleApplicationDemo.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: 25938 $
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 #include <nn/hid/CTR/hid_TouchPanelReader.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* FONT_SHADER_FILE_NAME = NW_DEMO_FILE_PATH(L"nwfont_RectDrawerShader.shbin");
42 const wchar_t* FONT_FILE_NAME = NW_DEMO_FILE_PATH(L"Font.bcfnt");
43 const wchar_t* SKY_SPHERE_FILE_NAME = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
44
45 //----------------------------------------
46 // プロファイル関係
47 const int NW_LOAD_METER_INTERVAL = 60;
48
49 //----------------------------------------
50 // 描画関係
51 const int RENDER_TARGET_COUNT = 1;
52 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
53
54 RenderTargetArray s_RenderTargets;
55 nw::demo::SceneSystem* s_SceneSystem = NULL;
56 nw::demo::RenderSystem* s_RenderSystem = NULL;
57 nw::gfx::ParticleContext* s_ParticleContext = NULL;
58
59 nw::demo::GraphicsDrawing s_GraphicsDrawing;
60
61 //----------------------------------------
62 // リソース関係
63 nw::demo::ResourceArray s_Resources;
64
65 //----------------------------------------
66 // シーン関係
67 nw::gfx::SceneNode* s_SceneRoot = NULL;
68 nw::gfx::SceneNode* s_SceneRootInvisible = NULL;
69 s32 s_FrameCount = 0;
70 nw::gfx::Camera* s_BaseCamera = NULL;
71 nw::gfx::Camera* s_LeftCamera = NULL;
72 nw::gfx::Camera* s_RightCamera = NULL;
73 const f32 s_fNearPlane = 0.1f;
74
75 const s32 s_BaseCameraIndex = 0;
76 nw::demo::FlushCache* s_FlushCache;
77
78 //----------------------------------------
79 // パーティクル関係
80 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
81
82
83 /*!--------------------------------------------------------------------------*
84 @brief グラフィックス関連の初期化を行います。
85 *---------------------------------------------------------------------------*/
86 void
InitializeGraphics()87 InitializeGraphics()
88 {
89 nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
90
91 // renderDescriptionへステレオの設定を行います。
92 nw::demo::RenderSystem::Description renderDescription;
93
94 renderDescription.reusableCommandBufferSize = 0x100000;
95 renderDescription.reusableCommandRequestCount = 512;
96 renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
97
98 s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
99
100 s_GraphicsDrawing.SetScreenSize(
101 renderDescription.lowerScreenDescription.width,
102 renderDescription.lowerScreenDescription.height
103 );
104
105 bool result = s_GraphicsDrawing.InitializeFont(&s_DeviceAllocator, FONT_SHADER_FILE_NAME, FONT_FILE_NAME);
106
107 NN_ASSERTMSG(result, "Fail to load Font.");
108
109 s_RenderTargets.push_back(
110 nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
111 );
112 NW_ASSERT(!s_RenderTargets.empty());
113 s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
114
115 // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
116 nw::demo::SceneSystem::Description sceneDescription;
117 sceneDescription.maxSceneNodes = 256;
118 s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
119
120 s_ParticleContext = nw::gfx::ParticleContext::Builder()
121 .Create(&s_DeviceAllocator);
122
123 s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
124 .Create(&s_DeviceAllocator);
125
126 // デモ用の最遠景モデルをレンダリングシステムに設定します。
127 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
128 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
129
130 NW_GL_ASSERT();
131 }
132
133 /*!--------------------------------------------------------------------------*
134 @brief グラフィックス関連の後始末をします。
135 *---------------------------------------------------------------------------*/
136 void
TerminateGraphics()137 TerminateGraphics()
138 {
139 nw::gfx::SafeDestroy(s_LeftCamera);
140
141 nw::gfx::SafeDestroy(s_RightCamera);
142
143 nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
144
145 nw::gfx::SafeDestroy(s_ParticleContext);
146
147 nw::gfx::SafeDestroy(s_SceneSystem);
148
149 nw::gfx::SafeDestroyAll(s_RenderTargets);
150
151 s_GraphicsDrawing.Finalize();
152
153 nw::gfx::SafeDestroy(s_RenderSystem);
154
155 NW_GL_ASSERT();
156 }
157
158 /*!--------------------------------------------------------------------------*
159 @brief ルートノード関連の構築をします。
160 *---------------------------------------------------------------------------*/
161 void
BuildRootNodes()162 BuildRootNodes()
163 {
164 NW_ASSERT(s_SceneRoot == NULL);
165 s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
166 .IsFixedSizeMemory(false)
167 .MaxChildren(16)
168 .Create(&s_DeviceAllocator);
169 NW_NULL_ASSERT(s_SceneRoot);
170
171 s_SceneRootInvisible = nw::gfx::TransformNode::DynamicBuilder()
172 .IsFixedSizeMemory(false)
173 .MaxChildren(16)
174 .Create(&s_DeviceAllocator);
175 NW_NULL_ASSERT(s_SceneRootInvisible);
176 }
177
178 /*!--------------------------------------------------------------------------*
179 @brief カメラ関連の構築をします。
180 *---------------------------------------------------------------------------*/
181 void
BuildCameras()182 BuildCameras()
183 {
184 nw::demo::Utility::CreateStereoCameras(
185 &s_BaseCamera,
186 &s_LeftCamera,
187 &s_RightCamera,
188 &s_DeviceAllocator,
189 nw::math::VEC3(0.0f, 20.0f, 50.0f),
190 nw::math::VEC3(0.0f, 0.0f, 0.0f),
191 s_fNearPlane
192 );
193
194 s_SceneRoot->AttachChild(s_BaseCamera);
195 s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
196 }
197
198
199 /*!--------------------------------------------------------------------------*
200 @brief シーンを初期化します。
201 *---------------------------------------------------------------------------*/
202 void
InitializeScenes()203 InitializeScenes()
204 {
205 BuildRootNodes();
206
207 BuildCameras();
208
209 // シーンツリーを巡回して初期化を行います。
210 s_SceneSystem->InitializeScene(s_SceneRoot);
211 s_SceneSystem->UpdateScene();
212
213 // カメラを設定します。
214 nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
215 sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
216 nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
217
218 NW_GL_ASSERT();
219
220 s_FrameCount = 0;
221 }
222
223 /*!--------------------------------------------------------------------------*
224 @brief シーン関連の後始末をします。
225 *---------------------------------------------------------------------------*/
226 void
TerminateScenes()227 TerminateScenes()
228 {
229 nw::gfx::SafeDestroyBranch(s_SceneRoot);
230 nw::gfx::SafeDestroyBranch(s_SceneRootInvisible);
231 nw::demo::SafeCleanupResources(s_Resources);
232
233 NW_GL_ASSERT();
234
235 s_Resources.clear();
236 }
237
238 /*!--------------------------------------------------------------------------*
239 @brief シーンを更新します。
240 *---------------------------------------------------------------------------*/
241 void
UpdateScene()242 UpdateScene()
243 {
244 NW_ASSERT(0 < s_RenderTargets.size());
245
246 s_SceneSystem->GetCameraController()->Update();
247
248 s_SceneSystem->UpdateScene();
249
250 s_BaseCamera->UpdateCameraMatrix();
251
252 NW_NULL_ASSERT(s_ParticleSceneUpdater);
253 s_ParticleSceneUpdater->UpdateNode(
254 s_SceneSystem->GetSceneContext(),
255 s_ParticleContext);
256
257 s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
258
259 s_FrameCount++;
260
261 s_FlushCache->Execute();
262 }
263
264 /*!--------------------------------------------------------------------------*
265 @brief 負荷表示やテスト機能の処理をおこないます。
266 *---------------------------------------------------------------------------*/
267 void
ReportDemo()268 ReportDemo()
269 {
270 NW_PROFILE("ReportDemo");
271
272 // 負荷表示からはこれらの負荷は除きます。
273 s_RenderSystem->SuspendLoadMeter();
274
275 s_GraphicsDrawing.BeginDrawingString();
276
277 nw::demo::DebugUtility::DrawLoadMeter(
278 s_RenderSystem,
279 &s_GraphicsDrawing,
280 (s_FrameCount % NW_LOAD_METER_INTERVAL == 0)
281 );
282
283 s_GraphicsDrawing.FlushDrawing();
284
285 s_RenderSystem->ResumeLoadMeter();
286 }
287
288
289
290
291 //----------------------------------------
292 // デモ固有の変数
293
294 // パーティクルエフェクトクラス
295 nw::demo::ParticleEffect* s_ParticleEffect = NULL;
296
297 // パーティクルノードクラス
298 nw::demo::ParticleNode* s_ParticleNode = NULL;
299
300 // カウンタ
301 u32 s_Count = 0;
302
303 // 生成数
304 #define PARTICLE_EFFECT_NUM (10)
305
306 // ロードするエフェクトファイル名
307 const wchar_t* EFFECT_RESOURCE_FILE = NW_DEMO_FILE_PATH(L"light_particle.bcptl");
308
309
310 /*!--------------------------------------------------------------------------*
311 @brief ParticleApplicationDemoの初期化を行います。
312 *---------------------------------------------------------------------------*/
313 void
InitializeParticleApplicationDemo()314 InitializeParticleApplicationDemo()
315 {
316 // このデモは、10個のエフェクトインスタンスを準備し、
317 // 入力に応じて再生、再利用を行うデモです。
318 // 必要とされるインスタンスを前もって準備することで、
319 // 生成と破棄のコストを省略することができ、
320 // アプリケーションを安定したコストで実行することが可能です。
321
322 // パーティクルエフェクトクラスを生成します。
323 s_ParticleEffect = nw::demo::ParticleEffect::Create(&s_DeviceAllocator, &s_DeviceAllocator, false, s_ParticleContext);
324
325 // エフェクトデータをロードしてセットアップします。
326 nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, EFFECT_RESOURCE_FILE, &s_DeviceAllocator);
327
328 // リソースをセットアップを行います。
329 s_ParticleEffect->Setup(resourceSet->resource, true);
330
331 // ParticleEffectにリソースをセットします。
332 s_ParticleEffect->Register(resourceSet->resource);
333
334 // 10個のインスタンスを準備する。
335 s_ParticleEffect->AddPool(PARTICLE_EFFECT_NUM);
336
337 // パーティクルノードクラスのインスタンスをリースします。
338 s_ParticleNode = s_ParticleEffect->LeaseInstance();
339
340 // シーンに追加します。
341 s_SceneRoot->AttachChild(s_ParticleNode);
342 s_SceneSystem->InitializeScene(s_SceneRoot);
343 s_SceneSystem->UpdateScene();
344
345 // 操作説明をログ出力します。
346 NW_LOG("[Particle Application Demo usage]\n");
347 NW_LOG("touch panel: create\n");
348 }
349
350 /*!--------------------------------------------------------------------------*
351 @brief ParticleApplicationDemoの定期処理です。
352 *---------------------------------------------------------------------------*/
353 void
UpdateParticleApplicationDemo(nn::hid::CTR::TouchPanelReader & touchPanelReader)354 UpdateParticleApplicationDemo( nn::hid::CTR::TouchPanelReader& touchPanelReader)
355 {
356 // タッチパネルメッセージ処理を行います。
357 nn::hid::CTR::TouchPanelStatus touchPanelStatus;
358 static u16 touchPanelX = 0;
359 static u16 touchPanelY = 0;
360 touchPanelReader.ReadLatest( &touchPanelStatus );
361
362 bool isSceneUpdate = false;
363
364 // タッチされたらエフェクトを生成します。
365 if ( ( touchPanelX == 0 && touchPanelStatus.x != 0 ) || ( touchPanelY == 0 && touchPanelStatus.y != 0 ) )
366 {
367 // s_FireEffectから空いているインスタンスを借りてきます。
368 nw::demo::ParticleNode* particleNode = s_ParticleEffect->LeaseInstance();
369 if (particleNode != NULL)
370 {
371 // 表示位置を設定します。
372 f32 fposx = static_cast<f32>(touchPanelStatus.x)/8.f - 20.f;
373 f32 fposy = static_cast<f32>(touchPanelStatus.y)/8.f - 15.f;
374 particleNode->SetTranslate(fposx, -fposy, 0);
375
376 // シーンに追加します。
377 s_SceneRoot->AttachChild(particleNode);
378
379 isSceneUpdate = true;
380 }
381 }
382
383 // 終了しているエフェクトがあるならば、シーンからデタッチを行います。
384 for ( u32 i = 0; i < PARTICLE_EFFECT_NUM; ++i)
385 {
386 nw::demo::ParticleNode* particleNode = s_ParticleEffect->GetActiveEffect(i);
387 if (particleNode && particleNode->IsDone())
388 {
389 s_SceneRoot->DetachChild(particleNode);
390 s_ParticleEffect->ReleaseInstance(particleNode);
391 isSceneUpdate = true;
392 }
393 }
394
395 // シーンに変更があれば更新処理を行います。
396 if (isSceneUpdate)
397 {
398 s_SceneSystem->InitializeScene(s_SceneRoot);
399 }
400
401 touchPanelX = touchPanelStatus.x;
402 touchPanelY = touchPanelStatus.y;
403
404 ++s_Count;
405 }
406
407 /*!--------------------------------------------------------------------------*
408 @brief ParticleApplicationDemoのスクリーンデバッグ表示です。
409 *---------------------------------------------------------------------------*/
410 void
ReportParticleApplicationDemo()411 ReportParticleApplicationDemo()
412 {
413 if(s_Count%20 != 0)
414 {
415 s_GraphicsDrawing.DrawString(120, 110, "TOUCH ME!!");
416 }
417
418 u32 alive[PARTICLE_EFFECT_NUM];
419 for ( u32 i = 0; i < PARTICLE_EFFECT_NUM; ++i)
420 {
421 nw::demo::ParticleNode* particleNode = s_ParticleEffect->GetActiveEffect(i);
422 if (!particleNode)
423 {
424 alive[i] = false;
425 }
426 else
427 {
428 if (particleNode->IsDone())
429 {
430 alive[i] = false;
431 }
432 else
433 {
434 alive[i] = true;
435 }
436 }
437 }
438
439 s_GraphicsDrawing.DrawString(30, 10, "[%d][%d][%d][%d][%d][%d][%d][%d][%d][%d]",
440 alive[0],alive[1],alive[2],alive[3],alive[4],alive[5],alive[6],alive[7],alive[8],alive[9]);
441 }
442
443
444 /*!--------------------------------------------------------------------------*
445 @brief ParticleApplicationDemoの終了処理を行います。
446 *---------------------------------------------------------------------------*/
447 void
TerminateParticleApplicationDemo()448 TerminateParticleApplicationDemo()
449 {
450 nw::demo::ParticleNode* prevTarget = s_ParticleEffect->GetActiveEffect(0);
451 while (prevTarget != NULL)
452 {
453 s_ParticleEffect->ReleaseInstance(prevTarget);
454 prevTarget = s_ParticleEffect->GetActiveEffect(0);
455 }
456
457 s_ParticleEffect->FreePool();
458
459 nw::gfx::SafeDestroy(s_ParticleEffect);
460 }
461
462
463
464
465 /*!--------------------------------------------------------------------------*
466 @brief シーンをデモンストレーションします。
467 *---------------------------------------------------------------------------*/
468 void
DemoScene()469 DemoScene()
470 {
471 NW_ASSERT(!s_RenderTargets.empty());
472
473 nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
474
475 InitializeScenes();
476
477 // ParticleApplicationDemoの初期化処理です。
478 InitializeParticleApplicationDemo();
479
480 bool isContinuing = true;
481
482 // タッチパネルリーダ
483 nn::hid::CTR::TouchPanelReader s_TouchPanelReader;
484
485 while ( isContinuing )
486 {
487 nw::demo::DebugUtility::AdvanceAutoTestFrame();
488
489 nw::demo::PadFactory::GetPad()->Update();
490
491 // ParticleApplicationDemoの定期処理です。
492 UpdateParticleApplicationDemo( s_TouchPanelReader );
493
494 UpdateScene();
495
496 renderContext->SetActiveCamera(s_BaseCameraIndex);
497 s_RenderSystem->SubmitView(s_SceneSystem);
498
499 s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
500 s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
501
502 s_RenderSystem->ClearBySkyModel(s_BaseCamera);
503 ReportDemo();
504
505 // ParticleApplicationDemoのレポートを表示します。
506 ReportParticleApplicationDemo();
507
508 s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
509
510 s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
511
512 renderContext->ResetState();
513
514 if (nw::demo::Utility::IsTerminating())
515 {
516 isContinuing = false;
517 }
518 }
519
520 // ParticleApplicationDemoの終了処理です。
521 TerminateParticleApplicationDemo();
522
523 TerminateScenes();
524 }
525
526 } // namespace
527
528 /*!--------------------------------------------------------------------------*
529 @brief メイン関数です。
530 *---------------------------------------------------------------------------*/
531 void
nnMain()532 nnMain()
533 {
534 nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
535 nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
536
537 nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
538
539 NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
540 {
541 InitializeGraphics();
542
543 s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
544
545 DemoScene();
546
547 nw::ut::SafeDestroy(s_FlushCache);
548
549 TerminateGraphics();
550 }
551
552 nw::demo::PadFactory::Finalize();
553
554 nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
555
556 nw::demo::FinalizeGraphicsSystem();
557 }
558