创建一个最小的D3D11实例

我想复习一下D3D11的一些基础API,于是翻了翻Microsoft DirectX SDK (June 2010)找到其中一个最简单的D3D11的实例(\Samples\C++\Direct3D11\Tutorials\Tutorial02)。可惜因为SDK版本太旧,安装的教学工程是VS2010的,我尝试升级成VS2017的工程但失败了。于是我决定手动新创建一个工程来跑起来这个教学范例,过程中也抛弃掉了一些比较边缘,不影响效果的内容(其中较为重要的被舍弃的内容是:1.清理掉对象;2.输出shader编译的错误)。

实践

首先,需要安装Microsoft DirectX SDK (June 2010),因为用到了其中的函数。

0.创建一个空工程

在这里插入图片描述
之后创建一个cpp文件。

1.目标是创建一个窗口

1.1 入口函数

我们的入口函数是

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)

要确保配置中 链接器 =》系统 =》子系统 设置为窗口,这将表示我们的入口函数是WinMain而不是main
在这里插入图片描述

1.2 生成窗口

我们窗口的Handle将存在一个全局变量中:

HWND                    g_hWnd = NULL;

同时,需要一个“窗口过程”来接收Windows发来的消息:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_DESTROY:
			PostQuitMessage(0);
			break;

		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}

	return 0;
}

然后,就可以初始化窗口了

HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow)
{
	// Register class
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)"");
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = "TestD3D11WindowClass";
	wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)"");
	if (!RegisterClassEx(&wcex))
		return E_FAIL;

	// Create window
	RECT rc = { 0, 0, WindowWidth, WindowHeight };
	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
	g_hWnd = CreateWindowA("TestD3D11WindowClass", "TestD3D11Window",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance,
		NULL);
	if (!g_hWnd)
		return E_FAIL;

	ShowWindow(g_hWnd, nCmdShow);

	return S_OK;
}

将入口函数改为:

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
	InitWindow(hInstance, nCmdShow);
	
	MSG msg = { 0 };
	while (WM_QUIT != msg.message)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return msg.wParam;
}

运行后可看见窗口:
在这里插入图片描述

2.目标是初始化D3D11并且以一颜色清理BackBuffer

首先将D3D11相关的头文件配置上:
在这里插入图片描述
然后,需要添加lib,
先把lib的路径添加进来
在这里插入图片描述

然后依赖d3d11.libd3dx11.lib
在这里插入图片描述
下面,写一个新函数InitD3D,他将初始化D3D相关的内容

HRESULT InitD3D()
{
	HRESULT hr = S_OK;

	return hr;
}
2.1 尝试创建Device和SwapChain,得到ImmediateContext

首先声明他们的全局变量

ID3D11Device*           g_pd3dDevice = NULL;
ID3D11DeviceContext*    g_pImmediateContext = NULL;
IDXGISwapChain*         g_pSwapChain = NULL;

然后开始写InitD3D中的代码:
列出所有考虑的FeatureLevel:

D3D_FEATURE_LEVEL featureLevels[] =
{
	D3D_FEATURE_LEVEL_11_0,
	D3D_FEATURE_LEVEL_10_1,
	D3D_FEATURE_LEVEL_10_0,
};

列出所有考虑的驱动类型(越靠前越优先考虑)

D3D_DRIVER_TYPE driverTypes[] =
{
	D3D_DRIVER_TYPE_HARDWARE,
	D3D_DRIVER_TYPE_WARP,
	D3D_DRIVER_TYPE_REFERENCE,
};

创建SwapChain的描述结构体

DXGI_SWAP_CHAIN_DESC swapchainDescription;
ZeroMemory(&swapchainDescription, sizeof(swapchainDescription));
swapchainDescription.BufferCount = 1;
swapchainDescription.BufferDesc.Width = WindowWidth;
swapchainDescription.BufferDesc.Height = WindowHeight;
swapchainDescription.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapchainDescription.BufferDesc.RefreshRate.Numerator = 60;
swapchainDescription.BufferDesc.RefreshRate.Denominator = 1;
swapchainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapchainDescription.OutputWindow = g_hWnd;
swapchainDescription.SampleDesc.Count = 1;
swapchainDescription.SampleDesc.Quality = 0;
swapchainDescription.Windowed = TRUE;

调用D3D11CreateDeviceAndSwapChain来创建Device和SwapChain,得到ImmediateContext

D3D_DRIVER_TYPE         outDriverType;	//最终决定的DriverType
D3D_FEATURE_LEVEL       outFeatureLevel;//最终决定的FeatureLevel
//按照驱动类型依次尝试创建Device和SwapChain
for (UINT driverTypeIndex = 0; driverTypeIndex < ARRAYSIZE(driverTypes); driverTypeIndex++)
{
	outDriverType = driverTypes[driverTypeIndex];
	hr = D3D11CreateDeviceAndSwapChain(NULL, outDriverType, NULL, 0, featureLevels, ARRAYSIZE(featureLevels),
		D3D11_SDK_VERSION, &swapchainDescription, &g_pSwapChain, &g_pd3dDevice, &outFeatureLevel, &g_pImmediateContext);
	if (SUCCEEDED(hr))
		break;
}
if (FAILED(hr))
	return hr;
2.2创建一个 render target view

先声明全局变量

ID3D11RenderTargetView* g_pRenderTargetView = NULL;

继续写 InitD3D:
从SwapChain那里得到BackBuffer

ID3D11Texture2D* pBackBuffer = NULL;
hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
if (FAILED(hr))
	return hr;

调用CreateRenderTargetView创建一个 render target view

hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
pBackBuffer->Release();
if (FAILED(hr))
	return hr;

输出合并阶段(Output-Merger Stage)设置RenderTarget

g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);
2.3

Render函数:
只是以一个浅绿色来清理 back buffer

void Render()
{
	// 清理 back buffer 
	float ClearColor[4] = { 0.5f, 1.0f, 0.6f, 1.0f }; 
	g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);

	// Present the information rendered to the back buffer to the front buffer (the screen)
	g_pSwapChain->Present(0, 0);
}

然后改变我们的入口函数:

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
	InitWindow(hInstance, nCmdShow);

	InitD3D();

	MSG msg = { 0 };
	while (WM_QUIT != msg.message)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			Render();
		}
	}

	return msg.wParam;
}

运行会看到:
在这里插入图片描述

3.目标是画出一个三角形

3.1着色器文件

创建一个着色器文件TestShader.fx,内容很简单:

float4 VS( float4 Pos : POSITION ) : SV_POSITION
{
    return Pos;
}

float4 PS( float4 Pos : SV_POSITION ) : SV_Target
{
    return float4( 0.8f, 0.7f, 0.9f, 1.0f );    
}

顶点着色器只是返回位置,不做任何变换
像素着色器则只输出一个浅紫色

3.2

所需要的的全局变量:

ID3D11VertexShader*     g_pVertexShader = NULL;		//顶点着色器
ID3D11PixelShader*      g_pPixelShader = NULL;		//像素着色器
ID3D11InputLayout*      g_pVertexLayout = NULL;		//顶点输入布局
ID3D11Buffer*           g_pVertexBuffer = NULL;		//顶点缓冲

顶点输入结构:(只有一个“位置”)

struct SimpleVertex
{
	XMFLOAT3 Pos;
};

设置视窗

D3D11_VIEWPORT vp;
vp.Width = (FLOAT)WindowWidth;
vp.Height = (FLOAT)WindowHeight;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
//光栅化阶段(Rasterize Stage)设置视窗
g_pImmediateContext->RSSetViewports(1, &vp);

创建顶点着色器

//编译顶点着色器
ID3DBlob* pVSBlob = NULL;
hr = D3DX11CompileFromFileA("TestShader.fx", NULL, NULL, "VS", "vs_4_0",0, 0, NULL, &pVSBlob, &pErrorBlob, NULL);
if (FAILED(hr))
	return hr;
//创建顶点着色器
hr = g_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader);
if (FAILED(hr))
{
	pVSBlob->Release();
	return hr;
}

创建输入布局

//定义顶点输入布局(与SimpleVertex对应)
D3D11_INPUT_ELEMENT_DESC layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
//创建输入布局
hr = g_pd3dDevice->CreateInputLayout(layout, ARRAYSIZE(layout), pVSBlob->GetBufferPointer(),
	pVSBlob->GetBufferSize(), &g_pVertexLayout);
pVSBlob->Release();
if (FAILED(hr))
	return hr;
//输入装配阶段(Input-Assembler Stage)设置输入布局
g_pImmediateContext->IASetInputLayout(g_pVertexLayout);

创建像素着色器

//编译像素着色器
ID3DBlob* pPSBlob = NULL;
hr = D3DX11CompileFromFileA("TestShader.fx", NULL, NULL, "PS", "ps_4_0", 0, 0, NULL, &pPSBlob, &pErrorBlob, NULL);
if (FAILED(hr))
	return hr;
//创建像素着色器
hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader);
pPSBlob->Release();
if (FAILED(hr))
	return hr;

创建顶点缓冲,只是个简单的三角形

//输入的顶点数据
SimpleVertex vertices[] =
{
	XMFLOAT3(0.0f, 0.5f, 0.5f),
	XMFLOAT3(0.5f, -0.5f, 0.5f),
	XMFLOAT3(-0.5f, -0.5f, 0.5f),
};
//缓冲描述
D3D11_BUFFER_DESC bufferDescription;
ZeroMemory(&bufferDescription, sizeof(bufferDescription));
bufferDescription.Usage = D3D11_USAGE_DEFAULT;
bufferDescription.ByteWidth = sizeof(SimpleVertex) * 3;
bufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDescription.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = vertices;
//创建顶点缓冲
hr = g_pd3dDevice->CreateBuffer(&bufferDescription, &InitData, &g_pVertexBuffer);
if (FAILED(hr))
	return hr;
	
UINT stride = sizeof(SimpleVertex);
UINT offset = 0;
//输入装配阶段(Input-Assembler Stage)设置顶点缓冲
g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);

//输入装配阶段(Input-Assembler Stage)设置拓扑结构
g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
3.3

改变Render函数,中间加上三段:

void Render()
{
	// 清理 back buffer 
	float ClearColor[4] = { 0.5f, 1.0f, 0.6f, 1.0f }; //浅绿色
	g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);

	// 渲染
	g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
	g_pImmediateContext->PSSetShader(g_pPixelShader, NULL, 0);
	g_pImmediateContext->Draw(3, 0);

	// Present the information rendered to the back buffer to the front buffer (the screen)
	g_pSwapChain->Present(0, 0);
}

运行后:
在这里插入图片描述

完整代码

#include <windows.h>

#include <d3d11.h>
#include <D3DX11.h>
#include <d3dcompiler.h>
#include <xnamath.h>

HWND                    g_hWnd = NULL;
ID3D11Device*           g_pd3dDevice = NULL;
ID3D11DeviceContext*    g_pImmediateContext = NULL;
IDXGISwapChain*         g_pSwapChain = NULL;
ID3D11RenderTargetView* g_pRenderTargetView = NULL;
ID3D11VertexShader*     g_pVertexShader = NULL;		//顶点着色器
ID3D11PixelShader*      g_pPixelShader = NULL;		//像素着色器
ID3D11InputLayout*      g_pVertexLayout = NULL;		//顶点输入布局
ID3D11Buffer*           g_pVertexBuffer = NULL;		//顶点缓冲

const int WindowWidth = 800;
const int WindowHeight = 600;

//顶点输入数据
struct SimpleVertex
{
	XMFLOAT3 Pos;
};


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_DESTROY:
			PostQuitMessage(0);
			break;

		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}

	return 0;
}

HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow)
{
	// Register class
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)"");
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = "TestD3D11WindowClass";
	wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)"");
	if (!RegisterClassEx(&wcex))
		return E_FAIL;

	// Create window
	RECT rc = { 0, 0, WindowWidth, WindowHeight };
	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
	g_hWnd = CreateWindowA("TestD3D11WindowClass", "TestD3D11Window",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance,
		NULL);
	if (!g_hWnd)
		return E_FAIL;

	ShowWindow(g_hWnd, nCmdShow);

	return S_OK;
}

HRESULT InitD3D()
{
	HRESULT hr = S_OK;

	//所有考虑的FeatureLevel
	D3D_FEATURE_LEVEL featureLevels[] =
	{
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_10_0,
	};

	//所有考虑的驱动类型(越靠前越优先考虑)
	D3D_DRIVER_TYPE driverTypes[] =
	{
		D3D_DRIVER_TYPE_HARDWARE,
		D3D_DRIVER_TYPE_WARP,
		D3D_DRIVER_TYPE_REFERENCE,
	};

	//创建SwapChain的描述结构体
	DXGI_SWAP_CHAIN_DESC swapchainDescription;
	ZeroMemory(&swapchainDescription, sizeof(swapchainDescription));
	swapchainDescription.BufferCount = 1;
	swapchainDescription.BufferDesc.Width = WindowWidth;
	swapchainDescription.BufferDesc.Height = WindowHeight;
	swapchainDescription.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	swapchainDescription.BufferDesc.RefreshRate.Numerator = 60;
	swapchainDescription.BufferDesc.RefreshRate.Denominator = 1;
	swapchainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapchainDescription.OutputWindow = g_hWnd;
	swapchainDescription.SampleDesc.Count = 1;
	swapchainDescription.SampleDesc.Quality = 0;
	swapchainDescription.Windowed = TRUE;

	D3D_DRIVER_TYPE         outDriverType;	//最终决定的DriverType
	D3D_FEATURE_LEVEL       outFeatureLevel;//最终决定的FeatureLevel
	//按照驱动类型依次尝试创建Device和SwapChain
	for (UINT driverTypeIndex = 0; driverTypeIndex < ARRAYSIZE(driverTypes); driverTypeIndex++)
	{
		outDriverType = driverTypes[driverTypeIndex];
		hr = D3D11CreateDeviceAndSwapChain(NULL, outDriverType, NULL, 0, featureLevels, ARRAYSIZE(featureLevels),
			D3D11_SDK_VERSION, &swapchainDescription, &g_pSwapChain, &g_pd3dDevice, &outFeatureLevel, &g_pImmediateContext);
		if (SUCCEEDED(hr))
			break;
	}
	if (FAILED(hr))
		return hr;


	//创建一个 render target view
	ID3D11Texture2D* pBackBuffer = NULL;
	hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
	if (FAILED(hr))
		return hr;
	hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
	pBackBuffer->Release();
	if (FAILED(hr))
		return hr;
	//输出合并阶段(Output-Merger Stage)设置RenderTarget
	g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);



	// 设置视窗
	D3D11_VIEWPORT vp;
	vp.Width = (FLOAT)WindowWidth;
	vp.Height = (FLOAT)WindowHeight;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
	//光栅化阶段(Rasterize Stage)设置视窗
	g_pImmediateContext->RSSetViewports(1, &vp);

	ID3DBlob* pErrorBlob;

	//编译顶点着色器
	ID3DBlob* pVSBlob = NULL;
	hr = D3DX11CompileFromFileA("TestShader.fx", NULL, NULL, "VS", "vs_4_0",0, 0, NULL, &pVSBlob, &pErrorBlob, NULL);
	if (FAILED(hr))
		return hr;
	//创建顶点着色器
	hr = g_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader);
	if (FAILED(hr))
	{
		pVSBlob->Release();
		return hr;
	}

	//定义顶点输入布局(与SimpleVertex对应)
	D3D11_INPUT_ELEMENT_DESC layout[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};
	//创建输入布局
	hr = g_pd3dDevice->CreateInputLayout(layout, ARRAYSIZE(layout), pVSBlob->GetBufferPointer(),
		pVSBlob->GetBufferSize(), &g_pVertexLayout);
	pVSBlob->Release();
	if (FAILED(hr))
		return hr;
	//输入装配阶段(Input-Assembler Stage)设置输入布局
	g_pImmediateContext->IASetInputLayout(g_pVertexLayout);


	//编译像素着色器
	ID3DBlob* pPSBlob = NULL;
	hr = D3DX11CompileFromFileA("TestShader.fx", NULL, NULL, "PS", "ps_4_0", 0, 0, NULL, &pPSBlob, &pErrorBlob, NULL);
	if (FAILED(hr))
		return hr;
	//创建像素着色器
	hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader);
	pPSBlob->Release();
	if (FAILED(hr))
		return hr;


	//输入的顶点数据
	SimpleVertex vertices[] =
	{
		XMFLOAT3(0.0f, 0.5f, 0.5f),
		XMFLOAT3(0.5f, -0.5f, 0.5f),
		XMFLOAT3(-0.5f, -0.5f, 0.5f),
	};
	//缓冲描述
	D3D11_BUFFER_DESC bufferDescription;
	ZeroMemory(&bufferDescription, sizeof(bufferDescription));
	bufferDescription.Usage = D3D11_USAGE_DEFAULT;
	bufferDescription.ByteWidth = sizeof(SimpleVertex) * 3;
	bufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bufferDescription.CPUAccessFlags = 0;
	D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory(&InitData, sizeof(InitData));
	InitData.pSysMem = vertices;
	//创建顶点缓冲
	hr = g_pd3dDevice->CreateBuffer(&bufferDescription, &InitData, &g_pVertexBuffer);
	if (FAILED(hr))
		return hr;

	
	UINT stride = sizeof(SimpleVertex);
	UINT offset = 0;
	//输入装配阶段(Input-Assembler Stage)设置顶点缓冲
	g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);

	//输入装配阶段(Input-Assembler Stage)设置拓扑结构
	g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	return S_OK;
}

void Render()
{
	// 清理 back buffer 
	float ClearColor[4] = { 0.5f, 1.0f, 0.6f, 1.0f }; //浅绿色
	g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);

	// 渲染
	g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
	g_pImmediateContext->PSSetShader(g_pPixelShader, NULL, 0);
	g_pImmediateContext->Draw(3, 0);

	// Present the information rendered to the back buffer to the front buffer (the screen)
	g_pSwapChain->Present(0, 0);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
	InitWindow(hInstance, nCmdShow);

	InitD3D();

	MSG msg = { 0 };
	while (WM_QUIT != msg.message)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			Render();
		}
	}

	return msg.wParam;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值