1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ParticleChokeDemo.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 エミッタからの放出を停止し、全てのパーティクルの終了を待つデモです。
19 */
20 
21 #define NW_DEBUG_CHECK_MEMORY_LEAK
22 
23 #include <nn/os.h>
24 #include <nn/fs.h>
25 
26 #include <nw/types.h>
27 #include <nw/demo.h>
28 #include <nw/dev.h>
29 #include <nw/gfx.h>
30 #include <nw/ut.h>
31 
32 namespace
33 {
34 
35 //----------------------------------------
36 // メモリ関係
37 
38 // デバイスメモリを確保するためのアロケータです。
39 nw::demo::DemoAllocator s_DeviceAllocator;
40 nw::demo::DemoAllocator s_ParticleAllocator;
41 
42 //----------------------------------------
43 // ファイル名の定義です。
44 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
45 
46 const wchar_t* MODEL_RESOURCE_FILES[] =
47 {
48     NW_DEMO_FILE_PATH(L"fountain_particle_all.bcptl"),
49     NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
50     NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"),
51 };
52 
53 //----------------------------------------
54 // 描画関係
55 const int RENDER_TARGET_COUNT = 1;
56 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
57 
58 RenderTargetArray s_RenderTargets;
59 nw::demo::SceneSystem*  s_SceneSystem = NULL;
60 nw::demo::RenderSystem* s_RenderSystem = NULL;
61 nw::gfx::ParticleContext* s_ParticleContext = NULL;
62 
63 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
64 
65 //----------------------------------------
66 // リソース関係
67 nw::demo::ResourceArray s_Resources;
68 
69 //----------------------------------------
70 // シーン関係
71 nw::gfx::SceneNode* s_SceneRoot = NULL;
72 s32 s_FrameCount = 0;
73 nw::gfx::Camera* s_BaseCamera = NULL;
74 nw::gfx::Camera* s_LeftCamera = NULL;
75 nw::gfx::Camera* s_RightCamera = NULL;
76 const f32 s_fNearPlane = 0.1f;
77 
78 const s32 s_BaseCameraIndex = 0;
79 
80 //----------------------------------------
81 // パーティクル関係
82 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
83 
84 nw::demo::FlushCache* s_FlushCache;
85 
86 
87 /*!--------------------------------------------------------------------------*
88   @brief        グラフィックス関連の初期化を行います。
89  *---------------------------------------------------------------------------*/
90 void
InitializeGraphics()91 InitializeGraphics()
92 {
93     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
94 
95     // renderDescriptionへステレオの設定を行います。
96     nw::demo::RenderSystem::Description renderDescription;
97 
98     renderDescription.reusableCommandBufferSize = 0x100000;
99     renderDescription.reusableCommandRequestCount      = 512;
100     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
101 
102     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
103 
104     s_GraphicsDrawing.SetScreenSize(
105         renderDescription.lowerScreenDescription.width,
106         renderDescription.lowerScreenDescription.height
107     );
108 
109     nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
110 
111     s_RenderTargets.push_back(
112         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
113     );
114     NW_ASSERT(!s_RenderTargets.empty());
115     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
116 
117     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
118     nw::demo::SceneSystem::Description sceneDescription;
119     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
120 
121     s_ParticleContext = nw::gfx::ParticleContext::Builder()
122         .Create(&s_DeviceAllocator);
123 
124     s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
125         .Create(&s_DeviceAllocator);
126 
127     // デモ用の最遠景モデルをレンダリングシステムに設定します。
128     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
129     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
130 
131     NW_GL_ASSERT();
132 }
133 
134 /*!--------------------------------------------------------------------------*
135   @brief        グラフィックス関連の後始末をします。
136  *---------------------------------------------------------------------------*/
137 void
TerminateGraphics()138 TerminateGraphics()
139 {
140     nw::gfx::SafeDestroy(s_LeftCamera);
141 
142     nw::gfx::SafeDestroy(s_RightCamera);
143 
144     nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
145 
146     nw::gfx::SafeDestroy(s_ParticleContext);
147 
148     nw::gfx::SafeDestroy(s_SceneSystem);
149 
150     nw::gfx::SafeDestroyAll(s_RenderTargets);
151 
152     s_GraphicsDrawing.Finalize();
153 
154     nw::gfx::SafeDestroy(s_RenderSystem);
155 
156     NW_GL_ASSERT();
157 }
158 
159 
160 /*!--------------------------------------------------------------------------*
161   @brief        ルートノード関連の構築をします。
162  *---------------------------------------------------------------------------*/
163 void
BuildRootNodes()164 BuildRootNodes()
165 {
166     NW_ASSERT(s_SceneRoot == NULL);
167     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
168         .IsFixedSizeMemory(false)
169         .Create(&s_DeviceAllocator);
170     NW_NULL_ASSERT(s_SceneRoot);
171 }
172 
173 /*!--------------------------------------------------------------------------*
174   @brief        カメラ関連の構築をします。
175  *---------------------------------------------------------------------------*/
176 void
BuildCameras()177 BuildCameras()
178 {
179     nw::demo::Utility::CreateStereoCameras(
180         &s_BaseCamera,
181         &s_LeftCamera,
182         &s_RightCamera,
183         &s_DeviceAllocator,
184         nw::math::VEC3(28.0f, 22.0f, 28.0f),
185         nw::math::VEC3(0.0f, 0.0f, 0.0f),
186         s_fNearPlane
187     );
188 
189     s_SceneRoot->AttachChild(s_BaseCamera);
190     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
191 }
192 
193 
194 /*!--------------------------------------------------------------------------*
195   @brief        シーンを初期化します。
196  *---------------------------------------------------------------------------*/
197 void
InitializeScenes()198 InitializeScenes()
199 {
200     BuildRootNodes();
201 
202     BuildCameras();
203 
204     // シーンツリーを巡回して初期化を行います。
205     s_SceneSystem->InitializeScene(s_SceneRoot);
206     s_SceneSystem->UpdateScene();
207 
208     // カメラを設定します。
209     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
210     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
211     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
212 
213     NW_GL_ASSERT();
214 
215     //-----------------------------------------------------------------------------
216     s_FrameCount = 0;
217 }
218 
219 /*!--------------------------------------------------------------------------*
220   @brief        シーン関連の後始末をします。
221  *---------------------------------------------------------------------------*/
222 void
TerminateScenes()223 TerminateScenes()
224 {
225     nw::gfx::SafeDestroyBranch(s_SceneRoot);
226     nw::demo::SafeCleanupResources(s_Resources);
227 
228     NW_GL_ASSERT();
229 
230     s_Resources.clear();
231 }
232 
233 /*!--------------------------------------------------------------------------*
234   @brief        シーンを更新します。
235  *---------------------------------------------------------------------------*/
236 void
UpdateScene()237 UpdateScene()
238 {
239     NW_ASSERT(0 < s_RenderTargets.size());
240 
241     s_SceneSystem->GetCameraController()->Update();
242 
243     s_SceneSystem->UpdateScene();
244 
245     s_BaseCamera->UpdateCameraMatrix();
246 
247     NW_NULL_ASSERT(s_ParticleSceneUpdater);
248     s_ParticleSceneUpdater->UpdateNode(
249         s_SceneSystem->GetSceneContext(),
250         s_ParticleContext);
251 
252     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
253 
254     s_FrameCount++;
255 
256     s_FlushCache->Execute();
257 }
258 
259 /*!--------------------------------------------------------------------------*
260   @brief        負荷表示やテスト機能の処理をおこないます。
261  *---------------------------------------------------------------------------*/
262 void
ReportDemo()263 ReportDemo()
264 {
265     NW_PROFILE("ReportDemo");
266 
267     // 負荷表示からはこれらの負荷は除きます。
268     s_RenderSystem->SuspendLoadMeter();
269 
270     nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
271 
272     s_GraphicsDrawing.BeginDrawingShape();
273 
274     nw::demo::DebugUtility::DrawLoadMeter(
275         s_RenderSystem,
276         &s_GraphicsDrawing
277     );
278 
279     s_GraphicsDrawing.EndDrawingShape();
280 
281     s_GraphicsDrawing.BeginDrawingString();
282 
283     nw::demo::DebugUtility::DrawLoadMeterText(
284         s_RenderSystem,
285         &s_GraphicsDrawing
286     );
287 
288     s_GraphicsDrawing.EndDrawingString();
289 
290     s_RenderSystem->ResumeLoadMeter();
291 }
292 
293 
294 
295 
296 //----------------------------------------
297 // デモ固有の変数
298 
299 // パーティクルエフェクトクラス
300 nw::demo::ParticleEffect* s_ParticleEffect = NULL;
301 
302 // パーティクルノードクラス
303 nw::demo::ParticleNode* s_particleNode = NULL;
304 
305 // 親ノード
306 nw::gfx::SceneNode* s_ParentNode = NULL;
307 
308 // 再生が終了しているか?
309 bool s_IsDone = false;
310 
311 // ロードするエフェクトファイル名
312 const wchar_t* EFFECT_RESOURCE_FILE = NW_DEMO_FILE_PATH(L"light_particle.bcptl");
313 
314 // ロードするエフェクトシェーダファイル
315 const wchar_t* SHADER_RESOURCE_FILE_NAME = NW_DEMO_FILE_PATH(L"nwgfx_ParticleDefaultShader.bcsdr");
316 
317 
318 /*!--------------------------------------------------------------------------*
319   @brief        ParticleChokeDemoの初期化を行います。
320  *---------------------------------------------------------------------------*/
321 void
InitializeParticleChokeDemo()322 InitializeParticleChokeDemo()
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     // ParticleEffect内にインスタンスを1つだけ準備します。
342     s_ParticleEffect->AddPool(1);
343 
344     // ParticleEffect内に準備されたインスタンスを借りてきます。
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     // このデモでは、親ノードへAttach,Detachを行うので、親ノードを保持します。
353     s_ParentNode = s_particleNode->GetParent();
354 
355     // 操作説明をログ出力します。
356     NW_DEV_LOG("[ParticleChokeDemo]\n");
357     NW_DEV_LOG("Button R : Restart Partcile\n");
358 }
359 
360 /*!--------------------------------------------------------------------------*
361   @brief        ParticleChokeDemoの定期処理です。
362  *---------------------------------------------------------------------------*/
363 void
UpdateParticleChokeDemo()364 UpdateParticleChokeDemo()
365 {
366     // 再生が終了しているかチェックします。
367     // IsDoneメソッド内では、ParticleModelが保持するパーティクル数と、
368     // ParticleEmitterの放出完了かどうかをチェックします。
369     if ( !s_IsDone && s_particleNode->IsDone() )
370     {
371         // 再生が終了しているのであれば、Detachを行います。
372         // 再生終了したエフェクトのDetachを行うことで、
373         // 余計なシーングラフのコストを省きます。
374         s_ParentNode->DetachChild(s_particleNode);
375         s_SceneSystem->InitializeScene(s_SceneRoot);
376         s_IsDone = true;
377     }
378 
379     // 終了状態、且つ、Rボタンでリセットします。
380     if (s_IsDone && nw::demo::PadFactory::GetPad()->IsButtonDown(nw::demo::Pad::BUTTON_R))
381     {
382         // Resetメソッド内では、ParticleEmitterのリセット処理、
383         // ParticleModel内、アニメーションフレームの0初期化、
384         // 及び、ParticleCollectionのClear処理が行われています。
385         // また、コマンド2重化時には、ResetメソッドをGPU処理中にコールすることができません。
386         // Detachした後、GPU処理が終了の後、コールしてください。
387         s_particleNode->Reset();
388 
389         // リセット処理ののち、シーングラフ再度Attachを行います。
390         s_ParentNode->AttachChild(s_particleNode);
391         s_SceneSystem->InitializeScene(s_SceneRoot);
392         s_IsDone = false;
393     }
394 }
395 
396 /*!--------------------------------------------------------------------------*
397   @brief        ParticleChokeDemoのスクリーンデバッグ表示です。
398  *---------------------------------------------------------------------------*/
399 void
ReportParticleChokeDemo()400 ReportParticleChokeDemo()
401 {
402     s_GraphicsDrawing.DrawString(10, 10, "Particle Num  :%d\n", s_particleNode->GetParticleSize() );
403 
404     if (s_IsDone)
405     {
406         s_GraphicsDrawing.DrawString(10, 22, "Done:Push R Restart!\n" );
407     }
408     else
409     {
410         s_GraphicsDrawing.DrawString(10, 22, "Playing\n" );
411     }
412 }
413 
414 
415 /*!--------------------------------------------------------------------------*
416   @brief        ParticleChokeDemoの終了処理を行います。
417  *---------------------------------------------------------------------------*/
418 void
TerminateParticleChokeDemo()419 TerminateParticleChokeDemo()
420 {
421     nw::demo::ParticleNode* prevTarget = s_ParticleEffect->GetActiveEffect(0);
422     while (prevTarget != NULL)
423     {
424         s_ParticleEffect->ReleaseInstance(prevTarget);
425         prevTarget = s_ParticleEffect->GetActiveEffect(0);
426     }
427 
428     s_ParticleEffect->FreePool();
429 
430     nw::gfx::SafeDestroy(s_ParticleEffect);
431 
432     // ロードしたパーティクルシェーダを破棄します。
433     nw::demo::ParticleEffect::FinalizeShaderBinary();
434 }
435 
436 
437 
438 
439 /*!--------------------------------------------------------------------------*
440   @brief        シーンをデモンストレーションします。
441  *---------------------------------------------------------------------------*/
442 void
DemoScene()443 DemoScene()
444 {
445     NW_ASSERT(!s_RenderTargets.empty());
446 
447     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
448 
449     InitializeScenes();
450 
451     // ParticleChokeDemoの初期化処理です。
452     InitializeParticleChokeDemo();
453 
454     nw::demo::DebugUtility::PostInitializeScenes();
455 
456     int count = 0;
457     bool isContinuing = true;
458 
459     while ( isContinuing )
460     {
461         nw::demo::DebugUtility::AdvanceAutoTestFrame();
462 
463         nw::demo::PadFactory::GetPad()->Update();
464 
465         ++count;
466 
467         // ParticleChokeDemoの定期処理です。
468         UpdateParticleChokeDemo();
469 
470         UpdateScene();
471 
472         renderContext->SetActiveCamera(s_BaseCameraIndex);
473         s_RenderSystem->SubmitView(s_SceneSystem);
474 
475         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
476         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
477 
478         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
479         ReportDemo();
480 
481         // ParticleCtrlEmissionDemoのレポートを表示します。
482         ReportParticleChokeDemo();
483 
484         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
485 
486         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
487 
488         renderContext->ResetState();
489 
490         if (nw::demo::Utility::IsTerminating())
491         {
492             isContinuing = false;
493         }
494     }
495 
496     nw::demo::DebugUtility::PreTerminateScenes();
497 
498     // ParticleChokeDemoの終了処理です。
499     TerminateParticleChokeDemo();
500 
501     TerminateScenes();
502 }
503 
504 } // namespace
505 
506 /*!--------------------------------------------------------------------------*
507   @brief        メイン関数です。
508  *---------------------------------------------------------------------------*/
509 void
nnMain()510 nnMain()
511 {
512     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
513     nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
514 
515     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
516 
517     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
518     {
519         InitializeGraphics();
520 
521         s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
522 
523         DemoScene();
524 
525         nw::ut::SafeDestroy(s_FlushCache);
526 
527         TerminateGraphics();
528     }
529 
530     nw::demo::PadFactory::Finalize();
531 
532     nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
533 
534     nw::demo::FinalizeGraphicsSystem();
535 }
536