#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/ViewCameraHelper.h"
#include "Utility/UI/Manager.h"

#include "hud.h"

#ifdef _DEBUG
	#include <crtdbg.h>
#endif //_DEBUG

#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768

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

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_SCENE;
	engineConfig.pRootDirectoryPath = Utility::GetRootDirectoryPath();
	engineConfig.pPluginDirectoryPath = Utility::GetPluginsDirectoryPath();
	engineConfig.pUserDirectoryPath = Utility::GetUserDirectoryPath( L"Scene\\PostEffect\\LensFlare" );
	engineConfig.pCaption = L"Scene - PostEffect ( LensFlare )";
	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::Scene::IManager* pSceneMgr = Mix::Scene::GetManagerPtr();

		Mix::HID::IMouse* pMouse = NULL;
		Mix::HID::IKeyboard* pKeyboard = NULL;

		Mix::Graphics::IDevice* pGraphicsDev = NULL;
		Mix::Graphics::Utility::IFont* pFontS = NULL;
		Mix::Graphics::Utility::IFont* pFontL = NULL;
		Mix::Graphics::Utility::ICanvasRenderer* pCanvasRenderer = NULL;

		Mix::Scene::IEffectPackage* pSceneEffectPackage = NULL;
		Mix::Scene::IRenderer* pSceneRenderer = NULL;
		Mix::Scene::IViewCamera* pCamera = NULL;

		Utility::ViewCameraHelper camHelper;

		Utility::UI::Manager uiManager;
		HUD hud;

		Mix::StringW tempStr;

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

		pIOMgr->MountDirectory( L"Data" );

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

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

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

		pGraphicsMgr->GetDevice( &pGraphicsDev );

		pGraphicsMgr->CreateFontFromFile( L"Data\\Font\\mspg_12_200.fnt", &pFontS );
		pGraphicsMgr->CreateFontFromFile( L"Data\\Font\\mspg_16_400.fnt", &pFontL );

		if( pGraphicsMgr->CreateCanvasRenderer( &pCanvasRenderer, L"Sample" ) == True )
		{
			pCanvasRenderer->SetFont( pFontL );
		}

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

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

			config.caps = Mix::Scene::RCAP_LUMINOSITY | Mix::Scene::RCAP_ATMOSPHERE | Mix::Scene::RCAP_LENS_FLARE;

			if( pSceneMgr->CreateRenderer( pSceneEffectPackage, config, &pSceneRenderer, L"Sample" ) == True )
			{
				Mix::Scene::CAMERA_CONFIG camConfig;
				Mix::Scene::ISkyDome* pSkyDome = NULL;
				Mix::Scene::IAtmosphereScatter* pASScatter = NULL;
				Mix::Scene::IAtmosphereScatter::DAY_SETTINGS asDaySettings;
				Mix::Scene::IDirectionalLight* pDirLight = NULL;
				Mix::Scene::ITerrainModel* pRoomModel = NULL;
				Mix::Graphics::ITexture* pTempTex = NULL;

				/*
					カメラ
				*/

				camConfig.caps = config.caps;
				camConfig.targetSize.Set( SCREEN_WIDTH, SCREEN_HEIGHT );
				camConfig.colorTexFormat = Mix::Graphics::FMT_R16G16B16A16F;

				if( pSceneMgr->CreateViewCamera( camConfig, &pCamera ) == True )
				{
					Mix::Scene::ICamera::LENS_FLARE_SETTINGS lfSettings = pCamera->GetLensFlareSettings();

					pCamera->SetBackgroundColor( Mix::Vector4( 0.2f, 0.2f, 0.2f, 1.0f ) );
					pCamera->SetProjection( MIX_TO_RAD( 60.0f ), 0.01f, 2000.0f );

					lfSettings.brightPass.bLumInf = False;
					lfSettings.brightPass.white = 4.0f;
					lfSettings.brightPass.threshold = 4.0f;
					lfSettings.brightPass.offset = 1.0f;
					lfSettings.haloWidth = 0.4f;
					lfSettings.haloWeight = 1.0f;
					lfSettings.brustSharpness = 4.0f;
					lfSettings.brustIntensity = 1.5f;
					lfSettings.dirtSharpness = 4.0f;
					lfSettings.dirtIntensity = 1.0f;
					lfSettings.blur = Mix::Scene::BLUR::GAUSSIAN_EX( 32 );
					lfSettings.intensity = 0.15f;
					pCamera->SetLensFlareEnabled( True );
					pCamera->SetLensFlareSettings( lfSettings );

					if( pGraphicsDev->CreateTextureFromFile( L"Data\\Texture\\lfColor.png", &pTempTex ) == True )
					{
						pCamera->SetLensFlareTexture( Mix::Scene::ICamera::LFT_COLOR, pTempTex );
						MIX_RELEASE( pTempTex );
					}

					if( pGraphicsDev->CreateTextureFromFile( L"Data\\Texture\\lfBrust.png", &pTempTex ) == True )
					{
						pCamera->SetLensFlareTexture( Mix::Scene::ICamera::LFT_BRUST, pTempTex );
						MIX_RELEASE( pTempTex );
					}

					if( pGraphicsDev->CreateTextureFromFile( L"Data\\Texture\\lfDirt.png", &pTempTex ) == True )
					{
						pCamera->SetLensFlareTexture( Mix::Scene::ICamera::LFT_DIRT, pTempTex );
						MIX_RELEASE( pTempTex );
					}

					pCamera->SetFilmicType( Mix::Scene::ICamera::FI_HABLE );

					pSceneRenderer->AddCamera( pCamera );
				}

				/*
					スカイドーム
				*/

				if( pSceneMgr->CreateSkyDome( 1000.0f, 150.0f, Mix::Scene::ISkyDome::QL_MIDDLE, &pSkyDome, MIX_DEBUGNAME_T( L"Sample" ) ) == True )
				{
					pSceneRenderer->SetSkyDome( pSkyDome );
				}

				/*
					大気スキャッター
				*/

				pSceneRenderer->GetAtmosphereScatter( &pASScatter );
				asDaySettings = pASScatter->GetDaySettings();
				asDaySettings.sunIntensity = 0.12f;
				asDaySettings.sunTurbidity = 0.3f;
				asDaySettings.henyeyGreenstein = 0.9961f;
				asDaySettings.mie = 0.002f;
				pASScatter->SetDaySettings( asDaySettings );

				/*
					ディレクショナルライト
				*/

				if( pSceneMgr->CreateDirectionalLight( &pDirLight ) == True )
				{
					pDirLight->SetEnabled( True );
					pDirLight->SetDirection( pSkyDome->GetSunLight().dir );
					pDirLight->SetColor( pASScatter->GetSunLightColor() );

					pSceneRenderer->SetDirectionalLight( pDirLight );
				}

				/*
					地形モデル
				*/

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

				/*
					後始末
				*/

				MIX_RELEASE( pRoomModel );
				MIX_RELEASE( pDirLight );
				MIX_RELEASE( pASScatter );
				MIX_RELEASE( pSkyDome );
			}
		}

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

		camHelper.Initialize(	pMouse,
								pKeyboard,
								Mix::Vector3( 0.0f, 10.0f, 0.0f ),
								Mix::Vector2( MIX_TO_RAD( -90.0f ), MIX_TO_RAD( 0.0f ) ),
								8.0f,
								0.01f,
								0.002f );

		uiManager.Initialize( pMouse, pCanvasRenderer, pFontS );

		hud.Initialize( pCamera );
		hud.Open( &uiManager );

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

		pEngine->ResetFPS();

		while( pEngine->Update() == True )
		{
			////////////////////////////////////////////////////////////////////////////////////////////////////
			// カメラ
			////////////////////////////////////////////////////////////////////////////////////////////////////

			camHelper.Update();

			if( pCamera != NULL )
			{
				pCamera->SetView( camHelper.GetAt(), camHelper.GetRotation(), camHelper.GetDistance() );
			}

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

			if( pCanvasRenderer != NULL )
			{
				const Mix::Point& screenSize = pGraphicsDev->GetScreenSize();
				Mix::Vector2 tmpVec;

				// UI

				pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
				pCanvasRenderer->SetBlendType( Mix::Graphics::BLEND_NORMAL );

				uiManager.Update();

				// ???

				tempStr.Sprintf(	L"FPS %f\n"
									L"STps %f\n"
									L"IFCps %d/%d",	pEngine->GetFPS(),
													pEngine->GetSleepTimePerSec(),
													pEngine->GetInsomniaFrameCountPerSec(), pEngine->GetInsomniaFrameMax() );

				pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
				pCanvasRenderer->SetBlendType( Mix::Graphics::BLEND_NORMAL );

				pCanvasRenderer->AddString(	16.0f, 16.0f, tempStr.GetConstPtr() );

				// Desc

				tempStr.Sprintf(	L"Controls :\n"
									L"  Rotate camera  : Mouse middle button\n"
									L"  Move camera    : Mouse middle button + Shift key\n"
									L"  Distant camera : Mouse middle button + Ctrl key or Mouse wheel\n" );

				tmpVec = Mix::Graphics::Utility::MeasureString( pFontL, tempStr.GetConstPtr() );

				pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
				pCanvasRenderer->SetBlendType( Mix::Graphics::BLEND_NORMAL );

				pCanvasRenderer->AddString(	16.0f, static_cast<Float32>( screenSize.y ) - tmpVec.y - 16.0f, tempStr.GetConstPtr() );

				// Cursor

				pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
				pCanvasRenderer->SetBlendType( Mix::Graphics::BLEND_NORMAL );

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

#ifdef _DEBUG
				Mix::Rectangle debImgRect;

				debImgRect = Utility::Debug_DrawCameraImage( pCamera, Mix::Scene::DIT_LENS_FLARE, 0, pCanvasRenderer, Mix::Rectangle( screenSize.x - 192 - 16, 16, 192, 192 ) );
				debImgRect = Utility::Debug_DrawCameraImage( pCamera, Mix::Scene::DIT_LENS_FLARE, 1, pCanvasRenderer, Mix::Rectangle( screenSize.x - 192 - 16, debImgRect.GetBottom() + 16, 192, 192 ) );
#endif //_DEBUG

				pCanvasRenderer->Update();
			}

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

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

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

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

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

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

			pGraphicsDev->SetViewBounds( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );

			if( pGraphicsDev->Begin() == True )
			{
				if( pCamera != NULL )
				{
					pCamera->Draw();
				}

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

				pGraphicsDev->End();
			}

			pGraphicsDev->Present();
		}

		uiManager.Dispose();

		camHelper.Dispose();

		MIX_RELEASE( pCamera );
		MIX_RELEASE( pSceneRenderer );
		MIX_RELEASE( pSceneEffectPackage );
		MIX_RELEASE( pCanvasRenderer );
		MIX_RELEASE( pFontL );
		MIX_RELEASE( pFontS );
		MIX_RELEASE( pGraphicsDev );
		MIX_RELEASE( pKeyboard );
		MIX_RELEASE( pMouse );

		Mix::Finalize();
	}

	return 0;
}
