DirectX11の初期化

DirectX11を触り始めたのでメモ書きに書いておきます。
Windows7以降であれば動くと思います。
多少説明をしていますがわからないところは説明がないです。
動かなければコメント、Twitterで報告していただけると助かります。

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")

#include <tchar.h>
#include <Windows.h>
#include <D3D11.h>
#include <D3DX11.h>
#include <DxErr.h>

#define SAFE_RELEASE(x) { if(x){ (x)->Release(); (x)=nullptr; } }

#define WINDOW_W 640
#define WINDOW_H 480

// ウィンドウ
HWND g_HWnd;

// 機能レベル
D3D_FEATURE_LEVEL	g_pFeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0 };
UINT			g_FeatureLevels    = 3;	  // 配列の要素数
D3D_FEATURE_LEVEL	g_FeatureLevelsSupported; // デバイス作成時に返される機能レベル

// インターフェイス
ID3D11Device*		g_pD3DDevice        = nullptr;	// デバイス
ID3D11DeviceContext*	g_pImmediateContext = nullptr;	// デバイス・コンテキスト
IDXGISwapChain*		g_pSwapChain        = nullptr;	// スワップ・チェイン

ID3D11RenderTargetView*	g_pRenderTargetView = nullptr;	// 描画ターゲット・ビュー
D3D11_VIEWPORT		g_ViewPort[1];			// ビューポート
ID3D11Texture2D*	g_pDepthStencil;		// 深度/ステンシル・テクスチャを受け取る変数
ID3D11DepthStencilView*	g_pDepthStencilView = nullptr;		// 深度/ステンシルビュー

void InitWindow();	 // ウィンドウ生成
HRESULT InitD3D();	 // D3D初期化
void CleanupD3D();	 // D3D後処理
bool DeviceRemoveProc(); // デバイス消失処理

void Clear();            // 画面クリア
HRESULT Flip();          // 画面表示

// エントリポイント
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	InitWindow();
	ShowWindow(g_HWnd, SW_SHOWDEFAULT);
	UpdateWindow(g_HWnd);

	if (FAILED(InitD3D()))
	{
		return 0;
	}

	MSG msg = {};
	ZeroMemory(&msg, sizeof(msg));
	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			// デバイス消失処理
			if (DeviceRemoveProc()) break;

			// ゲームループ
			Clear();

			Flip();
		}
	}

	// 解放
	CleanupD3D();

	return 0;
}

// ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

// ウィンドウ生成
void InitWindow()
{
	WNDCLASSEX wc = {
		sizeof(WNDCLASSEX),
		CS_CLASSDC,
		WindowProc,
		0L,
		0L,
		GetModuleHandle(NULL),
		NULL,
		NULL, 
		NULL,
		NULL,
		L"sample",
		NULL
	};
	RegisterClassEx(&wc);

	g_HWnd = CreateWindow(L"sample", L"DirectX11 sample" , WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_W, WINDOW_H, NULL, NULL, wc.hInstance, NULL);
}

// D3D初期化
HRESULT InitD3D()
{
	HRESULT hr = S_OK;

	DXGI_SWAP_CHAIN_DESC sd;
	ZeroMemory(&sd, sizeof(sd));
	sd.BufferCount          = 1;		// バックバッファの数
	sd.BufferDesc.Width     = WINDOW_W;	// バックバッファの幅
	sd.BufferDesc.Height    = WINDOW_H;	// バックバッファの高さ
	sd.BufferDesc.Format    = DXGI_FORMAT_R8G8B8A8_UNORM; // フォーマット
	sd.BufferDesc.RefreshRate.Numerator	= 60;	// リフレッシュレート(分子)
	sd.BufferDesc.RefreshRate.Denominator   = 1;	// リフレッシュレート(分母)
	sd.BufferDesc.ScanlineOrdering  = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	sd.BufferDesc.Scaling           = DXGI_MODE_SCALING_UNSPECIFIED;
	sd.BufferUsage		= DXGI_USAGE_RENDER_TARGET_OUTPUT; // バックバッファの使用方法
	sd.OutputWindow		= g_HWnd;	// 関連付けるウィンドウ
	sd.SampleDesc.Count	= 1;		// マルチサンプルの数
	sd.SampleDesc.Quality	= 0;		// マルチサンプルのクオリティ
	sd.Windowed		= TRUE;		// ウィンドウモード
	sd.Flags		= DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // モード自動切り替え

	// デバイスとスワップチェインの作成
	hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, g_pFeatureLevels, 1, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pD3DDevice, NULL, &g_pImmediateContext);
	if (FAILED(hr))
	{
		hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0, g_pFeatureLevels, 1, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pD3DDevice, NULL, &g_pImmediateContext);
		if (FAILED(hr))
		{
			hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, 0, g_pFeatureLevels, 1, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pD3DDevice, NULL, &g_pImmediateContext);
			if (FAILED(hr))
				return E_FAIL;
		}
	}
	

	// バックバッファを描画ターゲットに設定
	// スワップチェインから最初のバックバッファを取得する
	ID3D11Texture2D* pBackBuffer; // バッファのアクセスに使うインターフェイス(バッファを2Dテクスチャとして扱う)
	hr = g_pSwapChain->GetBuffer(
		0,				// バックバッファのバン某
		__uuidof(ID3D11Texture2D),	// バッファにアクセスするインターフェイス
		(LPVOID*)&pBackBuffer		// バッファを受け取る変数
	);
	if (FAILED(hr))
		return E_FAIL;

	// バックバッファの描画ターゲットビューを作る
	hr = g_pD3DDevice->CreateRenderTargetView(
		pBackBuffer,			// ビューでアクセスするリソース
		NULL,				// 描画ターゲットビューの定義
		&g_pRenderTargetView            // 描画ターゲットビューを受け取る変数
	);
	if (FAILED(hr))
		return E_FAIL;

	// 描画ターゲットビューを出力マージャーの描画ターゲットとして設定
	g_pImmediateContext->OMSetRenderTargets(
		1,			        // 描画ターゲットの数
		&g_pRenderTargetView,	        // 描画ターゲットビューの配列
		NULL			        // 深度/ステンシルビューを設定しない
	);

	// ビューポートの設定(描画領域)
	g_ViewPort[0].TopLeftX	= 0.0f;		// ビューポート領域の左上X座標
	g_ViewPort[0].TopLeftY	= 0.0f;		// ビューポート領域の左上Y座標
	g_ViewPort[0].Width	= WINDOW_W;	// ビューポート領域の幅
	g_ViewPort[0].Height	= WINDOW_H;	// ビューポート領域の高さ
	g_ViewPort[0].MinDepth	= 0.0f;		// ビューポート領域の深度値の最小値
	g_ViewPort[0].MaxDepth	= 1.0f;		// ビューポート領域の深度値の最大値
	// ラスタライザにビューポートを設定
	g_pImmediateContext->RSSetViewports(1, g_ViewPort);

	// 深度/ステンシル・テクスチャの作成
	D3D11_TEXTURE2D_DESC descDepth;
	descDepth.Width		= WINDOW_W;     // 幅
	descDepth.Height	= WINDOW_H;	// 高さ
	descDepth.MipLevels	= 1;		// ミップマップ レベル数
	descDepth.ArraySize	= 1;		// 配列サイズ
	descDepth.Format	= DXGI_FORMAT_D32_FLOAT; // フォーマット(深度のみ)
	descDepth.SampleDesc.Count	= 1;    // マルチサンプリングの設定
	descDepth.SampleDesc.Quality	= 0;    // マルチサンプリングの品質
	descDepth.Usage			= D3D11_USAGE_DEFAULT;		// 使用方法 デフォルト
	descDepth.BindFlags		= D3D11_BIND_DEPTH_STENCIL;	// 深度/ステンシルとして使用
	descDepth.CPUAccessFlags	= 0;    // CPUからアクセスしない
	descDepth.MiscFlags		= 0;    // その他の設定なし
	hr = g_pD3DDevice->CreateTexture2D(
		&descDepth,		// 作成する2Dテクスチャ
		NULL,			// 
		&g_pDepthStencil	// 作成したテクスチャを受け取る
	);
	if (FAILED(hr))
		return E_FAIL;

	// 深度/ステンシルビューの作成
	D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
	descDSV.Format = descDepth.Format;
	descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	descDSV.Flags = 0;
	descDSV.Texture2D.MipSlice = 0;
	hr = g_pD3DDevice->CreateDepthStencilView(
		g_pDepthStencil,	// 深度/ステンシルビューを作るテクスチャ
		&descDSV,		// 深度/ステンシルビューの設定
		&g_pDepthStencilView	// 作成したビューを受け取る
	);
	if (FAILED(hr))
		return E_FAIL;

	return S_OK;
}

// 後処理
void CleanupD3D()
{
	// ステートのクリア
	if (g_pImmediateContext)
		g_pImmediateContext->ClearState();

	// インターフェイスの解放
	SAFE_RELEASE(g_pDepthStencilView);
	SAFE_RELEASE(g_pDepthStencil);
	SAFE_RELEASE(g_pRenderTargetView);
	SAFE_RELEASE(g_pSwapChain);
	SAFE_RELEASE(g_pImmediateContext);
	SAFE_RELEASE(g_pD3DDevice);
}
// デバイス消失処理
bool DeviceRemoveProc()
{
	HRESULT hr = g_pD3DDevice->GetDeviceRemovedReason();
	switch (hr)
	{
	case S_OK:
		break;
	case DXGI_ERROR_DEVICE_HUNG:
	case DXGI_ERROR_DEVICE_RESET:
		CleanupD3D();
		hr = InitD3D();
		if (FAILED(hr))
			return true;
	case DXGI_ERROR_DEVICE_REMOVED:
	case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
	case DXGI_ERROR_INVALID_CALL:
	default:
		return true;
	}

	return false;
}

// クリア
void Clear()
{
	// 描画ターゲットのクリア
	float clearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // クリアする値
	g_pImmediateContext->ClearRenderTargetView(
		g_pRenderTargetView,	// クリアする描画ターゲット
		clearColor		// クリアする値
	);

	// 深度/ステンシル値のクリア
	g_pImmediateContext->ClearDepthStencilView(
		g_pDepthStencilView,	// クリアする深度/ステンシルビュー
		D3D11_CLEAR_DEPTH,	// 深度値だけクリアする
		1.0f,			// 深度バッファをクリアする値
		0			// ステンシルバッファをクリアする値(今回は関係なし)
	);
}
// 描画
HRESULT Flip()
{
	// バックバッファの表示
	HRESULT hr = g_pSwapChain->Present(
		0,	// 画面をすぐに更新する
		0	// 画面を実際に更新する
	);

	return hr;
}