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