//----------------------------------------------------------
// フルスクリーン切り替え ( Alt + Enter )
//--------------------------------------------------------------
#include <windows.h>
#include <d3dx9.h>
#include <dxerr9.h>
#define RELEASE(x) if(x){x->Release();x=NULL;}
HINSTANCE g_hInstance = NULL; // インスタンス・ハンドル
HWND g_hWindow = NULL; // ウインドウ・ハンドル
HMENU g_hMenu = NULL; // メニュー・ハンドル
LPCSTR g_szAppTitle = "DirectX9 Screen Change";
LPCSTR g_szWndClass = "Window1";
RECT g_rectWindow; // ウインドウ・モードでの最後の位置
// 起動時の描画領域サイズ
bool g_bWindow = true; // 起動時の画面モード
SIZE g_sizeWindowMode = { 640, 480 }; // ウインドウ・モード
SIZE g_sizeFullMode = { 640, 480 }; // フルスクリーン・モード
D3DFORMAT g_formatFull = D3DFMT_X8R8G8B8; //
ディスプレイ(バック・バッファ)・フォーマット
// アプリケーションの動作フラグ
bool g_bActive = false; // アクティブ状態
/*-------------------------------------------
グローバル変数(DirectX関連)
--------------------------------------------*/
// インターフェイス
LPDIRECT3D9 g_pD3D = NULL; // Direct3Dインターフェイス
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL; // Direct3DDeviceインターフェイス
D3DPRESENT_PARAMETERS g_D3DPP; // D3DDeviceの設定(現在)
D3DPRESENT_PARAMETERS g_D3DPPWindow; //
D3DDeviceの設定(ウインドウ・モード用)
D3DPRESENT_PARAMETERS g_D3DPPFull; // D3DDeviceの設定(フルスクリーン・モード用)
bool g_bDeviceLost = false; // デバイスの消失フラグ
/*-------------------------------------------
関数定義
--------------------------------------------*/
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT msg,UINT
wParam,LONG lParam);
/*-------------------------------------------
アプリケーション初期化(最初に一度だけ呼ばれる)
--------------------------------------------*/
HRESULT InitApp(HINSTANCE hInst)
{
// アプリケーションのインスタンス・ハンドルを保存
g_hInstance = hInst;
// IMEを禁止する
ImmDisableIME(-1); // このスレッドで禁止
// ウインドウ・クラスの登録
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)MainWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInst;
wcex.hIcon = NULL;
wcex.hIconSm = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = g_szWndClass;
if (!RegisterClassEx(&wcex))
return DXTRACE_ERR("InitApp", GetLastError());
// メイン・ウインドウ作成
g_rectWindow.top = 0;
g_rectWindow.left = 0;
g_rectWindow.right = g_sizeWindowMode.cx;
g_rectWindow.bottom = g_sizeWindowMode.cy;
AdjustWindowRect(&g_rectWindow, WS_OVERLAPPEDWINDOW, FALSE);
g_rectWindow.right = g_rectWindow.right - g_rectWindow.left;
g_rectWindow.bottom = g_rectWindow.bottom - g_rectWindow.top;
g_rectWindow.top = 0;
g_rectWindow.left = 0;
RECT rect;
if (g_bWindow)
{
// (ウインドウ・モード用)
rect.top = CW_USEDEFAULT;
rect.left = CW_USEDEFAULT;
rect.right = g_rectWindow.right;
rect.bottom = g_rectWindow.bottom;
}
else
{
// (フルスクリーン・モード用)
rect.top = 0;
rect.left = 0;
rect.right = g_sizeFullMode.cx;
rect.bottom = g_sizeFullMode.cy;
//g_hMenu = LoadMenu(g_hInstance,
MAKEINTRESOURCE(IDR_MENU1));
}
g_hWindow = CreateWindow(g_szWndClass, g_szAppTitle,
g_bWindow ? WS_OVERLAPPEDWINDOW : WS_POPUP,
rect.left, rect.top, rect.right, rect.bottom,
NULL, NULL, hInst, NULL);
if (g_hWindow == NULL)
return DXTRACE_ERR("InitApp", GetLastError());
// ウインドウ表示
ShowWindow(g_hWindow, SW_SHOWNORMAL);
UpdateWindow(g_hWindow);
return S_OK;
}
/*-------------------------------------------
DirectX Graphics初期化
--------------------------------------------*/
HRESULT InitDXGraphics(void)
{
// Direct3Dオブジェクトの作成
g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (g_pD3D == NULL)
return DXTRACE_ERR("InitDXGraphics Direct3DCreate9", E_FAIL);
// D3DDeviceオブジェクトの設定(ウインドウ・モード用)
ZeroMemory(&g_D3DPPWindow, sizeof(g_D3DPPWindow));
g_D3DPPWindow.BackBufferWidth = 0;
g_D3DPPWindow.BackBufferHeight = 0;
g_D3DPPWindow.BackBufferFormat = D3DFMT_UNKNOWN;
g_D3DPPWindow.BackBufferCount = 1;
g_D3DPPWindow.MultiSampleType = D3DMULTISAMPLE_NONE;
g_D3DPPWindow.MultiSampleQuality = 0;
g_D3DPPWindow.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_D3DPPWindow.hDeviceWindow = g_hWindow;
g_D3DPPWindow.Windowed = TRUE;
g_D3DPPWindow.EnableAutoDepthStencil = FALSE;
g_D3DPPWindow.AutoDepthStencilFormat = D3DFMT_A1R5G5B5;
g_D3DPPWindow.Flags = 0;
g_D3DPPWindow.FullScreen_RefreshRateInHz= 0;
g_D3DPPWindow.PresentationInterval =
D3DPRESENT_INTERVAL_IMMEDIATE;
// D3DDeviceオブジェクトの設定(フルスクリーン・モード)
ZeroMemory(&g_D3DPPFull, sizeof(g_D3DPPFull));
g_D3DPPFull.BackBufferWidth = g_sizeFullMode.cx;
g_D3DPPFull.BackBufferHeight = g_sizeFullMode.cy;
g_D3DPPFull.BackBufferFormat = g_formatFull;
g_D3DPPFull.BackBufferCount = 1;
g_D3DPPFull.MultiSampleType = D3DMULTISAMPLE_NONE;
g_D3DPPFull.MultiSampleQuality = 0;
g_D3DPPFull.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_D3DPPFull.hDeviceWindow = g_hWindow;
g_D3DPPFull.Windowed = FALSE;
g_D3DPPFull.EnableAutoDepthStencil = FALSE;
g_D3DPPFull.AutoDepthStencilFormat = D3DFMT_A1R5G5B5;
g_D3DPPFull.Flags = 0;
g_D3DPPFull.FullScreen_RefreshRateInHz = 0;
g_D3DPPFull.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// D3DDeviceオブジェクトの作成
if (g_bWindow)
g_D3DPP = g_D3DPPWindow;
else
g_D3DPP = g_D3DPPFull;
HRESULT hr = g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, g_hWindow,
D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_D3DPP,
&g_pD3DDevice);
if (FAILED(hr))
{
hr = g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF,
g_hWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPP,
&g_pD3DDevice);
if (FAILED(hr))
return DXTRACE_ERR("InitDXGraphics CreateDevice", hr);
}
// ビューポートの設定
D3DVIEWPORT9 vp;
vp.X = 0;
vp.Y = 0;
vp.Width = g_D3DPP.BackBufferWidth;
vp.Height = g_D3DPP.BackBufferHeight;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
hr = g_pD3DDevice->SetViewport(&vp);
if (FAILED(hr))
return DXTRACE_ERR("InitDXGraphics SetViewport", hr);
return S_OK;
}
/*--------------------------------------------
画面の描画処理
--------------------------------------------*/
HRESULT Render(void)
{
// シーンのクリア
g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 255, 255),
1.0f, 0);
// シーンの描画開始
if (SUCCEEDED(g_pD3DDevice->BeginScene()))
{
// シーンの描画終了
g_pD3DDevice->EndScene();
}
// シーンの表示
return g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}
/*-------------------------------------------
ウインドウ・サイズの変更
--------------------------------------------*/
HRESULT ChangeWindowSize(void)
{
// ウインドウのクライアント領域に合わせる
HRESULT hr = g_pD3DDevice->Reset(&g_D3DPP);
if (FAILED(hr))
{
if (hr == D3DERR_DEVICELOST)
g_bDeviceLost = true;
else
DestroyWindow(g_hWindow);
return DXTRACE_ERR("ChangeWindowSize Reset", hr);
}
// ビューポートの設定
D3DVIEWPORT9 vp;
vp.X = 0;
vp.Y = 0;
vp.Width = g_D3DPP.BackBufferWidth;
vp.Height = g_D3DPP.BackBufferHeight;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
hr = g_pD3DDevice->SetViewport(&vp);
if (FAILED(hr))
{
DXTRACE_ERR("ChangeWindowSize SetViewport", hr);
DestroyWindow(g_hWindow);
}
return hr;
}
/*-------------------------------------------
画面モードの変更
--------------------------------------------*/
void ChangeDisplayMode(void)
{
g_bWindow = !g_bWindow;
if (g_bWindow)
{
g_D3DPP = g_D3DPPWindow;
}
else
{
g_D3DPP = g_D3DPPFull;
GetWindowRect(g_hWindow, &g_rectWindow);
}
HRESULT hr = g_pD3DDevice->Reset(&g_D3DPP);
if (FAILED(hr))
{
if (hr == D3DERR_DEVICELOST)
g_bDeviceLost = true;
else
DestroyWindow(g_hWindow);
DXTRACE_ERR("ChangeDisplayMode Reset", hr);
return;
}
if (g_bWindow)
{
SetWindowLong(g_hWindow, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
if(g_hMenu != NULL)
{
SetMenu(g_hWindow, g_hMenu);
g_hMenu = NULL;
}
SetWindowPos(g_hWindow, HWND_NOTOPMOST,
g_rectWindow.left, g_rectWindow.top,
g_rectWindow.right - g_rectWindow.left,
g_rectWindow.bottom - g_rectWindow.top,
SWP_SHOWWINDOW);
}
else
{
SetWindowLong(g_hWindow, GWL_STYLE, WS_POPUP | WS_VISIBLE);
if(g_hMenu == NULL)
{
g_hMenu = GetMenu(g_hWindow);
SetMenu(g_hWindow, NULL);
}
}
}
/*-------------------------------------------
DirectX Graphicsの終了処理(初期化に失敗したときも呼ばれる)
--------------------------------------------*/
bool CleanupDXGraphics(void)
{
RELEASE(g_pD3DDevice);
RELEASE(g_pD3D);
return true;
}
/*-------------------------------------------
アプリケーションの終了処理(最後に呼ばれる)
--------------------------------------------*/
bool CleanupApp(void)
{
// メニュー・ハンドルの削除
if (g_hMenu)
DestroyMenu(g_hMenu);
// ウインドウ・クラスの登録解除
UnregisterClass(g_szWndClass, g_hInstance);
return true;
}
/*-------------------------------------------
ウィンドウ処理
--------------------------------------------*/
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, UINT wParam, LONG lParam)
{
HRESULT hr = S_OK;
switch(msg)
{
case WM_ACTIVATE:
g_bActive = (LOWORD(wParam) != 0);
break;
case WM_DESTROY:
// DirectX Graphicsの終了処理
CleanupDXGraphics();
// ウインドウを閉じる
PostQuitMessage(0);
g_hWindow = NULL;
return 0;
// ウインドウ・サイズの変更処理
case WM_SIZE:
if (g_D3DPP.Windowed != TRUE)
break;
if (!g_pD3DDevice || wParam == SIZE_MINIMIZED)
break;
g_D3DPP.BackBufferWidth = LOWORD(lParam);
g_D3DPP.BackBufferHeight = HIWORD(lParam);
if(g_bDeviceLost)
break;
if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
ChangeWindowSize();
break;
case WM_SETCURSOR:
if (g_D3DPP.Windowed != TRUE)
{
SetCursor(NULL);
return 1;
}
break;
case WM_KEYDOWN:
// キー入力の処理
switch(wParam)
{
case VK_ESCAPE: // [ESCAPE]キーでウインドウを閉じる
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
}
break;
case WM_SYSKEYDOWN: // Alt + 特殊キーの処理に使う
switch(wParam)
{
case VK_RETURN: // Alt + Enterを押すと切り替え
ChangeDisplayMode();
break;
default:
break;
}
break;
}
// デフォルト処理
return DefWindowProc(hWnd, msg, wParam, lParam);
}
/*--------------------------------------------
アイドル時の処理
--------------------------------------------*/
bool AppIdle(void)
{
if (!g_pD3D || !g_pD3DDevice)
return false;
if (!g_bActive)
return true;
// 消失したデバイスの復元処理
HRESULT hr;
if (g_bDeviceLost)
{
Sleep(100); // 0.1秒待つ
// デバイス状態のチェック
hr = g_pD3DDevice->TestCooperativeLevel();
if (FAILED(hr))
{
if (hr == D3DERR_DEVICELOST)
return true; // デバイスはまだ失われている
if (hr != D3DERR_DEVICENOTRESET)
return false; // 予期せぬエラー
hr = g_pD3DDevice->Reset(&g_D3DPP); // 復元を試みる
if (FAILED(hr))
{
if (hr == D3DERR_DEVICELOST)
return true; // デバイスはまだ失われている
DXTRACE_ERR("AppIdle Reset", hr);
return false; // デバイスの復元に失敗
}
}
// デバイスが復元した
g_bDeviceLost = false;
}
// 画面の更新
hr = Render();
if (hr == D3DERR_DEVICELOST)
g_bDeviceLost = true; // デバイスの消失
else if (FAILED(hr))
return false;
return true;
}
/*--------------------------------------------
メイン
---------------------------------------------*/
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int
nCmdShow)
{
// アプリケーションに関する初期化
HRESULT hr = InitApp(hInst);
if (FAILED(hr))
{
DXTRACE_ERR("WinMain InitApp", hr);
return 0;
}
// DirectX Graphicsの初期化
hr = InitDXGraphics();
if (FAILED(hr))
DXTRACE_ERR("WinMain InitDXGraphics", hr);
// メッセージ・ループ
MSG msg;
do
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// アイドル処理
if (!AppIdle())
// エラーがある場合,アプリケーションを終了する
DestroyWindow(g_hWindow);
}
} while (msg.message != WM_QUIT);
// アプリケーションの終了処理
CleanupApp();
return msg.wParam;
}
|