1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ParticleChangeVtxDemo.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: 25401 $
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* FONT_SHADER_FILE_NAME = NW_DEMO_FILE_PATH(L"nwfont_RectDrawerShader.shbin");
40 const wchar_t* FONT_FILE_NAME        = NW_DEMO_FILE_PATH(L"Font.bcfnt");
41 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
42 
43 const wchar_t* MODEL_RESOURCE_FILES[] =
44 {
45     NW_DEMO_FILE_PATH(L"fountain_particle_all.bcptl"),
46     NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
47     NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"),
48 };
49 
50 //----------------------------------------
51 // プロファイル関係
52 const int NW_LOAD_METER_INTERVAL = 60;
53 
54 //----------------------------------------
55 // 描画関係
56 const int RENDER_TARGET_COUNT = 1;
57 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
58 
59 RenderTargetArray s_RenderTargets;
60 nw::demo::SceneSystem*  s_SceneSystem = NULL;
61 nw::demo::RenderSystem* s_RenderSystem = NULL;
62 nw::gfx::ParticleContext* s_ParticleContext = NULL;
63 
64 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
65 
66 //----------------------------------------
67 // リソース関係
68 nw::demo::ResourceArray s_Resources;
69 
70 //----------------------------------------
71 // シーン関係
72 nw::gfx::SceneNode* s_SceneRoot = NULL;
73 s32 s_FrameCount = 0;
74 nw::gfx::Camera* s_BaseCamera = NULL;
75 nw::gfx::Camera* s_LeftCamera = NULL;
76 nw::gfx::Camera* s_RightCamera = NULL;
77 const f32 s_fNearPlane = 0.1f;
78 
79 // このデモでは、シーンから取り外すので別に保持しておく
80 nw::gfx::ParticleEmitter* s_ParticleEmitter = NULL;
81 nw::gfx::ParticleModel* s_ParticleModel = NULL;
82 
83 //----------------------------------------
84 // シーン環境関係
85 const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
86 
87 typedef nw::ut::FixedSizeArray<nw::gfx::SceneEnvironmentSetting*, ENVIRONMENT_SETTINGS_COUNT> SceneEnvironmentSettingArray;
88 SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
89 
90 const s32 s_BaseCameraIndex = 0;
91 
92 //----------------------------------------
93 // パーティクル関係
94 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
95 
96 nw::demo::FlushCache* s_FlushCache;
97 
98 /*!--------------------------------------------------------------------------*
99   @brief        グラフィックス関連の初期化を行います。
100  *---------------------------------------------------------------------------*/
101 void
InitializeGraphics()102 InitializeGraphics()
103 {
104     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
105 
106     // renderDescriptionへステレオの設定を行います。
107     nw::demo::RenderSystem::Description renderDescription;
108 
109     renderDescription.reusableCommandBufferSize = 0x100000;
110     renderDescription.reusableCommandRequestCount      = 512;
111     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
112 
113     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
114 
115     s_GraphicsDrawing.SetScreenSize(
116         renderDescription.lowerScreenDescription.width,
117         renderDescription.lowerScreenDescription.height
118     );
119 
120     bool result = s_GraphicsDrawing.InitializeFont(&s_DeviceAllocator, FONT_SHADER_FILE_NAME, FONT_FILE_NAME);
121 
122     NN_ASSERTMSG(result, "Fail to load Font.");
123 
124     s_RenderTargets.push_back(
125         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
126     );
127     NW_ASSERT(!s_RenderTargets.empty());
128     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
129 
130     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
131     nw::demo::SceneSystem::Description sceneDescription;
132     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
133 
134     s_ParticleContext = nw::gfx::ParticleContext::Builder()
135         .MaxEmission(1000)
136         .Create(&s_DeviceAllocator);
137 
138     s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
139         .Create(&s_DeviceAllocator);
140 
141     // デモ用の最遠景モデルをレンダリングシステムに設定します。
142     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
143     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
144 
145     NW_GL_ASSERT();
146 }
147 
148 /*!--------------------------------------------------------------------------*
149   @brief        グラフィックス関連の後始末をします。
150  *---------------------------------------------------------------------------*/
151 void
TerminateGraphics()152 TerminateGraphics()
153 {
154     nw::gfx::SafeDestroy(s_LeftCamera);
155 
156     nw::gfx::SafeDestroy(s_RightCamera);
157 
158     nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
159 
160     nw::gfx::SafeDestroy(s_ParticleContext);
161 
162     nw::gfx::SafeDestroy(s_SceneSystem);
163 
164     nw::gfx::SafeDestroyAll(s_RenderTargets);
165 
166     s_GraphicsDrawing.Finalize();
167 
168     nw::gfx::SafeDestroy(s_RenderSystem);
169 
170     NW_GL_ASSERT();
171 }
172 
173 /*!--------------------------------------------------------------------------*
174   @brief        ルートノード関連の構築をします。
175  *---------------------------------------------------------------------------*/
176 void
BuildRootNodes()177 BuildRootNodes()
178 {
179     NW_ASSERT(s_SceneRoot == NULL);
180     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
181         .IsFixedSizeMemory(false)
182         .Create(&s_DeviceAllocator);
183     NW_NULL_ASSERT(s_SceneRoot);
184 }
185 
186 /*!--------------------------------------------------------------------------*
187   @brief        カメラ関連の構築をします。
188  *---------------------------------------------------------------------------*/
189 void
BuildCameras()190 BuildCameras()
191 {
192     nw::demo::Utility::CreateStereoCameras(
193         &s_BaseCamera,
194         &s_LeftCamera,
195         &s_RightCamera,
196         &s_DeviceAllocator,
197         nw::math::VEC3(28.0f, 22.0f, 28.0f),
198         nw::math::VEC3(0.0f, 0.0f, 0.0f),
199         s_fNearPlane
200     );
201 
202     s_SceneRoot->AttachChild(s_BaseCamera);
203     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
204 }
205 
206 /*!--------------------------------------------------------------------------*
207   @brief        リソース関連の構築をします。
208  *---------------------------------------------------------------------------*/
209 void
BuildResources(nw::demo::ResourceSet * resourceSet)210 BuildResources(nw::demo::ResourceSet* resourceSet)
211 {
212     resourceSet->resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
213     resourceSet->resource.ForeachIndexStream(nw::gfx::IndexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
214     resourceSet->resource.ForeachVertexStream(nw::gfx::VertexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
215 
216     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
217 
218     if (result.IsFailure())
219     {
220         NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
221     }
222 
223     nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(&s_DeviceAllocator);
224 
225     nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
226     nw::gfx::ResModelArray::iterator modelsEnd = models.end();
227     for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
228          modelResource != modelsEnd; ++modelResource)
229     {
230         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
231             &s_ParticleAllocator,
232             (*modelResource)
233         );
234         if (node != NULL)
235         {
236             sceneNodeArray.push_back(node);
237         }
238 
239         s_ParticleModel = nw::ut::DynamicCast<nw::gfx::ParticleModel*>(node);
240         NW_NULL_ASSERT(s_ParticleModel);
241     }
242 
243     nw::gfx::ResEmitterArray emitters = resourceSet->resource.GetEmitters();
244     for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin();
245          emitterResource != emitters.end(); ++emitterResource)
246     {
247         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
248             &s_ParticleAllocator,
249             (*emitterResource)
250         );
251         if (node != NULL)
252         {
253             sceneNodeArray.push_back(node);
254         }
255 
256         s_ParticleEmitter = nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(node);
257         NW_NULL_ASSERT(s_ParticleEmitter);
258     }
259 
260     nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
261     for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
262         lightResource != lights.end(); ++lightResource)
263     {
264         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
265             &s_DeviceAllocator,
266             (*lightResource)
267         );
268         NW_NULL_ASSERT(node);
269         sceneNodeArray.push_back(node);
270     }
271 
272     // 親子付け参照関係を解決
273     nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
274 
275     nw::gfx::ParticleUtil::SetupParticleObject(&sceneNodeArray, s_ParticleContext);
276 
277     // モデルとエミッタをシーンに追加
278     nw::gfx::SceneHelper::ForeachRootNodes(
279         sceneNodeArray.Begin(),
280         sceneNodeArray.End(),
281         nw::gfx::AttachNode(s_SceneRoot)
282     );
283 
284     nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
285     nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
286     for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
287         settingResource != settingsEnd; ++settingResource)
288     {
289         nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
290             .Resource(*settingResource)
291             .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
292 
293         nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
294             nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
295 
296         NW_NULL_ASSERT(sceneEnvironmentSetting);
297         s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
298     }
299 }
300 /*!--------------------------------------------------------------------------*
301   @brief        シーンを初期化します。
302  *---------------------------------------------------------------------------*/
303 void
InitializeScenes()304 InitializeScenes()
305 {
306     BuildRootNodes();
307 
308     BuildCameras();
309 
310     NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
311     {
312         BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
313     }
314 
315     // シーンツリーを巡回して初期化を行います。
316     s_SceneSystem->InitializeScene(s_SceneRoot);
317     s_SceneSystem->UpdateScene();
318 
319     // シーン環境の参照解決を行い設定します。
320     s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
321 
322     // カメラを設定します。
323     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
324     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
325     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
326 
327     NW_GL_ASSERT();
328 
329     s_FrameCount = 0;
330 }
331 
332 /*!--------------------------------------------------------------------------*
333   @brief        シーン関連の後始末をします。
334  *---------------------------------------------------------------------------*/
335 void
TerminateScenes()336 TerminateScenes()
337 {
338     if (s_ParticleModel->GetParent() != s_SceneRoot)
339     {
340         nw::gfx::SafeDestroyBranch(s_ParticleModel);
341         s_ParticleModel = NULL;
342     }
343 
344     if (s_ParticleEmitter->GetParent() != s_SceneRoot)
345     {
346         nw::gfx::SafeDestroyBranch(s_ParticleEmitter);
347         s_ParticleEmitter = NULL;
348     }
349 
350     nw::gfx::SafeDestroyBranch(s_SceneRoot);
351     nw::demo::SafeCleanupResources(s_Resources);
352     nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
353 
354     NW_GL_ASSERT();
355 
356     s_Resources.clear();
357     s_SceneEnvironmentSettings.clear();
358 }
359 
360 /*!--------------------------------------------------------------------------*
361   @brief        シーンを更新します。
362  *---------------------------------------------------------------------------*/
363 void
UpdateScene()364 UpdateScene()
365 {
366     NW_ASSERT(0 < s_RenderTargets.size());
367 
368     s_SceneSystem->GetCameraController()->Update();
369 
370     s_SceneSystem->UpdateScene();
371 
372     s_BaseCamera->UpdateCameraMatrix();
373 
374     NW_NULL_ASSERT(s_ParticleSceneUpdater);
375     s_ParticleSceneUpdater->UpdateNode(
376         s_SceneSystem->GetSceneContext(),
377         s_ParticleContext);
378 
379     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
380 
381     s_FrameCount++;
382 
383     nw::gfx::ParticleSet* particleSet = s_ParticleModel->GetParticleSets(0);
384     nw::gfx::ParticleCollection* collection = particleSet->GetParticleCollection();
385 
386     // 頂点パラメータの変更
387     {
388         nw::math::VEC3 newColor(0.0f, (s_FrameCount % 256) / 256.0f, 0.0f);
389         collection->SetParameter(nw::gfx::PARTICLEUSAGE_COLOR, nw::gfx::PARTICLE_BUFFER_FRONT, newColor);
390     }
391 
392     // CPUでのみ使うパラメータの変更(固定値のLIFE)
393     // LIFEはアニメーションとこれから生まれる粒子には影響しますが、
394     // 消滅判定はNEG_TIMELIMITを使うので、既に存在する粒子の寿命には影響しません。
395     // この相違によりアニメーションがおかしくなることがあります。
396     // これが問題となる場合は、NEG_TIMELIMITも修正するか、LIFEがストリームになるようにしてください。
397     {
398         nw::gfx::ParticleTime newLife = (s_FrameCount % 256) / 256.0f * 100 + 1;
399         collection->SetLifeParameter(&newLife);
400     }
401 
402     // 頂点ストリームの変更
403     // translateはVBOで、velocityは非VBOです。
404     {
405         // 有効なパーティクルへのインデックス・テーブル
406         u16* activeIndex =
407             (u16*)collection->GetStreamPtr(
408             nw::gfx::PARTICLEUSAGE_ACTIVEINDEX,
409             nw::gfx::PARTICLE_BUFFER_FRONT);
410 
411         nw::math::VEC3* translate =
412             (nw::math::VEC3*)collection->GetStreamPtr(
413             nw::gfx::PARTICLEUSAGE_TRANSLATE,
414             nw::gfx::PARTICLE_BUFFER_FRONT);
415 
416         nw::math::VEC3* velocity =
417             (nw::math::VEC3*)collection->GetStreamPtr(
418             nw::gfx::PARTICLEUSAGE_VELOCITY,
419             nw::gfx::PARTICLE_BUFFER_FRONT);
420 
421         const int count = collection->GetCount();
422 
423         for (int i = 0; i < count; ++i)
424         {
425             int index = activeIndex[i];
426 
427             bool bounceX = false;
428             if (translate[index].x < -5.0f)
429             {
430                 bounceX = true;
431                 translate[index].x = -5.0f;
432             }
433 
434             if (translate[index].x > 5.0f)
435             {
436                 bounceX = true;
437                 translate[index].x = 5.0f;
438             }
439 
440             if (bounceX)
441             {
442                 velocity[index].x *= -1.0f;
443             }
444         }
445     }
446 
447     s_FlushCache->Execute();
448 }
449 
450 /*!--------------------------------------------------------------------------*
451   @brief        負荷表示やテスト機能の処理をおこないます。
452  *---------------------------------------------------------------------------*/
453 void
ReportDemo()454 ReportDemo()
455 {
456     NW_PROFILE("ReportDemo");
457 
458     // 負荷表示からはこれらの負荷は除きます。
459     s_RenderSystem->SuspendLoadMeter();
460 
461     s_GraphicsDrawing.BeginDrawingString();
462 
463     nw::demo::DebugUtility::DrawLoadMeter(
464         s_RenderSystem,
465         &s_GraphicsDrawing,
466         (s_FrameCount % NW_LOAD_METER_INTERVAL == 0)
467     );
468 
469     s_GraphicsDrawing.FlushDrawing();
470 
471     s_RenderSystem->ResumeLoadMeter();
472 }
473 
474 /*!--------------------------------------------------------------------------*
475   @brief        シーンをデモンストレーションします。
476  *---------------------------------------------------------------------------*/
477 void
DemoScene()478 DemoScene()
479 {
480     NW_ASSERT(!s_RenderTargets.empty());
481 
482     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
483 
484     InitializeScenes();
485 
486     int count = 0;
487     bool isContinuing = true;
488 
489     while ( isContinuing )
490     {
491         nw::demo::DebugUtility::AdvanceAutoTestFrame();
492 
493         nw::demo::PadFactory::GetPad()->Update();
494 
495         ++count;
496 
497         UpdateScene();
498 
499         renderContext->SetActiveCamera(s_BaseCameraIndex);
500         s_RenderSystem->SubmitView(s_SceneSystem);
501 
502         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
503         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
504 
505         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
506         ReportDemo();
507         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
508 
509         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
510 
511         renderContext->ResetState();
512 
513         if (nw::demo::Utility::IsTerminating())
514         {
515             isContinuing = false;
516         }
517     }
518 
519     TerminateScenes();
520 }
521 
522 } // namespace
523 
524 /*!--------------------------------------------------------------------------*
525   @brief        メイン関数です。
526  *---------------------------------------------------------------------------*/
527 void
nnMain()528 nnMain()
529 {
530     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
531     nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
532 
533     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
534 
535     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
536     {
537         InitializeGraphics();
538 
539         s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
540 
541         DemoScene();
542 
543         nw::ut::SafeDestroy(s_FlushCache);
544 
545         TerminateGraphics();
546     }
547 
548     nw::demo::PadFactory::Finalize();
549 
550     nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
551 
552     nw::demo::FinalizeGraphicsSystem();
553 }
554