/*----------------------------------------------------------------------

    Application shadow map sample for DirectX

    Copyright (C) 2008 SEGA Corporation Creative Center Graphics Sect.
    All Rights Reserved.

    Module  : Application shadow map sample for DirectX
    File    : smpmain.cpp
    Create  : 2008/06/13
    Modify  : 2008/11/14 (Ver.0.10.02)
			    プラットフォーム別処理関数を smpapp.cpp から移動し initSystem, exitSystem 関数を追加
    Modify  : 2009/01/13 (Ver.0.10.03)
			    smpWinShowWindow()、smpWinUpdateWindow() 関数を追加。
				ウインドウサイズの更新のとき DirectX の初期化がされていなければ何もしないを追加。
    Modify  : 2009/01/19 (Ver.0.10.04)
				nnSetD3DXIncludeDXG20 関数を追加。
				CSmpDx::setIncludeCallbackFunc 関数を追加。
				smpExitConfigureSystemDXG20() 関数を追加。
    Modify  : 2009/06/11 (Ver.0.10.05)
			    プラットフォーム別処理関数(IDirect3DDevice9_CreateVertexBuffer, IDirect3DVertexBuffer9_Release)を smpapp.cpp から移動した。
    Version : 0.10.05
    Note    : 

----------------------------------------------------------------------*/

#define __SMPMAIN_CPP__

//--------------------
// 組み込みファイル名
//--------------------
#include "smpWin.h"
#include "smpDx.h"

#include "smpapp.h"
#include "smputil.h"
#include "cameractrl.h"

////////////////////////////////////////////////////////////////////////////////
#define WINDOW_WIDTH			1200
#define WINDOW_HEIGHT			900

#define WINDOW_TITLE			"NN for DirectX G2.0 Sample"

#define FULLSCREEN_WIDTH		1600
#define FULLSCREEN_HEIGHT		1200
#define FULLSCREEN_FORMAT		D3DFMT_X8R8G8B8
#define FULLSCREEN_REFRESH_RATE	60

////////////////////////////////////////////////////////////////////////////////
static BOOL g_chgDeviceFg = FALSE;

static IDirect3DVertexBuffer9 *g_pTmpVB = NULL;	// ワーク頂点バッファ

////////////////////////////////////////////////////////////////////////////////
//----------------------
// システムを初期化する
//----------------------
static void initSystem(void)
{
	// NNライブラリ初期化
	nnConfigureSystemDXG20(CSmpDx::getDirect3DDevice(), CSmpDx::getD3DPresentParameters(), NNE_SHADER_VERSION_DEFAULT, NNE_SHADER_VERSION_DEFAULT);
	// サンプルライブラリの初期化
	smpConfigureSystemDXG20();

	// ID3DXIncludeインターフェイスをセットする
	nnSetD3DXIncludeDXG20(CSmpDx::getD3DXInclude());
	// #include 擬似命令用のコールバック関数の設定
	CSmpDx::setIncludeCallbackFunc((CSmpDx::INCLUDE_CALLBACK_FUNC)smpIncludeCallbackDXG20);

	// ワーク用頂点バッファの設定
	IDirect3DDevice9_CreateVertexBuffer((LPDIRECT3DDEVICE9)nnGetDirect3DDeviceDXG20(), 0x100000, D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &g_pTmpVB , NULL);
	nnInitVertexBufferDXG20(g_pTmpVB, 0x100000);
}

//--------------------
// システムを終了する
//--------------------
static void exitSystem(void)
{
	// 頂点バッファの終了
	nnExitVertexBufferDXG20();
	// ワーク頂点バッファの解放
	IDirect3DVertexBuffer9_Release(g_pTmpVB);

	// サンプルライブラリの終了
	smpExitConfigureSystemDXG20();
	// NNライブラリの終了
	nnExitConfigureSystemDXG20();
}

////////////////////////////////////////////////////////////////////////////////
//------------------------------
// ウインドウのサイズを変更する
//------------------------------
static void changeWindowSize(void)
{
	if(g_chgDeviceFg == FALSE){
		// サイズ変更開始
		g_chgDeviceFg = TRUE;
		// デバイスの消失時の処理
		UserDeviceLost();
		// システムを終了する
		exitSystem();
		{
			D3DPRESENT_PARAMETERS *d3dpp = CSmpDx::getD3DPresentParameters();

			d3dpp->BackBufferWidth  = 0;
			d3dpp->BackBufferHeight = 0;

			HRESULT hr;
			hr = CSmpDx::getDirect3DDevice()->Reset(d3dpp);
			if(FAILED(hr)){
				if (hr == D3DERR_DEVICELOST){
					NNM_ASSERT(0,"Error(DEVICELOST) : IDirect3DDevice9::Reset(…).\n");
				} else{
					NNM_ASSERT(0,"Error : IDirect3DDevice9::Reset(…).\n");
				}
			}
		}
		// システムを初期化する
		initSystem();
		// デバイスのリストアの処理
		UserDeviceReset();
		// サイズ変更終了
		g_chgDeviceFg = FALSE;
	}
}

//------------------------------
// ディスプレイモードを変更する
//------------------------------
static void changeDisplayMode(int fullFg)
{
	if(g_chgDeviceFg == FALSE){
		// モード変更開始
		g_chgDeviceFg = TRUE;
		// デバイスの消失時の処理
		UserDeviceLost();
		// システムを終了する
		exitSystem();
		{
			HRESULT hr;
			if(fullFg == 1){
				// フルスクリーンモードに変更する
				hr = CSmpDx::changeFullScreenMode();
				if(FAILED(hr)){
					NNM_ASSERT(0,"Error : CSmpDx::changeFullScreenMode(…).\n");
				}
			} else{
				// ウインドウモードに変更する
				hr = CSmpDx::changeWindowMode();
				if(FAILED(hr)){
					NNM_ASSERT(0,"Error : CSmpDx::changeWindowMode(…).\n");
				}
			}
		}
		// システムを初期化する
		initSystem();
		// デバイスのリストアの処理
		UserDeviceReset();
		// モード変更終了
		g_chgDeviceFg = FALSE;
	}
}

//----------------
// メッセージ処理
//----------------
static void winProc(unsigned long evtType, void *ptr)
{
	static int moveFg = 0;
	static int fullFg = 0;

	SMPWINEvent *evt = (SMPWINEvent*)ptr;
	switch(evtType){
		case SMPWIN_TYPE_DESTROY:
			CSmpDx::addFlag(CSmpDx::FLAG_QUIT);
			break;

		case SMPWIN_TYPE_ENTERSIZEMOVE:
			moveFg = 1;	// 移動開始
			break;

		case SMPWIN_TYPE_MOVE:
			moveFg = 1;	// 移動中
			break;

		case SMPWIN_TYPE_SIZE:
			if(CSmpDx::getDirect3D() == NULL){
				break;
			}
#if 1 // 念のため残しておく
			if(CSmpDx::getD3DPresentParameters()->Windowed != TRUE){
				// フルスクリーン状態でサイズ変更があった場合は無視する。
				// これはフルスクリーンモードからウインドウモードになるとき
				// SetWindowPos(…)関数が使われているのでここに来てしまうため、
				// この後の処理に行くのはまずい。
				//
				// g_chgDeviceFg を追加したのでこの if 文は必要なくなったが念のため残しておく。
				break;
			}
#endif
			if(evt->m_state == SMPWIN_SIZE_MAXIMIZED || evt->m_state == SMPWIN_SIZE_RESTORED){
				// ウインドウのサイズを変更する
				changeWindowSize();
			}
			break;

		case SMPWIN_TYPE_EXITSIZEMOVE:
			if(moveFg == 0){
				// サイズ変更
				changeWindowSize();
			}
			break;

		case SMPWIN_TYPE_KEY_DOWN:
			switch(evt->m_code){
				case SMPWIN_KEY_F5:
					// ディスプレイモードを変更する
					fullFg ^= 1;
					if(CSmpDx::getD3DPresentParameters()->Windowed == fullFg){
						changeDisplayMode(fullFg);
					} else{
						changeDisplayMode(!fullFg);
					}
					break;

				case VK_ESCAPE:
					smpWinMainLoopQuit();
					break;

				default:
					break;
			}
			break;

		default:
			break;
	}

	CameraCtrlMain(evtType, ptr);
}

//--------------
// アイドル処理
//--------------
static void idleProc(void)
{
	if(! CSmpDx::getFlag() & CSmpDx::FLAG_QUIT){
		LPDIRECT3DDEVICE9 dev;

		dev = CSmpDx::getDirect3DDevice();
		dev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0x80,0x80,0x80), 1.0f, 0 );
		if( SUCCEEDED( dev->BeginScene() ) ){
			//
			UserMain();
			//
			dev->EndScene();
		}
		HRESULT hr;
		// シーンの表示
		hr = dev->Present( NULL, NULL, NULL, NULL );
		if(FAILED(hr)){
			if (hr == D3DERR_DEVICELOST){
				NNM_ASSERT(0,"Error(DEVICELOST) : IDirect3DDevice9::Present(…).\n");
			} else{
				NNM_ASSERT(0,"Error : IDirect3DDevice9::Present(…).\n");
			}
		}
	}
}

//--------
// メイン
//--------
int main(int argc, char *argv[])
{
	UNREFERENCED_PARAMETER(argc);
	UNREFERENCED_PARAMETER(argv);

	// 初期化
	smpWinInit();
	// ウインドウを生成
	smpWinCreateWindow(WINDOW_TITLE, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
	// メッセージ処理関数をセット
	smpWinSetWinProc(winProc);
	// アイドル処理関数をセット
	smpWinSetIdleProc(idleProc);
	// ウィンドウをアクティブにして表示
	smpWinShowWindow();
	// ウインドウの更新
	smpWinUpdateWindow();
	{
		CSmpDx::init((HWND) smpWinGetWindowHandle());
		CSmpDx::initFullScreen(FULLSCREEN_WIDTH, FULLSCREEN_HEIGHT, FULLSCREEN_FORMAT, FULLSCREEN_REFRESH_RATE);

		// DirectX Graphics で使用するデバイスを生成する
		CSmpDx::create();
		// システムを初期化する
		initSystem();
		//
		UserInit();
	}
	// イベント処理ループ
	smpWinMainLoop();
	{
		//
		UserExit();
		// システムを終了する
		exitSystem();
		// DirectX Graphics の終了
		CSmpDx::release();
	}
	// 終了
	smpWinEnd();
	return(0);
}
