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