#ifndef __d3dUtilityH__
#define __d3dUtilityH__
#include
namespace d3d
{
//初始化DirectX3D
bool InitD3D(
HINSTANCE hInstance, // [in] Application instance
int width, int height, // [in] Backbuffer dimensions
bool windowed, // [in] Windowed (true)or full screen (false)
D3DDEVTYPE deviceType, // [in] HAL or REF
IDirect3DDevice9** device);// [out]The created device
//消息循环
int EnterMsgLoop(
bool(*ptr_display)(float timeDelta));
LRESULT CALLBACK Wnd_Proc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam);
template void Release(T t)
{
if (t)
{
t->Release();
t = 0;
}
}
template void Delete(T t)
{
if (t)
{
delete t;
t = 0;
}
}
}
#endif
#include "d3dUtility.h"
//#pragma comment(lib,"d3d9.lib")
//#pragma comment(lib,"d3dx9.lib")
//#pragma comment(lib,"winmm.lib")
bool d3d::InitD3D(
HINSTANCE hInstance,
int width, int height,
bool windowed,
D3DDEVTYPE deviceType,
IDirect3DDevice9** device)
{
//
// Create the main application window.
//
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)d3d::Wnd_Proc;
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() - FAILED", 0, 0);
return false;
}
HWND hwnd = 0;
hwnd = ::CreateWindow(
"Direct3D9App",
"Direct3D9App",
WS_EX_APPWINDOW,
0, 0, width, height,
0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/);
//HWND CreateWindow(
// LPCTSTR lpWindowName, // 窗口标题
// DWORD dwStyle, // 窗口风格
// int x, // 初始 x 坐标
// int y, // 初始 y 坐标
// int nWidth, // 初始 x 方向尺寸
// int nHeight, // 初始 y 方向尺寸
// HWND hWndParent, // 父窗口句柄
// HMENU hMenu, // 窗口菜单句柄
// HINSTANCE hInstance, // 程序实例句柄
// LPVOID lpParam // 创建参数
//);
if (!hwnd)
{
::MessageBox(0, "CreateWindow() - FAILED", 0, 0);
return false;
}
::ShowWindow(hwnd, SW_SHOW);
::UpdateWindow(hwnd);
// Init D3D:
HRESULT hr = 0;
//要初始化IDirect3D,首先必须获取指向接口IDrect3D9的指针。使得一个专门的Direct3D函数可以很容易做到
IDirect3D9* d3d9 = 0;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if (!d3d9)
{
::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
return false;
}
//检验图形卡是否支持该硬件顶点运算
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
int vp = 0;
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
//硬件顶点运算
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
//软件顶点运算
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
//填充D3DPRESENT_PARAMETERS结构体
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = width; //后台缓存中表面的宽度,单位为像素
d3dpp.BackBufferHeight = height; //后台缓存中表面的高度,单位为像素
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; //后台缓存的像素格式(如32位像素格式:D3DFMT_A8R8G8B8)
d3dpp.BackBufferCount = 1; //所需使用的后台缓存的个数,通常是1,需要一个后台缓存
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; //多重采样类型
d3dpp.MultiSampleQuality = 0; //多重采样的质量水平
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //枚举类型指定交换链中的缓存的页面设置方式。
d3dpp.hDeviceWindow = hwnd; //与设备相关的窗口句柄。指定了所有进行绘制的应用程序窗口
d3dpp.Windowed = windowed; //窗口模式,为false时表示全屏模式
d3dpp.EnableAutoDepthStencil = true; //为true时,自动创建并维护深度缓存或模板缓存
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; //深度缓存或模板缓存的像素格式
d3dpp.Flags = 0; //附加特性
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; //刷新频率
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //一般为立即提交或由Direct3D来选择提交
// 创建IDrect3Device9接口
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT,
deviceType,
hwnd,
vp,
&d3dpp,
device);
//HRESULT CreateDevice(
// UINT Adapter, // 希望代表的物理显卡
// D3DDEVTYPE DeviceType, // 设备类型
// HWND hFocusWindow, // 窗口句柄,指设备要绘制的目标窗口
// DWORD BehaviorFlags, // 顶点运算类型
// D3DPRESENT_PARAMETERS *pPresentationParameters, // 完成初始化的D3DPRESENT_PARAMETERS结构体
// IDirect3DDevice9 **ppReturnedDeviceInterface // 返回所创建的设备
//);
if (FAILED(hr))
{
// 再次使用16位深度缓存尝试
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();
//计算相邻两次调用ptr_display的时间间隔
float timeDelta = (currTime - lastTime)*0.001f;
//调用指定display函数
ptr_display(timeDelta);
lastTime = currTime;
}
}
return msg.wParam;
}
#include "d3dUtility.h"
//初始化设备
IDirect3DDevice9* device = NULL;
//初始化顶点缓存和索引缓存
IDirect3DVertexBuffer9* VB = 0;
IDirect3DIndexBuffer9* IB = 0;
//定义屏幕分辨率
const int width = 640;
const int height = 480;
//定义顶点结构和灵活顶点格式
typedef struct Vertex {
Vertex() {}
Vertex(float x, float y, float z) {
_x = x;
_y = y;
_z = z;
}
float _x, _y, _z;
static const DWORD FVF; //灵活顶点格式
}vertex;
const DWORD vertex::FVF = D3DFVF_XYZ;
//setup
bool setup()
{
//创建顶点缓存
device->CreateVertexBuffer(8 * sizeof(vertex), D3DUSAGE_WRITEONLY, vertex::FVF, D3DPOOL_MANAGED, &VB, 0);
//HRESULT CreateVertexBuffer(
// UINT Length, //为缓存分配的字节数
// DWORD Usage, //顶点缓冲区的附加属性,D3DUSAGE_WRITEONLY为"只写"
// DWORD FVF, //灵活顶点格式
// D3DPOOL Pool, //顶点缓冲的内存池
// IDirect3DVertexBuffer9** ppVertexBuffer, //顶点缓冲指针
// HANDLE* pSharedHandle //保留参数,置为0
//);
//创建索引缓存
device->CreateIndexBuffer(36 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16/*索引大小*/, D3DPOOL_MANAGED, &IB, 0);
//填充顶点缓存
vertex* vertices;
VB->Lock(0, 0, (void**)&vertices, 0);
vertices[0] = vertex(-1.0f, -1.0f, -1.0f);
vertices[1] = vertex(-1.0f, 1.0f, -1.0f);
vertices[2] = vertex( 1.0f, 1.0f, -1.0f);
vertices[3] = vertex( 1.0f, -1.0f, -1.0f);
vertices[4] = vertex(-1.0f, -1.0f, 1.0f);
vertices[5] = vertex(-1.0f, 1.0f, 1.0f);
vertices[6] = vertex( 1.0f, 1.0f, 1.0f);
vertices[7] = vertex( 1.0f, -1.0f, 1.0f);
VB->Unlock();
//填充索引缓存
WORD* indices = 0;
IB->Lock(0, 0, (void**)&indices, 0);
indices[ 0] = 0; indices[ 1] = 1; indices[ 2] = 2;
indices[ 3] = 0; indices[ 4] = 2; indices[ 5] = 3;
indices[ 6] = 4; indices[ 7] = 6; indices[ 8] = 5;
indices[ 9] = 4; indices[10] = 7; indices[11] = 6;
indices[12] = 4; indices[13] = 5; indices[14] = 1;
indices[15] = 4; indices[16] = 1; indices[17] = 0;
indices[18] = 3; indices[19] = 2; indices[20] = 6;
indices[21] = 3; indices[22] = 6; indices[23] = 7;
indices[24] = 1; indices[25] = 5; indices[26] = 6;
indices[27] = 1; indices[28] = 6; indices[29] = 2;
indices[30] = 4; indices[31] = 0; indices[32] = 3;
indices[33] = 4; indices[34] = 3; indices[35] = 7;
IB->Unlock();
//创建观察坐标系变换矩阵并设定变换
D3DXVECTOR3 position(0.0f, 0.0f, -5.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX v;
D3DXMatrixLookAtLH(&v, &position, &target, &up);
device->SetTransform(D3DTS_VIEW, &v);
//创建投影变换矩阵并设定变换
D3DXMATRIX projection;
D3DXMatrixPerspectiveFovLH(&projection, D3DX_PI*0.5f, (float)width / (float)height, 1.0, 1000.0f);
device->SetTransform(D3DTS_PROJECTION, &projection);
//设定绘制状态为线框模式
device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
return true;
}
//cleanup
void cleanup()
{
// 释放顶点缓存和索引缓存
d3d::Release(VB);
d3d::Release(IB);
}
//display
bool display(float timeDelta)
{
if (device == NULL)
return false;
//平移矩阵
D3DXMATRIX translation;
static float tx = -3.0f;
static float ty = 0.0f;
static const float multi = 1.0f;
static float multix = multi;
static float multiy = multi;
tx += multix*timeDelta;
ty += multiy*timeDelta;
D3DXMatrixTranslation(&translation, tx, ty, 0);
if (tx >= 3.0f)
multix = -1.0f*multi;
else if (tx <= -3.0f)
multix = 1.0f*multi;
if (ty >= 3.0f)
multiy = -1.0f*multi;
else if (ty <= -3.0f)
multiy = 1.0f*multi;
//旋转矩阵
D3DXMATRIX rotationXM, rotationYM;
static float r = 0.0f;
D3DXMatrixRotationX(&rotationXM, r);
D3DXMatrixRotationY(&rotationYM, r);
r += timeDelta;
if (r >= 6.28)
r = 0.0f;
D3DXMATRIX p = rotationXM*rotationYM*translation;
device->SetTransform(D3DTS_WORLD, &p);
device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
//HRESULT Clear(
// DWORD Count, //pRects数组中矩形的数目
// const D3DRECT *pRects, //所要执行清除操作的屏幕矩形数组
// DWORD Flags, //所要清除的表面,包括D3DCLEAR_TARGET(后台缓存), D3DCLEAR_ZBUFFER(Z深度缓存), D3DCLEAR_STENCIL(模板平面缓存)
// D3DCOLOR Color, //指定将绘制目标体设置为何种颜色
// float Z, // 设定深度缓存,[0,1]
// DWORD Stencil // 模板缓存所要设定的值
//);
device->BeginScene();
//绘制之前的准备工作
device->SetStreamSource(0, VB, 0, sizeof(vertex)); //指定数据流输入源
device->SetFVF(vertex::FVF); //设置顶点格式
device->SetIndices(IB); //设置索引缓存(任意时刻只允许使用一个索引缓存)
device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12); //绘制三角形
//HRESULT DrawIndexedPrimitive(
// D3DPRIMITIVETYPE Type, //所要绘制的图元类型
// INT BaseVertexIndex, //起始顶点索引
// UINT MinIndex, //最小索引(相对于起始顶点索引)
// UINT NumVertices, //使用的顶点数量
// UINT StartIndex, //索引缓存中的起始索引
// UINT PrimitiveCount //所要绘制的图元数量
//);
device->EndScene();
// 提交后台缓存(表面交换)
device->Present(NULL, NULL, NULL, NULL);
return true;
}
//窗口过程函数
LRESULT CALLBACK d3d::Wnd_Proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
//按下esc退出
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
//WinMain
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show)
{
if (!d3d::InitD3D(inst, 640, 480, true, D3DDEVTYPE_HAL, &device))
{
MessageBox(NULL, "init_d3d() - failed.", 0, MB_OK);
return 0;
}
if (!setup())
{
MessageBox(NULL, "Steup() - failed.", 0, MB_OK);
return 0;
}
d3d::EnterMsgLoop(display);
cleanup();
device->Release();
return 0;
}