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