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