#pragma once

#include "enumD3DFormat.h"
#include "enumTransformState.h"
#include "enumTextureStageState.h"
#include "enumRenderState.h"
#include "valDisplayMode.h"
#include "valMatrix.h"
#include "共通\CritSec.h"

namespace FDK
{
	// アプリとカスタムプレゼンタの両方から必要とされる共通機能をMixedC++クラスとして実装したもの。
	// プレゼンタからもアクセス可能にするために static クラスとしている。
	// Managed アプリからは、これをラップする CDirect3D クラスを使用すること。
	private class CDirect3DNative abstract sealed
	{
	public:
		static void t初期化( SIZE sz描画サイズ原寸px );
		static void t終了();

		// 呼び出し側では、作成前にリソースを解放し、作成後に復元すること。また、必要あれば CMediaSession の EVR 通知も行うこと。
		static void tデバイスを作成する( HWND hWindow, bool b全画面モード, int nWidth, int nHeight, bool b垂直帰線同期を待つ );
		static void tデバイスを再構築する();
		static void tデバイス作成パラメータを取得する( _In_ bool b全画面モード, _In_ int nWidth, _In_ int nHeight, _Out_ D3DPRESENT_PARAMETERS* pPP, _Out_ D3DDISPLAYMODEEX* pDM );

		// ロックしたデバイスへのポインタと、新しく発行されたハンドルへのポインタを返す。
		// ppDeviceEx = NULL の場合は、ポインタを返さない（ので、CDirect3DNative::pD3DDevice9Ex を使うこと）。
		static void tデバイスをロックする( bool bBlock, [Out] HANDLE *phDevice, [Out] IDirect3DDevice9Ex **ppDeviceEx );
		
		// デバイスをロックした状態のハンドルを渡さないと例外発生。
		static void tデバイスのロックを解除する( HANDLE &hLockedDevice );

		// 現在のデバイスの状態を返す。戻り値は、以下のいずれか、その他のエラーコードになる。
		//   D3D_OK
		//   D3DERR_DEVICELOST			デバイスが失われたが、この時点ではリセットできない。アプリは、リソースを破棄し、デバイスを破棄し、終了し、Reset する必要がある。
		//   D3DERR_DEVICEHUNG			ハードウェアアダプターが OS によってリセットされた。アプリは、リソースを破棄し、デバイスを破棄し、終了し、Reset する必要がある。
		//   D3DERR_DEVICEREMOVED		ハードウェアアダプターが削除された。アプリは、デバイスを破棄し、アダプターを列挙し、別のアダプタのデバイスを作成する必要がある。
		//   D3DERR_OUTOFVIDEOMEMORY	Direct3D が処理を行ううえで十分なディスプレイメモリーがない。リソースを減らすこと。
		//   S_PRESENT_MODE_CHANGED		デスクトップの表示モードが変更された。アプリはレンダリングを継続できるが、色変換/伸縮が発生している場合がある。Reset するとこの状態から抜ける。
		//   S_PRESENT_OCCLUDED			描画ウィンドウが最小化されるか、同じモニター上で別のデバイスが全画面モードに入った。アプリはレンダリングを停止し、S_OK または S_PRESENT_MODE_CHANGED が返されるまで IDirect3DDevice9Ex::CheckDeviceState を呼び出し続けるのが望ましい。
		static HRESULT tデバイスの状態を取得する();								// 内部でデバイスをロックする。
		static HRESULT tデバイスの状態を取得する( HANDLE hLockedDevice );		// ロック済みの場合はこちら。

		static void tデバイスをクリアする();							// 内部でデバイスをロックする。
		static void tデバイスをクリアする( HANDLE hLockedDevice );		// ロック済みの場合はこちら。

		static void tデバイスをリセットする();							// 内部でデバイスをロックする。
		static void tデバイスをリセットする( HANDLE hLockedDevice );	// ロック済みの場合はこちら。

		static List<DisplayMode>^ tフォーマットに対応するディスプレイモードを取得する( HWND hWindow, D3DFormat format );	// Direct3DDevice9Ex は関係無し。

		static void tデバイスをデバイスマネージャーに登録する();
		static void tデバイスをデバイスマネージャーに登録する( IDirect3DDevice9Ex* pDeviceEx );

		// ステート関連
		static void SetTransform( TransformState state, Matrix value );
		
		static void SetRenderState( RenderState state, int value );
		static void SetRenderState( RenderState state, bool value );
		static void SetRenderState( RenderState state, float value );
		generic< typename T >
		static void SetRenderState( RenderState state, T value );
		
		static void SetTextureStageState( int stage, TextureStageState state, int value );
		static void SetTextureStageState( int stage, TextureStageState state, bool value );
		static void SetTextureStageState( int stage, TextureStageState state, float value );
		generic< typename T >
		static void SetTextureStageState( int stage, TextureStageState state, T value );


		// FDK内部から……というか、プレゼンタ、テクスチャからのアクセス用。

		static IDirect3D9Ex *GetDirect3DEx();
		static IDirect3DDeviceManager9 *GetDirect3DDeviceManager();
		static IDirect3DDevice9Ex *GetDirect3DDevice9Ex();
		static D3DDISPLAYMODE GetDirect3DDisplayMode();
		
		// その他。これはプレゼンタやテクスチャ以外からもアクセスされる。

		static D3DVIEWPORT9 GetViewPort();


	private:
		static HWND hWindow;				// 初期化時のパラメータを保存。
		static Atom<bool> b全画面モード;	//
		static bool b垂直帰線同期を待つ;	// 
		static SIZE sz描画サイズ原寸px;		//
		static SIZE sz表示サイズpx;			//

		static IDirect3D9Ex *pDirect3D9Ex;
		static UINT nDeviceResetToken;
		static IDirect3DDeviceManager9 *pD3DDeviceManager9;
		static IDirect3DDevice9Ex *pD3DDevice9Ex;
		static D3DDISPLAYMODE *pDisplayMode;
		static D3DVIEWPORT9 viewPort;
		static UINT uアダプタID;
		static DWORD dwデバイスを作成したスレッドのID;

		static UINT tモニタに対応するアダプタを取得する( IDirect3D9Ex *pD3D9, HMONITOR hMonitor );
	};
}