1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: ParticleMissileDemo.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: $
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 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 //----------------------------------------
58 // シーン関係
59 nw::gfx::SceneNode* s_SceneRoot = NULL;
60 s32 s_FrameCount = 0;
61 nw::gfx::Camera* s_BaseCamera = NULL;
62 nw::gfx::Camera* s_LeftCamera = NULL;
63 nw::gfx::Camera* s_RightCamera = NULL;
64 const f32 s_fNearPlane = 0.1f;
65
66 const s32 s_BaseCameraIndex = 0;
67
68 //----------------------------------------
69 // パーティクル関係
70 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
71
72 nw::demo::FlushCache* s_FlushCache;
73
74 /*!--------------------------------------------------------------------------*
75 @brief グラフィックス関連の初期化を行います。
76 *---------------------------------------------------------------------------*/
77 void
InitializeGraphics()78 InitializeGraphics()
79 {
80 nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
81
82 // renderDescriptionへステレオの設定を行います。
83 nw::demo::RenderSystem::Description renderDescription;
84
85 renderDescription.reusableCommandBufferSize = 0x100000;
86 renderDescription.reusableCommandRequestCount = 512;
87 renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
88
89 s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
90
91 s_GraphicsDrawing.SetScreenSize(
92 renderDescription.lowerScreenDescription.width,
93 renderDescription.lowerScreenDescription.height
94 );
95
96 nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
97
98 s_RenderTargets.push_back(
99 nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
100 );
101 NW_ASSERT(!s_RenderTargets.empty());
102 s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
103
104 // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
105 nw::demo::SceneSystem::Description sceneDescription;
106 s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
107
108 s_ParticleContext = nw::gfx::ParticleContext::Builder()
109 .Create(&s_DeviceAllocator);
110
111 s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
112 .Create(&s_DeviceAllocator);
113
114 // デモ用の最遠景モデルをレンダリングシステムに設定します。
115 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
116 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
117
118 NW_GL_ASSERT();
119 }
120
121 /*!--------------------------------------------------------------------------*
122 @brief グラフィックス関連の後始末をします。
123 *---------------------------------------------------------------------------*/
124 void
TerminateGraphics()125 TerminateGraphics()
126 {
127 nw::gfx::SafeDestroy(s_LeftCamera);
128
129 nw::gfx::SafeDestroy(s_RightCamera);
130
131 nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
132
133 nw::gfx::SafeDestroy(s_ParticleContext);
134
135 nw::gfx::SafeDestroy(s_SceneSystem);
136
137 nw::gfx::SafeDestroyAll(s_RenderTargets);
138
139 s_GraphicsDrawing.Finalize();
140
141 nw::gfx::SafeDestroy(s_RenderSystem);
142
143 NW_GL_ASSERT();
144 }
145
146 /*!--------------------------------------------------------------------------*
147 @brief ルートノード関連の構築をします。
148 *---------------------------------------------------------------------------*/
149 void
BuildRootNodes()150 BuildRootNodes()
151 {
152 NW_ASSERT(s_SceneRoot == NULL);
153 s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
154 .IsFixedSizeMemory(false)
155 .Create(&s_DeviceAllocator);
156 NW_NULL_ASSERT(s_SceneRoot);
157 }
158
159 /*!--------------------------------------------------------------------------*
160 @brief カメラ関連の構築をします。
161 *---------------------------------------------------------------------------*/
162 void
BuildCameras()163 BuildCameras()
164 {
165 nw::demo::Utility::CreateStereoCameras(
166 &s_BaseCamera,
167 &s_LeftCamera,
168 &s_RightCamera,
169 &s_DeviceAllocator,
170 nw::math::VEC3(0.0f, 15.0f, 80.f),
171 nw::math::VEC3(0.0f, 15.0f, 0.0f),
172 s_fNearPlane
173 );
174
175 s_SceneRoot->AttachChild(s_BaseCamera);
176 s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
177 }
178
179
180 /*!--------------------------------------------------------------------------*
181 @brief シーンを初期化します。
182 *---------------------------------------------------------------------------*/
183 void
InitializeScenes()184 InitializeScenes()
185 {
186 BuildRootNodes();
187
188 BuildCameras();
189
190 // シーンツリーを巡回して初期化を行います。
191 s_SceneSystem->InitializeScene(s_SceneRoot);
192 s_SceneSystem->UpdateScene();
193
194 // カメラを設定します。
195 nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
196 sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
197 nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
198
199 NW_GL_ASSERT();
200
201 s_FrameCount = 0;
202 }
203
204 /*!--------------------------------------------------------------------------*
205 @brief シーン関連の後始末をします。
206 *---------------------------------------------------------------------------*/
207 void
TerminateScenes()208 TerminateScenes()
209 {
210 nw::gfx::SafeDestroyBranch(s_SceneRoot);
211
212 NW_GL_ASSERT();
213 }
214
215 /*!--------------------------------------------------------------------------*
216 @brief シーンを更新します。
217 *---------------------------------------------------------------------------*/
218 void
UpdateScene()219 UpdateScene()
220 {
221 NW_ASSERT(0 < s_RenderTargets.size());
222
223 s_SceneSystem->GetCameraController()->Update();
224
225 s_SceneSystem->UpdateScene();
226
227 s_BaseCamera->UpdateCameraMatrix();
228
229 NW_NULL_ASSERT(s_ParticleSceneUpdater);
230 s_ParticleSceneUpdater->UpdateNode(
231 s_SceneSystem->GetSceneContext(),
232 s_ParticleContext);
233
234 s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
235
236 s_FrameCount++;
237
238 s_FlushCache->Execute();
239 }
240
241 /*!--------------------------------------------------------------------------*
242 @brief 負荷表示やテスト機能の処理をおこないます。
243 *---------------------------------------------------------------------------*/
244 void
ReportDemo()245 ReportDemo()
246 {
247 NW_PROFILE("ReportDemo");
248
249 // 負荷表示からはこれらの負荷は除きます。
250 s_RenderSystem->SuspendLoadMeter();
251
252 nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
253
254 s_GraphicsDrawing.BeginDrawingShape();
255
256 nw::demo::DebugUtility::DrawLoadMeter(
257 s_RenderSystem,
258 &s_GraphicsDrawing
259 );
260
261 s_GraphicsDrawing.EndDrawingShape();
262
263 s_GraphicsDrawing.BeginDrawingString();
264
265 nw::demo::DebugUtility::DrawLoadMeterText(
266 s_RenderSystem,
267 &s_GraphicsDrawing
268 );
269
270 s_GraphicsDrawing.EndDrawingString();
271
272 s_RenderSystem->ResumeLoadMeter();
273 }
274
275
276
277
278 //----------------------------------------
279 // デモ固有の変数
280
281 // パーティクルエフェクトクラス
282 nw::demo::ParticleEffect* s_ParticleEffect = NULL;
283
284 // パーティクルノードクラス
285 nw::demo::ParticleNode* s_PaticleNode = NULL;
286
287 //----------------------------------------
288 // リソース関係
289 nw::demo::ResourceArray s_Resources;
290
291 // ロードするエフェクトファイル
292 const wchar_t* EFFECT_RESOURCE_FILE = NW_DEMO_FILE_PATH(L"missile_particle.bcptl");
293
294 // ロードするエフェクトシェーダファイル
295 const wchar_t* SHADER_RESOURCE_FILE_NAME = NW_DEMO_FILE_PATH(L"nwgfx_ParticleDefaultShader.bcsdr");
296
297 // 射出角度
298 f32 s_ShootAngle = 0.0f;
299
300 /*!--------------------------------------------------------------------------*
301 @brief ParticleMissileDemoの初期化を行います。
302 *---------------------------------------------------------------------------*/
303 void
InitializeParticleMissileDemo()304 InitializeParticleMissileDemo()
305 {
306 // 親からチャイルドへ速度継承を利用してパーティクルでミサイルを作成するデモです。
307 // データ内には、ParticleSetが親1つ、子2つの3つのParticleSetがあり、
308 // 2つ目のParticleSetが生成時に親からの速度継承を行っています。
309
310 // ParticleSet0:ミサイル本体
311 // ParticleSet1:ミサイル本体に追従するパーティクル(親速度を継承する)
312 // ParticleSet2:ミサイル本体消滅後に再生されるパーティクル
313
314 s_ShootAngle = 0.0f;
315
316 // シェーダバイナリをロードします。
317 nw::demo::ParticleEffect::InitializeShaderBinary(SHADER_RESOURCE_FILE_NAME, &s_DeviceAllocator);
318
319 // パーティクルエフェクトクラスを生成します。
320 s_ParticleEffect = nw::demo::ParticleEffect::Create(&s_DeviceAllocator, &s_DeviceAllocator, false, s_ParticleContext);
321
322 // エフェクトデータをロードしてセットアップします。
323 nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, EFFECT_RESOURCE_FILE, &s_DeviceAllocator);
324
325 // リソースをセットアップを行います。
326 s_ParticleEffect->Setup(resourceSet->resource, false);
327
328 // ParticleEffectにリソースをセットします。
329 s_ParticleEffect->Register(resourceSet->resource);
330 s_ParticleEffect->AddPool(1);
331
332 // パーティクルノードクラスのインスタンスをリースします。
333 s_PaticleNode = s_ParticleEffect->LeaseInstance();
334
335 // シーンに追加します。
336 s_SceneRoot->AttachChild(s_PaticleNode);
337
338 // シーンを更新します。
339 s_SceneSystem->InitializeScene(s_SceneRoot);
340 s_SceneSystem->UpdateScene();
341 }
342
343 /*!--------------------------------------------------------------------------*
344 @brief ParticleMissileDemoの定期処理です。
345 *---------------------------------------------------------------------------*/
346 void
UpdateParticleMissileDemo()347 UpdateParticleMissileDemo()
348 {
349 // 任意のタイミングで削除するParticleSetの名前です。
350 const char* DESTROY_MISSILE_NAME0 = "Missile_Particle"; // ミサイル本体
351 const char* DESTROY_MISSILE_NAME1 = "Missile_Flash_Particle"; // ミサイルノズルの光
352
353 // パッドで射出角度を調整します。
354 if (nw::demo::PadFactory::GetPad()->IsButtonPress(nw::demo::Pad::BUTTON_RIGHT))
355 {
356 s_ShootAngle -= nw::math::F_PI * 0.01f;
357 if (s_ShootAngle < -nw::math::F_PI/2.f)
358 {
359 s_ShootAngle = -nw::math::F_PI/2.f;
360 }
361 }
362
363 if (nw::demo::PadFactory::GetPad()->IsButtonPress(nw::demo::Pad::BUTTON_LEFT))
364 {
365 s_ShootAngle += nw::math::F_PI * 0.01f;
366 if (s_ShootAngle > nw::math::F_PI/2.f)
367 {
368 s_ShootAngle = nw::math::F_PI/2.f;
369 }
370 }
371
372 // ミサイルの射出角度を調整します。
373 for (u32 i = 0; i < s_PaticleNode->GetParticleEmitterSize(); ++i)
374 {
375 nw::gfx::ParticleEmitter* emitter = s_PaticleNode->GetParticleEmitter(i);
376 emitter->Transform().SetRotateXYZ( 0.0f, 0.0f, s_ShootAngle );
377 }
378
379
380 // パッドAで射出(放出)します。
381 // リソース側で同時に発射できるミサイル数だけ実行時ワークメモリを設定しておく必要があります。
382 if (nw::demo::PadFactory::GetPad()->IsButtonDown(nw::demo::Pad::BUTTON_A))
383 {
384 s_PaticleNode->Emission(s_ParticleContext);
385 }
386
387 // パッドBで全てのミサイルを削除します。
388 if (nw::demo::PadFactory::GetPad()->IsButtonDown(nw::demo::Pad::BUTTON_B))
389 {
390 nw::gfx::ParticleSet* particleSet0 = s_PaticleNode->GetParticleSet(DESTROY_MISSILE_NAME0);
391 nw::gfx::ParticleSet* particleSet1 = s_PaticleNode->GetParticleSet(DESTROY_MISSILE_NAME1);
392
393 nw::gfx::ParticleCollection* collection0= particleSet0->GetParticleCollection();
394 nw::gfx::ParticleCollection* collection1= particleSet1->GetParticleCollection();
395
396 collection0->KillParticles();
397 collection1->KillParticles();
398 }
399
400
401 // 射出されたミサイル(粒)を任意のタイミング(コリジョンなど)で削除します。
402 {
403 nw::gfx::ParticleSet* particleSet0 = s_PaticleNode->GetParticleSet(DESTROY_MISSILE_NAME0);
404 nw::gfx::ParticleSet* particleSet1 = s_PaticleNode->GetParticleSet(DESTROY_MISSILE_NAME1);
405
406 nw::gfx::ParticleCollection* collection0= particleSet0->GetParticleCollection();
407 nw::gfx::ParticleCollection* collection1= particleSet1->GetParticleCollection();
408
409 // ミサイル本体の有効なパーティクルの個数を取得します。
410 const int count0 = collection0->GetCount();
411 if (count0 != 0)
412 {
413 // 有効なパーティクルへのインデックス
414 u16* activeIndex =
415 (u16*)collection0->GetStreamPtr(
416 nw::gfx::PARTICLEUSAGE_ACTIVEINDEX,nw::gfx::PARTICLE_BUFFER_FRONT);
417
418 // パーティクルの位置
419 nw::math::VEC3* translate =
420 (nw::math::VEC3*)collection0->GetStreamPtr(
421 nw::gfx::PARTICLEUSAGE_TRANSLATE, nw::gfx::PARTICLE_BUFFER_FRONT);
422
423 for (int i = 0; i < count0; ++i)
424 {
425 int index = activeIndex[i];
426
427 // 発射位置から距離25.fでミサイル本体を削除します。
428 if ( translate[index].Length() > 25.f )
429 {
430 collection0->KillParticle(index);
431 }
432 }
433 }
434
435
436 // ミサイルノズル光にも同様の処理を行います。
437 const int count1 = collection0->GetCount();
438 if (count1 != 0)
439 {
440 // 有効なパーティクルへのインデックス
441 u16* activeIndex =
442 (u16*)collection1->GetStreamPtr(
443 nw::gfx::PARTICLEUSAGE_ACTIVEINDEX,nw::gfx::PARTICLE_BUFFER_FRONT);
444
445 // パーティクルの位置
446 nw::math::VEC3* translate =
447 (nw::math::VEC3*)collection1->GetStreamPtr(
448 nw::gfx::PARTICLEUSAGE_TRANSLATE, nw::gfx::PARTICLE_BUFFER_FRONT);
449
450 for (int i = 0; i < count1; ++i)
451 {
452 int index = activeIndex[i];
453
454 // 発射位置から距離25.fでミサイル本体を削除します。
455 if ( translate[index].Length() > 25.f )
456 {
457 collection1->KillParticle(index);
458 }
459 }
460 }
461 }
462 }
463
464 /*!--------------------------------------------------------------------------*
465 @brief ParticleMissileDemoのスクリーンデバッグ表示です。
466 *---------------------------------------------------------------------------*/
467 void
ReportParticleMissileDemo()468 ReportParticleMissileDemo()
469 {
470 s32 degree = s_ShootAngle * 114.6f;
471 s_GraphicsDrawing.DrawString(10, 10, "Angle :%d\n", degree);
472 s_GraphicsDrawing.DrawString(10, 22, "Button A :Shoot\n", degree);
473 s_GraphicsDrawing.DrawString(10, 36, "Button B :Destruction\n", degree);
474 s_GraphicsDrawing.DrawString(10, 48, "Pad L<->R:Angle Adjust\n", degree);
475 }
476
477 /*!--------------------------------------------------------------------------*
478 @brief ParticleMissileDemoの終了処理を行います。
479 *---------------------------------------------------------------------------*/
480 void
TerminateParticleMissileDemo()481 TerminateParticleMissileDemo()
482 {
483 nw::demo::ParticleNode* prevTarget = s_ParticleEffect->GetActiveEffect(0);
484 while (prevTarget != NULL)
485 {
486 s_ParticleEffect->ReleaseInstance(prevTarget);
487 prevTarget = s_ParticleEffect->GetActiveEffect(0);
488 }
489
490 s_ParticleEffect->FreePool();
491
492 nw::ut::SafeDestroy(s_ParticleEffect);
493
494 // ロードしたパーティクルシェーダを破棄します。
495 nw::demo::ParticleEffect::FinalizeShaderBinary();
496
497 nw::demo::SafeCleanupResources(s_Resources);
498 s_Resources.clear();
499 }
500
501
502
503
504 /*!--------------------------------------------------------------------------*
505 @brief シーンをデモンストレーションします。
506 *---------------------------------------------------------------------------*/
507 void
DemoScene()508 DemoScene()
509 {
510 NW_ASSERT(!s_RenderTargets.empty());
511
512 nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
513
514 InitializeScenes();
515
516 // ParticleMissileDemoの初期化処理です。
517 InitializeParticleMissileDemo();
518
519 bool isContinuing = true;
520
521 while ( isContinuing )
522 {
523 nw::demo::DebugUtility::AdvanceAutoTestFrame();
524
525 nw::demo::PadFactory::GetPad()->Update();
526
527
528 // ParticleMissileDemoの定期処理です。
529 UpdateParticleMissileDemo();
530
531 UpdateScene();
532
533 renderContext->SetActiveCamera(s_BaseCameraIndex);
534 s_RenderSystem->SubmitView(s_SceneSystem);
535
536 s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
537 s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
538
539 s_RenderSystem->ClearBySkyModel(s_BaseCamera);
540 ReportDemo();
541
542 // ParticleMissileDemoのレポートを表示します。
543 ReportParticleMissileDemo();
544
545 s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
546
547 s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
548
549 renderContext->ResetState();
550
551 if (nw::demo::Utility::IsTerminating())
552 {
553 isContinuing = false;
554 }
555 }
556
557 // ParticleMissileDemoの終了処理です。
558 TerminateParticleMissileDemo();
559
560 TerminateScenes();
561 }
562
563 } // namespace
564
565 /*!--------------------------------------------------------------------------*
566 @brief メイン関数です。
567 *---------------------------------------------------------------------------*/
568 void
nnMain()569 nnMain()
570 {
571 nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
572 nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
573
574 nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
575
576 NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
577 {
578 InitializeGraphics();
579
580 s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
581
582 DemoScene();
583
584 nw::ut::SafeDestroy(s_FlushCache);
585
586 TerminateGraphics();
587 }
588
589 nw::demo::PadFactory::Finalize();
590
591 nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
592
593 nw::demo::FinalizeGraphicsSystem();
594 }
595