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