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