【原创】《DirectX 9 3D 图形程序设计》 Tutorial 05 光照系统
1
#include
<
D3DX9.h
>
2 #include < string >
3 typedef std:: string String;
4 #define SAFE_RELEASE(o) {if(o){o->Release();o = 0;}}
5
6
7 LPDIRECT3D9 g_pD3D = 0 ; // D3D Driver
8 LPDIRECT3DDEVICE9 g_pd3dDevice = 0 ; // D3D 设备
9 D3DCAPS9 g_Caps = {(D3DDEVTYPE) 0 } ; // D3D 的帽子
10 LPDIRECT3DVERTEXBUFFER9 g_pVB = 0 ; // 顶点缓冲区
11 LPDIRECT3DINDEXBUFFER9 g_pIB = 0 ; // 索引缓冲区
12
13 // 顶点定义
14 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL )
15 struct CUSTOMVERTEX
16 {
17 D3DXVECTOR3 position;
18 D3DXVECTOR3 normal;
19 } ;
20
21 // 错误记录
22 void D3DErr(String strMsg)
23 {
24 MessageBox( 0 , strMsg.c_str() , " 错误 " , MB_OK);
25 }
26
27 // 初始化顶点缓冲区
28 HRESULT InitVB()
29 {
30 // 创建顶点缓冲区
31 if (FAILED(g_pd3dDevice -> CreateVertexBuffer( 50 * 2 * sizeof (CUSTOMVERTEX) , 0 , D3DFVF_CUSTOMVERTEX , D3DPOOL_DEFAULT , & g_pVB , 0 )))
32 return E_FAIL;
33
34 CUSTOMVERTEX * pVertecies;
35 // 锁定缓冲区
36 if (SUCCEEDED(g_pVB -> Lock( 0 , 0 , ( void ** ) & pVertecies , 0 )))
37 {
38 for ( int i = 0 ; i < 100 ; i += 2 )
39 {
40 float theta = 2 * D3DX_PI * i / ( 50 - 1 );
41 // 根据圆的方程 x = x' + r * sin(θ)
42 // y = y' + r * cos(θ)
43 // 求解圆
44 pVertecies[i].position = D3DXVECTOR3(sinf(theta) , 1 , cosf(theta));
45 pVertecies[i].normal = D3DXVECTOR3(sinf(theta) , 0 , cosf(theta));
46
47 pVertecies[i + 1 ].position = D3DXVECTOR3(sinf(theta) , - 1 , cosf(theta));
48 pVertecies[i + 1 ].normal = D3DXVECTOR3(sinf(theta) , 0 , cosf(theta));
49
50 }
51 g_pVB -> Unlock();
52 }
53 else
54 {
55 return E_FAIL;
56 }
57 return S_OK;
58 }
59
60 // 初始化模型
61 HRESULT InitGeometry()
62 {
63 // 创建顶点缓冲区
64 if (FAILED(InitVB()))
65 return E_FAIL;
66 return S_OK;
67 }
68
69 // 设置矩阵变换
70 void SetTransform()
71 {
72
73 // 世界变换
74 D3DXMATRIX matWorld , matT1 , matT2 , matR;
75 D3DXMatrixIdentity( & matWorld);
76 DWORD dwTime = timeGetTime();
77 // 角度
78 float fAngle = 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f ;
79
80 // 平移到原点
81 D3DXMatrixTranslation( & matT1 , - 0.5 , - 1 , 0 );
82 // Z旋转
83 D3DXMatrixRotationZ( & matR , sin(fAngle));
84 // 移动到原来的位置
85 D3DXMatrixTranslation( & matT2 , 0.5 /**/ /* - 3 * (dwTime % 5000) / 5000.0f */ , 1 , 0 );
86 // 平移到原点再旋转
87 matWorld = matT1 * matR;
88 // 平移回原来的位置
89 matWorld *= matT2;
90
91
92 // 放大缩小
93 D3DXMatrixScaling( & matWorld , abs(sin( 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f )) , abs(sin( 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f )) , abs(sin( 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f )));
94 // 设置缩放点
95 matWorld._41 = ( 1.0f - matWorld._11) * 0.5 ; // x
96 matWorld._42 = ( 1.0f - matWorld._22) * 0.5 ; // y
97 matWorld._43 = ( 1.0f - matWorld._33) * 0 ; // z
98
99
100 // 设置世界矩阵
101 g_pd3dDevice -> SetTransform(D3DTS_WORLD , & matWorld);
102 // Set up our view matrix. A view matrix can be defined given an eye point,
103 // a point to lookat, and a direction for which way is up. Here, we set the
104 // eye five units back along the z-axis and up three units, look at the
105 // origin, and define "up" to be in the y-direction.
106 // 视口变换
107 D3DXMATRIX matView;
108 D3DXMatrixLookAtLH( & matView , & D3DXVECTOR3( 0 , 3 , - 5 )
109 , & D3DXVECTOR3( 0 , 0 , 0 )
110 , & D3DXVECTOR3( 0 , 1 , 0 ));
111 g_pd3dDevice -> SetTransform(D3DTS_VIEW , & matView);
112 // For the projection matrix, we set up a perspective transform (which
113 // transforms geometry from 3D view space to 2D viewport space, with
114 // a perspective divide making objects smaller in the distance). To build
115 // a perpsective transform, we need the field of view (1/4 pi is common),
116 // the aspect ratio, and the near and far clipping planes (which define at
117 // what distances geometry should be no longer be rendered).
118 D3DXMATRIXA16 matProj;
119 D3DXMatrixPerspectiveFovLH( & matProj, D3DX_PI / 4 , 1.0f , 1.0f , 100.0f );
120 g_pd3dDevice -> SetTransform( D3DTS_PROJECTION, & matProj );
121 }
122
123 // 设置灯光
124 void SetupLight()
125 {
126 // Set up a material. The material here just has the diffuse and ambient
127 // colors set to yellow. Note that only one material can be used at a time.
128 // set up lights
129 D3DXVECTOR3 vecDir;
130 // 创建一个平行光
131 D3DLIGHT9 light;
132 ZeroMemory( & light, sizeof (D3DLIGHT9) );
133 light.Type = D3DLIGHT_DIRECTIONAL; // 平行光
134 light.Diffuse.r = 0.0f ;
135 light.Diffuse.g = 1.0f ; // 红色
136 light.Diffuse.b = 0.0f ;
137 vecDir = D3DXVECTOR3( 10 , 10 , - 10 ); // 方向是从0,0,0指向10,10,-10
138
139 // 正规化向量,就是说把向量长度正规化成1,方向不变!好处是光照运算时的误差会降到最小(纯属我的理解,不知道正确与否)
140 D3DXVec3Normalize( (D3DXVECTOR3 * ) & light.Direction, & vecDir );
141 // 设置0号光照为此灯光参数
142 g_pd3dDevice -> SetLight( 0 , & light );
143
144 // 开启0号光照
145 g_pd3dDevice -> LightEnable( 0 , TRUE );
146 // 开启光照系统
147 g_pd3dDevice -> SetRenderState( D3DRS_LIGHTING, TRUE );
148
149 D3DXVECTOR3 vecPos2;
150 // 一个点光源
151 D3DLIGHT9 light2;
152 ZeroMemory( & light2, sizeof (D3DLIGHT9) );
153 light2.Type = D3DLIGHT_POINT; // 点光源
154 light2.Diffuse.r = 0.9f ; // 红色
155 light2.Diffuse.g = 0.0f ;
156 light2.Diffuse.b = 0.0f ;
157
158 // 位置,随着时间的推移,围绕Y轴周围的圆圈旋转,根据圆的方程来建立的sinf和cosf函数
159 light2.Position = D3DXVECTOR3( 10 * sinf(timeGetTime() / 350.0f ) ,
160 10 ,
161 10 * cosf(timeGetTime() / 350.0f ) );
162
163 light2.Range = 15 ;
164 light2.Attenuation0 = 1.0f ;
165 g_pd3dDevice -> SetLight( 1 , & light2 );
166 g_pd3dDevice -> LightEnable( 1 , TRUE );
167
168 // 开启光照系统(纯属多余!开启一次就行了!)
169 g_pd3dDevice -> SetRenderState( D3DRS_LIGHTING, TRUE );
170
171 // 最后,开启环境光
172 g_pd3dDevice -> SetRenderState( D3DRS_AMBIENT, 0x00202020 );
173
174 D3DMATERIAL9 mtrl;
175 ZeroMemory( & mtrl, sizeof (D3DMATERIAL9) );
176 mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f ;
177 mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f ;
178 mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f ;
179 mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f ;
180 // 设置物体的材质
181 g_pd3dDevice -> SetMaterial( & mtrl );
182
183 }
184
185 // 渲染场景
186 void Render()
187 {
188 if (g_pd3dDevice)
189 {
190 // 清空场景
191 g_pd3dDevice -> Clear( 0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB( 0 , 0 , 0 ) , 1 , 0 );
192 // 开始渲染
193 if (SUCCEEDED(g_pd3dDevice -> BeginScene()))
194 {
195 SetTransform();
196 SetupLight();
197 g_pd3dDevice -> SetRenderState(D3DRS_AMBIENT , D3DCOLOR_XRGB( 64 , 64 , 64 ));
198 g_pd3dDevice -> SetStreamSource( 0 , g_pVB , 0 , sizeof (CUSTOMVERTEX));
199 g_pd3dDevice -> SetFVF(D3DFVF_CUSTOMVERTEX);
200 g_pd3dDevice -> DrawPrimitive(D3DPT_TRIANGLESTRIP , 0 , 2 * 50 - 2 );
201 g_pd3dDevice -> EndScene();
202 }
203 // 显示
204 g_pd3dDevice -> Present( 0 , 0 , 0 , 0 );
205 }
206 }
207
208 // 初始化 D3D 设备
209 HRESULT InitD3D(HWND hWnd)
210 {
211 // 创建 D3D Driver
212 if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
213 {
214 D3DErr( " 无法创建Direct3D9设备 " );
215 return E_FAIL;
216 }
217 // 获取当前显示模式
218 D3DDISPLAYMODE d3ddm;
219 if (FAILED(g_pD3D -> GetAdapterDisplayMode(D3DADAPTER_DEFAULT , & d3ddm)))
220 {
221 D3DErr( " 无法获取D3D显示器模式 " );
222 return E_FAIL;
223 }
224
225 // 获取窗口的大小
226 RECT rect;
227 GetClientRect(hWnd , & rect);
228
229 // 填充参数
230 D3DPRESENT_PARAMETERS d3dpp;
231 memset( & d3dpp , 0 , sizeof (d3dpp));
232 d3dpp.BackBufferFormat = d3ddm.Format;
233 d3dpp.BackBufferWidth = rect.right - rect.left;
234 d3dpp.BackBufferHeight = rect.bottom - rect.top;
235 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
236 d3dpp.Windowed = true ;
237 d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
238 d3dpp.EnableAutoDepthStencil = TRUE;
239
240 // 获取帽子
241 if (FAILED(g_pD3D -> GetDeviceCaps(D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , & g_Caps)))
242 {
243 D3DErr( " 获取D3D 帽子时发生错误 " );
244 return E_FAIL;
245 }
246
247 // 创建D3D设备
248 if (FAILED(g_pD3D -> CreateDevice(D3DADAPTER_DEFAULT
249 , D3DDEVTYPE_HAL
250 , hWnd
251 // 检查是否支持硬件顶点处理
252 , g_Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING
253 , & d3dpp
254 , & g_pd3dDevice
255 )
256 ))
257 {
258 D3DErr( " 创建D3D设备时发生错误 " );
259 return E_FAIL;
260 }
261 g_pd3dDevice -> SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
262 g_pd3dDevice -> SetRenderState( D3DRS_ZENABLE, TRUE );
263
264 if (FAILED(InitGeometry()))
265 return E_FAIL;
266 return S_OK;
267 }
268
269 // 清空所有占用的资源
270 void CleanUp()
271 {
272 SAFE_RELEASE(g_pIB);
273 SAFE_RELEASE(g_pVB);
274 SAFE_RELEASE(g_pd3dDevice);
275 SAFE_RELEASE(g_pD3D);
276 }
277
278
279 // 消息处理
280 LRESULT WINAPI MsgProc(HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam)
281 {
282 switch (message)
283 {
284 case WM_DESTROY:
285 CleanUp();
286 PostQuitMessage( 0 );
287 break ;
288 }
289 return ::DefWindowProc(hWnd, message , wParam , lParam);
290 }
291
292 // Windows 入口
293 int WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
294 {
295 WNDCLASS wndClass;
296 memset( & wndClass , 0 , sizeof (wndClass));
297 wndClass.hInstance = hInstance;
298 wndClass.lpszClassName = " Tutorial02 " ;
299 wndClass.lpfnWndProc = MsgProc;
300 RegisterClass( & wndClass);
301
302 // 创建窗口
303 HWND hWnd = CreateWindow( " Tutorial02 " , " Tutorial02 Lighting "
304 , WS_OVERLAPPEDWINDOW , 0 , 0 , 512 , 512 , GetDesktopWindow()
305 , 0 , wndClass.hInstance , 0 );
306 // 显示窗口
307 ShowWindow(hWnd , SW_SHOWDEFAULT);
308 UpdateWindow(hWnd);
309
310 // 初始化 D3D 设备
311 if (SUCCEEDED(InitD3D(hWnd)))
312 {
313 // 消息处理循环
314 MSG msg;
315 memset( & msg , 0 , sizeof (msg));
316 while (msg.message != WM_QUIT)
317 {
318 if (PeekMessage( & msg , 0 , 0 , 0 , PM_REMOVE))
319 {
320 TranslateMessage( & msg);
321 DispatchMessage( & msg);
322 }
323 else
324 {
325 Render();
326 }
327 }
328 }
329 // 清空场景
330 CleanUp();
331
332 UnregisterClass( " Tutorial02 " , wndClass.hInstance);
333
334 return 0 ;
335 }
2 #include < string >
3 typedef std:: string String;
4 #define SAFE_RELEASE(o) {if(o){o->Release();o = 0;}}
5
6
7 LPDIRECT3D9 g_pD3D = 0 ; // D3D Driver
8 LPDIRECT3DDEVICE9 g_pd3dDevice = 0 ; // D3D 设备
9 D3DCAPS9 g_Caps = {(D3DDEVTYPE) 0 } ; // D3D 的帽子
10 LPDIRECT3DVERTEXBUFFER9 g_pVB = 0 ; // 顶点缓冲区
11 LPDIRECT3DINDEXBUFFER9 g_pIB = 0 ; // 索引缓冲区
12
13 // 顶点定义
14 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL )
15 struct CUSTOMVERTEX
16 {
17 D3DXVECTOR3 position;
18 D3DXVECTOR3 normal;
19 } ;
20
21 // 错误记录
22 void D3DErr(String strMsg)
23 {
24 MessageBox( 0 , strMsg.c_str() , " 错误 " , MB_OK);
25 }
26
27 // 初始化顶点缓冲区
28 HRESULT InitVB()
29 {
30 // 创建顶点缓冲区
31 if (FAILED(g_pd3dDevice -> CreateVertexBuffer( 50 * 2 * sizeof (CUSTOMVERTEX) , 0 , D3DFVF_CUSTOMVERTEX , D3DPOOL_DEFAULT , & g_pVB , 0 )))
32 return E_FAIL;
33
34 CUSTOMVERTEX * pVertecies;
35 // 锁定缓冲区
36 if (SUCCEEDED(g_pVB -> Lock( 0 , 0 , ( void ** ) & pVertecies , 0 )))
37 {
38 for ( int i = 0 ; i < 100 ; i += 2 )
39 {
40 float theta = 2 * D3DX_PI * i / ( 50 - 1 );
41 // 根据圆的方程 x = x' + r * sin(θ)
42 // y = y' + r * cos(θ)
43 // 求解圆
44 pVertecies[i].position = D3DXVECTOR3(sinf(theta) , 1 , cosf(theta));
45 pVertecies[i].normal = D3DXVECTOR3(sinf(theta) , 0 , cosf(theta));
46
47 pVertecies[i + 1 ].position = D3DXVECTOR3(sinf(theta) , - 1 , cosf(theta));
48 pVertecies[i + 1 ].normal = D3DXVECTOR3(sinf(theta) , 0 , cosf(theta));
49
50 }
51 g_pVB -> Unlock();
52 }
53 else
54 {
55 return E_FAIL;
56 }
57 return S_OK;
58 }
59
60 // 初始化模型
61 HRESULT InitGeometry()
62 {
63 // 创建顶点缓冲区
64 if (FAILED(InitVB()))
65 return E_FAIL;
66 return S_OK;
67 }
68
69 // 设置矩阵变换
70 void SetTransform()
71 {
72
73 // 世界变换
74 D3DXMATRIX matWorld , matT1 , matT2 , matR;
75 D3DXMatrixIdentity( & matWorld);
76 DWORD dwTime = timeGetTime();
77 // 角度
78 float fAngle = 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f ;
79
80 // 平移到原点
81 D3DXMatrixTranslation( & matT1 , - 0.5 , - 1 , 0 );
82 // Z旋转
83 D3DXMatrixRotationZ( & matR , sin(fAngle));
84 // 移动到原来的位置
85 D3DXMatrixTranslation( & matT2 , 0.5 /**/ /* - 3 * (dwTime % 5000) / 5000.0f */ , 1 , 0 );
86 // 平移到原点再旋转
87 matWorld = matT1 * matR;
88 // 平移回原来的位置
89 matWorld *= matT2;
90
91
92 // 放大缩小
93 D3DXMatrixScaling( & matWorld , abs(sin( 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f )) , abs(sin( 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f )) , abs(sin( 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f )));
94 // 设置缩放点
95 matWorld._41 = ( 1.0f - matWorld._11) * 0.5 ; // x
96 matWorld._42 = ( 1.0f - matWorld._22) * 0.5 ; // y
97 matWorld._43 = ( 1.0f - matWorld._33) * 0 ; // z
98
99
100 // 设置世界矩阵
101 g_pd3dDevice -> SetTransform(D3DTS_WORLD , & matWorld);
102 // Set up our view matrix. A view matrix can be defined given an eye point,
103 // a point to lookat, and a direction for which way is up. Here, we set the
104 // eye five units back along the z-axis and up three units, look at the
105 // origin, and define "up" to be in the y-direction.
106 // 视口变换
107 D3DXMATRIX matView;
108 D3DXMatrixLookAtLH( & matView , & D3DXVECTOR3( 0 , 3 , - 5 )
109 , & D3DXVECTOR3( 0 , 0 , 0 )
110 , & D3DXVECTOR3( 0 , 1 , 0 ));
111 g_pd3dDevice -> SetTransform(D3DTS_VIEW , & matView);
112 // For the projection matrix, we set up a perspective transform (which
113 // transforms geometry from 3D view space to 2D viewport space, with
114 // a perspective divide making objects smaller in the distance). To build
115 // a perpsective transform, we need the field of view (1/4 pi is common),
116 // the aspect ratio, and the near and far clipping planes (which define at
117 // what distances geometry should be no longer be rendered).
118 D3DXMATRIXA16 matProj;
119 D3DXMatrixPerspectiveFovLH( & matProj, D3DX_PI / 4 , 1.0f , 1.0f , 100.0f );
120 g_pd3dDevice -> SetTransform( D3DTS_PROJECTION, & matProj );
121 }
122
123 // 设置灯光
124 void SetupLight()
125 {
126 // Set up a material. The material here just has the diffuse and ambient
127 // colors set to yellow. Note that only one material can be used at a time.
128 // set up lights
129 D3DXVECTOR3 vecDir;
130 // 创建一个平行光
131 D3DLIGHT9 light;
132 ZeroMemory( & light, sizeof (D3DLIGHT9) );
133 light.Type = D3DLIGHT_DIRECTIONAL; // 平行光
134 light.Diffuse.r = 0.0f ;
135 light.Diffuse.g = 1.0f ; // 红色
136 light.Diffuse.b = 0.0f ;
137 vecDir = D3DXVECTOR3( 10 , 10 , - 10 ); // 方向是从0,0,0指向10,10,-10
138
139 // 正规化向量,就是说把向量长度正规化成1,方向不变!好处是光照运算时的误差会降到最小(纯属我的理解,不知道正确与否)
140 D3DXVec3Normalize( (D3DXVECTOR3 * ) & light.Direction, & vecDir );
141 // 设置0号光照为此灯光参数
142 g_pd3dDevice -> SetLight( 0 , & light );
143
144 // 开启0号光照
145 g_pd3dDevice -> LightEnable( 0 , TRUE );
146 // 开启光照系统
147 g_pd3dDevice -> SetRenderState( D3DRS_LIGHTING, TRUE );
148
149 D3DXVECTOR3 vecPos2;
150 // 一个点光源
151 D3DLIGHT9 light2;
152 ZeroMemory( & light2, sizeof (D3DLIGHT9) );
153 light2.Type = D3DLIGHT_POINT; // 点光源
154 light2.Diffuse.r = 0.9f ; // 红色
155 light2.Diffuse.g = 0.0f ;
156 light2.Diffuse.b = 0.0f ;
157
158 // 位置,随着时间的推移,围绕Y轴周围的圆圈旋转,根据圆的方程来建立的sinf和cosf函数
159 light2.Position = D3DXVECTOR3( 10 * sinf(timeGetTime() / 350.0f ) ,
160 10 ,
161 10 * cosf(timeGetTime() / 350.0f ) );
162
163 light2.Range = 15 ;
164 light2.Attenuation0 = 1.0f ;
165 g_pd3dDevice -> SetLight( 1 , & light2 );
166 g_pd3dDevice -> LightEnable( 1 , TRUE );
167
168 // 开启光照系统(纯属多余!开启一次就行了!)
169 g_pd3dDevice -> SetRenderState( D3DRS_LIGHTING, TRUE );
170
171 // 最后,开启环境光
172 g_pd3dDevice -> SetRenderState( D3DRS_AMBIENT, 0x00202020 );
173
174 D3DMATERIAL9 mtrl;
175 ZeroMemory( & mtrl, sizeof (D3DMATERIAL9) );
176 mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f ;
177 mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f ;
178 mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f ;
179 mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f ;
180 // 设置物体的材质
181 g_pd3dDevice -> SetMaterial( & mtrl );
182
183 }
184
185 // 渲染场景
186 void Render()
187 {
188 if (g_pd3dDevice)
189 {
190 // 清空场景
191 g_pd3dDevice -> Clear( 0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB( 0 , 0 , 0 ) , 1 , 0 );
192 // 开始渲染
193 if (SUCCEEDED(g_pd3dDevice -> BeginScene()))
194 {
195 SetTransform();
196 SetupLight();
197 g_pd3dDevice -> SetRenderState(D3DRS_AMBIENT , D3DCOLOR_XRGB( 64 , 64 , 64 ));
198 g_pd3dDevice -> SetStreamSource( 0 , g_pVB , 0 , sizeof (CUSTOMVERTEX));
199 g_pd3dDevice -> SetFVF(D3DFVF_CUSTOMVERTEX);
200 g_pd3dDevice -> DrawPrimitive(D3DPT_TRIANGLESTRIP , 0 , 2 * 50 - 2 );
201 g_pd3dDevice -> EndScene();
202 }
203 // 显示
204 g_pd3dDevice -> Present( 0 , 0 , 0 , 0 );
205 }
206 }
207
208 // 初始化 D3D 设备
209 HRESULT InitD3D(HWND hWnd)
210 {
211 // 创建 D3D Driver
212 if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
213 {
214 D3DErr( " 无法创建Direct3D9设备 " );
215 return E_FAIL;
216 }
217 // 获取当前显示模式
218 D3DDISPLAYMODE d3ddm;
219 if (FAILED(g_pD3D -> GetAdapterDisplayMode(D3DADAPTER_DEFAULT , & d3ddm)))
220 {
221 D3DErr( " 无法获取D3D显示器模式 " );
222 return E_FAIL;
223 }
224
225 // 获取窗口的大小
226 RECT rect;
227 GetClientRect(hWnd , & rect);
228
229 // 填充参数
230 D3DPRESENT_PARAMETERS d3dpp;
231 memset( & d3dpp , 0 , sizeof (d3dpp));
232 d3dpp.BackBufferFormat = d3ddm.Format;
233 d3dpp.BackBufferWidth = rect.right - rect.left;
234 d3dpp.BackBufferHeight = rect.bottom - rect.top;
235 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
236 d3dpp.Windowed = true ;
237 d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
238 d3dpp.EnableAutoDepthStencil = TRUE;
239
240 // 获取帽子
241 if (FAILED(g_pD3D -> GetDeviceCaps(D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , & g_Caps)))
242 {
243 D3DErr( " 获取D3D 帽子时发生错误 " );
244 return E_FAIL;
245 }
246
247 // 创建D3D设备
248 if (FAILED(g_pD3D -> CreateDevice(D3DADAPTER_DEFAULT
249 , D3DDEVTYPE_HAL
250 , hWnd
251 // 检查是否支持硬件顶点处理
252 , g_Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING
253 , & d3dpp
254 , & g_pd3dDevice
255 )
256 ))
257 {
258 D3DErr( " 创建D3D设备时发生错误 " );
259 return E_FAIL;
260 }
261 g_pd3dDevice -> SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
262 g_pd3dDevice -> SetRenderState( D3DRS_ZENABLE, TRUE );
263
264 if (FAILED(InitGeometry()))
265 return E_FAIL;
266 return S_OK;
267 }
268
269 // 清空所有占用的资源
270 void CleanUp()
271 {
272 SAFE_RELEASE(g_pIB);
273 SAFE_RELEASE(g_pVB);
274 SAFE_RELEASE(g_pd3dDevice);
275 SAFE_RELEASE(g_pD3D);
276 }
277
278
279 // 消息处理
280 LRESULT WINAPI MsgProc(HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam)
281 {
282 switch (message)
283 {
284 case WM_DESTROY:
285 CleanUp();
286 PostQuitMessage( 0 );
287 break ;
288 }
289 return ::DefWindowProc(hWnd, message , wParam , lParam);
290 }
291
292 // Windows 入口
293 int WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
294 {
295 WNDCLASS wndClass;
296 memset( & wndClass , 0 , sizeof (wndClass));
297 wndClass.hInstance = hInstance;
298 wndClass.lpszClassName = " Tutorial02 " ;
299 wndClass.lpfnWndProc = MsgProc;
300 RegisterClass( & wndClass);
301
302 // 创建窗口
303 HWND hWnd = CreateWindow( " Tutorial02 " , " Tutorial02 Lighting "
304 , WS_OVERLAPPEDWINDOW , 0 , 0 , 512 , 512 , GetDesktopWindow()
305 , 0 , wndClass.hInstance , 0 );
306 // 显示窗口
307 ShowWindow(hWnd , SW_SHOWDEFAULT);
308 UpdateWindow(hWnd);
309
310 // 初始化 D3D 设备
311 if (SUCCEEDED(InitD3D(hWnd)))
312 {
313 // 消息处理循环
314 MSG msg;
315 memset( & msg , 0 , sizeof (msg));
316 while (msg.message != WM_QUIT)
317 {
318 if (PeekMessage( & msg , 0 , 0 , 0 , PM_REMOVE))
319 {
320 TranslateMessage( & msg);
321 DispatchMessage( & msg);
322 }
323 else
324 {
325 Render();
326 }
327 }
328 }
329 // 清空场景
330 CleanUp();
331
332 UnregisterClass( " Tutorial02 " , wndClass.hInstance);
333
334 return 0 ;
335 }