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