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