Theme NexT works best with JavaScript enabled
0%

简单粒子系统

模拟洒水系统

思路简述

Main文件部分与创建茶壶网格模型基本相同,不同点在于 全局变量、顶点格式、 InitGeometry 函数、 Render 函数、 ClearUp 函数部分有所不同。

全局变量

增加

1
CParticleSystem*        g_pSprayParticles;     //喷洒粒子系统对象

顶点格式

1
2
3
4
5
6
struct CUSTOMVERTEX
{
D3DXVECTOR3 position;
D3DXVECTOR3 normal;
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL)

InitGeometry

1
2
3
//创建喷洒粒子系统对象
g_pSprayParticles = new CParticleSystem(500,2000);
g_pSprayParticles->Create( g_pd3dDevice );

Render

增加粒子系统的渲染

1
2
//渲染粒子系统
g_pSprayParticles->Render(g_pd3dDevice);

ClearUp

增加粒子系统的删除

1
2
3
4
//销毁粒子系统对象
if( g_pSprayParticles != NULL )
g_pSprayParticles->Destroy();
SAFE_DELETE(g_pSprayParticles);

ParticalSystem类

处理粒子系统部分,包括粒子系统的定义、创建、渲染和销毁

源代码

ParticalSystem.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//============================================================================= 
// Desc: 喷洒粒子系统类头文件
//=============================================================================
#pragma once
#include "UtilMacro.h";


//点精灵顶点结构和顶点格式
struct POINTVERTEX
{
D3DXVECTOR3 pos;
D3DCOLOR color;
};
#define D3DFVF_POINTVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)


//-----------------------------------------------------------------------------
// Desc: 粒子结构
//-----------------------------------------------------------------------------
struct PARTICLE
{
D3DXVECTOR3 m_vPos0; //初始位置
D3DXVECTOR3 m_vVel0; //初始速度
float m_fTime0; //创建时间
D3DXVECTOR3 m_vPos; //当前位置
D3DXVECTOR3 m_vVel; //当前速度
D3DXCOLOR m_vColor; //粒子颜色
PARTICLE* m_pNext; //指向下一粒子的指针
};


//-----------------------------------------------------------------------------
// Desc: 粒子系统类的定义
//-----------------------------------------------------------------------------
class CParticleSystem
{
private:
DWORD m_dwParticlesLim; //链表中粒子的最大数量
PARTICLE* m_pParticles; //当前粒子链表
PARTICLE* m_pParticlesFree; //保存已经死亡粒子的链表, 从该链表为新粒子分配内存

LPDIRECT3DVERTEXBUFFER9 m_pVB; //保存粒子数据的顶点缓存
LPDIRECT3DTEXTURE9 m_pTexture; //粒子纹理

DWORD m_dwBase; //每次填充顶点缓存时的起始位置
DWORD m_dwFlush; //一次填充顶点缓存的粒子数量
DWORD m_dwDiscard; //顶点缓存能够容纳的最大粒子数量

public:
DWORD m_dwParticles; //当前链表中粒子的数量

public:
CParticleSystem( DWORD dwFlush, DWORD dwDiscard);
~CParticleSystem();
HRESULT Create(LPDIRECT3DDEVICE9 pd3dDevice);
HRESULT Update( float fSecsPerFrame);
HRESULT Render( LPDIRECT3DDEVICE9 pd3dDevice );
HRESULT Destroy();
};

ParticleSystem.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
//=============================================================================
// Desc: 喷洒粒子系统类源文件
//=============================================================================
#include "d3dx9.h"
#include "ParticleSystem.h"

//-----------------------------------------------------------------------------
// Desc: 构造函数
//-----------------------------------------------------------------------------
CParticleSystem::CParticleSystem( DWORD dwFlush, DWORD dwDiscard)
{
m_dwBase = 0;
m_dwFlush = dwFlush;
m_dwDiscard = dwDiscard;

m_dwParticles = 0;
m_dwParticlesLim = 2000;

m_pParticles = NULL;
m_pParticlesFree = NULL;
m_pVB = NULL;
m_pTexture = NULL;
}


//-----------------------------------------------------------------------------
// Desc: 析构函数
//-----------------------------------------------------------------------------
CParticleSystem::~CParticleSystem()
{
while( m_pParticles )
{
PARTICLE* pParticle = m_pParticles;
m_pParticles = pParticle->m_pNext;
delete pParticle;
}

while( m_pParticlesFree )
{
PARTICLE *pParticle = m_pParticlesFree;
m_pParticlesFree = pParticle->m_pNext;
delete pParticle;
}
}


//-----------------------------------------------------------------------------
// Desc: 创建粒子纹理
//-----------------------------------------------------------------------------
HRESULT CParticleSystem::Create( LPDIRECT3DDEVICE9 pd3dDevice )
{
HRESULT hr;

V_RETURN( D3DXCreateTextureFromFile(pd3dDevice, L"particle.bmp", &m_pTexture ));

V_RETURN( pd3dDevice->CreateVertexBuffer( m_dwDiscard *
sizeof(POINTVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS,
D3DFVF_POINTVERTEX, D3DPOOL_SYSTEMMEM, &m_pVB, NULL ));

return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 更新当前粒子的属性
//-----------------------------------------------------------------------------
HRESULT CParticleSystem::Update( float fSecsPerFrame)
{
PARTICLE *pParticle, **ppParticle;
static float fTime = 0.0f;
fTime += fSecsPerFrame;

//更新已存在粒子的属性值
ppParticle = &m_pParticles; //粒子链表
while( *ppParticle )
{
pParticle = *ppParticle; //取出当前粒子

//计算粒子的新位置
float fT = fTime - pParticle->m_fTime0; //当前粒子已存活的时间
float fGravity = -9.8f;
pParticle->m_vPos = pParticle->m_vVel0 * fT + pParticle->m_vPos0;
pParticle->m_vPos.y += (0.5f * fGravity) * (fT * fT);
pParticle->m_vVel.y = pParticle->m_vVel0.y + fGravity * fT;

//如果粒子死亡则删除
if( pParticle->m_vPos.y < 0 ) //在本中判断粒子死亡的条件是粒子已经落到地面
{
*ppParticle = pParticle->m_pNext;
pParticle->m_pNext = m_pParticlesFree;
m_pParticlesFree = pParticle;
m_dwParticles--;
}
else //准备处理下一个粒子
{
ppParticle = &pParticle->m_pNext;
}
}


//添加新粒子
DWORD dwEmited = 0;
UINT numEmitedPerFrame = (UINT)(1000*fSecsPerFrame); //每次发射的粒子数
while( m_dwParticles < m_dwParticlesLim && dwEmited<=numEmitedPerFrame)
{
//创建一个新粒子
if( m_pParticlesFree )
{
pParticle = m_pParticlesFree;
m_pParticlesFree = pParticle->m_pNext;
}
else
{
if( NULL == ( pParticle = new PARTICLE ) )
return E_OUTOFMEMORY;
}

//将新粒子链接到粒子链表
pParticle->m_pNext = m_pParticles;
m_pParticles = pParticle;
m_dwParticles++;
dwEmited++;

//为新粒子设置初始位置、初始速度、当前位置、当前速度、颜色和创建时间等属性
float fRand = ((float)rand()/(float)RAND_MAX)*2.0f - 1.0f; //[-1,1]
pParticle->m_vPos0 = D3DXVECTOR3(0,1,0); //粒子初始位置
pParticle->m_vVel0.x = 8.0f*fRand; //粒子初始速度
pParticle->m_vVel0.z = 10.0f;
pParticle->m_vVel0.y = 0.0f;

pParticle->m_vPos = pParticle->m_vPos0;
pParticle->m_vVel = pParticle->m_vVel0;

pParticle->m_vColor = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); //粒子颜色
pParticle->m_fTime0 = fTime; //粒子创建时间
}

return S_OK;
}


//将FLOAT型参数转换为DWORD型
inline DWORD FtoDW( FLOAT f ) { return *((DWORD*)&f); }

//-----------------------------------------------------------------------------
// Desc: 渲染粒子系统
//-----------------------------------------------------------------------------
HRESULT CParticleSystem::Render( LPDIRECT3DDEVICE9 pd3dDevice )
{
HRESULT hr;

//为使用点精灵设置相关渲染状态
pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, true ); //使用点精灵
pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE, true );
pd3dDevice->SetRenderState( D3DRS_POINTSIZE, FtoDW(0.1f) ); //粒子大小
pd3dDevice->SetRenderState( D3DRS_POINTSIZE_MIN, FtoDW(0.00f) ); //点的最小尺寸
pd3dDevice->SetRenderState( D3DRS_POINTSCALE_A, FtoDW(0.00f) );
pd3dDevice->SetRenderState( D3DRS_POINTSCALE_B, FtoDW(0.00f) );
pd3dDevice->SetRenderState( D3DRS_POINTSCALE_C, FtoDW(1.00f) );

pd3dDevice->SetRenderState( D3DRS_LIGHTING, false ); //禁用光照处理
pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, false ); //禁用深度缓存操作
pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true ); //启用Alpha 混合
pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE ); //注意Alpha混合方式
pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );

pd3dDevice->SetTexture(0, m_pTexture ); //设置粒子纹理

//为渲染粒子准备顶点缓存数据
pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(POINTVERTEX) );
pd3dDevice->SetFVF( D3DFVF_POINTVERTEX );

PARTICLE* pParticle = m_pParticles;
POINTVERTEX* pVertices;
DWORD dwNumParticlesToRender = 0;

//确定锁定顶点缓存的起始位置
m_dwBase += m_dwFlush;
if(m_dwBase >= m_dwDiscard) //顶点缓存已满, 重新从头开始锁定
m_dwBase = 0;

//锁定一个顶点缓存片段
V_RETURN( hr = m_pVB->Lock( m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
(void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ));

//使用粒子位置和颜色数据填充顶点缓存, 并渲染
while( pParticle )
{
//根据粒子的运动速度确定其模糊程度,
D3DXVECTOR3 vPos(pParticle->m_vPos);
D3DXVECTOR3 vVel(pParticle->m_vVel);
FLOAT fLengthSq = D3DXVec3LengthSq(&vVel);
UINT dwSteps;

if( fLengthSq < 1.0f ) dwSteps = 2;
else if( fLengthSq < 4.00f ) dwSteps = 3;
else if( fLengthSq < 9.00f ) dwSteps = 4;
else if( fLengthSq < 12.25f ) dwSteps = 5;
else if( fLengthSq < 16.00f ) dwSteps = 6;
else if( fLengthSq < 20.25f ) dwSteps = 7;
else dwSteps = 8;

vVel *= -0.04f / (float)dwSteps;
DWORD dwDiffuse = (DWORD) pParticle->m_vColor;

//通过对其在不同位置渲染多次来实现模糊效果
for( DWORD i = 0; i < dwSteps; i++ )
{
pVertices->pos = vPos; //点图元的位置
pVertices->color = dwDiffuse; //点图元的颜色
pVertices++;
vPos += vVel; //为实现模糊效果确定该点图元的下一位置

if( ++dwNumParticlesToRender == m_dwFlush ) //填充完毕指定的数据块
{
m_pVB->Unlock();
pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender);

m_dwBase += m_dwFlush;
if(m_dwBase >= m_dwDiscard)
m_dwBase = 0;

m_pVB->Lock( m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
(void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD );
dwNumParticlesToRender = 0; //将需要渲染的顶点数重新置零
} //end if
} //end for
pParticle = pParticle->m_pNext;
} //end while

// Unlock the vertex buffer
m_pVB->Unlock();

//渲染剩余不足一块的粒子
if( dwNumParticlesToRender )
{
pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender );
}

//恢复相关渲染状态
pd3dDevice->SetRenderState( D3DRS_LIGHTING, true );
pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, false );
pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE, false );
pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, true );
pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, false );

return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 释放粒子顶点缓存和粒子纹理
//-----------------------------------------------------------------------------
HRESULT CParticleSystem::Destroy()
{
SAFE_RELEASE(m_pVB);
SAFE_RELEASE(m_pTexture);
return S_OK;
}

UtilMacro.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//=============================================================================
// Desc: 辅助宏定义
//=============================================================================

#pragma once

#ifndef V
#define V(x) { hr = x; }
#endif

#ifndef V_RETURN
#define V_RETURN(x) { hr = x; if( FAILED(hr) ) { return hr; } }
#endif

#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
#endif
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#endif

Main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
//=============================================================================
// Desc: 绘制茶壶模型
//=============================================================================
#include <d3dx9.h> //该头文件中又包含了d3d9.h头文件
#include <tchar.h>
#include <d3dx9core.h>
#include "UtilMacro.h"


//-----------------------------------------------------------------------------
// Desc: 全局变量
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL; //Direct3D对象
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; //Direct3D设备对象
LPD3DXFONT g_pFont = 0; //字体对象
LPD3DXMESH g_pTeapotMesh = NULL; //茶壶网格模型

RECT g_ClientRect; //窗口客户区
float g_FPS = 0; //帧速率
WCHAR g_strFPS[20]; //包含帧速率的字符数组


//-----------------------------------------------------------------------------
// Desc: 顶点结构和顶点格式
//-----------------------------------------------------------------------------
struct CUSTOMVERTEX
{
D3DXVECTOR3 position;
DWORD color;
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)


//-----------------------------------------------------------------------------
// Desc: 设置世界矩阵
//-----------------------------------------------------------------------------
void SetWorldMatrix()
{
//创建并设置世界矩阵
D3DXMATRIXA16 matWorld;
float time = timeGetTime() * 0.001f;
float fAngle = time * D3DX_PI / 2;
//fAngle = 0;
D3DXMatrixRotationY(&matWorld, fAngle); //旋转
g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);
}


//-----------------------------------------------------------------------------
// Desc: 设置观察矩阵和投影矩阵
//-----------------------------------------------------------------------------
void SetViewandProjMatrices()
{
//建立并设置观察矩阵
D3DXVECTOR3 vEyePt(0.0f, 0.0f, -5.0f);
D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);

//建立并设置投影矩阵
D3DXMATRIXA16 matProj;
float aspect = (float)(g_ClientRect.right - g_ClientRect.left) / (g_ClientRect.bottom - g_ClientRect.top);
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, aspect, 1.0f, 100.0f);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}


//-----------------------------------------------------------------------------
// Desc: 设置灯光
//-----------------------------------------------------------------------------
void SetLights()
{
//方向光
D3DXVECTOR3 vecDir;
D3DLIGHT9 light;
ZeroMemory(&light, sizeof(D3DLIGHT9));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse.r = 1.0f;
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;
vecDir = D3DXVECTOR3(1, -1, 1);
D3DXVec3Normalize((D3DXVECTOR3*)&light.Direction, &vecDir);
light.Range = 1000.0f;
g_pd3dDevice->SetLight(0, &light);
g_pd3dDevice->LightEnable(0, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, true);

//全局环境光
g_pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0xff505050);
}

//-----------------------------------------------------------------------------
// Desc: 设置材质
//-----------------------------------------------------------------------------
void SetMaterial()
{
D3DMATERIAL9 mtrl;
ZeroMemory(&mtrl, sizeof(D3DMATERIAL9));
mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
mtrl.Diffuse.g = mtrl.Ambient.g = 0.0f;
mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f;
mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
g_pd3dDevice->SetMaterial(&mtrl);
}


//-----------------------------------------------------------------------------
// Desc: 初始化Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D(HWND hWnd)
{
HRESULT hr;

//创建Direct3D对象, 该对象用来创建Direct3D设备对象
g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (g_pD3D == NULL)
return E_FAIL;

//检查设备性能
D3DCAPS9 caps;
g_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);

//检查设备是否支持硬件顶点处理
int vp = 0;
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}

//设置D3DPRESENT_PARAMETERS结构
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

//创建Direct3D设备对象
V_RETURN(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, vp, &d3dpp, &g_pd3dDevice));

//创建字体对象
V_RETURN(D3DXCreateFont(g_pd3dDevice, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"Arial", &g_pFont));

//获取窗口客户区
GetClientRect(hWnd, &g_ClientRect);

//设置观察和投影矩阵
SetViewandProjMatrices();

return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 创建场景图形
//-----------------------------------------------------------------------------
HRESULT InitGeometry()
{
HRESULT hr;
V_RETURN(D3DXCreateTeapot(g_pd3dDevice, &g_pTeapotMesh, NULL));
return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 计算帧速率
//-----------------------------------------------------------------------------
float GetFPS()
{
static float fps = 0;
static int frameCount = 0;
static float currentTime = 0.0f;
static float lastTime = 0.0f;

frameCount++;
currentTime = timeGetTime()*0.001f;

if (currentTime - lastTime > 1.0f)
{
fps = (float)frameCount / (currentTime - lastTime);
lastTime = currentTime;
frameCount = 0;
}

return fps;
}


//-----------------------------------------------------------------------------
// Desc: 渲染图形
//-----------------------------------------------------------------------------
void Render()
{
//清空后台缓存
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(45, 50, 170), 1.0f, 0);

//开始在后台缓存绘制图形
if (SUCCEEDED(g_pd3dDevice->BeginScene()))
{
//设置灯光和材质
SetLights();
SetMaterial();

//设置世界矩阵
SetWorldMatrix();

//绘制茶壶
g_pTeapotMesh->DrawSubset(0);

//在窗口左上角绘制文本
int charCount = swprintf_s(g_strFPS, 20, L"FPS: %0.2f", GetFPS());
g_pFont->DrawText(NULL, g_strFPS, charCount, &g_ClientRect, DT_TOP | DT_LEFT, 0xffffffff);

//结束在后台缓存渲染图形
g_pd3dDevice->EndScene();
}

//将在后台缓存绘制的图形提交到前台缓存显示
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}


//-----------------------------------------------------------------------------
// Desc: 释放创建的对象
//-----------------------------------------------------------------------------
void Cleanup()
{
SAFE_RELEASE(g_pTeapotMesh);
SAFE_RELEASE(g_pFont);
SAFE_RELEASE(g_pd3dDevice);
SAFE_RELEASE(g_pD3D);
}


//-----------------------------------------------------------------------------
// Desc: 消息处理
//-----------------------------------------------------------------------------
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
PostQuitMessage(0);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;
}

return DefWindowProc(hWnd, msg, wParam, lParam);
}


//-----------------------------------------------------------------------------
// Desc: 程序入口
//-----------------------------------------------------------------------------
int _stdcall _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PTSTR szCmdLine, int iCmdShow)
{
//定义窗口类
WNDCLASSEX wndClassEx;
wndClassEx.cbSize = sizeof(WNDCLASSEX);
wndClassEx.style = CS_CLASSDC;
wndClassEx.lpfnWndProc = WndProc;
wndClassEx.cbClsExtra = 0;
wndClassEx.cbWndExtra = 0;
wndClassEx.hInstance = hInstance;
wndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClassEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClassEx.lpszMenuName = NULL;
wndClassEx.lpszClassName = L"ClassName";
wndClassEx.hIconSm = NULL;

//注册窗口类
if (!RegisterClassEx(&wndClassEx))
{
MessageBox(NULL, L"注册窗口类失败!", L"Teapot", 0);
return 0;
}

//创建窗口
HWND hWnd = NULL;
hWnd = CreateWindowEx(NULL, //窗口扩展风格
L"ClassName", //窗口类名称
L"Teapot", //窗口标题
WS_OVERLAPPEDWINDOW, //窗口风格
CW_USEDEFAULT, //窗口初始X位置
CW_USEDEFAULT, //窗口初始Y位置
600, //窗口初始宽度
480, //窗口初始高度
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL); // 创建参数

if (hWnd == NULL)
{
MessageBox(NULL, L"创建窗口失败!", L"Teapot", 0);
return 0;
}


//初始化Direct3D
if (SUCCEEDED(InitD3D(hWnd)))
{
//创建并填充顶点缓存
if (SUCCEEDED(InitGeometry()))
{
//显示窗口
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);

//进入消息循环
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Render(); //渲染图形
}
}
}
}

//释放创建的相关对象
Cleanup();

return 0;
}