HLSL概述
HLSL是高阶着色器(High Level Shader Language)的简称,是由微软拥有及开发的一种语言,只能供微软的Direct3D使用。
如果要了解HLSL可以参考一下这篇文章,在这里就不做介绍了.
http://wenku.baidu.com/link?url=q-CpdL5JU8Vh87W2olwCWkiajjlyMElDiUh5F36pXSUhzL8rhKBSWX5zX-XYHldwApE0Tp1djQZfwNYZ5S-5X5eYcdPeLfQym-4XYuYzN1S
本文主要讲解如何从文件中载入HLSL文件以及创建顶点缓存
编译HLSL文件
要编译HLSL文件,需要使用D3DX11CompileFromFile函数进行,该函数的原型如下
HRESULT D3DX11CompileFromFile(
_In LPCTSTR pSrcFile,
_In const D3D10_SHADER_MACRO *pDefines,
_In LPD3D10INCLUDE pInclude,
_In LPCSTR pFunctionName,
_In LPCSTR pProfile,
_In UINT Flags1,
_In UINT Flags2,
_In ID3DX11ThreadPump *pPump,
_Out ID3D10Blob **ppShader,
_Out ID3D10Blob **ppErrorMsgs,
_Out HRESULT *pHResult
);
- LPCSTR pSrcFile:这里填我们要加载的HLSL文件的文件名
- const D3D10_SHADER_MACRO *pDefines:这是个可选项,指向一个包含宏定义的数组,可以设为NULL
- LPD3D10INCLUDE pInclude:可选项,指向一个操作包含文件的接口,不需要就设为NULL
- LPCSTR pFunctionName:一个字符串,指向着色器入口函数。
- LPCSTR pProfile:一个字符串,表示着色器的模型。可以理解问版本
- UINT Flag1:着色器编译标识符。详情可以查看MSDN中关于compile flag的描述。这里我们使用D3DCOMPILE_ENABLE_STRICTNESS,表示严格编译
- UINT Flags2:Effect编译标识,如果不是编译Effect就设为0。即便是编译Effect文件,设为0也是比较好的选择
- ID3DX11ThreadPump *pPump:使用一个线程来异步地执行该函数。如果不需要就设为NULL
- ID3D10Blob **ppShader:输出编译好的着色器会存放在缓存中。这里我们使用ID3DBlob定义的接口来作为参数,可以通过其GetBufferPointer方法获得其内存段首地址
- ID3D10Blob **ppErrorMsg:输出错误信息,保存在缓存中。同样是ID3DBlob定义的接口,如果不需要可以设置为NULL
- HRESULT *pHResult:一个输出参数,该参数会被启用,仅当该函数是异步执行的时候
创建顶点着色器
通过刚才那个步骤,我们已经把HLSL文件中相应的函数编译后得到的字节码加载到内存中了.要创建顶点着色器,需要到这段内存的具体数据。然后通过调用设备接口的CreateVertexShader创建顶点着色器
HRESULT CreateVertexShader(
[in] const void *pShaderBytecode,
[in] SIZE_T BytecodeLength,
[in, optional] ID3D11ClassLinkage *pClassLinkage,
[out, optional] ID3D11VertexShader **ppVertexShader
);
- const void *pShaderBytecode:表示着色器字节码所在的我位置.通过刚才初始化好的ID3DBlob接口的GetBufferPointer方法获取
- SIZE_T BytecodeLength:着色器字节码所在内存段的长度.通过刚才初始化好的ID3DBlob接口的GetSize方法获取
- ID3D11ClassLinkage *pClassLinkag:一个输入可选项.表示HLSL动态链接。这里设为NULL即可
-
ID3D11VertexShader **ppVertexShader:输出参数,输出我没想要初始化的顶点着色器接口,如果设为NULL,表示验证其他参数,验证通过则返回S_FALSE
像素着色器的创建和顶点着色器的创建方式相同。这里不再赘述
创建并设置输入布局
所谓输入布局,就是制定了顶点结构所包含的信息和含义。我们要把顶点拿去着色,那就需要告诉程序我们该怎样输入。
创建输入布局
在创建输入布局之前,首先要描述它,我们使用D3D11_INPUT_ELEMENT_DESC来描述。
如果我们将该结构体解剖,可以看到它的内脏是长这样的:
typedef struct D3D11_INPUT_ELEMENT_DESC {
LPCSTR SemanticName;
UINT SemanticIndex;
DXGI_FORMAT Format;
UINT InputSlot;
UINT AlignedByteOffset;
D3D11_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate;
} D3D11_INPUT_ELEMENT_DESC;
- LPCSTR SemanticName:表示语义标识符,例如VSMain参数中的POSITION
- UINT SemanticIndex:emanticIndex为该语义说明的序号,是这样的,在一个顶点结构中,不同的成员可以使用相同的语义说明,这时要用不同的序号来区分他们,相应的序号就是这个SemanticIndex。比如一个顶点有两层纹理坐标,tex1和tex2,它们的语义说明都为”TEXTCOORD”,相应的序号则为0和1
- DXGI_FORMAT Format:为该成员数据格式,我们选择DXGI_FORMAT_R32G32B32_FLOAT(3个float).关于该类型的详细说明可以查看MSDN中关于DXGI_FORMAT的定义
- UINT InputSlot:输入槽,可以取值0~15,一般情况下取0,在个别情况下,不同的顶点信息可以通过不同的输入槽提供给GPU,这时通过该成员来指定其输入槽序号
- UINT AlignedByteOffset:即该成员在顶点结构中字节偏移量,对于这里的位置坐标,为第一个成员,因此偏移为0。对于颜色值,由于位置坐标占据了12个字节,因此颜色值对应的偏移为12,依次类推;InputaSlotClass,对于一般情况,为D3D11_INPUT_PER_VERTEX_DATA
- D3D11_INPUT_CLASSIFICATION InputSlotClass:为单个输入槽定义输入类型。该类型由D3D11_INPUT_CLASSIFICATION枚举类型定义,该枚举类型的结构如下:
typedef enum D3D11_INPUT_CLASSIFICATION { D3D11_INPUT_PER_VERTEX_DATA = 0, D3D11_INPUT_PER_INSTANCE_DATA = 1 } D3D11_INPUT_CLASSIFICATION;
- D3D11_INPUT_PER_VERTEX_DATA:输入数据是顶点
- D3D11_INPUT_PER_INSTANCE_DATA:输入数据是实例
-
UINT InstanceDataStepRate:如果上一个参数设为D3D11_INPUT_PER_VERTEX_DATA,这里将该参数设为0
描述完整个结构体之后。就可以调用设备接口的CreateInputLayout来创建输入布局
该函数的原型如下:
HRESULT CreateInputLayout(
[in] const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs,
[in] UINT NumElements,
[in] const void *pShaderBytecodeWithInputSignature,
[in] SIZE_T BytecodeLength,
[out, optional] ID3D11InputLayout **ppInputLayout
);
- const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs:该参数明显是我们刚才用于描述输入布局的结构体。不过需要注意的是,这里需要输入数组
- UINT NumElements:第一个数组参数中元素的个数
- const void *pShaderBytecodeWithInputSignature:一个指针,指向了已经编译好的着色器字节码所在内存中的首地址
- SIZE_T BytecodeLength:着色器字节码所在内存段的长度
- ID3D11InputLayout **ppInputLayout:输出创建好的输入布局,如果设为NULL则检验其他参数,检验通过则返回S_FALSE
设置输入结构布局
设置输入结构特别简单,只需要调用设备上下文接口的IASetInputLayout方法.
void IASetInputLayout(
[in, optional] ID3D11InputLayout *pInputLayout
);
- 唯一一个参数,填我们刚才创建好ID3D11InputLayout
创建并设置顶点缓存
顶点的具体表现形式是顶点缓存,顶点缓存保存了顶点数据和内存克难攻坚。顶点缓存的存储位置比较随意,既可以在内存中,也可以在显卡的显存中。
创建顶点缓存
要创建顶点缓存,首先要描述顶点缓存的结构。该结构由D3D11_BUFFER_DESC结构体描述,我们继续解剖该结构体内部结构,可以轻易地发现其内部结构是这样的
typedef struct D3D11_BUFFER_DESC {
UINT ByteWidth;
D3D11_USAGE Usage;
UINT BindFlags;
UINT CPUAccessFlags;
UINT MiscFlags;
UINT StructureByteStride;
} D3D11_BUFFER_DESC;
- UINT ByteWidth:表示缓存的大小,以字节为单位
- D3D11_USAGE Udage:定义了缓存该怎样读写。我们使用D3D11_USAGE_DEFAULT作为参数。关于D3D11_USAGE的具体说明可查看MSDN
- UINT BindFlags:标识了缓存如何绑定到渲染管线.因为是顶点缓存,所以我们使用D3D11_BIND_VERTEX_BUFFER。关于D3D11_BIND_FLAG的具体详情,可以查看MSDN
- UINT CPUAccessFlags:标识了如何访问CPU,如果不需要访问CPU则将其置为0。关于D3D11_ACCESS_FLAG的具体详情可参考MSDN
- UINT MiscFlags:额外数据选项。这里用不到,设为0
-
UINT StructureByteStride:标识缓存中每个数据元素的大小
讲缓存结构描述完成之后,还需要描述数据资源,描述数据资源使用D3D11_SUBRESOURCE_DATA结构体来描述。该结构体可以查阅MSDN获取详细说明。我们只需设置其中一个成员就可以了,它就是:D3D11_SUBRESOURCE_DATA::pSysMem.
描述好数据资源之后,接下来就该创建顶点缓存了。创建顶点缓存是通过使用设备接口的CreateBuffer创建的。它的原型如下:
HRESULT CreateBuffer(
[in] const D3D11_BUFFER_DESC *pDesc,
[in, optional] const D3D11_SUBRESOURCE_DATA *pInitialData,
[out, optional] ID3D11Buffer **ppBuffer
);
- const D3D11_BUFFER_DESC *pDesc:输入缓存结构的描述
- const D3D11_SUBRESOURCE_DATA *pInitialData:输入缓存数据的描述
- ID3D11Buffer **ppBuffer:输出最终需要初始化的顶点缓存
设置顶点缓存
创建好顶点缓存之后,就该设置顶点缓存了。设置顶点缓存还是通过设备上下文接口来完成的。调用的方法为IASetVertexBuffers,它的原型如下:
void IASetVertexBuffers(
[in] UINT StartSlot,
[in] UINT NumBuffers,
[in, optional] ID3D11Buffer *const *ppVertexBuffers,
[in, optional] const UINT *pStrides,
[in, optional] const UINT *pOffsets
);
- UINT StartSlot:第一个输入槽
- UINT NumBuffers:缓存的数量
- ID3D11Buffer *const *ppVertexBuffers:刚才创建的顶点缓存
- const UINT *pStrides:表示缓存中一个元素的大小
- const UINT *pOffsets:设置偏移量指向第一个元素
结局
至今为止,已经把需要的各种对象都创建好了。万事俱备只欠东风,我们只需把刚才创建好的顶点着色器,像素着色器等等对象通过设备上下文进行设置即可用这些工具来绘制出美丽的图形了。
实例代码
//HLSL文件
float4 VSMain(float4 Pos:POSITION) :SV_POSITION
{
return Pos;
}
float4 PSMain(float Pos : POSITION) : SV_TARGET
{
return float4(,,,);
}
//d3dUtil.h
#pragma once
#include<windows.h>
#include<d3dcompiler.h>
#include<xnamath.h>
#include<d3d11.h>
#include<d3dx11.h>
#pragma comment(lib,"d3d11.lib")
#pragma comment(lib,"d3dx11.lib")
#pragma comment(lib,"d3dcompiler.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"winmm.lib")
#define SAFE_RELEASE(p) {if((p)){(p)->Release();}}
class DirectSystem
{
//私有字段
private:
//基础接口
ID3D11Device *m_pDevice; //DX设备接口,用于生成各种各样的对象
ID3D11DeviceContext *m_pDeviceContext; //DX设备上下文,用于生成设备渲染指令
//视图区域
ID3D11RenderTargetView *m_pRenderTargetView;//DX渲染目标视图,字面意思
ID3D11DepthStencilView *m_pDepthStencilView;//DX深度模板缓存视图
ID3D11Texture2D *m_pDepthStencil; //深度模板缓存
//图形接口
IDXGISwapChain *m_pSwapChain; //DX图形接口,交换链
public:
DirectSystem()
:m_pDevice(NULL),
m_pDeviceContext(NULL),
m_pRenderTargetView(NULL),
m_pDepthStencilView(NULL),
m_pDepthStencil(NULL),
m_pSwapChain(NULL)
{
}
HRESULT Direct3D_Init(HWND hwnd,int WINDOW_WIDTH,int WINDOW_HEIGHT) {
//描述交换链
DXGI_SWAP_CHAIN_DESC scDesc;
::ZeroMemory(&scDesc, sizeof(scDesc));
scDesc.OutputWindow = hwnd; //描述输出窗口
scDesc.BufferCount = ;//缓存数量
scDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;//描述后台缓存格式
scDesc.BufferDesc.Width = WINDOW_WIDTH; //描述后台缓存分辨率宽度
scDesc.BufferDesc.Height = WINDOW_HEIGHT;//描述后台缓存分辨率高度
scDesc.BufferDesc.RefreshRate.Denominator = ;//刷新频率的分母
scDesc.BufferDesc.RefreshRate.Numerator = ;//刷新频率的分子,这两项表明每秒刷新6次
scDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
scDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scDesc.Flags = ;
scDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scDesc.SampleDesc.Count = ; //这里不使用多重采样,因此数量设为1
scDesc.SampleDesc.Quality = ; //不使用多重采样,设为0
scDesc.Windowed = true; //设置为窗口模式
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0, //D3D11.0 所支持的功能特征
D3D_FEATURE_LEVEL_10_1, //D3D10.1 所支持的功能特征
D3D_FEATURE_LEVEL_10_0 //D3D10.0 所支持的功能特征
};
UINT numFeature = ARRAYSIZE(featureLevels);
//创建设备,设备上下文,交换链
if (FAILED(D3D11CreateDeviceAndSwapChain(
NULL,
D3D_DRIVER_TYPE_HARDWARE,NULL,,
featureLevels,numFeature,
D3D11_SDK_VERSION,&scDesc,
&m_pSwapChain,&m_pDevice,NULL,&m_pDeviceContext)))
{
MessageBox(NULL, L"Create Device and Swapchain Error", L"Error", NULL);
return E_FAIL;
}
//获取后台缓冲区
ID3D11Texture2D *pBack = NULL;
if (FAILED(m_pSwapChain->GetBuffer(,__uuidof(ID3D11Texture2D),(void**)&pBack))) {
MessageBox(NULL, L"GetBuffer Error", L"Error", NULL);
return E_FAIL;
}
//创建渲染目标视图
HRESULT hr;
hr=m_pDevice->CreateRenderTargetView(pBack, NULL, &m_pRenderTargetView);
SAFE_RELEASE(pBack);
if (FAILED(hr))
{
MessageBox(NULL, L"Create Render Target View Error", L"Error", NULL);
return E_FAIL;
}
//这里没有开启深度模板,因此不需要
////描述深度模板缓存
//D3D11_TEXTURE2D_DESC dsDesc;
//::ZeroMemory(&dsDesc, sizeof(dsDesc));
//dsDesc.ArraySize = 1;
//dsDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
//dsDesc.CPUAccessFlags = 0;
//dsDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
//dsDesc.Height = WINDOW_HEIGHT;
//dsDesc.Width = WINDOW_WIDTH;
//dsDesc.MipLevels = 1;
//dsDesc.MiscFlags = 0;
//dsDesc.SampleDesc.Count = 1;
//dsDesc.SampleDesc.Quality = 0;
//dsDesc.Usage = D3D11_USAGE_DEFAULT;
//if (FAILED(m_pDevice->CreateTexture2D(&dsDesc, NULL, &m_pDepthStencil)))
//{
// MessageBox(NULL, L"Create Depth Stencil Buffer Error", L"Error", NULL);
// return E_FAIL;
//}
//if (FAILED(m_pDevice->CreateDepthStencilView(m_pDepthStencil, 0, &m_pDepthStencilView)))
//{
// MessageBox(NULL, L"Create Depth Stencil Buffer View Error", L"Error", NULL);
// return E_FAIL;
//}
m_pDeviceContext->OMSetRenderTargets(, &m_pRenderTargetView,NULL);
//第四步,设置视口大小,D3D11默认不会设置视口,此步骤必须手动设置
D3D11_VIEWPORT vp; //创建一个视口的对象
vp.TopLeftX = ; //视口左上角的横坐标
vp.TopLeftY = ; //视口左上角的总坐标
vp.Width = WINDOW_WIDTH; //视口的宽
vp.Height = WINDOW_HEIGHT; //视口的高
vp.MinDepth = f; //深度值的下限,**由于深度值是[0, 1]所以下限值是0
vp.MaxDepth = f; //深度值的上限,上限值是1
m_pDeviceContext->RSSetViewports(, &vp);
m_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
return S_OK;
}
void Direct3D_Render()
{
}
void Direct3D_Clear()
{
if (m_pDevice) {
static FLOAT color[] = { f,f,f,f };
m_pDeviceContext->ClearRenderTargetView(m_pRenderTargetView, color);
}
}
void Direct3D_Present()
{
if (m_pDevice)
{
m_pSwapChain->Present(,);
}
}
bool SetUp()
{
return true;
}
~DirectSystem()
{
SAFE_RELEASE(m_pDevice);
SAFE_RELEASE(m_pDeviceContext);
SAFE_RELEASE(m_pRenderTargetView);
SAFE_RELEASE(m_pDepthStencilView);
SAFE_RELEASE(m_pDepthStencil);
SAFE_RELEASE(m_pSwapChain);
}
ID3D11Device *D3DDevice() {
return m_pDevice;
}
ID3D11DeviceContext *D3DDeviceContext() {
return m_pDeviceContext;
}
};
//Triangle.h
#pragma once
#include"dxUtil.h"
struct Vertex
{
XMFLOAT3 Pos;
};
class Triangle
{
private:
ID3D11VertexShader *m_pVertexShader; //顶点着色器
ID3D11PixelShader *m_pPixelShader; //像素着色器
ID3D11InputLayout *m_pInputLayout; //输入布局
ID3D11Buffer *m_pVertexBuffer; //顶点缓存
UINT m_Stride; //顶点结构跨度
UINT m_Offset; //缓存到第一个元素所用的偏移量
Vertex vertices[]; //顶点数据
public:
HRESULT Draw(DirectSystem* d3dSys)
{
d3dSys->D3DDeviceContext()->VSSetShader(m_pVertexShader, NULL, NULL);
d3dSys->D3DDeviceContext()->PSSetShader(m_pPixelShader, NULL, NULL);
d3dSys->D3DDeviceContext()->IASetInputLayout(m_pInputLayout);
d3dSys->D3DDeviceContext()->IASetVertexBuffers(, , &m_pVertexBuffer, &m_Stride, &m_Offset);
d3dSys->D3DDeviceContext()->Draw(,);
//d3dSys->D3DDeviceContext()->ClearState();
return S_OK;
}
Triangle()
:m_pVertexShader(NULL), m_pPixelShader(NULL),m_pInputLayout(NULL),m_pVertexBuffer(NULL),
m_Stride(),m_Offset()
{
}
HRESULT InitObject(LPCTSTR fileName,LPCSTR functionVertexName,LPCSTR functionPixelName,DirectSystem* d3dSys)
{
//初始化顶点数据
vertices[].Pos = XMFLOAT3(f, f, f);
vertices[].Pos = XMFLOAT3(f, f, f);
vertices[].Pos = XMFLOAT3(-f, f, f);
vertices[].Pos = XMFLOAT3(f, f, f);
vertices[].Pos = XMFLOAT3(f, -f, f);
vertices[].Pos = XMFLOAT3(-f, f, f);
//创建顶点着色器字节码缓存和像素着色器字节码缓存
ID3DBlob *VertexBlob = NULL;//顶点缓存
ID3DBlob *PixelBlob = NULL;//像素缓存
if (FAILED(D3DX11CompileFromFile(fileName, NULL, NULL,
functionVertexName, "vs_5_0", D3DCOMPILE_ENABLE_STRICTNESS,
, NULL, &VertexBlob, NULL, NULL))) {
MessageBox(NULL, L"HLSL 编译失败", L"Error", NULL);
return E_FAIL;
}
if (FAILED(D3DX11CompileFromFile(fileName, NULL, NULL,
functionPixelName, "ps_5_0", D3DCOMPILE_ENABLE_STRICTNESS,
, NULL, &PixelBlob, NULL, NULL))) {
MessageBox(NULL, L"HLSL 编译失败", L"Error", NULL);
return E_FAIL;
}
if (FAILED(d3dSys->D3DDevice()->CreateVertexShader(VertexBlob->GetBufferPointer(), VertexBlob->GetBufferSize(), NULL, &m_pVertexShader)))
{
MessageBox(NULL, L"创建顶点着色器 失败", L"Error", NULL);
return E_FAIL;
}
if (FAILED(d3dSys->D3DDevice()->CreatePixelShader(PixelBlob->GetBufferPointer(), PixelBlob->GetBufferSize(), NULL, &m_pPixelShader)))
{
MessageBox(NULL, L"创建像素着色器 失败", L"Error", NULL);
return E_FAIL;
}
//描述输入布局结构
D3D11_INPUT_ELEMENT_DESC InputLayoutDesc[]=
{
{
"POSITION",
,
DXGI_FORMAT_R32G32B32_FLOAT,
,
,
D3D11_INPUT_PER_VERTEX_DATA,
}
};
UINT inputLayoutSize = ARRAYSIZE(InputLayoutDesc);
d3dSys->D3DDevice()->CreateInputLayout(InputLayoutDesc, inputLayoutSize,
VertexBlob->GetBufferPointer(), VertexBlob->GetBufferSize(), &m_pInputLayout);
D3D11_BUFFER_DESC VertexBufferDesc;
//描述顶点缓存
::ZeroMemory(&VertexBufferDesc, sizeof(VertexBufferDesc));
VertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
VertexBufferDesc.ByteWidth = sizeof(Vertex) * ;
VertexBufferDesc.MiscFlags = ;
VertexBufferDesc.StructureByteStride = sizeof(Vertex);
VertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
VertexBufferDesc.CPUAccessFlags = ;
D3D11_SUBRESOURCE_DATA VertexBufferDataDesc; //顶点数据描述
//描述顶点数据
::ZeroMemory(&VertexBufferDataDesc, sizeof(VertexBufferDataDesc));
VertexBufferDataDesc.pSysMem = vertices;
//创建顶点缓存
d3dSys->D3DDevice()->CreateBuffer(&VertexBufferDesc, &VertexBufferDataDesc, &m_pVertexBuffer);
m_Stride = sizeof(Vertex);
m_Offset = ;
}
~Triangle()
{
//delete m_pInputLayout;
SAFE_RELEASE(m_pVertexShader);
SAFE_RELEASE(m_pPixelShader);
SAFE_RELEASE(m_pInputLayout); //输入布局
SAFE_RELEASE(m_pVertexBuffer); //顶点缓存
}
};
//Main.cpp
#include"dxUtil.h"
#include"Triangle.h"
const int WINDOW_WIDTH = ;
const int WINDOW_HEIGHT = ;
DirectSystem *g_pDirect = NULL;
Triangle *g_pTriangle = NULL;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow)
{
WNDCLASSEX wc;
::ZeroMemory(&wc,sizeof(wc));
wc.cbClsExtra = ;
wc.cbSize = sizeof(wc);
wc.cbWndExtra = ;
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"MainWindow";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
::RegisterClassEx(&wc);
HWND hwnd = CreateWindow(L"MainWindow", L"寒江雪——游戏开发", WS_OVERLAPPED,CW_USEDEFAULT,CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
UpdateWindow(hwnd);
ShowWindow(hwnd, cmdShow);
MoveWindow(hwnd, , , WINDOW_WIDTH, WINDOW_HEIGHT, true);
g_pDirect = new DirectSystem();
g_pTriangle = new Triangle();
if (FAILED(g_pDirect->Direct3D_Init(hwnd, WINDOW_WIDTH, WINDOW_HEIGHT)))
{
delete g_pDirect;
return ;
}
if (FAILED(g_pTriangle->InitObject(L"VertexShader.hlsl", "VSMain", "PSMain", g_pDirect))) {
delete g_pDirect;
delete g_pTriangle;
return ;
}
MSG msg = { };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg,NULL, , , PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
g_pDirect->Direct3D_Clear();
g_pTriangle->Draw(g_pDirect);
g_pDirect->Direct3D_Present();
}
}
UnregisterClass(L"MainWindow", hInstance);
if (g_pDirect) { delete g_pDirect; }
return ;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage();
break;
case WM_KEYDOWN:
if (VK_ESCAPE==wParam)
DestroyWindow(hwnd);
break;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
Copyright© by 寒江雪
Date:2016.12.26