本文介绍编写Direct3D程序的一般步骤和框架函数:
一般步骤:
1.注册窗口类
2.创建窗口
3.创建设备
4.初始化程序要用的资源如顶点或索引缓存
5.游戏循环即消息循环,在没有消息时进行场景的绘制
6.程序退出前的清理操作,释放申请的资源
框架函数:
1.InitDirect3D函数完成步骤1、2、3
2.Setup函数完成步骤4
3.GameLoop函数完成步骤5
4.Render函数进行场景绘制
5.Cleanup函数完成步骤6
以下是框架函数的声明头文件:
/***************************************************************
* Direct3D程序框架的函数声明文件
***************************************************************
* FileName : Common.h
* Author : Anonymous
* Time : 2013/12/22
***************************************************************/
#pragma once
#include<d3d9.h>
/****************************************************************
*函数名 : InitDirect3D
*功能 : 注册窗口类,创建程序窗口,创建IDirect3DDevice9接口对象
*输入 : hInstance:程序实例句柄,
* nWidth:窗口宽度,nHeight:窗口高度,
* bWindowed:窗口模式还是全屏模式
*输出 : 无
*返回值 : 成功:TRUE 失败:FALSE
****************************************************************/
BOOL InitDirect3D(HINSTANCE hInstance,int nWidth,int nHeight,BOOL bWindowed);
/****************************************************************
*函数名 : Setup
*功能 : 创建与初始化资源、缓存、变换等
*输入 : hWnd:窗口句柄
*输出 : 无
*返回值 : 成功:TRUE 失败:FALSE
****************************************************************/
BOOL Setup(HWND hWnd);
/****************************************************************
*函数名 : GameLoop
*功能 : 游戏循环(消息循环)
*输入 : 无
*输出 : 无
*返回值 : 无
****************************************************************/
void GameLoop();
/****************************************************************
*函数名 : Render
*功能 : 场景绘制
*输入 : 无
*输出 : 无
*返回值 : 无
****************************************************************/
void Render();
/****************************************************************
*函数名 : Cleanup
*功能 : 程序退出时释放申请的资源
*输入 : 无
*输出 : 无
*返回值 : 无
****************************************************************/
void Cleanup();
以下是框架函数的实现(注释非常清楚):
/****************************************************************
*函数名 : InitDirect3D
*功能 : 注册窗口类,创建程序窗口,创建IDirect3DDevice9接口对象
*输入 : hInstance:程序实例句柄,
* nWidth:窗口宽度,nHeight:窗口高度,
* bWindowed:窗口模式还是全屏模式
*输出 : 无
*返回值 : 成功:TRUE 失败:FALSE
****************************************************************/
BOOL InitDirect3D(HINSTANCE hInstance,int nWidth,int nHeight,BOOL bWindowed)
{
HINSTANCE hInst=hInstance;
if(NULL==hInst)
hInst=GetModuleHandle(NULL);//如果hInstance为NULL,则得到当前程序的实例句柄
/********** Step 1 : 注册窗口类 **************/
WNDCLASS wndcls;//窗口类
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);//使用系统自带的灰色画刷
wndcls.hCursor=LoadCursor(hInst,MAKEINTRESOURCE(IDC_MAIN_CURSOR));//设置光标
wndcls.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_MAIN_ICON));//设置图标
wndcls.hInstance=hInst;
wndcls.lpfnWndProc=WndProc;//设置窗口过程,用于处理各种消息
wndcls.lpszClassName=g_pszClassName;//窗口类名
wndcls.lpszMenuName=NULL;
wndcls.style=CS_VREDRAW|CS_HREDRAW;
//注册窗口类,失败返回FALSE
if(!RegisterClass(&wndcls))
return FALSE;
/********** Step 2 : 创建窗口 **************/
g_hWnd=CreateWindow(g_pszClassName,//类名
g_pszWindowName,//窗口标题
WS_OVERLAPPEDWINDOW,//风格
300,//左上角点的横坐标
80,//左上角点的纵坐标
nWidth,//窗口宽度
nHeight,//窗口高度
NULL,//父窗口实例句柄
NULL,//菜单句柄
hInst,//实例句柄
NULL);
//判断窗口是否创建成功
if(NULL==g_hWnd)
{
UnregisterClass(g_pszClassName,hInst);
return FALSE;
}
/********** Step 3 : 创建IDirect3DDevice9接口对象 **************/
//Step 3.1 : 创建IDirect3D9 接口对象
LPDIRECT3D9 pD3D=NULL;
pD3D=Direct3DCreate9(D3D_SDK_VERSION);
if(NULL==pD3D)//创建失败
{
UnregisterClass(g_pszClassName,hInst);
return FALSE;
}
//Step 3.2 : 获取设备性能信息,设置顶点处理方式:软件or硬件
D3DCAPS9 caps;
int vp=0;//顶点处理方式
if(FAILED(pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,&caps)))
{
SAFE_RELEASE(pD3D);
return FALSE;
}
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)//判断设备是否支持硬件顶点处理(转换和光照)
vp=D3DCREATE_HARDWARE_VERTEXPROCESSING;//硬件处理
else
vp=D3DCREATE_SOFTWARE_VERTEXPROCESSING;//软件处理
//Step 3.3 : 初始化创建设备的参数
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.AutoDepthStencilFormat=D3DFMT_D24S8;//24位深度缓存,8位模板缓存
d3dpp.BackBufferCount=1;//后台缓存数
d3dpp.BackBufferFormat=D3DFMT_A8R8G8B8;//后台缓存像素点格式
d3dpp.BackBufferHeight=nHeight;//后台缓存高度(像素)
d3dpp.BackBufferWidth=nWidth;//宽度
d3dpp.EnableAutoDepthStencil=true;//自动管理深度缓存和模板缓存
d3dpp.Flags=0;//其他标识
d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;//刷新频率
d3dpp.hDeviceWindow=g_hWnd;//要绘制的窗口句柄
d3dpp.MultiSampleQuality=0;//多重采样质量
d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;//多重采样设为无
d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;//立即提交/交换
d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;//交换时销毁缓存
d3dpp.Windowed=bWindowed;//窗口模式还是全屏模式
//Step 3.4 : 创建设备
if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,g_hWnd,vp,&d3dpp,&g_pd3dDevice)))
{
SAFE_RELEASE(pD3D);
return FALSE;
}
SAFE_RELEASE(pD3D);
return TRUE;
}
/****************************************************************
*函数名 : Setup
*功能 : 创建与初始化资源、缓存、变换等
*输入 : hWnd:窗口句柄
*输出 : 无
*返回值 : 成功:TRUE 失败:FALSE
****************************************************************/
BOOL Setup(HWND hWnd)
{
if(NULL==hWnd)
return FALSE;
//显示窗口
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
return TRUE;
}
/****************************************************************
*函数名 : GameLoop
*功能 : 游戏循环(消息循环)
*输入 : 无
*输出 : 无
*返回值 : 无
****************************************************************/
void GameLoop()
{
MSG msg;
ZeroMemory(&msg,sizeof(MSG));
//消息循环,收到WM_QUIT时退出程序
while(WM_QUIT != msg.message)
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
//有消息产生,转发消息
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//没有消息,利用空余时间绘制场景
Render();
}
}
}
/****************************************************************
*函数名 : Render
*功能 : 场景绘制
*输入 : 无
*输出 : 无
*返回值 : 无
****************************************************************/
void Render()
{
//清屏,颜色设为灰色,深度缓存置为1.0,模板缓存置为0
g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(150,150,150),1.0,0);
if(SUCCEEDED(g_pd3dDevice->BeginScene()))//开始绘制
{
/*在此绘制其他*/
g_pd3dDevice->EndScene();//结束绘制
}
g_pd3dDevice->Present(NULL,NULL,NULL,NULL);//翻转,显示
}
/****************************************************************
*函数名 : Cleanup
*功能 : 程序退出时释放申请的资源
*输入 : 无
*输出 : 无
*返回值 : 无
****************************************************************/
void Cleanup()
{
SAFE_RELEASE(g_pd3dDevice);
}
在Cleanup函数中SAFE_RELEASE为宏定义,以便释放COM接口对象,其定义如下:
//释放COM接口对象的宏
#define SAFE_RELEASE(p) \
do \
{ \
if(p) \
{ \
(p)->Release(); \
(p)=NULL; \
} \
}while(0);
下面就是程序的主函数与窗口过程函数以及一些全局变量的定义以方便后期的修改:
//全局变量
HWND g_hWnd=NULL;//窗口句柄
LPTSTR g_pszClassName=TEXT("Demo_01");//类名
LPTSTR g_pszWindowName=TEXT("Demo_01 : 实现Direct3D程序的主框架");//窗口标题
const int g_nWidth=800;//窗口宽度
const int g_nHeight=600;//窗口高度
LPDIRECT3DDEVICE9 g_pd3dDevice=NULL;//IDirect3DDevice9接口对象,用它绘制场景及其他操作
//窗口过程
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_PAINT:
Render();
ValidateRect(hWnd,NULL);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
if(VK_ESCAPE==wParam)
DestroyWindow(hWnd);
break;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
//程序主函数,入口点
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR pszCmdLine,int nCmdShow)
{
//Step 1 : 注册窗口类,创建窗口,创建设备
if(!InitDirect3D(hInstance,g_nWidth,g_nHeight,TRUE))
return 0;
//Step 2 : 创建与初始化资源、缓存、变换等
if(!Setup(g_hWnd))
return 0;
//Step 3 : 游戏循环
GameLoop();
//Step 4 : 游戏退出,清理
Cleanup();
UnregisterClass(g_pszClassName,hInstance);
return 0;
}
最后是程序运行的截图: