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