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