/*---------------------------------------------------------------------------*
Project: NintendoWare
File: ParticleUpdaterDemo.cpp
Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved.
These coded instructions, statements, and computer programs contain proprietary
information of Nintendo and/or its licensed developers and are protected by
national and international copyright laws. They may not be disclosed to third
parties or copied or duplicated in any form, in whole or in part, without the
prior written consent of Nintendo.
The content herein is highly confidential and should be handled accordingly.
$Revision: 31311 $
*---------------------------------------------------------------------------*/
/*
現在は、UserUpdaterをCreativeStudio上で追加することができないので、
中間ファイルのParticleUpdatersのリスト内に
を追加してください。
ParticleUpdatersはParticleSet毎の設定です。
*/
#define NW_DEBUG_CHECK_MEMORY_LEAK
#include
#include
#include
#include
#include
#include
#include
namespace
{
//----------------------------------------
// メモリ関係
// デバイスメモリを確保するためのアロケータです。
nw::demo::DemoAllocator s_DeviceAllocator;
nw::demo::DemoAllocator s_ParticleAllocator;
//----------------------------------------
// ファイル名の定義です。
const wchar_t* SKY_SPHERE_FILE_NAME = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
const wchar_t* MODEL_RESOURCE_FILES[] =
{
NW_DEMO_FILE_PATH(L"fountain_particle_all.bcptl"),
NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"),
};
//----------------------------------------
// 描画関係
const int RENDER_TARGET_COUNT = 1;
typedef nw::ut::FixedSizeArray RenderTargetArray;
RenderTargetArray s_RenderTargets;
nw::demo::SceneSystem* s_SceneSystem = NULL;
nw::demo::RenderSystem* s_RenderSystem = NULL;
nw::gfx::ParticleContext* s_ParticleContext = NULL;
nw::demo::GraphicsDrawing s_GraphicsDrawing;
//----------------------------------------
// リソース関係
nw::demo::ResourceArray s_Resources;
//----------------------------------------
// シーン関係
nw::gfx::SceneNode* s_SceneRoot = NULL;
s32 s_FrameCount = 0;
nw::gfx::Camera* s_BaseCamera = NULL;
nw::gfx::Camera* s_LeftCamera = NULL;
nw::gfx::Camera* s_RightCamera = NULL;
const f32 s_fNearPlane = 0.1f;
//----------------------------------------
// シーン環境関係
const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
typedef nw::ut::FixedSizeArray SceneEnvironmentSettingArray;
SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
const s32 s_BaseCameraIndex = 0;
//----------------------------------------
// パーティクル関係
nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
nw::demo::FlushCache* s_FlushCache;
/*!--------------------------------------------------------------------------*
@brief グラフィックス関連の初期化を行います。
*---------------------------------------------------------------------------*/
void
InitializeGraphics()
{
nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
// renderDescriptionへステレオの設定を行います。
nw::demo::RenderSystem::Description renderDescription;
renderDescription.reusableCommandBufferSize = 0x100000;
renderDescription.reusableCommandRequestCount = 512;
renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
s_GraphicsDrawing.SetScreenSize(
renderDescription.lowerScreenDescription.width,
renderDescription.lowerScreenDescription.height
);
nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
s_RenderTargets.push_back(
nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
);
NW_ASSERT(!s_RenderTargets.empty());
s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
// sceneDescriptionへの標準的な設定はコンストラクタで行われています。
nw::demo::SceneSystem::Description sceneDescription;
s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
s_ParticleContext = nw::gfx::ParticleContext::Builder()
.MaxEmission(1000)
.Create(&s_DeviceAllocator);
s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
.Create(&s_DeviceAllocator);
// デモ用の最遠景モデルをレンダリングシステムに設定します。
// gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
NW_GL_ASSERT();
}
/*!--------------------------------------------------------------------------*
@brief グラフィックス関連の後始末をします。
*---------------------------------------------------------------------------*/
void
TerminateGraphics()
{
nw::gfx::SafeDestroy(s_LeftCamera);
nw::gfx::SafeDestroy(s_RightCamera);
nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
nw::gfx::SafeDestroy(s_ParticleContext);
nw::gfx::SafeDestroy(s_SceneSystem);
nw::gfx::SafeDestroyAll(s_RenderTargets);
s_GraphicsDrawing.Finalize();
nw::gfx::SafeDestroy(s_RenderSystem);
NW_GL_ASSERT();
}
/*!--------------------------------------------------------------------------*
@brief 再生ステップを設定します。
@param[in] 再生ステップです。
*---------------------------------------------------------------------------*/
void
SetStepFrame(f32 stepFrame)
{
nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext();
nw::gfx::SceneNodeArray::iterator end = sceneContext->GetSceneNodesEnd();
for (nw::gfx::SceneNodeArray::iterator i = sceneContext->GetSceneNodesBegin(); i != end; ++i)
{
nw::gfx::ParticleEmitter* emitter = nw::ut::DynamicCast(*i);
if (emitter != NULL)
{
emitter->ParticleAnimFrameController().SetStepFrame(stepFrame);
}
else
{
nw::gfx::ParticleModel* model = nw::ut::DynamicCast(*i);
if (model != NULL)
{
model->ParticleAnimFrameController().SetStepFrame(stepFrame);
}
}
}
}
/*!--------------------------------------------------------------------------*
@brief ユーザ定義のアップデータです
*---------------------------------------------------------------------------*/
static void UserUpdater(
nw::gfx::ParticleContext* context,
nw::gfx::ParticleSet* particleSet,
const nw::gfx::ResParticleUserUpdater* userUpdater,
f32 prevTime,
f32 time
)
{
NW_UNUSED_VARIABLE(context);
NW_UNUSED_VARIABLE(particleSet);
NW_UNUSED_VARIABLE(userUpdater);
NW_UNUSED_VARIABLE(prevTime);
NW_UNUSED_VARIABLE(time);
nw::gfx::ParticleCollection* collection = particleSet->GetParticleCollection();
NW_NULL_ASSERT(collection);
// 有効なパーティクルの個数
const int count = collection->GetCount();
if (count == 0)
{
return;
}
// 有効なパーティクルへのインデックス・テーブル
// 必ずPARTICLE_BUFFER_BACKから取得してください
u16* activeIndex =
(u16*)collection->GetStreamPtr(
nw::gfx::PARTICLEUSAGE_ACTIVEINDEX,
nw::gfx::PARTICLE_BUFFER_BACK);
// ACTIVEINDEX以外はPARTICLE_BUFFER_FRONTから取得します。
nw::math::VEC3* translate =
(nw::math::VEC3*)collection->GetStreamPtr(
nw::gfx::PARTICLEUSAGE_TRANSLATE,
nw::gfx::PARTICLE_BUFFER_FRONT);
if (translate == NULL)
{
// アニメーションが元々付いていない場合などは固定値の扱いとなります
// 粒子毎の設定が要らない場合は、Shapeのアトリビュートを変更するほうが効率的です
return;
}
nw::math::VEC3* velocity =
(nw::math::VEC3*)collection->GetStreamPtr(
nw::gfx::PARTICLEUSAGE_VELOCITY,
nw::gfx::PARTICLE_BUFFER_FRONT);
if (velocity == NULL)
{
return;
}
const bool isAscendingOrder = particleSet->IsAscendingOrder();
const int startIndex = (isAscendingOrder) ? 0 : collection->GetCapacity() - 1;
const int incrIndex = (isAscendingOrder) ? 1 : -1;
activeIndex += startIndex;
for (int i = 0; i < count; ++i)
{
int index = *activeIndex;
activeIndex += incrIndex;
nw::math::VEC3 nextPosition;
nextPosition = translate[index] + velocity[index];
if (nextPosition.x > 2.0f)
{
#if 1 // 反射
velocity[index].x *= -1.0f;
velocity[index].z *= -1.0f;
#else // 消滅
collection->KillParticle(index);
#endif
}
}
}
/*!--------------------------------------------------------------------------*
@brief ユーザ定義のアップデータを設定します
@param[in] sceneNodeArray シーンノードのアレイです。
*---------------------------------------------------------------------------*/
void
SetUserUpdater(
nw::ut::MoveArray *sceneNodeArray
)
{
NW_NULL_ASSERT(sceneNodeArray);
NW_FOREACH(nw::gfx::SceneNode* node, *sceneNodeArray)
{
switch (node->GetResSceneNode().ptr()->typeInfo)
{
case nw::gfx::ResParticleModel::TYPE_INFO:
{
nw::gfx::ParticleModel* model = reinterpret_cast(node);
for (u32 i = 0; i < model->GetParticleSetsCount(); ++i)
{
nw::gfx::ParticleSet* particleSet = model->GetParticleSets(i);
nw::ut::MoveArray* updaters =
particleSet->GetUpdaters();
nw::ut::MoveArray::iterator endIter = updaters->end();
for (nw::ut::MoveArray::iterator iter = updaters->begin();
iter != endIter;)
{
nw::gfx::ParticleSet::Updater& updater = *iter++;
nw::gfx::ResParticleUpdater resUpdater(updater.resource);
NW_ASSERT(resUpdater.IsValid());
if (resUpdater.GetTypeInfo() == nw::gfx::ResParticleUserUpdater::TYPE_INFO)
{
nw::gfx::ResParticleUserUpdater userUpdater =
nw::gfx::ResDynamicCast(resUpdater);
updater.work = (u32)UserUpdater;
}
}
}
}
break;
}
}
}
/*!--------------------------------------------------------------------------*
@brief ルートノード関連の構築をします。
*---------------------------------------------------------------------------*/
void
BuildRootNodes()
{
NW_ASSERT(s_SceneRoot == NULL);
s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
.IsFixedSizeMemory(false)
.Create(&s_DeviceAllocator);
NW_NULL_ASSERT(s_SceneRoot);
}
/*!--------------------------------------------------------------------------*
@brief カメラ関連の構築をします。
*---------------------------------------------------------------------------*/
void
BuildCameras()
{
nw::demo::Utility::CreateStereoCameras(
&s_BaseCamera,
&s_LeftCamera,
&s_RightCamera,
&s_DeviceAllocator,
nw::math::VEC3(28.0f, 22.0f, 28.0f),
nw::math::VEC3(0.0f, 0.0f, 0.0f),
s_fNearPlane
);
s_SceneRoot->AttachChild(s_BaseCamera);
s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
}
/*!--------------------------------------------------------------------------*
@brief リソース関連の構築をします。
*---------------------------------------------------------------------------*/
void
BuildResources(nw::demo::ResourceSet* resourceSet)
{
resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
resourceSet->resource.ForeachIndexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
resourceSet->resource.ForeachVertexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
if (result.IsFailure())
{
NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
}
nw::ut::MoveArray sceneNodeArray(&s_DeviceAllocator);
nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
nw::gfx::ResModelArray::iterator modelsEnd = models.end();
for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
modelResource != modelsEnd; ++modelResource)
{
nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
&s_ParticleAllocator,
(*modelResource)
);
if (node != NULL)
{
sceneNodeArray.push_back(node);
}
}
nw::gfx::ResEmitterArray emitters = resourceSet->resource.GetEmitters();
for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin();
emitterResource != emitters.end(); ++emitterResource)
{
nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
&s_ParticleAllocator,
(*emitterResource)
);
if (node != NULL)
{
sceneNodeArray.push_back(node);
}
}
nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
lightResource != lights.end(); ++lightResource)
{
nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
&s_DeviceAllocator,
(*lightResource)
);
NW_NULL_ASSERT(node);
sceneNodeArray.push_back(node);
}
// 親子付け参照関係を解決
nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
nw::gfx::ParticleUtil::SetupParticleObject(&sceneNodeArray, s_ParticleContext);
SetUserUpdater(&sceneNodeArray);
// モデルとエミッタをシーンに追加
nw::gfx::SceneHelper::ForeachRootNodes(
sceneNodeArray.Begin(),
sceneNodeArray.End(),
nw::gfx::AttachNode(s_SceneRoot)
);
nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
settingResource != settingsEnd; ++settingResource)
{
nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
.Resource(*settingResource)
.CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
nw::ut::DynamicCast(sceneObject);
NW_NULL_ASSERT(sceneEnvironmentSetting);
s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
}
}
/*!--------------------------------------------------------------------------*
@brief シーンを初期化します。
*---------------------------------------------------------------------------*/
void
InitializeScenes()
{
BuildRootNodes();
BuildCameras();
NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
{
BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
}
// シーンツリーを巡回して初期化を行います。
s_SceneSystem->InitializeScene(s_SceneRoot);
s_SceneSystem->UpdateScene();
// シーン環境の参照解決を行い設定します。
s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
// カメラを設定します。
nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
NW_GL_ASSERT();
s_FrameCount = 0;
}
/*!--------------------------------------------------------------------------*
@brief シーン関連の後始末をします。
*---------------------------------------------------------------------------*/
void
TerminateScenes()
{
nw::gfx::SafeDestroyBranch(s_SceneRoot);
nw::demo::SafeCleanupResources(s_Resources);
nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
NW_GL_ASSERT();
s_Resources.clear();
s_SceneEnvironmentSettings.clear();
}
/*!--------------------------------------------------------------------------*
@brief シーンを更新します。
*---------------------------------------------------------------------------*/
void
UpdateScene()
{
NW_ASSERT(0 < s_RenderTargets.size());
s_SceneSystem->GetCameraController()->Update();
s_SceneSystem->UpdateScene();
s_BaseCamera->UpdateCameraMatrix();
NW_NULL_ASSERT(s_ParticleSceneUpdater);
s_ParticleSceneUpdater->UpdateNode(
s_SceneSystem->GetSceneContext(),
s_ParticleContext);
s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
s_FrameCount++;
s_FlushCache->Execute();
}
/*!--------------------------------------------------------------------------*
@brief 負荷表示やテスト機能の処理をおこないます。
*---------------------------------------------------------------------------*/
void
ReportDemo()
{
NW_PROFILE("ReportDemo");
// 負荷表示からはこれらの負荷は除きます。
s_RenderSystem->SuspendLoadMeter();
nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
s_GraphicsDrawing.BeginDrawingShape();
nw::demo::DebugUtility::DrawLoadMeter(
s_RenderSystem,
&s_GraphicsDrawing
);
s_GraphicsDrawing.EndDrawingShape();
s_GraphicsDrawing.BeginDrawingString();
nw::demo::DebugUtility::DrawLoadMeterText(
s_RenderSystem,
&s_GraphicsDrawing
);
s_GraphicsDrawing.EndDrawingString();
s_RenderSystem->ResumeLoadMeter();
}
/*!--------------------------------------------------------------------------*
@brief シーンをデモンストレーションします。
*---------------------------------------------------------------------------*/
void
DemoScene()
{
NW_ASSERT(!s_RenderTargets.empty());
nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
InitializeScenes();
nw::demo::DebugUtility::PostInitializeScenes();
bool isContinuing = true;
while ( isContinuing )
{
nw::demo::DebugUtility::AdvanceAutoTestFrame();
nw::demo::PadFactory::GetPad()->Update();
SetStepFrame(1.0f);
UpdateScene();
renderContext->SetActiveCamera(s_BaseCameraIndex);
s_RenderSystem->SubmitView(s_SceneSystem);
s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
s_RenderSystem->ClearBySkyModel(s_BaseCamera);
ReportDemo();
s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
renderContext->ResetState();
if (nw::demo::Utility::IsTerminating())
{
isContinuing = false;
}
}
nw::demo::DebugUtility::PreTerminateScenes();
TerminateScenes();
}
} // namespace
/*!--------------------------------------------------------------------------*
@brief メイン関数です。
*---------------------------------------------------------------------------*/
void
nnMain()
{
nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
{
InitializeGraphics();
s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
DemoScene();
nw::ut::SafeDestroy(s_FlushCache);
TerminateGraphics();
}
nw::demo::PadFactory::Finalize();
nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
nw::demo::FinalizeGraphicsSystem();
}