首先是头文件,在那里面定义了3个函数,分别是初始化函数InitD3D(),消息循环函数EnterMsgLoop ,窗口过程函数WndProc()
其余的Release() Delete()都是以模板函数定义。
Release()为了方便释放接口,并设置为NULL,而Delete()则是为了方便删除,并清空指针。
注释很多(毕竟本弱是Win32的新手,很多概念都得靠网上百度才能理解)
d3dUtility.h#ifndef __d3dUtilityH__
#define __d3dUtilityH__
#include<d3dx9.h>
#include <string>
namespace d3d
{
bool InitD3D(
HINSTANCE hInstance, //当前应用程序实例的句柄
int width, int height, //后台缓存的表面宽度和高度
bool windowed, //是否窗口化
D3DDEVTYPE deviceType, //D3D设备类型 硬件(HAL)或者引用(REF)或软件(SW)
IDirect3DDevice9** device);//以创建的设备(用于输出)
int EnterMsgLoop(
bool(*ptr_display)(float timeDelta));
LRESULT CALLBACK WndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam);
template<class T>void Release(T t)
{
if (t)
{
t->Release();
t = 0;
}
}
template<class T>void Delete(T t)
{
if (t)
{
delete t;
t = 0;
}
}
}
#endif // __d3dUtilityH__
d3dUtility.cpp
分了四个步骤去实现D3D的初始化。
步骤1:创建 IDirect3D9 对象
步骤2:校验硬件顶点计算
步骤3:填充D3DPRESENT_PARAMETERS 结构的初始值
步骤 4:创建设备(除此以外还实现了该程序的消息循环,EnterMsgLoop(其余注释的补充了很多我就不多说了)
#include "d3dUtility.h"
bool d3d::InitD3D(HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9 **device)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;//窗口类型(当水平长度,垂直长度,或者位置改变,重画整个窗口)
wc.lpfnWndProc = (WNDPROC)d3d::WndProc;//窗口处理函数
wc.cbClsExtra = 0;//窗口类无扩展
wc.cbWndExtra = 0;//窗口实例无扩展
wc.hInstance = hInstance;//实例句柄
wc.hIcon = LoadIcon(0, IDI_APPLICATION);//窗口最小化的图标为缺省图标
wc.hCursor = LoadCursor(0, IDC_ARROW);//窗口采用箭头光标
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//窗口的背景颜色为白色
wc.lpszMenuName = 0;//窗口无菜单
wc.lpszClassName = "Direct3D9App"; //窗口类名
if (!RegisterClass(&wc))//如果注册失败,发出警告
{
::MessageBox(0, "RegisterClass() - FALIED", 0, 0);
/**
MessageBox(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
hWnd : 消息框拥有的窗口
lpText :消息框的内容
lpCaption :消息框的标题
uType :指定标志中的一个来显示消息框的按钮以及图标(默认,只有一个确认按钮)
**/
return false;
}
HWND hwnd = 0;
hwnd = ::CreateWindow("Direct3D9App", "Direct3D9App",
WS_EX_TOPMOST,//设置窗口风格,将窗口设为置顶
0,0,width,height,
0/*父窗口*/, 0/*菜单*/, hInstance,0/*扩展*/);
if (!hwnd)
{
::MessageBox(0, "CreateWindow() - FALIED", 0, 0);
return false;
}
::ShowWindow(hwnd, SW_SHOW);
::UpdateWindow(hwnd);
HRESULT hr = 0;
//步骤1:创建 IDirect3D9 对象
IDirect3D9 *d3d9 = 0;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if (!d3d9)
{
::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
return false;
}
//步骤2:校验硬件顶点计算
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
//caps会返回装载着当前显卡设备能力的信息
int vp = 0;
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
//步骤3:填充D3DPRESENT_PARAMETERS 结构的初始值
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleQuality = 0;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = windowed;
d3dpp.EnableAutoDepthStencil = true;//若设置为true,则D3D自动创建并维护深度缓存或模板缓存
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//D24S8用24位表示深度并将8位保留供模板使用
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;//刷新频率设为默认值
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//当交换链中后台缓存切换到前台缓的时候最大速率设为立即提交
//步骤 4:创建设备
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT,//主适配器
deviceType,
hwnd,
vp,
&d3dpp,
device); //返回创建的设备
if (FAILED(hr))
{
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, device);
if (FAILED(hr))
{
d3d9->Release();
::MessageBox(0, "CreateDevice - FAILED", 0, 0);
return false;
}
}
d3d9->Release();
return true;
}
int d3d::EnterMsgLoop(bool(*ptr_display)(float timeDelta))
{
MSG msg;
::ZeroMemory(&msg, sizeof(MSG));
static float lastTime = (float)timeGetTime();
while (msg.message != WM_QUIT)
{
if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);//发出消息
}
else
{
float currTime = (float)timeGetTime();
float timeDelta = (currTime - lastTime)*0.001f;
ptr_display(timeDelta);
lastTime = currTime;
}
}
return msg.wParam;//来自一条表示退出的消息
}
d3dInit.cpp
这里主要是实现了Display()显示函数。主要的实现细节都在注释里补充,唯一需要强调的 - - 注意自己创建的是控制台还是win32应用程序。若是控制台,需要转化为win32应用程序
#include"d3dUtility.h"
IDirect3DDevice9* Device = 0;
bool Setup()
{
return true;
}
void Cleanup()
{
}
bool Display(float timeDelta)
{
if (Device)
{
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
/**
Clear(DWORD Count,const D3DRECT *pRects,DWORD Flags , DWORD Color ,float Z , DWORD Stencil);
Count pRect数组中矩形的数目
pRect 所要执行清除操作的屏幕矩形数组。该参数允许我们只对表面的部分区域进行清除操作。
Flags 指定所要清除的表面.我们可清除下列表面中的一个或多个。
D3DCLEAR_TARGET 绘制目标表面,通常指后台缓存
D3DCLEAR_ZBUFFER 深度缓存
D3DCLEAR_STRNCIL 模板缓存
Color 指定将绘制目标体设置为何种颜色
Z 深度缓存所要设定的值
Stencil 模板缓存所要设定的值
**/
Device->Present(0, 0, 0, 0);//提交后台缓存
}
return true;
}
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
::PostQuitMessage(0);
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
::DestroyWindow(hwnd);
break;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
if (!d3d::InitD3D(hinstance, 640, 480, true, D3DDEVTYPE_HAL, &Device))
{
::MessageBox(0, "InitD3D() - FAILED", 0, 0);
return 0;
}
if (!Setup())
{
::MessageBox(0, "Setup() - FAILED", 0, 0);
return 0;
}
d3d::EnterMsgLoop(Display);
Cleanup();
Device->Release();
return 0;
}