#include <windows.h>
#include <tchar.h>
#include <d3dx9.h>
#pragma comment(lib,"D3D9.lib")
//函数声明
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);//窗口过程
bool InitD3D(HINSTANCE hInstance);
bool Setup();
void Cleanup();
void Render(); //绘制
//窗口相关全局变量
const TCHAR g_szWindowTitleName[] = _T("顶点缓存"); //窗口标题
const TCHAR g_szWindowClassName[] = _T("WindowClass"); //窗口类名
int g_cxWindow = 640; //窗口宽
int g_cyWindow = 480; //窗口高
//Direct3D全局变量
IDirect3D9 * g_pD3d = nullptr; //Direct3D对象指针
IDirect3DDevice9 * g_pDevice = nullptr; //Direct3D设备对象指针
IDirect3DVertexBuffer9 * g_pVertexBuffer = nullptr; //顶点缓存
struct Vertex //定义顶点结构
{
Vertex(float x, float y, float z, float rhw, DWORD color)
{
_x = x;
_y = y;
_z = z;
_rhw = rhw;
_color = color;
}
float _x, _y, _z, _rhw;
DWORD _color;
static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_DIFFUSE | D3DFVF_XYZRHW; //使用了D3DFVF_XYZRHW标记,表示不对顶点进行变换
int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE hPreInstance,
LPTSTR lpCmdLine,
int nShowCmd)
{
if (!InitD3D(hInstance))
{
MessageBox(NULL, _T("初始化D3D失败"), NULL, MB_OK);
return 0;
}
if (!Setup())
{
MessageBox(NULL, _T("启动失败!"), NULL, MB_OK);
return 0;
}
MSG msg;
memset(&msg, 0, sizeof(msg));
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Render(); //5 绘制
}
}
Cleanup(); //6 清理资源
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
bool InitD3D(HINSTANCE hInstance)
{
WNDCLASS wndClass; //初始化窗口类结构体
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.hInstance = hInstance;
wndClass.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.lpfnWndProc = WndProc;
wndClass.lpszClassName = g_szWindowClassName;
wndClass.lpszMenuName = NULL;
BOOL bRet;
bRet = RegisterClass(&wndClass); //注册窗口类
if (!bRet)
{
MessageBox(NULL, _T("Register window class fail"), NULL, MB_OK);
return FALSE;
}
HWND hWnd;
hWnd = CreateWindow(g_szWindowClassName,//创建窗口
g_szWindowTitleName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
g_cxWindow,
g_cyWindow,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd)
{
MessageBox(NULL, _T("Create Window FAil"), NULL, MB_OK);
return FALSE;
}
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
//init Direct3D
g_pD3d = Direct3DCreate9(D3D_SDK_VERSION); //1、创建D3D对象
if (!g_pD3d)
{
MessageBox(NULL, _T("创建D3D对象失败!"), NULL, MB_OK);
return false;
}
D3DCAPS9 caps; //2、检查设备能力,硬件是否支持顶点运算
g_pD3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
int cap;
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
cap = D3DCREATE_HARDWARE_VERTEXPROCESSING; //用硬件方式处理顶点运算
else
cap = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //用软件方式处理顶点运算
HRESULT hr;
D3DPRESENT_PARAMETERS d3dpp; //3、初始化D3DPRESENT_PARAMETERS结构体
memset(&d3dpp, 0, sizeof(D3DPRESENT_PARAMETERS));
d3dpp.BackBufferWidth = 640;
d3dpp.BackBufferHeight = 480;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Windowed = true;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferCount = 1;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
hr = g_pD3d->CreateDevice(D3DADAPTER_DEFAULT, //4、创建D3D设备对象
D3DDEVTYPE_HAL,
hWnd,
cap,
&d3dpp,
&g_pDevice);
if (FAILED(hr))
{
MessageBox(NULL, _T("创建D3D设备对象失败!"), NULL, MB_OK);
return false;
}
return true;
}
bool Setup()
{
HRESULT hr;
//顶点缓存的使用1:创建顶点缓存
hr = g_pDevice->CreateVertexBuffer(sizeof(Vertex)* 3,
D3DUSAGE_DYNAMIC,
Vertex::FVF,
D3DPOOL_DEFAULT,
&g_pVertexBuffer,
NULL);
if (FAILED(hr))
{
MessageBox(NULL, _T("创建顶点缓存失败!"), NULL, MB_OK);
return false;
}
//顶点缓存的使用2:写入顶点数据(在此之前需要定义顶点结构)
/*画一个三角形
v1
/\
/ \
/ \
v3------v2
注意三角形的顶点顺序(v1、v2、v3)为顺时针(即正面)
这样才能将效果给渲染出来,因为默认情况下D3D只渲染正面三角形
*/
Vertex * pVertexs = nullptr;
g_pVertexBuffer->Lock(0, 0, (void**)&pVertexs, 0);
pVertexs[0] = Vertex(g_cxWindow / 2, g_cyWindow / 2 - 100, 1.f, 1.f, D3DCOLOR_XRGB(255, 0, 0));
pVertexs[1] = Vertex(g_cxWindow / 2 + 100, g_cyWindow / 2 + 100, 1.f, 1.f, D3DCOLOR_XRGB(0, 255, 0));
pVertexs[2] = Vertex(g_cxWindow / 2 - 100, g_cyWindow / 2 + 100, 1.f, 1.f, D3DCOLOR_XRGB(0, 0, 255));
g_pVertexBuffer->Unlock();
return true;
}
void Cleanup()
{
if (g_pDevice){ g_pDevice->Release(); g_pDevice = nullptr; }
if (g_pD3d){ g_pD3d->Release(); g_pD3d = nullptr; }
if (g_pVertexBuffer){ g_pVertexBuffer->Release(), g_pVertexBuffer = nullptr; } //顶点缓存的使用7:释放顶点数据
}
void Render()
{
HRESULT hr;
hr = g_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255, 255, 255, 255), 1.f, 0);
hr = g_pDevice->BeginScene();
if (SUCCEEDED(hr))
{
g_pDevice->SetStreamSource(0, g_pVertexBuffer, 0, sizeof(Vertex)); //顶点缓存的使用3:将顶点缓存绑定到一个设备数据流
g_pDevice->SetFVF(Vertex::FVF); //顶点缓存的使用4:定制灵活顶点格式
g_pDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); //顶点缓存的使用5:设置着色模式
g_pDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);//D3D默认设置为该值
g_pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1); //顶点缓存的使用6:
g_pDevice->EndScene();
}
hr = g_pDevice->Present(nullptr, nullptr, NULL, nullptr);
}
运行结果: