#include "stdafx.h"

#include <vector>

#include "Mix/IO.h"
#include "Mix/HID.h"
#include "Mix/Dynamics.h"
#include "Mix/Sound.h"
#include "Mix/Graphics.h"
#include "Mix/Scene.h"

#include "Utility/Common.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
// 定数
////////////////////////////////////////////////////////////////////////////////////////////////////

static const UInt32 SCREEN_WIDTH = 1024;
static const UInt32 SCREEN_HEIGHT = 768;

static const UInt32 MAX_SOUNDFILE = 32;
static const Mix::Vector3 SOUND_LOCAL_FRONT( 0.0f, 0.0f, 1.0f );
static const Mix::Vector3 SOUND_LOCAL_UP( 0.0f, 1.0f, 0.0f );
static const Float32 SOUND_DOPPLER_SCALER = 0.1f;

static const Mix::Vector2 TXT_ORIGIN( 16.0f, 64.0f );
static const Float32 TXT_MARGIN = 4.0f;
static const Float32 TXT_BG_PADDING = 2.0f;
static const Float32 TXT_BG_PADDING2 = TXT_BG_PADDING * 2.0f;

static const Float32 SPHERE_RADIUS = 0.5f;
static const Float32 SPHERE_HEIGHT = 1.3f;

static const Float32 KG_HEIGHT = 1.7f;
static const Float32 KG_RADIUS = 0.3f;
static const Mix::Vector3 KG_INIT_POS( 0.0f, 0.0f, -5.0f );
static const Mix::Vector3 KG_EYE_OFFSET( 0.0f, KG_HEIGHT - 0.2f, 0.0f );
static const Mix::Vector3 KG_BASE_FORWARD( 0.0f, 0.0f, 1.0f );
static const Float32 KG_GROUND_MOVE_SPEED = 0.2f;
static const Float32 KG_AERIAL_MOVE_SPEED = 0.1f;
static const Float32 KG_ROT_SPEED = 0.5f;
static const Float32 KG_ELEV_SPEED = 0.5f;
static const Float32 KG_ELEV_MAX = MIX_TO_RAD( 45.0f );
static const Float32 KG_AERIAL_FRICTION = 0.05f;

////////////////////////////////////////////////////////////////////////////////////////////////////
// クラス
////////////////////////////////////////////////////////////////////////////////////////////////////

class Context
{
private:
	struct INFO
	{
		Mix::Vector2 size;
		Mix::Sound::IEmitter* pEmitter;
	};

	typedef std::vector<Context::INFO> InfoList;

private:
	Mix::Graphics::Utility::IFont* m_pFont;
	Mix::Sound::IListener* m_pListener;
	Mix::Vector3 m_LocalFront;
	Mix::Vector3 m_LocalUp;
	Mix::Matrix4x4 m_WorldMat;
	Context::InfoList m_InfoList;
	UInt32 m_InfoIndex;
	UInt32 m_CheckCount;

public:
	Context( void ) :
	m_InfoIndex( 0xFFFFFFFF ),
	m_CheckCount( 0 )
	{
	}

	~Context( void )
	{
		MIX_ASSERT( m_pFont == NULL );
		MIX_ASSERT( m_pListener == NULL );
		MIX_ASSERT( m_InfoList.size() == 0 );
	}

	void Initialize( Mix::Graphics::Utility::IFont* pFont, Mix::Sound::IListener* pListener, const Mix::Vector3& localFront, const Mix::Vector3& localUp, const Mix::Vector3& worldPos )
	{
		MIX_ASSERT( pFont != NULL );
		MIX_ASSERT( pListener != NULL );
		MIX_ASSERT( Mix::GetEnginePtr() != NULL );

		MIX_ADD_REF( pFont );
		m_pFont = pFont;

		MIX_ADD_REF( pListener );
		m_pListener = pListener;

		m_LocalFront = localFront;
		m_LocalUp = localUp;
		m_WorldMat.SetTranslation( worldPos );

		Mix::GetEnginePtr()->SetMessageProc( Context::MessageProc, this );
	}

	void Dispose( void )
	{
		MIX_ASSERT( Mix::GetEnginePtr() != NULL );

		Mix::GetEnginePtr()->SetMessageProc( NULL );

		if( m_InfoList.size() > 0 )
		{
			Context::InfoList::iterator it_begin = m_InfoList.begin();
			Context::InfoList::iterator it_end = m_InfoList.end();
			Context::InfoList::iterator it;

			for( it = it_begin; it != it_end; ++it )
			{
				Context::INFO* pInfo = &( *it );
				MIX_RELEASE( pInfo->pEmitter );
			}

			m_InfoList.clear();
		}

		MIX_RELEASE( m_pListener );

		MIX_RELEASE( m_pFont );
	}

	void Update( void )
	{
		if( m_InfoIndex != 0xFFFFFFFF )
		{
			MIX_ASSERT( m_InfoList.size() > m_InfoIndex );

			if( m_InfoList[m_InfoIndex].pEmitter->IsPlaying() == False )
			{
				if( m_CheckCount >= 8 )
				{
					m_InfoIndex = 0xFFFFFFFF;
				}
				else
				{
					m_CheckCount++;
				}
			}
			else
			{
				if( m_pListener->GetVelocity().GetLength() > 5.0f )
				{
					int i = 0;
				}

				m_InfoList[m_InfoIndex].pEmitter->Update();
			}
		}
	}

	UInt32 GetNum( void ) const
	{
		return static_cast<UInt32>( m_InfoList.size() );
	}

	Mix::RectangleF GetRect( UInt32 index ) const
	{
		MIX_ASSERT( m_InfoList.size() > index );

		const Mix::Vector2& size = m_InfoList[index].size;
		Mix::RectangleF ret;

		ret.x = TXT_ORIGIN.x;
		ret.y = TXT_ORIGIN.y + ( static_cast<Float32>( m_pFont->GetHeight() ) + TXT_MARGIN ) * static_cast<Float32>( index );
		ret.width = size.x;
		ret.height = size.y;

		return ret;
	}

	const wchar_t* GetFilePath( UInt32 index ) const
	{
		MIX_ASSERT( m_InfoList.size() > index );

		return m_InfoList[index].pEmitter->GetFilePath();
	}

	UInt32 GetActiveIndex( void ) const
	{
		return m_InfoIndex;
	}

	void Switch( UInt32 index )
	{
		MIX_ASSERT( index != 0xFFFFFFFF );
		MIX_ASSERT( m_InfoList.size() > index );

		if( m_InfoIndex == index )
		{
			m_InfoList[m_InfoIndex].pEmitter->Stop();
			m_InfoIndex = 0xFFFFFFFF;
		}
		else
		{
			if( m_InfoIndex != 0xFFFFFFFF )
			{
				m_InfoList[m_InfoIndex].pEmitter->Stop();
			}

			m_InfoList[index].pEmitter->Play( True );
			m_InfoIndex = index;
		}

		m_CheckCount = 0;
	}

private:
	static void __stdcall MessageProc( HWND hWnd, UInt32 message, WPARAM wParam, LPARAM lParam, void* pData )
	{
		Context* pCtx = static_cast<Context*>( pData );

		if( message == WM_DROPFILES )
		{
			HDROP hDrop = ( HDROP )wParam;
			UInt32 fileNum = DragQueryFile( hDrop, 0xFFFFFFFF, NULL, 0 );
			wchar_t temp[4096] = { 0 };

			////////////////////////////////////////////////////////////////////////////////////////////////////

			if( pCtx->m_InfoList.size() > 0 )
			{
				Context::InfoList::iterator it_begin = pCtx->m_InfoList.begin();
				Context::InfoList::iterator it_end = pCtx->m_InfoList.end();
				Context::InfoList::iterator it;

				for( it = it_begin; it != it_end; ++it )
				{
					Context::INFO* pInfo = &( *it );
					MIX_RELEASE( pInfo->pEmitter );
				}

				pCtx->m_InfoList.clear();
			}

			pCtx->m_InfoIndex = 0xFFFFFFFF;
			pCtx->m_CheckCount = 0;

			////////////////////////////////////////////////////////////////////////////////////////////////////

			Mix::IO::IManager* pIOMgr = Mix::IO::GetManagerPtr();
			Mix::Sound::IManager* pSoundMgr = Mix::Sound::GetManagerPtr();

			MIX_ASSERT( pIOMgr != NULL );
			MIX_ASSERT( pSoundMgr != NULL );

			for( UInt32 i = 0; ( i < fileNum ) && ( pCtx->m_InfoList.size() < MAX_SOUNDFILE ); i++ )
			{
				DragQueryFile( hDrop, i, temp, sizeof( temp ) );

				if( pIOMgr->MountFile( temp ) == True )
				{
					Mix::IO::IReader* pReader = NULL;

					if( pIOMgr->CreateFileReader( temp, &pReader ) == True )
					{
						Mix::Sound::IEmitter* pEmitter = NULL;

						if( pReader->GetSize() < 1048576 )
						{
							pSoundMgr->CreateSimpleEmitter( pCtx->m_pListener, pReader, pCtx->m_LocalFront, pCtx->m_LocalUp, &pEmitter );
						}
						else
						{
							pSoundMgr->CreateStreamingEmitter( pCtx->m_pListener, pReader, pCtx->m_LocalFront, pCtx->m_LocalUp, &pEmitter );
						}

						if( pEmitter != NULL )
						{
							Context::INFO info;

							pEmitter->SetDopplerScaler( SOUND_DOPPLER_SCALER );
							pEmitter->SetWorldMatrix( pCtx->m_WorldMat );

							info.pEmitter = pEmitter;
							info.size = Mix::Graphics::Utility::MeasureString( pCtx->m_pFont, pEmitter->GetFilePath() );

							pCtx->m_InfoList.push_back( info );
						}

						MIX_RELEASE( pReader );
					}
				}
			}

			DragFinish( hDrop );
		}
	}
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// メイン
////////////////////////////////////////////////////////////////////////////////////////////////////

int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow )
{
#ifdef _DEBUG
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif //_DEBUG

	Mix::ENGINE_CONFIG engineConfig;

	engineConfig.flags = Mix::EC_IO_NARROW | Mix::EC_KEYBOARD | Mix::EC_MOUSE | Mix::EC_GRAPHICS | Mix::EC_SOUND | Mix::EC_DYNAMICS | Mix::EC_SCENE;
	engineConfig.pRootDirectoryPath = Utility::GetRootDirectoryPath();
	engineConfig.pPluginDirectoryPath = Utility::GetPluginsDirectoryPath();
	engineConfig.pUserDirectoryPath = Utility::GetUserDirectoryPath( L"Sound\\Basic3D" );
	engineConfig.pCaption = L"Sound - Basic3D";
	engineConfig.targetSize = Mix::Point( SCREEN_WIDTH, SCREEN_HEIGHT );
	engineConfig.bAcceptDrop = True;
	engineConfig.shaderModel = Mix::Graphics::SHADER_MODEL_3;

	if( Mix::Initialize( engineConfig ) == True )
	{
		Mix::IEngine* pEngine = Mix::GetEnginePtr();
		Mix::IO::IManager* pIOMgr = Mix::IO::GetManagerPtr();
		Mix::HID::IManager* pInputMgr = Mix::HID::GetManagerPtr();
		Mix::HID::IMouse* pMouse = NULL;
		Mix::HID::IKeyboard* pKeyboard = NULL;
		Mix::Dynamics::IManager* pDynamicsMgr = Mix::Dynamics::GetManagerPtr();
		Mix::Sound::IManager* pSoundMgr = Mix::Sound::GetManagerPtr();
		Mix::Sound::IListener* pSoundListener = NULL;
		Mix::Graphics::IManager* pGraphicsMgr = Mix::Graphics::GetManagerPtr();
		Mix::Graphics::IDevice* pGraphicsDev = NULL;
		Mix::Graphics::Utility::ICanvasRenderer* pCanvasRenderer = NULL;
		Mix::Graphics::Utility::IFont* pFont = NULL;
		Mix::Scene::IManager* pSceneMgr = Mix::Scene::GetManagerPtr();
		Mix::Scene::IEffectPackage* pSceneEffectPackage = NULL;
		Mix::Scene::IRenderer* pSceneRenderer = NULL;
		Mix::Scene::IUniversalCamera* pCamera = NULL;
		Mix::Scene::IGhost* pKGhost = NULL;
		Mix::Scene::ISimpleKinematicCharacter* pKChar = NULL;
		Mix::String tempStr;

		Context context;

		////////////////////////////////////////////////////////////////////////////////////////////////////

		pIOMgr->MountDirectory( L"Data" );

		////////////////////////////////////////////////////////////////////////////////////////////////////

		pInputMgr->GetMouse( &pMouse );
		pInputMgr->GetKeyboard( &pKeyboard );

		////////////////////////////////////////////////////////////////////////////////////////////////////

		pSoundMgr->CreateListener( SOUND_LOCAL_FRONT, SOUND_LOCAL_UP, &pSoundListener );

		////////////////////////////////////////////////////////////////////////////////////////////////////

		pGraphicsMgr->GetDevice( &pGraphicsDev );

		if( pGraphicsMgr->CreateCanvasRenderer( &pCanvasRenderer, MIX_DEBUGNAME ) == True )
		{
			if( pGraphicsMgr->CreateFontFromFile( L"Data\\Font\\mspg_16_400.fnt", &pFont ) == True )
			{
				pCanvasRenderer->SetFont( pFont );
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( pSceneMgr->CreateEffectPackage( L"Data", L"effects", &pSceneEffectPackage ) == True )
		{
			Mix::Scene::RENDERER_CONFIG rdrConfig;

			rdrConfig.caps = Mix::Scene::RCAP_DYNAMICS | Mix::Scene::RCAP_SHADOW_MAPPING;

			if( pSceneMgr->CreateRenderer( pSceneEffectPackage, rdrConfig, &pSceneRenderer, MIX_DEBUGNAME ) == True )
			{
				Mix::Scene::CAMERA_CONFIG camConfig;
				Mix::Scene::IDirectionalLight* pDirLight = NULL;
				Mix::Scene::ITerrainModel* pFloorModel = NULL;
				Mix::Scene::IActorModel* pSphereModel = NULL;
				Mix::Scene::IFloor* pFloor = NULL;
				Mix::Scene::IGhost* pSphereGhost = NULL;
				Mix::Dynamics::ICapsuleShape* pCapsuleShape = NULL;

				/*
					平行光源
				*/

				if( pSceneMgr->CreateDirectionalLight( &pDirLight ) == True )
				{
					pDirLight->SetEnabled( True );
					pDirLight->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
					pDirLight->SetDirection( Mix::Vector3( -0.5f, -1.0f, -0.5f ).ToNormalize() );

					pSceneRenderer->SetDirectionalLight( pDirLight );

					MIX_RELEASE( pDirLight );
				}

				/*
					カメラ
				*/

				camConfig.caps = Mix::Scene::RCAP_SHADOW_MAPPING;
				camConfig.targetSize.Set( SCREEN_WIDTH, SCREEN_HEIGHT );
				camConfig.colorTexFormat = Mix::Graphics::FMT_R8G8B8A8;
				camConfig.smDepthTexSize = 512;

				if( pSceneMgr->CreateUniversalCamera( camConfig, &pCamera ) == True )
				{
					Mix::Scene::ICamera::SHADOW_MAPPING_SETTINGS smSettings = pCamera->GetShadowMappingSettings();

					pCamera->SetBackgroundColor( Mix::Vector4( 0.1f, 0.1f, 0.1f, 1.0f ) );
					pCamera->SetProjection( MIX_TO_RAD( 60.0f ), 0.01f, 100.0f );
					pCamera->SetView( Mix::Vector3( 0.0f, 1.6f, -5.0f ), Mix::Vector3( 0.0f, 1.2f, 0.0f ), Mix::Vector3( 0.0f, 1.0f, 0.0f ) );

					smSettings.depthBias = 0.1f;
					pCamera->SetShadowMappingSettings( smSettings );

					pSceneRenderer->AddCamera( pCamera );
				}

				/*
					フロアモデル
				*/

				if( pSceneMgr->CreateTerrainModelFromFile( pSceneEffectPackage, L"Data\\Model\\floor.mtm", &pFloorModel ) == True )
				{
					pSceneRenderer->AddTerrainModel( pFloorModel );
					MIX_RELEASE( pFloorModel );
				}

				/*
					スフィアモデル
				*/

				if( pSceneMgr->CreateActorModelFromFile( pSceneEffectPackage, L"Data\\Model\\sphere.mam", &pSphereModel ) == True )
				{
					Mix::Matrix4x4 worldMat;

					worldMat.SetScaling( SPHERE_RADIUS );
					worldMat.SetRow( 3, Mix::Vector4( 0.0f, SPHERE_HEIGHT, 0.0f, 1.0f ) );

					pSphereModel->SetWorldMatrix( worldMat );
					pSphereModel->Update();
					pSphereModel->Refresh();

					pSceneRenderer->AddActorModel( pSphereModel );

					MIX_RELEASE( pSphereModel );
				}

				/*
					フロアモデルのコライダー( スタティック )
				*/

				if( pSceneMgr->CreateFloor( Mix::Vector3( 0.0f, 1.0f, 0.0f ), 0.0f, &pFloor ) == True )
				{
					pSceneRenderer->SetFloor( pFloor );
					MIX_RELEASE( pFloor );
				}

				/*
					スフィアモデルを囲むゴースト( スタティック )
				*/

				if( pDynamicsMgr->CreateCapsuleShape( Mix::Dynamics::AXIS_Y, SPHERE_HEIGHT + SPHERE_RADIUS, SPHERE_RADIUS, &pCapsuleShape, MIX_DEBUGNAME ) == True )
				{
					if( pSceneMgr->CreateBasisGhost( pCapsuleShape, True, &pSphereGhost, MIX_DEBUGNAME ) == True )
					{
						Mix::Scene::IDynamicsObject* pDynamicsObj = NULL;

						pSphereGhost->SetWorldPosition( Mix::Vector3( 0.0f, SPHERE_HEIGHT * 0.5f, 0.0f ) );

						if( pSphereGhost->GetDynamicsObject( &pDynamicsObj ) == True )
						{
							MIX_ASSERT( pDynamicsObj->GetType() == Mix::Scene::IDynamicsObject::LIBERTY_COLLIDER );
							Mix::Scene::ILibertyCollider* pCollider = static_cast<Mix::Scene::ILibertyCollider*>( pDynamicsObj );

							pCollider->SetStatus( Mix::Dynamics::IRigidBody::STATIC );
							pCollider->SetFilterGroup( Mix::Dynamics::OF_STATIC );
							pCollider->SetFilterMask( Mix::Dynamics::OF_STATIC_MASK );

							MIX_RELEASE( pDynamicsObj );
						}

						pSceneRenderer->AddGhost( pSphereGhost );

						MIX_RELEASE( pSphereGhost );
					}

					MIX_RELEASE( pCapsuleShape );
				}

				/*
					キネマティックゴースト
				*/

				if( pSceneMgr->CreateKinematicGhost( KG_HEIGHT, KG_RADIUS, 0.35f, &pKGhost, MIX_DEBUGNAME ) == True )
				{
					Mix::Scene::IDynamicsObject* pDynamicsObj = NULL;

					if( pKGhost->GetDynamicsObject( &pDynamicsObj ) == True )
					{
						MIX_ASSERT( pDynamicsObj->GetType() == Mix::Scene::IDynamicsObject::SIMPLE_KINEMATIC_CHARACTER );

						pKChar = static_cast<Mix::Scene::ISimpleKinematicCharacter*>( pDynamicsObj );
						pKChar->SetGravity( 7.8f );
					}

					pKGhost->SetWorldPosition( KG_INIT_POS );

					pSceneRenderer->AddGhost( pKGhost );
				}
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////

		context.Initialize( pFont, pSoundListener, SOUND_LOCAL_FRONT, SOUND_LOCAL_UP, Mix::Vector3( 0.0f, SPHERE_HEIGHT, 0.0f ) );

		////////////////////////////////////////////////////////////////////////////////////////////////////

		Float32 kgElev( 0.0f );
		Mix::Quaternion kgRot( 0.0f, 0.0f, 0.0f, 1.0f );
		Mix::Vector3 kgPrePos = pKGhost->GetWorldPosition() + KG_EYE_OFFSET;
		Mix::Vector3 kgConstVelocity = Mix::Vector3::Zero();

		pEngine->ResetFPS();

		while( pEngine->Update() == True )
		{
			Mix::Vector2 mousePos = pMouse->GetPos();
			Mix::Vector2 mouseVel = pMouse->GetVelocity();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// キネマティックゴースト
			////////////////////////////////////////////////////////////////////////////////////////////////////

			if( pMouse->GetButtonState( 2 ) & Mix::HID::DOWN )
			{
				Mix::Vector2 rot;

				/*
					進行方向
				*/

				if( ::fabs( mouseVel.x ) > MIX_FLOAT_EPSILON )
				{
					Mix::Quaternion rot;

					rot.SetRotationAxis( Mix::Vector3( 0.0f, 1.0f, 0.0f ), MIX_TO_RAD( mouseVel.x * KG_ROT_SPEED ) );

					kgRot *= rot;
					kgRot.Normalize();
				}

				/*
					仰角
				*/

				if( ::fabs( mouseVel.y ) > MIX_FLOAT_EPSILON )
				{
					kgElev -= MIX_TO_RAD( mouseVel.y * KG_ELEV_SPEED );
					kgElev = MIX_CLAMP( kgElev, -KG_ELEV_MAX, +KG_ELEV_MAX );
				}
			}

			/*
				移動
			*/

			Mix::Vector3 kgVelocity = Mix::Vector3::Zero();
			Mix::Vector3 kgForward = Mix::Matrix4x4( kgRot ) * KG_BASE_FORWARD;
			Mix::Vector3 kgCross = Mix::Vector3::Cross( kgForward, Mix::Vector3( 0.0f, 1.0f, 0.0f ) );

			if( pKeyboard->GetKeyState( Mix::HID::KEY_A ) & Mix::HID::DOWN )
			{
				kgVelocity += kgCross;
			}
			else if( pKeyboard->GetKeyState( Mix::HID::KEY_D ) & Mix::HID::DOWN )
			{
				kgVelocity -= kgCross;
			}

			if( pKeyboard->GetKeyState( Mix::HID::KEY_W ) & Mix::HID::DOWN )
			{
				kgVelocity += kgForward;
			}
			else if( pKeyboard->GetKeyState( Mix::HID::KEY_S ) & Mix::HID::DOWN )
			{
				kgVelocity -= kgForward;
			}

			if( pKChar->OnGround() == True )
			{
				kgConstVelocity = Mix::Vector3::Zero();

				if( pKeyboard->GetKeyState( Mix::HID::KEY_SPACE ) & Mix::HID::PRESSED )
				{
					if( pKChar->Jump() == True )
					{
						kgConstVelocity = pKChar->GetLinearVelocity();
					}
				}

				kgVelocity *= KG_GROUND_MOVE_SPEED;
			}
			else
			{
				kgConstVelocity -= kgConstVelocity.ToNormalize() * KG_AERIAL_FRICTION * pEngine->GetDT();
				kgVelocity *= KG_AERIAL_MOVE_SPEED;
			}

			pKChar->SetLinearVelocity( kgConstVelocity + kgVelocity );

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// コンテキスト
			////////////////////////////////////////////////////////////////////////////////////////////////////

			context.Update();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// セレクト
			////////////////////////////////////////////////////////////////////////////////////////////////////

			if( context.GetNum() > 0 )
			{
				if( pMouse->GetButtonState( 0 ) & Mix::HID::PRESSED )
				{
					for( UInt32 i = 0; i < context.GetNum(); i++ )
					{
						Mix::RectangleF txtRect = context.GetRect( i );

						if( txtRect.Contains( mousePos ) == True )
						{
							context.Switch( i );
						}
					}
				}
			}

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// キャンバス
			////////////////////////////////////////////////////////////////////////////////////////////////////

			Mix::Vector2 descSize;

			if( context.GetNum() > 0 )
			{
				UInt32 activeIndex = context.GetActiveIndex();
				Mix::Vector4 bgColor;
				Mix::Vector4 txtColor;

				pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
				pCanvasRenderer->AddString( 16.0f, 16.0f,	L"サウンドファイルをクリックすることで再生、停止を行うことができます。\n"
													L"また、サウンドの再生中は中央の球体から音を発します。" );

				for( UInt32 i = 0; i < context.GetNum(); i++ )
				{
					Mix::RectangleF txtRect = context.GetRect( i );
					Mix::RectangleF bgRect( txtRect.x - TXT_BG_PADDING, txtRect.y - TXT_BG_PADDING, txtRect.width + TXT_BG_PADDING2, txtRect.height + TXT_BG_PADDING2 );

					if( txtRect.Contains( mousePos ) == True )
					{
						bgColor.Set( 0.2f, 0.2f, 0.2f, 0.5f );
					}
					else
					{
						bgColor.Set( 0.1f, 0.1f, 0.1f, 0.5f );
					}

					if( i == activeIndex )
					{
						txtColor.Set( 1.0f, 1.0f, 1.0f, 1.0f );
					}
					else
					{
						txtColor.Set( 0.5f, 0.5f, 0.5f, 1.0f );
					}

					pCanvasRenderer->SetColor( bgColor );
					pCanvasRenderer->AddFillRectangle( bgRect );

					pCanvasRenderer->SetColor( txtColor );
					pCanvasRenderer->AddString( txtRect.x, txtRect.y, context.GetFilePath( i ) );
				}
			}
			else
			{
				tempStr.Sprintf( L"サウンドファイルをドラッグアンドドロップしてください。( 最大%d個 )", MAX_SOUNDFILE );
				pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
				pCanvasRenderer->AddString( 16.0f, 16.0f, tempStr.GetConstPtr() );
			}

			tempStr.Sprintf( L"%s",	L"Controls :\n"
									L"  Rotate : Mouse middle button\n"
									L"  Move   : W S A D Key\n"
									L"  Jump   : Space key\n" );

			descSize = Mix::Graphics::Utility::MeasureString( pFont, tempStr.GetConstPtr() );

			pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
			pCanvasRenderer->AddString( 16.0f, static_cast<Float32>( SCREEN_HEIGHT ) - descSize.y - 16.0f, tempStr.GetConstPtr() );

			Utility::DrawMouseCursor( pCanvasRenderer, pMouse->GetPos() );

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// 更新
			////////////////////////////////////////////////////////////////////////////////////////////////////

			pCamera->Update();
			pSceneRenderer->Update( pEngine->GetDT() );
			pCanvasRenderer->Update();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// リフレッシュ
			////////////////////////////////////////////////////////////////////////////////////////////////////

			Mix::Matrix4x4 kgMat;

			/*
				キネマティックゴースト
			*/

			pKGhost->Refresh();

			kgMat.SetRotation( kgRot );
			kgMat.SetRow( 3, Mix::Vector4( pKGhost->GetWorldPosition() + KG_EYE_OFFSET ) );

			pSoundListener->SetWorldMatrix( kgMat );

			Mix::Vector3 vel = kgMat.GetTranslation() - kgPrePos;
			pSoundListener->SetVelocity( vel / pEngine->GetDT() );
			kgPrePos = kgMat.GetTranslation();

			/*
				カメラ
			*/

			Mix::Quaternion tempRot;
			Mix::Vector3 camDir;

			tempRot.SetRotationAxis( Mix::Vector3( -1.0f, 0.0f, 0.0f ), kgElev );
			camDir = Mix::Matrix4x4( tempRot ) * KG_BASE_FORWARD;
			camDir = Mix::Matrix4x4( kgRot ) * camDir;

			Mix::Vector3 camEye = pKGhost->GetWorldPosition() + KG_EYE_OFFSET;
			Mix::Vector3 camAt = camEye + camDir;
			Mix::Vector3 camUp( 0.0f, 1.0f, 0.0f );

			pCamera->SetView( camEye, camAt, camUp );
			pCamera->Update();

			pSceneRenderer->Refresh();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// 描画
			////////////////////////////////////////////////////////////////////////////////////////////////////

			pGraphicsDev->SetViewBounds( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
			pGraphicsDev->Clear( True, False );

			if( pGraphicsDev->Begin() == True )
			{
				pCamera->Draw();
				pCanvasRenderer->Draw();

				pGraphicsDev->End();
			}

			pGraphicsDev->Present();
		}

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////

		context.Dispose();

		MIX_RELEASE( pKChar );
		MIX_RELEASE( pKGhost );
		MIX_RELEASE( pCamera );
		MIX_RELEASE( pSceneRenderer );
		MIX_RELEASE( pSceneEffectPackage );
		MIX_RELEASE( pFont );
		MIX_RELEASE( pCanvasRenderer );
		MIX_RELEASE( pGraphicsDev );
		MIX_RELEASE( pSoundListener );
		MIX_RELEASE( pKeyboard );
		MIX_RELEASE( pMouse );

		Mix::Finalize();
	}

	return 0;
}
