#include"CVideoCardDriverD3D9.h"

#include"ShaderModel0000/CPixelShaderCompiler0000.h"
#include"ShaderModel0000/CVertexShaderCompiler0000.h"

#include"../../../../../Auxiliary/Debug/CException.h"
#include"../../../../../Auxiliary/Debug/CTrace.h"
#include"../../../../../Auxiliary/Debug/CWarning.h"
#include"../../../../../Auxiliary/CString.h"

#include<list>

namespace Maid
{

struct SWAPWINDOWINFO
{
	HWND	hWnd;
	RECT2DI	Rect;
};

static MySTL::list<SWAPWINDOWINFO>	s_WindowInfoList;

BOOL CALLBACK EnumWindowsProc(HWND hWnd , LPARAM lp) 
{
	SWAPWINDOWINFO	info;
	RECT			rc;

	::GetWindowRect( hWnd, &rc );

	info.hWnd = hWnd;
	info.Rect.x = rc.left;
	info.Rect.y = rc.top;
	info.Rect.w = rc.right - rc.left;
	info.Rect.h = rc.bottom- rc.top;

	MySTL::list<SWAPWINDOWINFO>* pList = (MySTL::list<SWAPWINDOWINFO>*)lp;

	pList->push_back(info);

	return TRUE;
}

/*!
 	@class	CVideoDriverD3D9 CVideoDriverD3D9.h
 	@brief	レンダリングドライバ Direct3D9 Ver.
 */

CVideoCardDriverD3D9::CVideoCardDriverD3D9( HWND hWnd, SHADERMODEL shader )
{
	m_hWnd = hWnd;
	m_ShaderModel = shader;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! IVideoCardDriver::Initialize() を参照
void CVideoCardDriverD3D9::Initialize( const SCREENMODE& mode )
{
	m_WindowModeStyle = ::GetWindowLong( m_hWnd, GWL_STYLE );
	m_AspectLock.w = ::GetSystemMetrics(SM_CXSCREEN);
	m_AspectLock.h = ::GetSystemMetrics(SM_CYSCREEN);

	Finalize();

	if( m_pDirect3D.IsNull() ) { CreateD3D9(); }
	
	CreateDevice( mode );

	m_pDevice->GetDeviceCaps(&m_DeviceCaps);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! IVideoCardDriver::Finalize() を参照
void CVideoCardDriverD3D9::Finalize()
{
	m_pDevice.reset();
	m_pDirect3D.reset();
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! IVideoCardDriver::Flip() を参照
void CVideoCardDriverD3D9::Flip()
{
	const SCREENMODE& m = m_ScreenMode;
	if( IsAspectLock() )
	{
		SPD3DSURFACEBUFFER pSrc = m_pAspectLockBuffer;
		SPD3DSURFACEBUFFER pDst;

		{
			IDirect3DSurface9* pSurface=NULL;

			m_pDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pSurface );

			pDst.reset( pSurface );
		}

		RECT2DI DstRC;

		const int ScreenW = m.Size.w;
		const int ScreenH = m.Size.h;
		const int ExtendW = m_AspectLock.w;
		const int ExtendH = m_AspectLock.h;

		//	なるべく液晶に拡大できるように調節する
		int WScale = ExtendW*ScreenH/ScreenW;
		int HScale = ExtendH*ScreenW/ScreenH;
		if( WScale <= ExtendH ) {
			//	横を基準に縦を計算した場合(縦があまる)
			DstRC.x = 0;
			DstRC.y = (ExtendH-WScale)/2;
			DstRC.w = ExtendW;
			DstRC.h = WScale;

		}else {
			//	縦を基準に横を計算した場合(横があまる)
			DstRC.x = (ExtendW-HScale)/2;
			DstRC.y = 0;
			DstRC.w = HScale;
			DstRC.h = ExtendH;
		}

		m_pDevice->SetRenderTarget( 0, pDst.get() );
		m_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0.0f, 0 );

		{
			const RECT src = { 0, 0, ScreenW,ScreenH };
			const RECT dst = { DstRC.x, DstRC.y, DstRC.GetRight(), DstRC.GetBottom() };

			HRESULT ret = m_pDevice->StretchRect( pSrc.get(), &src, pDst.get(), &dst, D3DTEXF_LINEAR );
			if( FAILED(ret) )
			{
				ret = m_pDevice->StretchRect( pSrc.get(), &src, pDst.get(), &dst, D3DTEXF_NONE );
				if( FAILED(ret) ) { MAID_THROWEXCEPTION( MAIDTEXT("IDirect3DDevice9::StretchRect") ); }
			}
		}
	}


	const HRESULT ret = m_pDevice->Present( NULL, NULL, NULL, NULL );
	if( ret==D3DERR_DEVICELOST ) { }
	ef( FAILED(ret) ) { MAID_THROWEXCEPTION( MAIDTEXT("IDirect3DDevice9::Present") ); }
}

void CVideoCardDriverD3D9::Restore()
{
	if( ::IsIconic( m_hWnd )==TRUE ) { return ; }

	for( int i=0; i<8; ++i ) { m_pDevice->SetTexture( i, NULL ); }
	for( int i=0; i<8; ++i ) { m_pDevice->SetStreamSource( i, NULL, 0, 0 ); }

	m_pDevice->SetIndices( NULL );
	m_pDevice->SetPixelShader( NULL );
	m_pDevice->SetVertexShader( NULL );
	m_pDevice->SetVertexDeclaration( NULL );

	D3DMATRIX view, proj;
	m_pDevice->GetTransform( D3DTS_VIEW, &view );
	m_pDevice->GetTransform( D3DTS_PROJECTION, &proj );

	ReleaseRTSurface();

	InitializePresertParameters( m_DeviceInfo, m_ScreenMode );

	const HRESULT ret = m_pDevice->Reset( &m_DeviceInfo );
	if( FAILED(ret) ) { return; }

	CreateRTSurface();

	m_pDevice->SetTransform( D3DTS_VIEW, &view );
	m_pDevice->SetTransform( D3DTS_PROJECTION, &proj );

	m_pDevice->GetDeviceCaps(&m_DeviceCaps);
}




/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! IVideoCardDriver::Reset() 参照
void	CVideoCardDriverD3D9::Reset( const SCREENMODE& Mode )
{
	for( int i=0; i<8; ++i ) { m_pDevice->SetTexture( i, NULL ); }
	for( int i=0; i<8; ++i ) { m_pDevice->SetStreamSource( i, NULL, 0, 0 ); }

	m_pDevice->SetIndices( NULL );
	m_pDevice->SetPixelShader( NULL );
	m_pDevice->SetVertexShader( NULL );
	m_pDevice->SetVertexDeclaration( NULL );

	D3DMATRIX view, proj;
	m_pDevice->GetTransform( D3DTS_VIEW, &view );
	m_pDevice->GetTransform( D3DTS_PROJECTION, &proj );

	ReleaseRTSurface();

	//	フルスクリーン -> フルスクリーンの場合も考えて
	//	ウィンドウ -> フルスクリーン　の時だけウィンドウ座標を取る

	if( m_DeviceInfo.Windowed==TRUE && Mode.Mode!=SCREENMODE::TYPE_WINDOW )
	{
		UpdateWindowInfo();
	}

	InitializePresertParameters( m_DeviceInfo, Mode );


	const HRESULT ret = m_pDevice->Reset( &m_DeviceInfo );
	if( FAILED(ret) ) { return; }

	if( m_DeviceInfo.Windowed==TRUE )
	{
		//	フルスクリーンからウィンドウに戻ってきたらウィンドウを再配置
		for( MySTL::list<SWAPWINDOWINFO>::iterator ite=s_WindowInfoList.begin();
					ite!=s_WindowInfoList.end(); ++ite )
		{
			SWAPWINDOWINFO& info = *ite;
			::MoveWindow( info.hWnd, info.Rect.x,  info.Rect.y, info.Rect.w, info.Rect.h, TRUE );
		}

		RECT	rc = { 0, 0, m_DeviceInfo.BackBufferWidth, m_DeviceInfo.BackBufferHeight };
		AdjustWindowRect( &rc, m_WindowModeStyle, FALSE );
		const int w = rc.right  - rc.left;
		const int h = rc.bottom - rc.top;

		::SetWindowLong( m_hWnd, GWL_STYLE, m_WindowModeStyle );
		::SetWindowPos( m_hWnd, HWND_NOTOPMOST,
				m_WindowModePos.x, m_WindowModePos.y,
				w, h,
				SWP_DRAWFRAME|SWP_SHOWWINDOW );
		::InvalidateRect(NULL, NULL, FALSE);
	}else
	{
		::SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_EX_TOPMOST );
		::SetWindowPos( m_hWnd, HWND_TOPMOST,
				0, 0,
				Mode.Size.w, Mode.Size.h,
				SWP_DRAWFRAME|SWP_SHOWWINDOW );
	}


	CreateRTSurface();

//	m_pDevice->EvictManagedResources();
	m_pDevice->SetTransform( D3DTS_VIEW, &view );
	m_pDevice->SetTransform( D3DTS_PROJECTION, &proj );

	m_pDevice->GetDeviceCaps(&m_DeviceCaps);
}

IVideoCardDriver::DEVICESTATE CVideoCardDriverD3D9::TestCooperativeLevel()
{
	const HRESULT ret = m_pDevice->TestCooperativeLevel();

	if( ret==D3D_OK ) { return DEVICESTATE_OK; }
	ef( ret==D3DERR_DEVICENOTRESET ) { return DEVICESTATE_NOTRESET; }

	return DEVICESTATE_LOST;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! IVideoCardDriver::BeginScene() を参照
void CVideoCardDriverD3D9::BeginScene()
{
	const HRESULT ret = m_pDevice->BeginScene();
	if( FAILED(ret) )
	{
		char buf[256];
		sprintf( buf, "%d", ret );
		MAID_THROWEXCEPTION(MAIDTEXT("IDirect3DDevice::BeginScene()") +CString::ConvertSJIStoMAID(buf) ); }

	if( IsAspectLock() )
	{
		m_pDevice->SetRenderTarget( 0, m_pAspectLockBuffer.get() );
	}
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! IVideoCardDriver::EndScene() を参照
void CVideoCardDriverD3D9::EndScene()
{
	const HRESULT ret = m_pDevice->EndScene();
	if( FAILED(ret) ) { MAID_THROWEXCEPTION(MAIDTEXT("IDirect3DDevice::EndScene()")); }
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! IDirect3D9 の作成
/*!
 	このオブジェクトが作成されて初めて Init() された時にだけ呼ばれる
 
	@exception CException IDirect3D9の作成に失敗した場合
 */
void	CVideoCardDriverD3D9::CreateD3D9()
{
	if( m_pDirect3D.get()!=NULL ) { return; }

	m_d3d9DLL.Load( MAIDTEXT("D3D9.dll") );

	{
		typedef IDirect3D9* (WINAPI *FUNCTIONPTR)(UINT);
		FUNCTIONPTR pd3dCreate9 = (FUNCTIONPTR)m_d3d9DLL.GetProcAddress(MAIDTEXT("Direct3DCreate9"));

		IDirect3D9* pD3D = pd3dCreate9( D3D_SDK_VERSION );

		if( pD3D==NULL ) { MAID_THROWEXCEPTION( MAIDTEXT("Direct3DCreate9 の失敗") ); }

		m_pDirect3D.reset( pD3D );
	}

	m_pDirect3D->GetAdapterIdentifier( D3DADAPTER_DEFAULT, 0, &m_AdaptrerInfo );

	const D3DFORMAT	CheckList[] = 
	{
		D3DFMT_X1R5G5B5,
		D3DFMT_A1R5G5B5,
		D3DFMT_R5G6B5,
		D3DFMT_X8R8G8B8,
		D3DFMT_A8R8G8B8,
		D3DFMT_A2B10G10R10,
	};


	m_16BitModeFormat = D3DFMT_UNKNOWN;
	m_32BitModeFormat = D3DFMT_UNKNOWN;
	m_WindowModeFormat= D3DFMT_UNKNOWN;
	for( int BppMode=0; BppMode<NUMELEMENTS(CheckList); ++BppMode )
	{
		const D3DFORMAT fmt = CheckList[BppMode];
		const UINT	uAdapter = m_pDirect3D->GetAdapterModeCount(D3DADAPTER_DEFAULT,fmt);

		for( UINT i=0; i<uAdapter; ++i )
		{
			D3DDISPLAYMODE mode;
			const HRESULT ret = m_pDirect3D->EnumAdapterModes( D3DADAPTER_DEFAULT, fmt, i, &mode );

			if( FAILED(ret) ) { continue; }

			switch( mode.Format )
			{
			case D3DFMT_X1R5G5B5:	m_16BitModeFormat = D3DFMT_X1R5G5B5; break;
			case D3DFMT_R5G6B5  :	m_16BitModeFormat = D3DFMT_R5G6B5  ; break;
			case D3DFMT_X8R8G8B8:	m_32BitModeFormat = D3DFMT_X8R8G8B8; break;
			case D3DFMT_A8R8G8B8:	m_32BitModeFormat = D3DFMT_A8R8G8B8; break;
			}
			m_DisplayModeList.push_back(mode);
		}
	}

	//	現在のBPPを調べてウィンドウモード時のピクセルフォーマットを調べる
	//	レンダリングターゲットにできないフォーマットだったらウィンドウモードにはできないようにする
	//	詳しくはDirectX8ヘルプのD3DFORMAT構造体を参照
	{
		D3DDISPLAYMODE d3ddm;
		m_pDirect3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm );


		if( d3ddm.Format!=D3DFMT_X1R5G5B5	&& 
			d3ddm.Format!=D3DFMT_A1R5G5B5	&&
			d3ddm.Format!=D3DFMT_R5G6B5		&&
			d3ddm.Format!=D3DFMT_X8R8G8B8	&&
			d3ddm.Format!=D3DFMT_A8R8G8B8	)
		{
			m_WindowModeFormat = D3DFMT_UNKNOWN;
		}else
		{
			m_WindowModeFormat = d3ddm.Format;
		}
	}
}


//! ディスプレイの初期化
/*!
  	@param	mode		[i ]	初期化するモード
 
	@exception CException IDirect3DDevice9の作成に失敗した場合
 */
void CVideoCardDriverD3D9::CreateDevice( const SCREENMODE& mode )
{
	D3DPRESENT_PARAMETERS& info = m_DeviceInfo;

	InitializePresertParameters( info, mode );


	if( mode.Mode!=SCREENMODE::TYPE_WINDOW )
	{
		UpdateWindowInfo();
	}


	{
		//	最後に初期化
		//	CreateDevice が失敗した場合
		//	・そもそも作れない
		//　・ドライバ側が作成できる条件を設定してくれる
		// の２つがあるので条件を変えていろいろチャレンジ
		DWORD flag = D3DCREATE_MULTITHREADED;
		IDirect3DDevice9* pDevice=NULL;

		if( mode.IsSoftTnL ) { flag |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; }
		else				 { flag |= D3DCREATE_MIXED_VERTEXPROCESSING; }

		for( int i=0; i<2; ++i )
		{
			HRESULT	ret;
			ret = m_pDirect3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flag, &info, &pDevice );
			if( SUCCEEDED(ret) ) { break; }
		}

		if( pDevice==NULL ) 
		{
			for( int i=0; i<2; ++i )
			{
				HRESULT	ret;
				ret = m_pDirect3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_MULTITHREADED|D3DCREATE_SOFTWARE_VERTEXPROCESSING, &info, &pDevice );
				if( SUCCEEDED(ret) ) { break; }
			}
			if( pDevice==NULL ) 
			{
				MAID_THROWEXCEPTION( MAIDTEXT("m_pDirect3D->CreateDevice()に失敗") );
			}
		}

		m_pDevice.reset( pDevice );
		m_pDevice->GetDeviceCaps(&m_DeviceCaps);
	}

	{
		//	デバイス能力から、対応したシェーダーを作成
		//	PixelShader の性能 = Shaderの性能として
		//	VertexShader が足りていないときは VertexShader はソフトウェアで行う

		const DWORD pixel = m_DeviceCaps.PixelShaderVersion;
		const DWORD vertex = m_DeviceCaps.VertexShaderVersion;

		switch( m_ShaderModel )
		{
		case SHADERMODEL_DEFAULT:
/*
		case SHADERMODEL_0300:
			{
				if( pixel>=D3DPS_VERSION(3,0) )
				{
					m_pPixelShaderCompiler.reset( new CPixelShaderCompiler0300 );
					m_pVertexShaderCompiler.reset( new CVertexShaderCompiler0300 );
					break;
				}
			}
		case SHADERMODEL_0200:
			{
				if( pixel>=D3DPS_VERSION(2,0) )
				{
					m_pPixelShaderCompiler.reset( new CPixelShaderCompiler0200 );
					m_pVertexShaderCompiler.reset( new CVertexShaderCompiler0200 );
					break;
				}

			}
		case SHADERMODEL_0101:
			{
				if( pixel>=D3DPS_VERSION(1,1) )
				{
					m_pPixelShaderCompiler.reset( new CPixelShaderCompiler0101 );
					m_pVertexShaderCompiler.reset( new CVertexShaderCompiler0101 );
					break;
				}
			}
*/
		case SHADERMODEL_0000:
			{
				m_pPixelShaderCompiler.reset( new CPixelShaderCompiler0000 );
				m_pVertexShaderCompiler.reset( new CVertexShaderCompiler0000 );
			}break;
		}
	}

	CreateRTSurface();
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//!	指定したモードの D3DPRESENT_PARAMETERS を作成する
/*!	
	@param	Info		[ o]	作成先	
 	@param	Mode		[i ]	スクリーンモード
 */
void	CVideoCardDriverD3D9::InitializePresertParameters( D3DPRESENT_PARAMETERS& Info, const SCREENMODE& Mode  )
{
	m_ScreenMode = Mode;

	//	各モード共通の設定
	ZeroMemory( &Info, sizeof(Info) );
	Info.BackBufferWidth = Mode.Size.w;
	Info.BackBufferHeight= Mode.Size.h;
	Info.hDeviceWindow   = m_hWnd;
	Info.EnableAutoDepthStencil = TRUE;
	Info.AutoDepthStencilFormat = D3DFMT_D16;
	Info.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER ;
//	Info.Flags = 0 ;
	Info.BackBufferFormat = GetBackBufferFormatD3D( Mode.Mode );


	{
		//	スクリーンモードで違う個所の設定
		//	ウィンドウモードだったら BackBuffer は１。 Flip はコピー
		//	フルスクリーンだったら BackBuffer 任意。 Flip はコピーor交換＋VSync任意

		if( Mode.Mode==SCREENMODE::TYPE_WINDOW )
		{
			Info.Windowed = TRUE;  
			Info.BackBufferCount = 1;
			Info.SwapEffect = D3DSWAPEFFECT_COPY;
			Info.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
			Info.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
		}
		else
		{
			Info.Windowed = FALSE;

			if( IsAspectLock() )
			{
				Info.BackBufferWidth = m_AspectLock.w;
				Info.BackBufferHeight= m_AspectLock.h;
			}


			if( Mode.IsWaitVSync )
			{
				Info.BackBufferCount = 1; 
				Info.SwapEffect = D3DSWAPEFFECT_FLIP;
				Info.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT  ;
			}
			else
			{	//	コピー
				Info.SwapEffect = D3DSWAPEFFECT_COPY;	
				Info.BackBufferCount = 1;
				Info.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
			}

			//	ハードウェアが指定したリフレッシュレートに対応しているならそれにする
			if( SerchDisplayMode( Mode.Size.w, Mode.Size.h, Mode.RefreshRate, Info.BackBufferFormat ) )
			{
				Info.FullScreen_RefreshRateInHz = Mode.RefreshRate;
			}else{
				Info.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
			}
		}
	}

}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! バックバッファに使えるフォーマットの取得
/*!
 	@param	Mode	[i ]	調べたいスクリーンモード
 
 	@return	指定したスクリーンモード
 */
D3DFORMAT	CVideoCardDriverD3D9::GetBackBufferFormatD3D( SCREENMODE::TYPE Mode ) const
{
	switch( Mode )
	{
	case SCREENMODE::TYPE_FULL16:	{ return m_16BitModeFormat; }break;
	case SCREENMODE::TYPE_FULL32:	{ return m_32BitModeFormat;	}break;
	case SCREENMODE::TYPE_WINDOW:	{ return m_WindowModeFormat;}break;
	}
	return D3DFMT_UNKNOWN;
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//!	指定したディスプレイモードがサポートされているか調べる
/*!	各引数は負の値を指定することで比較しないようにできる
 
	@param	Size		[i ]	解像度	
	@param	RefreshRate	[i ]	リフレッシュレート
	@param	Format		[i ]	バックバッファのピクセルフォーマット
 
 	@return サポートされていたらＴＲＵＥ
 			サポートされていなかったらＦＡＬＳＥ
 */
bool CVideoCardDriverD3D9::SerchDisplayMode( int Width, int Height, int RefreshRate, D3DFORMAT Format )
{
	typedef MySTL::vector<D3DDISPLAYMODE>::iterator	MODELISTITE;
	const  MODELISTITE iteEnd = m_DisplayModeList.end();
	
	for( MODELISTITE ite = m_DisplayModeList.begin(); ite!=iteEnd; ++ite )
	{
		if( 0<=Width && ite->Width!=Width )						{ continue; }
		if( 0<=Height && ite->Height!=Height )					{ continue; }
		if( 0<=RefreshRate && ite->RefreshRate!=RefreshRate )	{ continue; }
		if( D3DFMT_UNKNOWN!=Format && ite->Format!=Format )		{ continue; }

		return true;
	}
	return false;
}

void CVideoCardDriverD3D9::UpdateWindowInfo()
{
	{
		RECT rc;
		GetWindowRect( m_hWnd, &rc );

		m_WindowModePos = POINT2DI(rc.left,rc.top);
		m_WindowModeStyle = ::GetWindowLong( m_hWnd, GWL_STYLE );
	}

	s_WindowInfoList.clear();

	EnumWindows( EnumWindowsProc, (LPARAM)&s_WindowInfoList );

	for( MySTL::list<SWAPWINDOWINFO>::iterator ite=s_WindowInfoList.begin();
							ite!=s_WindowInfoList.end(); ++ite )
	{
		if( ite->hWnd==m_hWnd )
		{
			s_WindowInfoList.erase( ite );
			break;
		}
	}
}

void CVideoCardDriverD3D9::CreateRTSurface()
{
	const SCREENMODE& m = m_ScreenMode;

	if( IsAspectLock() )
	{
		IDirect3DSurface9* pBuffer=NULL;
		MySTL::vector<PIXELFORMAT> type = EnumFormat( D3DFORMATtoPIXELFORMAT(GetBackBufferFormatD3D(m.Mode)) );
		for( int i=0; i<(int)type.size(); ++i )
		{
			const D3DFORMAT fmt = PIXELFORMATtoD3DFORMAT( type[i] );

			const HRESULT ret = m_pDevice->CreateRenderTarget( m.Size.w, m.Size.h, fmt, D3DMULTISAMPLE_NONE, 0, FALSE, &pBuffer, NULL );
			if( SUCCEEDED(ret) ) { break; }
		}

		m_pAspectLockBuffer.reset(pBuffer);
	}

	IDirect3DSurface9* pDepth;
	m_pDevice->GetDepthStencilSurface( &pDepth );
	m_pDefaultDepthStencil.reset(pDepth);
}

void CVideoCardDriverD3D9::ReleaseRTSurface()
{
	m_pAspectLockBuffer.reset();
	m_pDefaultDepthStencil.reset();
}

bool CVideoCardDriverD3D9::IsAspectLock()
{
	const SCREENMODE& m = m_ScreenMode;

	if( m.Mode==SCREENMODE::TYPE_WINDOW ) { return false; }

	return m.IsAspectLock;
}


mstring CVideoCardDriverD3D9::GetVideoInfo()
{
	const com_ptr<IDirect3D9>&	p3D = m_pDirect3D;
	const D3DADAPTER_IDENTIFIER9&	AdapterCaps = m_AdaptrerInfo;
	const D3DCAPS9& DeviceCaps = m_DeviceCaps;
	D3DDISPLAYMODE			DisplayMode;
	D3DDEVICE_CREATION_PARAMETERS	InitParams;

	m_pDevice->GetCreationParameters( &InitParams );


	MySTL::string OutString;
	char   text[256];
	OutString.reserve(512);


	//	アダプタ情報の出力
	OutString += "Adapter Caps----------------------------------------------------------------\r\n";
	OutString += "Driver ";		 OutString += AdapterCaps.Driver;		OutString += "\r\n";
	OutString += "Description "; OutString += AdapterCaps.Description; OutString += "\r\n";

	sprintf( text, "%x", AdapterCaps.VendorId );
	OutString += "VendorId "; OutString += text; OutString += "\r\n";

	sprintf( text, "%x", AdapterCaps.DeviceId );
	OutString += "DeviceId "; OutString += text; OutString += "\r\n";

	sprintf( text, "%x", AdapterCaps.SubSysId );
	OutString += "SubSysId "; OutString += text; OutString += "\r\n";

	sprintf( text, "%x", AdapterCaps.Revision );
	OutString += "Revision "; OutString += text; OutString += "\r\n";

	OutString += "\r\n";

	//	現在のデバイス情報
	OutString += "Device Caps----------------------------------------------------------------\r\n";

	p3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &DisplayMode );
	OutString += "DisplayMode\r\n";
	sprintf( text, "\tWidth=%d Height=%d\r\n", DisplayMode.Width, DisplayMode.Height );	OutString += text;
	sprintf( text, "\tRefreshRate=%d\r\n", DisplayMode.RefreshRate );						OutString += text;
	sprintf( text, "\tBackBufferNum=%d\r\n", m_DeviceInfo.BackBufferCount );				OutString += text;

	switch( DisplayMode.Format )
	{
	case D3DFMT_X1R5G5B5: { OutString += "\tPixelFormat=X1R5G5B5\r\n"; }break;
	case D3DFMT_R5G6B5:   { OutString += "\tPixelFormat=R5G6B5\r\n"; }break;
	case D3DFMT_X8R8G8B8: { OutString += "\tPixelFormat=X8R8G8B8\r\n"; }break;
	case D3DFMT_A8R8G8B8: { OutString += "\tPixelFormat=A8R8G8B8\r\n"; }break;
	default: { OutString += "\tPixelFormat=UNKNOWN\r\n"; }break;
	}

	{
		OutString += "DeviceType\r\n";
		OutString += "\t";
		switch( DeviceCaps.DeviceType )
		{
		case D3DDEVTYPE_HAL: { OutString += "D3DDEVTYPE_HAL"; }break;
		case D3DDEVTYPE_REF: { OutString += "D3DDEVTYPE_REF"; }break;
		case D3DDEVTYPE_SW : { OutString += "D3DDEVTYPE_SW";  }break;
		}
		OutString += "\r\n";

		OutString += "\t";
		const DWORD Flag = InitParams.BehaviorFlags;

		if( Flag & D3DCREATE_HARDWARE_VERTEXPROCESSING	) { OutString += "HardwareT&L"; }
		ef( Flag & D3DCREATE_MIXED_VERTEXPROCESSING		) { OutString += "MixedT&L";	}
		ef( Flag & D3DCREATE_SOFTWARE_VERTEXPROCESSING	) { OutString += "SoftwareT&L"; }
		OutString += "\r\n";

	}


	OutString += "SrcBlendCaps\r\n";
	OutString += "\tINVSRCALPHA\t";		OutString += DeviceCaps.SrcBlendCaps&D3DPBLENDCAPS_INVSRCALPHA?	"OK" : "NONE" ; OutString += "\r\n";
	OutString += "\tONE\t\t";			OutString += DeviceCaps.SrcBlendCaps&D3DPBLENDCAPS_ONE?		"OK" : "NONE" ; OutString += "\r\n";
	OutString += "\tSRCALPHA\t";		OutString += DeviceCaps.SrcBlendCaps&D3DPBLENDCAPS_SRCALPHA?	"OK" : "NONE" ; OutString += "\r\n";

	OutString += "DestBlendCaps\r\n";
	OutString += "\tINVSRCALPHA\t";		OutString += DeviceCaps.DestBlendCaps&D3DPBLENDCAPS_INVSRCALPHA?	"OK" : "NONE" ; OutString += "\r\n";
	OutString += "\tONE\t\t";			OutString += DeviceCaps.DestBlendCaps&D3DPBLENDCAPS_ONE?		"OK" : "NONE" ; OutString += "\r\n";
	OutString += "\tSRCALPHA\t";		OutString += DeviceCaps.DestBlendCaps&D3DPBLENDCAPS_SRCALPHA?	"OK" : "NONE" ; OutString += "\r\n";

	wsprintf( text, "MaxTexture Width=%d Height=%d\r\n", DeviceCaps.MaxTextureWidth, DeviceCaps.MaxTextureHeight );
	OutString += text;
	wsprintf( text, "GetAvailableTextureMem %d (%dM)\r\n", m_pDevice->GetAvailableTextureMem(), m_pDevice->GetAvailableTextureMem()/(1024*1024) );
	OutString += text;
	wsprintf( text, "MaxSimultaneousTextures %d\r\n", DeviceCaps.MaxSimultaneousTextures );
	OutString += text;

	const struct 
	{
		D3DFORMAT	fmt;
		char*		str;
	} data[] =
	{
		{ D3DFMT_R8G8B8   ,"D3DFMT_R8G8B8"		},
		{ D3DFMT_A8R8G8B8 ,"D3DFMT_A8R8G8B8"	},
		{ D3DFMT_X8R8G8B8 ,"D3DFMT_X8R8G8B8"	},
		{ D3DFMT_R5G6B5   ,"D3DFMT_R5G6B5"  	},
		{ D3DFMT_X1R5G5B5 ,"D3DFMT_X1R5G5B5"	},
		{ D3DFMT_A1R5G5B5 ,"D3DFMT_A1R5G5B5"	},
		{ D3DFMT_A4R4G4B4 ,"D3DFMT_A4R4G4B4"	},
		{ D3DFMT_X4R4G4B4 ,"D3DFMT_X4R4G4B4"	},
		{ D3DFMT_DXT1     ,"D3DFMT_DXT1"    	},
		{ D3DFMT_DXT2     ,"D3DFMT_DXT2"    	},
		{ D3DFMT_DXT3     ,"D3DFMT_DXT3"    	},
		{ D3DFMT_DXT4     ,"D3DFMT_DXT4"    	},
		{ D3DFMT_DXT5     ,"D3DFMT_DXT5"    	},
		{ D3DFMT_A8P8     ,"D3DFMT_A8P8"    	},
		{ D3DFMT_P8		  ,"D3DFMT_P8"	    	},
	};

	OutString += "TextureFormat\r\n";

	HRESULT ret;

	for( int i=0; i<NUMELEMENTS(data); ++i )
	{
		ret = p3D->CheckDeviceFormat( D3DADAPTER_DEFAULT,
                                      DeviceCaps.DeviceType,
                                      DisplayMode.Format,
                                      0,
                                      D3DRTYPE_TEXTURE,
                                      data[i].fmt);
		OutString += "\t";
		OutString += data[i].str;
		OutString += "\t";
		if( ret==D3D_OK )
		{
			OutString += "OK\r\n";
		}else
		{
			OutString += "NONE\r\n";
		}
	}
	



	const DWORD dwCaps = DeviceCaps.TextureOpCaps;

	OutString += "TextureOpCaps\r\n";
	OutString += "\tADD\t\t";		OutString += IsFlag(dwCaps, D3DTEXOPCAPS_ADD)		?	"OK" : "NONE" ; OutString += "\r\n";
	OutString += "\tSUB\t\t";		OutString += IsFlag(dwCaps, D3DTEXOPCAPS_SUBTRACT)	?	"OK" : "NONE" ; OutString += "\r\n";
	OutString += "\tMODULATE\t";	OutString += IsFlag(dwCaps, D3DTEXOPCAPS_MODULATE)	?	"OK" : "NONE" ; OutString += "\r\n";
	OutString += "\tSELECTARG1\t";	OutString += IsFlag(dwCaps, D3DTEXOPCAPS_SELECTARG1)	?	"OK" : "NONE" ; OutString += "\r\n";
	OutString += "\tSELECTARG2\t";	OutString += IsFlag(dwCaps, D3DTEXOPCAPS_SELECTARG2)	?	"OK" : "NONE" ; OutString += "\r\n";
	
	
	{
		OutString += "ShaderVersion\r\n";

		char buf[256];
		sprintf( buf, "\tVertexShader %x\r\n", DeviceCaps.VertexShaderVersion );
		OutString += buf;
		sprintf( buf, "\tPixelShader %x\r\n", DeviceCaps.PixelShaderVersion );
		OutString += buf;
	}

	return CString::ConvertSJIStoMAID(OutString);
}


}

