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