#include
<
d3dx9.h
>
#pragma
comment(lib,"d3d9.lib")
#pragma
comment(lib,"d3dx9.lib")
#pragma
comment(lib,"winmm.lib")
D3DXVECTOR3 CubeLookAt[]
=
{
D3DXVECTOR3(
0.0f
,
-
30.0f
,
-
30.0f
),
D3DXVECTOR3(
0.0f
,
0.0f
,
0.0f
),
D3DXVECTOR3(
0.0f
,
1.0f
,
0.0f
)
};
LPDIRECT3D9 g_pD3D
=
NULL;
//
Direct3D对象
LPDIRECT3DDEVICE9 g_pD3DDevice
=
NULL;
//
Direct3D设备对象
LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer
=
NULL;
//
Buffer to hold vertices
PDIRECT3DTEXTURE9 g_pTexture
=
NULL;
//
纹理指针
LPD3DXMESH g_pMesh
=
NULL;
//
网格模型对象
D3DMATERIAL9
*
g_pMeshMaterials
=
NULL;
//
网格模型材质
LPDIRECT3DTEXTURE9
*
g_pMeshTextures
=
NULL;
//
网格模型纹理
DWORD g_dwNumMaterials
=
0L
;
//
网格模型材质数量
struct
CUSTOMVERTEX
//
自定义的顶点格式
{
FLOAT x, y, z;
//
顶点坐标
DWORD color;
//
顶点颜色
FLOAT tu, tv;
//
纹理坐标
};
//
Flexible Vertex Format (FVF) 灵活顶点格式
#define
D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
//
释放对象
#define
SafeRelease(pObject) if(pObject != NULL) {pObject->Release(); pObject=NULL;}
//
释放对象数组
#define
SafeDelete(pObjectArray) if(pObjectArray != NULL){delete[] pObjectArray;}
//
键盘控制
#define
KeyDown(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define
KeyUp(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
/*
*************************************************************
* Desc: 初始化 Direct3D
*************************************************************
*/
HRESULT InitialiseD3D(HWND hWnd)
{
//
First of all, create the main D3D object. If it is created successfully we
//
should get a pointer to an IDirect3D8 interface.
g_pD3D
=
Direct3DCreate9(D3D_SDK_VERSION);
if
(g_pD3D
==
NULL)
{
return
E_FAIL;
}
//
Get the current display mode
/*
D3DDISPLAYMODE d3ddm;
if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
{
return E_FAIL;
}
*/
//
Create a structure to hold the settings for our device
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(
&
d3dpp,
sizeof
(d3dpp));
//
Fill the structure.
//
We want our program to be windowed, and set the back buffer to a format
//
that matches our current display mode
d3dpp.Windowed
=
TRUE;
d3dpp.SwapEffect
=
D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat
=
D3DFMT_UNKNOWN;
//
深度缓冲
d3dpp.AutoDepthStencilFormat
=
D3DFMT_D16;
d3dpp.EnableAutoDepthStencil
=
TRUE;
//
Create a Direct3D device.
if
(FAILED(g_pD3D
->
CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&
d3dpp,
&
g_pD3DDevice)))
{
return
E_FAIL;
}
//
开启背面拣选
//
g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
//
去除灯光
//
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
//
激活深度缓冲
//
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
//
设置环境灯光
g_pD3DDevice
->
SetRenderState(D3DRS_AMBIENT,
0xFFFFFFFF
);
return
S_OK;
}
/*
*************************************************************
* Desc: 初始化顶点缓冲(立方体)
*************************************************************
*/
HRESULT InitVertexBuffer()
{
VOID
*
pVertices;
//
Store each point of the cube together with it's colour
//
Make sure that the points of a polygon are specified in a clockwise direction,
//
this is because anti-clockwise faces will be culled
//
We will use a three triangle strips to render these polygons
//
(Top, Sides, Bottom).
CUSTOMVERTEX cvVertices[]
=
{
//
Top Face
{
-
5.0f
,
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
0
,
0
,
255
),
0.0f
,
1.0f
},
//
Vertex 0 - Blue
{
-
5.0f
,
5.0f
,
5.0f
, D3DCOLOR_XRGB(
255
,
0
,
0
),
0.0f
,
0.0f
},
//
Vertex 1 - Red
{
5.0f
,
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
255
,
0
,
0
),
1.0f
,
1.0f
},
//
Vertex 2 - Red
{
5.0f
,
5.0f
,
5.0f
, D3DCOLOR_XRGB(
0
,
255
,
0
),
1.0f
,
0.0f
},
//
Vertex 3 - Green
//
Face 1
{
-
5.0f
,
-
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
255
,
0
,
0
),
0.0f
,
1.0f
},
//
Vertex 4 - Red
{
-
5.0f
,
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
0
,
0
,
255
),
0.0f
,
0.0f
},
//
Vertex 5 - Blue
{
5.0f
,
-
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
0
,
255
,
0
),
1.0f
,
1.0f
},
//
Vertex 6 - Green
{
5.0f
,
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
255
,
0
,
0
),
1.0f
,
0.0f
},
//
Vertex 7 - Red
//
Face 2
{
5.0f
,
-
5.0f
,
5.0f
, D3DCOLOR_XRGB(
0
,
0
,
255
),
0.0f
,
1.0f
},
//
Vertex 8 - Blue
{
5.0f
,
5.0f
,
5.0f
, D3DCOLOR_XRGB(
0
,
255
,
0
),
0.0f
,
0.0f
},
//
Vertex 9 - Green
//
Face 3
{
-
5.0f
,
-
5.0f
,
5.0f
, D3DCOLOR_XRGB(
0
,
255
,
0
),
1.0f
,
1.0f
},
//
Vertex 10 - Green
{
-
5.0f
,
5.0f
,
5.0f
, D3DCOLOR_XRGB(
255
,
0
,
0
),
1.0f
,
0.0f
},
//
Vertex 11 - Red
//
Face 4
{
-
5.0f
,
-
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
255
,
0
,
0
),
0.0f
,
1.0f
},
//
Vertex 12 - Red
{
-
5.0f
,
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
0
,
0
,
255
),
0.0f
,
0.0f
},
//
Vertex 13 - Blue
//
Bottom Face
{
5.0f
,
-
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
0
,
255
,
0
),
0.0f
,
1.0f
},
//
Vertex 14 - Green
{
5.0f
,
-
5.0f
,
5.0f
, D3DCOLOR_XRGB(
0
,
0
,
255
),
0.0f
,
0.0f
},
//
Vertex 15 - Blue
{
-
5.0f
,
-
5.0f
,
-
5.0f
, D3DCOLOR_XRGB(
255
,
0
,
0
),
1.0f
,
1.0f
},
//
Vertex 16 - Red
{
-
5.0f
,
-
5.0f
,
5.0f
, D3DCOLOR_XRGB(
0
,
255
,
0
),
1.0f
,
0.0f
},
//
Vertex 17 - Green
};
//
Create the texture from file
if
(FAILED(D3DXCreateTextureFromFile(g_pD3DDevice,
"
1.bmp
"
,
&
g_pTexture)))
{
return
E_FAIL;
}
//
Create the vertex buffer from our device.
if
(FAILED(g_pD3DDevice
->
CreateVertexBuffer(
18
*
sizeof
(CUSTOMVERTEX),
0
, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&
g_pVertexBuffer, NULL)))
{
return
E_FAIL;
}
//
Get a pointer to the vertex buffer vertices and lock the vertex buffer
if
(FAILED(g_pVertexBuffer
->
Lock(
0
,
sizeof
(cvVertices), (
void
**
)
&
pVertices,
0
)))
{
return
E_FAIL;
}
//
Copy our stored vertices values into the vertex buffer
memcpy(pVertices, cvVertices,
sizeof
(cvVertices));
//
Unlock the vertex buffer
g_pVertexBuffer
->
Unlock();
return
S_OK;
}
/*
*************************************************************
* Desc: 响应键盘事件
*************************************************************
*/
VOID ProcInput()
{
if
(KeyDown(VK_DOWN))
{
CubeLookAt[
0
].z
-=
0.2f
;
CubeLookAt[
1
].z
-=
0.2f
;
}
if
(KeyDown(VK_UP))
{
CubeLookAt[
0
].z
+=
0.2f
;
CubeLookAt[
1
].z
+=
0.2f
;
}
if
(KeyDown(VK_RIGHT))
{
CubeLookAt[
1
].x
+=
0.2f
;
}
if
(KeyDown(VK_LEFT))
{
CubeLookAt[
1
].x
-=
0.2f
;
}
}
/*
*************************************************************
* Desc: 初始化网格模型
*************************************************************
*/
HRESULT InitMesh()
{
LPD3DXBUFFER pMaterialsBuffer;
//
从磁盘文件加载网格模型
if
(FAILED(D3DXLoadMeshFromX(
"
SKULL.x
"
, D3DXMESH_MANAGED, g_pD3DDevice, NULL,
&
pMaterialsBuffer, NULL,
&
g_dwNumMaterials,
&
g_pMesh)))
{
MessageBox(NULL,
"
Could not find corresponding mesh file
"
,
"
Mesh
"
, MB_OK);
return
E_FAIL;
}
//
从网格模型中提取材质属性和纹理文件名
D3DXMATERIAL
*
matMaterials
=
(D3DXMATERIAL
*
)pMaterialsBuffer
->
GetBufferPointer();
//
Create two arrays. One to hold the materials and other to hold the textures
g_pMeshMaterials
=
new
D3DMATERIAL9[g_dwNumMaterials];
g_pMeshTextures
=
new
LPDIRECT3DTEXTURE9[g_dwNumMaterials];
//
逐块提取网格模型材质属性和纹理文件名
for
(DWORD i
=
0
; i
<
g_dwNumMaterials; i
++
)
{
//
材料属性
g_pMeshMaterials[i]
=
matMaterials[i].MatD3D;
//
设置模型材料的环境光反射系数,因为模型材料本身没有设置
g_pMeshMaterials[i].Ambient
=
g_pMeshMaterials[i].Diffuse;
//
创建纹理
if
(FAILED(D3DXCreateTextureFromFile(g_pD3DDevice,
matMaterials[i].pTextureFilename,
&
g_pMeshTextures[i])))
{
g_pMeshTextures[i]
=
NULL;
}
}
//
We've finished with the material buffer, so release it
SafeRelease(pMaterialsBuffer);
return
S_OK;
}
/*
*************************************************************
* Desc: 渲染立方体
*************************************************************
*/
void
RenderCube()
{
ProcInput();
/*
***************************
* Desc: 创建并设置世界矩阵 *
***************************
*/
D3DXMATRIX matWorld, matWorldX, matWorldY, matWorldZ;
//
Create the transformation matrices
D3DXMatrixRotationX(
&
matWorldX, timeGetTime()
/
400.0f
);
D3DXMatrixRotationY(
&
matWorldY, timeGetTime()
/
400.0f
);
D3DXMatrixRotationZ(
&
matWorldZ, timeGetTime()
/
400.0f
);
/*
我们调用了D3DXMatrixRotationX、D3DXMatrixRotationY和D3DXMatrixRotationZ
函数产生了3个矩阵而且分别将它们保存在了3个D3DXMATRIX结构中
然后我们将它们相乘后形成了世界矩阵
*/
D3DXMatrixMultiply(
&
matWorld,
&
matWorldX,
&
matWorldY);
D3DXMatrixMultiply(
&
matWorld,
&
matWorld,
&
matWorldZ);
//
我们又调用了SetTransform函数为我们的顶点应用了此变换
g_pD3DDevice
->
SetTransform(D3DTS_WORLD,
&
matWorld);
/*
***************************
* Desc: 创建并设置观察矩阵 *
***************************
*/
D3DXMATRIX matView;
D3DXMatrixLookAtLH(
&
matView,
&
CubeLookAt[
0
],
//
Camera Position
&
CubeLookAt[
1
],
//
Look At Position
&
CubeLookAt[
2
]);
//
Up Direction
g_pD3DDevice
->
SetTransform(D3DTS_VIEW,
&
matView);
/*
***************************
* Desc: 创建并设置投影矩阵 *
***************************
*/
D3DXMATRIX matProj;
/*
我们设置摄像机的镜头:我们确定了视界为PI/4(正常)而横纵比为1
我们还确定了前、后裁剪平面分别为1和500,这意味着范围之外的三角形将会被裁剪掉
*/
D3DXMatrixPerspectiveFovLH(
&
matProj, D3DX_PI
/
4
,
1.0f
,
1.0f
,
500.0f
);
g_pD3DDevice
->
SetTransform(D3DTS_PROJECTION,
&
matProj);
//
Set how the texture should be rendered.
if
(g_pTexture
!=
NULL)
{
//
A texture has been set. We don't want to blend our texture with
//
the colours of our vertices, so use D3DTOP_SELECTARG1
g_pD3DDevice
->
SetTexture(
0
, g_pTexture);
g_pD3DDevice
->
SetTextureStageState(
0
, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
}
else
{
//
No texture has been set. So we will disable texture rendering.
g_pD3DDevice
->
SetTextureStageState(
0
, D3DTSS_COLOROP, D3DTOP_DISABLE);
}
//
Rendering our objects
g_pD3DDevice
->
SetStreamSource(
0
, g_pVertexBuffer,
0
,
sizeof
(CUSTOMVERTEX));
g_pD3DDevice
->
SetFVF(D3DFVF_CUSTOMVERTEX);
g_pD3DDevice
->
DrawPrimitive(D3DPT_TRIANGLESTRIP,
0
,
2
);
//
Top
g_pD3DDevice
->
DrawPrimitive(D3DPT_TRIANGLESTRIP,
4
,
8
);
//
Sides
g_pD3DDevice
->
DrawPrimitive(D3DPT_TRIANGLESTRIP,
14
,
2
);
//
Bottom
}
/*
*************************************************************
* Desc: 渲染网格模型
*************************************************************
*/
DWORD RenderMesh()
{
//
创建并设置世界坐标系
D3DXMATRIX matWorld;
D3DXMatrixRotationY(
&
matWorld, timeGetTime()
/
1000.0f
);
g_pD3DDevice
->
SetTransform(D3DTS_WORLD,
&
matWorld);
//
创建并设置观察矩阵
D3DXMATRIX matView;
D3DXMatrixLookAtLH(
&
matView,
&
D3DXVECTOR3(
0.0f
,
0.0f
,
-
20.0f
),
&
D3DXVECTOR3(
0.0f
,
0.0f
,
0.0f
),
&
D3DXVECTOR3(
0.0f
,
1.0f
,
0.0f
));
g_pD3DDevice
->
SetTransform(D3DTS_VIEW,
&
matView);
//
创建并设置投影矩阵
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH(
&
matProj, D3DX_PI
/
4
,
1.0f
,
1.0f
,
100.0f
);
g_pD3DDevice
->
SetTransform(D3DTS_PROJECTION,
&
matProj);
//
逐块渲染网格模型
if
(g_pMesh
!=
NULL)
{
for
(DWORD i
=
0
; i
<
g_dwNumMaterials; i
++
)
{
g_pD3DDevice
->
SetMaterial(
&
g_pMeshMaterials[i]);
g_pD3DDevice
->
SetTexture(
0
, g_pMeshTextures[i]);
g_pMesh
->
DrawSubset(i);
}
return
g_pMesh
->
GetNumFaces();
}
else
{
MessageBox(NULL,
"
Could not open mesh file
"
,
"
Mesh
"
, MB_OK);
return
0
;
}
}
/*
*************************************************************
* Desc: 渲染主场景
*************************************************************
*/
void
Render()
{
if
(g_pD3DDevice
==
NULL)
{
return
;
}
//
清空深度缓冲
g_pD3DDevice
->
Clear(
0
, NULL, D3DCLEAR_TARGET
|
D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(
0
,
0
,
0
),
1.0f
,
0
);
//
Begin the scene
g_pD3DDevice
->
BeginScene();
//
RenderCube();
RenderMesh();
//
End the scene
g_pD3DDevice
->
EndScene();
//
Filp the back and front buffers so that whatever has been rendered on the
//
back buffer will now be visible on screen (front buffer).
g_pD3DDevice
->
Present(NULL, NULL, NULL, NULL);
}
/*
*************************************************************
* Desc: 释放对象
*************************************************************
*/
void
CleanUp()
{
SafeDelete(g_pMeshMaterials);
if
(g_pMeshTextures
!=
NULL)
{
for
(DWORD i
=
0
; i
<
g_dwNumMaterials; i
++
)
{
if
(g_pMeshTextures[i])
{
SafeRelease(g_pMeshTextures[i]);
}
}
}
SafeDelete(g_pMeshTextures);
SafeRelease(g_pMesh);
SafeRelease(g_pTexture);
SafeRelease(g_pVertexBuffer);
SafeRelease(g_pD3DDevice);
SafeRelease(g_pD3D);
}
/*
*************************************************************
* Desc: 游戏循环
*************************************************************
*/
void
GameLoop()
{
//
Enter the game loop
MSG msg;
BOOL fMessage;
PeekMessage(
&
msg, NULL,
0U
,
0U
, PM_NOREMOVE);
while
(msg.message
!=
WM_QUIT)
{
fMessage
=
PeekMessage(
&
msg, NULL,
0U
,
0U
, PM_REMOVE);
if
(fMessage)
{
//
Process message
TranslateMessage(
&
msg);
//
将虚拟键消息转换为字符消息
DispatchMessage(
&
msg);
//
将转换后的消息传送给windows
}
else
{
//
No message to process, so render the current scene
Render();
}
}
}
/*
*************************************************************
* Desc: 消息处理函数
*************************************************************
*/
LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch
(msg)
{
case
WM_DESTROY:
PostQuitMessage(
0
);
return
0
;
break
;
case
WM_KEYUP:
switch
(wParam)
{
case
VK_ESCAPE:
//
User has pressed the escape key, so quit
DestroyWindow(hWnd);
return
0
;
break
;
}
break
;
}
return
DefWindowProc(hWnd, msg, wParam, lParam);
//
调用默认消息处理过程
}
/*
*************************************************************
* Desc: WIN32入口函数
*************************************************************
*/
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
{
//
Register the window class
/*
WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, WinProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"DX Project 3", NULL};
*/
WNDCLASSEX wc;
//
指定了结构的大小
wc.cbSize
=
sizeof
(WNDCLASSEX);
wc.style
=
CS_CLASSDC;
//
指定窗口类别的消息处理函数
wc.lpfnWndProc
=
WinProc;
//
指定窗口结构的额外空间
wc.cbClsExtra
=
0L
;
wc.cbWndExtra
=
0L
;
//
代表程序的实例句柄
wc.hInstance
=
GetModuleHandle(NULL);
//
图标
wc.hIcon
=
LoadIcon(NULL,MAKEINTRESOURCE(IDI_ERROR));
//
鼠标指针
wc.hCursor
=
LoadCursor(NULL,MAKEINTRESOURCE(IDC_CROSS));
//
背景
wc.hbrBackground
=
NULL;
//
菜单
wc.lpszMenuName
=
NULL;
//
窗口类的名称
wc.lpszClassName
=
"
DX Project 3
"
;
//
包含了窗口类的小图标句柄
wc.hIconSm
=
NULL;
RegisterClassEx(
&
wc);
//
全屏模式
/*
HWND hWnd = CreateWindow("DX Project 3", "3D游戏",
WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
GetDesktopWindow(), NULL, wc.hInstance, NULL);
*/
//
窗口模式
HWND hWnd
=
CreateWindow(
"
DX Project 3
"
,
"
3D游戏
"
,
WS_OVERLAPPEDWINDOW
&
~
WS_MAXIMIZEBOX
&
~
WS_MINIMIZEBOX,
50
,
50
,
500
,
500
,
GetDesktopWindow(), NULL, wc.hInstance, NULL);
//
Initialize Direct3D
if
(SUCCEEDED(InitialiseD3D(hWnd)))
{
//
Show our window
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
//
Initialize Vertex Buffer
if
(SUCCEEDED(
/*
InitVertexBuffer()
*/
InitMesh()))
{
//
Start game running: Enter the game loop
GameLoop();
}
}
CleanUp();
UnregisterClass(
"
DX Project 3
"
, wc.hInstance);
return
0
;
}