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