#include "stdafx.h"

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

#include "Utility/Common.h"
#include "Utility/PlayableCharacter.h"
#include "Utility/PlayableCamera.h"

#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768

const Mix::Vector3 SUN_POS( 0.5f, 1.0f, -0.5f );

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	Mix::ENGINE_CONFIG engineConfig;

	engineConfig.flags = Mix::EC_IO_NARROW | Mix::EC_KEYBOARD | Mix::EC_GAMEPAD | Mix::EC_GRAPHICS | Mix::EC_SCENE | Mix::EC_DYNAMICS;
	engineConfig.pRootDirectoryPath = Utility::GetRootDirectoryPath();
	engineConfig.pPluginDirectoryPath = Utility::GetPluginsDirectoryPath();
	engineConfig.pUserDirectoryPath = Utility::GetUserDirectoryPath( L"Scene\\Motion\\StateMachine" );
	engineConfig.pCaption = L"Scene - Motion ( StateMachine )";
	engineConfig.targetSize = Mix::Point( SCREEN_WIDTH, SCREEN_HEIGHT );
	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::Graphics::IManager* pGraphicsMgr = Mix::Graphics::GetManagerPtr();

		Mix::HID::IKeyboard* pKeyboard = NULL;
		Mix::HID::IGamepad* pGamepad = NULL;

		Mix::Graphics::IDevice* pGraphicsDev = NULL;
		Mix::Graphics::Utility::ICanvasRenderer* pCanvasRenderer = 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::ITerrainModel* pFloorModel = NULL;
		Mix::Scene::IActorModel* pHumanModel = NULL;

		Mix::StringW tempStr;

		Utility::PlayableCharacter* pPlayableCharacter = NULL;
		Utility::PlayableCamera* pPlayableCamera = NULL;

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

		pIOMgr->MountDirectory( L"Data" );

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

		pInputMgr->GetKeyboard( &pKeyboard );
		pInputMgr->FindGamepad( Mix::HID::GAMEPAD_UNKNOWN, &pGamepad );

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

		pGraphicsMgr->GetDevice( &pGraphicsDev );

		if( pGraphicsMgr->CreateCanvasRenderer( &pCanvasRenderer, MIX_DEBUGNAME ) == True )
		{
			Mix::Graphics::Utility::IFont* pFont = NULL;
			
			if( pGraphicsMgr->CreateFontFromFile( L"Data\\Font\\mspg_16_400.fnt", &pFont ) == True )
			{
				pCanvasRenderer->SetFont( pFont );
			}

			MIX_RELEASE( 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::IFloor* pFloor = NULL;
				Mix::Scene::IDirectionalLight* pDirLight = NULL;

				if( pSceneMgr->CreateDirectionalLight( &pDirLight ) == True )
				{
					pDirLight->SetDirection( -SUN_POS.ToNormalize() );
					pSceneRenderer->SetDirectionalLight( pDirLight );
				}

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

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

				if( pSceneMgr->CreateActorModelFromFile( pSceneEffectPackage, L"Data\\Model\\human.mam", &pHumanModel ) == True )
				{
					pSceneRenderer->AddActorModel( pHumanModel );
				}

				camConfig.caps = Mix::Scene::RCAP_DYNAMICS | 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 )
				{
					pCamera->SetBackgroundColor( Mix::Vector4( 0.1f, 0.1f, 0.1f, 1.0f ) );
					pCamera->SetProjection( MIX_TO_RAD( 60.0f ), 0.01f, 1000.0f );

					pCamera->SetShadowMappingEnabled( True );

					pSceneRenderer->AddCamera( pCamera );
				}

				MIX_RELEASE( pDirLight );
				MIX_RELEASE( pFloor );
			}
		}

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

		pPlayableCharacter = new Utility::PlayableCharacter( pCamera, pGamepad, pHumanModel );
		pPlayableCamera = new Utility::PlayableCamera( pCamera, pGamepad, pHumanModel );

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

		pEngine->ResetFPS();

		while( pEngine->Update() == True )
		{
			////////////////////////////////////////////////////////////////////////////////////////////////////
			// プレイアブル
			////////////////////////////////////////////////////////////////////////////////////////////////////

			if( pKeyboard->GetKeyState( Mix::HID::KEY_SPACE ) & Mix::HID::PRESSED )
			{
				pPlayableCharacter->Action( Utility::PlayableCharacter::ACTION_DAMAGE );
			}

			pPlayableCharacter->OnUpdate( pEngine->GetDT() );
			pPlayableCamera->OnUpdate( pEngine->GetDT() );

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

			if( pCanvasRenderer != NULL )
			{
				pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );

				tempStr.Sprintf( L"FPS %.4f", pEngine->GetFPS() );
				pCanvasRenderer->AddString(	16.0f, 16.0f, tempStr.GetConstPtr() );

				pCanvasRenderer->AddString(	16.0f, 48.0f,
									L"GAME_PAD :\n"
									L"  STICK\n"
									L"    (L)[MOVE]\n"
									L"    (R)[CAMERA]\n"
									L"  POV\n"
									L"    (L)[CAMERA_DISTANCE(+)]\n"
									L"    (R)[CAMERA_DISTANCE(-)]\n"
									L"  BUTTON\n"
									L"    (A)[JUMP]\n"
									L"    (B)[BACK_STEP]\n"
									L"    (Y)[READY]->(X)[GUARD]\n"
									L"    SHOULDER\n"
									L"      (L)[LEFT_PUNCH]\n"
									L"      (R)[RIGHT_PUNCH]" );

				pCanvasRenderer->AddString(	16.0f, 304.0f,
									L"KEYBOARD :\n"
									L"  (SPACE)[DAMAGE]" );
			}

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

			if( pSceneRenderer != NULL )
			{
				pSceneRenderer->Update( pEngine->GetDT() );
			}

			if( pCanvasRenderer != NULL )
			{
				pCanvasRenderer->Update();
			}

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

			pPlayableCharacter->OnRefresh();
			pPlayableCamera->OnRefresh();

			if( pSceneRenderer != NULL )
			{
				pSceneRenderer->Refresh();
			}

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

			pGraphicsDev->Clear( True, False, Mix::Vector4( 0.1f, 0.1f, 0.1f, 1.0f ) );

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

				pGraphicsDev->End();
			}

			pGraphicsDev->Present();
		}

		MIX_DELETE( pPlayableCharacter );
		MIX_DELETE( pPlayableCamera );

		MIX_RELEASE( pHumanModel );
		MIX_RELEASE( pFloorModel );
		MIX_RELEASE( pCamera );
		MIX_RELEASE( pSceneRenderer );
		MIX_RELEASE( pSceneEffectPackage );

		MIX_RELEASE( pCanvasRenderer );
		MIX_RELEASE( pGraphicsDev );
		MIX_RELEASE( pGamepad );
		MIX_RELEASE( pKeyboard );

		Mix::Finalize();
	}

	return 0;
}
