Directx入門してみた１


#Directxでウィンドウ作成

メモです。

DXAppクラスでは初期化、更新、描画してます。
DXUtilヘッダーには解放の処理があります。


```cpp:DXApp.h
#pragma once
#define WIN32_LEAN_AND_MEAN
//WIN32_LEAN_AND_MEAN を #define することで
//余計なヘッダファイルは include されず、コンパイルはすばやく終わるらしい
#include<windows.h>
#include<tchar.h>
#include<string>
#include"DXUtil.h"

class DXApp {
public:
	DXApp(HINSTANCE hInstance,int showCmd);
	virtual ~DXApp();

	int Run();

	virtual bool Init();
	virtual void Update(float dt) = 0;
	virtual void Render(float dt) = 0;
	virtual LRESULT MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    //Window
	HWND			m_hAppWnd;
	HINSTANCE		m_hAppInstance;
	UINT			m_ClientWidth;
	UINT			m_ClientHeight;
	std::string		m_AppTitle;
	DWORD			m_WndStyle;
	int				m_Show;
	const int		WINDOW_WIDTH = 800;
	const int		WINDOW_HEIGHT = 600;
	//DIREDCTX
	ID3D11Device*			m_pDevice;
	ID3D11DeviceContext*	m_pImmediateContext;
	IDXGISwapChain*			m_pSwapChain;
	ID3D11RenderTargetView* m_pRenderTargetView;
	D3D_DRIVER_TYPE			m_DriverType;
	D3D_FEATURE_LEVEL		m_FeatureLevel;
	D3D11_VIEWPORT			m_Viewport;

protected:
	bool InitWindow();   //Windowの初期化
	bool InitDirect3D(); //Directxの初期化
};
```


```cpp:
#include "DXApp.h"

namespace {
	DXApp* g_pApp = nullptr;
}
//ウィンドウプロシージャ
//ウィンドウプロシージャは、メッセージを処理する専用のルーチンです。
static LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	
	if (g_pApp)
		return g_pApp->MsgProc(hWnd, msg, wParam, lParam);
	else
		return DefWindowProc(hWnd, msg, wParam, lParam);
}


DXApp::DXApp(HINSTANCE hInstance,int showCmd)
{
    //Window
	m_hAppInstance = hInstance;
	m_Show = showCmd;
	m_hAppWnd = NULL;
	m_AppTitle = "TUTORIAL";
	m_WndStyle = WS_OVERLAPPEDWINDOW;
	m_ClientWidth = this->WINDOW_WIDTH;
	m_ClientHeight = this->WINDOW_HEIGHT;
	g_pApp = this;
    //Directx
	m_pDevice = nullptr;
	m_pImmediateContext = nullptr;
	m_pRenderTargetView = nullptr;
	m_pSwapChain = nullptr;

}
//解放処理
DXApp::~DXApp() {
	if (m_pImmediateContext) {
		m_pImmediateContext->ClearState();
	}
	Memory::Saferelease(m_pRenderTargetView);
	Memory::Saferelease(m_pSwapChain);
	Memory::Saferelease(m_pImmediateContext);
	Memory::Saferelease(m_pDevice);
}
//初期化処理
bool DXApp::Init() {
	if (!InitWindow()) {
		return false;
	}
	if (!InitDirect3D()) {
		return false;
	}
	return true;
}
//Windowの初期化
bool DXApp::InitWindow() {
	WNDCLASSEX wc;                                    
	wc.cbSize = sizeof(WNDCLASSEX);//構造体のサイズ
	wc.style = CS_HREDRAW | CS_VREDRAW;//ウインドウスタイル
	wc.lpfnWndProc = MainWndProc;     //そのウインドウのメッセージを処理するコールバック関数へのポインタ
	wc.cbClsExtra = 0;//ウインドウクラス構造体の後ろに割り当てる補足バイト数
	wc.cbWndExtra = 0;//ウインドウインスタンスの後ろに割り当てる補足バイト数
	wc.hInstance = m_hAppInstance;//インスタンスハンドル
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//アイコンのハンドル
	wc.hIconSm = 0;//16×16の小さいサイズのアイコン
	wc.hCursor = LoadCursor(NULL, IDI_APPLICATION);//マウスカーソルのハンドル
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);//ウインドウ背景色
	wc.lpszMenuName = NULL;//デフォルトメニュー名
	wc.lpszClassName = _T("DefaultWindowClass");//このウインドウクラスにつける名前
	if (!RegisterClassEx(&wc)) {//Windowクラスを登録
		OutputDebugString("\nFAILED TO CREATE WINDOW CLASS\n");
		return false;
	}
     //windowの作成
	m_hAppWnd = CreateWindowEx(
		WS_EX_COMPOSITED,
		_T("DefaultWindowClass"),
		m_AppTitle.c_str(),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		m_ClientWidth,
		m_ClientHeight,
		NULL,
		NULL,
		m_hAppInstance,
		NULL);

	if (!m_hAppWnd) {
		OutputDebugString("\nFAILED TO CREATE WINDOW\n");
		return false;
	}
     //指定されたウィンドウの表示状態を設定します。
	ShowWindow(m_hAppWnd, m_Show);

	return true;

}
//Directxの初期化
bool DXApp::InitDirect3D()
{
	UINT createDeviceFlags = 0;
#ifdef _DEBUG
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif // _DEBUG

	const D3D_DRIVER_TYPE driverTypes[] {
		D3D_DRIVER_TYPE_HARDWARE,
		D3D_DRIVER_TYPE_WARP,
		D3D_DRIVER_TYPE_REFERENCE
	};
	UINT numDriverTypes = ARRAYSIZE(driverTypes);

	const D3D_FEATURE_LEVEL featureLevels[] {
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_9_3
	};

	UINT numFeatureLevels = ARRAYSIZE(featureLevels);

	DXGI_SWAP_CHAIN_DESC swapDesc;
	ZeroMemory(&swapDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
	swapDesc.BufferCount = 1;
	swapDesc.BufferDesc.Width = m_ClientWidth;
	swapDesc.BufferDesc.Height = m_ClientHeight;
	swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	swapDesc.BufferDesc.RefreshRate.Numerator = 60;
	swapDesc.BufferDesc.RefreshRate.Denominator = 1;
	swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapDesc.OutputWindow = m_hAppWnd;
	swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	swapDesc.Windowed = true;
	swapDesc.SampleDesc.Count = 1;
	swapDesc.SampleDesc.Quality = 0;
	swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
	
	HRESULT result;
	for (int i = 0; i < numDriverTypes; ++i) {
		result = D3D11CreateDeviceAndSwapChain(
		NULL, 
		driverTypes[i],
 		NULL, 
		createDeviceFlags,
		featureLevels, 
		numFeatureLevels, 
		D3D11_SDK_VERSION, 
		&swapDesc,
 		&m_pSwapChain,
 		&m_pDevice,
		&m_FeatureLevel,
		&m_pImmediateContext
);
		if (SUCCEEDED(result)) {
			m_DriverType = driverTypes[i];
			break;
		}
	}
	if (FAILED(result)) {
		OutputDebugString("FAILED TO CREATE DEVICE AND SWAP CHAIN");
		return false;
	}
	
	//CREATE RENDER TARGET VIEW

	ID3D11Texture2D*	m_pBackBufferTex = 0;
	m_pSwapChain->GetBuffer(NULL, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&m_pBackBufferTex));
//
	m_pDevice->CreateRenderTargetView(m_pBackBufferTex, nullptr, &m_pRenderTargetView);

	//BIND RENDER TARGET VIEW

	m_pImmediateContext->OMSetRenderTargets(1, &m_pRenderTargetView, nullptr);

	//VIEWPORT CREATION
	m_Viewport.Width = static_cast<float>(m_ClientWidth);
	m_Viewport.Height = static_cast<float>(m_ClientHeight);
	m_Viewport.TopLeftX = 0;
	m_Viewport.TopLeftY = 0;
	m_Viewport.MinDepth = 0.0f;
	m_Viewport.MaxDepth = 1.0f;
	
	m_pImmediateContext->RSSetViewports(1, &m_Viewport);

	return true;
}
LRESULT DXApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	switch (msg)
	{
	case WM_KEYDOWN:
		if (wParam == VK_ESCAPE)
			PostQuitMessage(0);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}
}

void DXApp::Update(float dt) {

}
void DXApp::Render(float dt) {

}

int DXApp::Run() {
	MSG msg {};
	while (WM_QUIT != msg.message) {
		if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		} else {

			//Update
			Update(0.0f);

			//Render
			Render(0.0f);

		}
	}
	return 0;

}
```

##WNDCLASSEX
ウインドウを作成するための基本的な情報の集まり
[WNDCLASSEX](https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms633577(v=vs.85).aspx)
##ID3D11Device::CreateRenderTargetView
リソース データへのアクセス用にレンダー ターゲット ビューを作成します。
[ID3D11Device::CreateRenderTargetView](https://msdn.microsoft.com/ja-jp/library/ee419800(v=vs.85).aspx)
##RegisterClassEx
ウィンドウクラスを登録します
[RegisterClassEx](https://msdn.microsoft.com/ja-jp/library/cc410996.aspx)
##CreateWindowEx
windowを作成
[CreateWindowEx](https://msdn.microsoft.com/ja-jp/library/cc410714.aspx)
##ShowWindow
指定されたウィンドウの表示状態を設定します。
[ShowWindow](https://msdn.microsoft.com/ja-jp/library/cc411211.aspx)
##D3D_DRIVER_TYPE
ドライバの種類のオプション
[D3D_DRIVER_TYPE](https://msdn.microsoft.com/ja-jp/library/ee417659(v=vs.85).aspx)
##D3D_FEATURE_LEVEL 
Direct3D デバイスのターゲットとなる機能セットを記述します。
[D3D_FEATURE_LEVEL](https://msdn.microsoft.com/ja-jp/library/ee417660(v=vs.85).aspx)

##D3D11CreateDeviceAndSwapChain
ディスプレイ アダプターを表すデバイスとレンダリングに使用するスワップ チェーンを作成します。
[D3D11CreateDeviceAndSwapChain](https://msdn.microsoft.com/ja-jp/library/ee416033(v=vs.85).aspx)

##DXGI_SWAP_CHAIN_DESC 
スワップ チェーンを記述します。
[DXGI_SWAP_CHAIN_DESC](https://msdn.microsoft.com/ja-jp/library/bb173075(v=vs.85).aspx)

##ID3D11Texture2D
2D テクスチャー インターフェイスは、構造化されたメモリーであるテクセル データを管理します。
[ID3D11Texture2D](https://msdn.microsoft.com/ja-jp/library/ee420038(v=vs.85).aspx)

##IDXGISwapChain::GetBuffer
スワップ チェーン バック バッファーの 1 つにアクセスします。
[IDXGISwapChain::GetBuffer](https://msdn.microsoft.com/ja-jp/library/bb174570(v=vs.85).aspx)

##ID3D11DeviceContext::OMSetRenderTargets
1 つ以上のレンダー ターゲットをアトミックにバインドし、出力結合ステージに深度ステンシル バッファーをバインドします。
[ID3D11DeviceContext::OMSetRenderTargets](https://msdn.microsoft.com/ja-jp/library/ee419706(v=vs.85).aspx)

##ID3D11DeviceContext::RSSetViewports
パイプラインのラスタライザー ステージにビューポートの配列をバインドします。
[ID3D11DeviceContext::RSSetViewports](https://msdn.microsoft.com/ja-jp/library/ee419744(v=vs.85).aspx)

```cpp:DXUtil.h
#pragma once
#include<d3d11.h>
#include<DirectXColors.h>

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

namespace Memory {
	template<class T> void SafeDelete(T& t) {
		if (t) {
			delete t;
			t = nullptr;
		}
	}
	template<class T> void SafeDeleteArr(T& t) {
		if (t) {
			delete[] t;
			t = nullptr;
		}
	}
	template<class T>void Saferelease(T& t) {
		if (t) {
			t->Release();
			t = nullptr;
		}
	}
}
```


```cpp:WinMain.cpp
#include"DXApp.h"
//テストアプリクラスを作成
class TestApp : public DXApp {
public:
	TestApp(HINSTANCE hInstance,int showCmd);
	~TestApp();

	bool Init() override;
	void Update(float dt) override;
	void Render(float dt) override;

};

TestApp::TestApp(HINSTANCE hInstance,int showCmd) :
	DXApp(hInstance,showCmd)
{}

TestApp::~TestApp() {

}

bool TestApp::Init() {
	if (!DXApp::Init()) {
		return false;
	}
	return true;
}

void TestApp::Update(float dt) {

}

void TestApp::Render(float dt) {
      //青で塗る
	m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, DirectX::Colors::CornflowerBlue);
	//レンダリング結果を表示
	m_pSwapChain->Present(0, 0);
}

//メイン
int WINAPI WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd) {

	TestApp tApp(hInstance,nShowCmd);
	if (!tApp.Init())return 1;

	return tApp.Run();
}
```