1 // +-------------------+
2 // | Direct3D and Aero |
3 // +-------------------+---------------------------------+
4 // | Example written by Tristan Ward for codeproject.com |
5 // +-----------------------------------------------------+
6
7 // +------------+
8 // | Directives |
9 // +------------+
10 // Specify Windows version
11 #define WINVER 0x0600
12 #define _WIN32_WINNT 0x0600
13
14 // Includes
15 #include <d3d9.h>
16 #include <d3dx9.h>
17 #include <dwmapi.h>
18
19 // Import libraries to link with
20 #pragma comment(lib, "d3d9.lib")
21 #pragma comment(lib, "d3dx9.lib")
22 #pragma comment(lib, "dwmapi.lib")
23
24 // Global constants
25 #define ARGB_RED 0xFFFF0000 // Full red full alpha
26 #define ARGB_GREEN 0xFF00FF00 // Full green full alpha
27 #define ARGB_BLUE 0x800000FF // Full blue 50% alpha
28 #define ARGB_CYAN 0xFF00FFFF // Full cyan full alpha
29 #define ARGB_TRANS 0x00000000 // 100% alpha
30 #define ARGB_AMBIENT 0xFF0A0A0A // Ambient light colour
31
32 // +---------+
33 // | Globals |
34 // +---------+
35 WCHAR *g_wcpAppName = L"VistaD3D";
36 INT g_iWidth = 256;
37 INT g_iHeight = 256;
38 MARGINS g_mgDWMMargins = {-1, -1, -1, -1};
39 IDirect3D9Ex *g_pD3D = NULL;
40 IDirect3DDevice9Ex *g_pD3DDevice = NULL;
41 IDirect3DVertexBuffer9 *g_pVB = NULL;
42
43 struct CUSTOMVERTEX
44 {
45 FLOAT fX, fY, fZ; // The position for the vertex
46 D3DVECTOR vctNormal; // The normal of each vector (for lighting calcs)
47 DWORD dwColour; // The vertex color
48 };
49
50 // +--------------+
51 // | D3DStartup() |
52 // +--------------+----------------------------------+
53 // | Initialise Direct3D and perform once only tasks |
54 // +-------------------------------------------------+
55 HRESULT D3DStartup(HWND hWnd)
56 {
57 BOOL bCompOk = FALSE; // Is composition enabled?
58 D3DPRESENT_PARAMETERS pp; // Presentation prefs
59 DWORD msqAAQuality = 0; // Non-maskable quality
60 D3DLIGHT9 ltDirectionalLight; // Light description
61 D3DVECTOR vctLightDirection = {-1.0f, // X component
62 -0.3f, // Y component
63 -1.0f}; // Z component
64 D3DXMATRIX mtxView; // View matrix
65 D3DXMATRIX mtxProjection; // Projection matrix
66
67 // Make sure that DWM composition is enabled
68 DwmIsCompositionEnabled(&bCompOk);
69 if(!bCompOk) return E_FAIL;
70
71 // Create a Direct3D object
72 if(FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &g_pD3D))) return E_FAIL;
73
74 // Setup presentation parameters
75 ZeroMemory(&pp, sizeof(pp));
76 pp.Windowed = TRUE;
77 pp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Required for multi sampling
78 pp.BackBufferFormat = D3DFMT_A8R8G8B8; // Back buffer format with alpha channel
79
80 // Set highest quality non-maskable AA available or none if not
81 if(SUCCEEDED(g_pD3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
82 D3DDEVTYPE_HAL,
83 D3DFMT_A8R8G8B8,
84 TRUE,
85 D3DMULTISAMPLE_NONMASKABLE,
86 &msqAAQuality
87 )))
88 {
89 // Set AA quality
90 pp.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE;
91 pp.MultiSampleQuality = msqAAQuality - 1;
92 }
93 else
94 {
95 // No AA
96 pp.MultiSampleType = D3DMULTISAMPLE_NONE;
97 }
98
99 // Create a Direct3D device object
100 if(FAILED(g_pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT,
101 D3DDEVTYPE_HAL,
102 hWnd,
103 D3DCREATE_HARDWARE_VERTEXPROCESSING,
104 &pp,
105 NULL,
106 &g_pD3DDevice
107 ))) return E_FAIL;
108
109 // Configure the device state
110 g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE); // Enable 3D lighting
111 g_pD3DDevice->SetRenderState(D3DRS_AMBIENT, ARGB_AMBIENT); // Set ambient lighting
112 g_pD3DDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE); // Disable specular highlighting
113
114 // Create a directional light
115 ZeroMemory(<DirectionalLight, sizeof(ltDirectionalLight));
116 ltDirectionalLight.Type = D3DLIGHT_DIRECTIONAL;
117 ltDirectionalLight.Diffuse.r = 1.0f;
118 ltDirectionalLight.Diffuse.g = 1.0f;
119 ltDirectionalLight.Diffuse.b = 1.0f;
120 ltDirectionalLight.Diffuse.a = 1.0f;
121 ltDirectionalLight.Direction = vctLightDirection;
122
123 // Add as light 0
124 g_pD3DDevice->SetLight(0, <DirectionalLight);
125 g_pD3DDevice->LightEnable(0, TRUE);
126
127 // Configure camera
128 D3DXMatrixLookAtLH(&mtxView,
129 &D3DXVECTOR3 (0.0f, 0.0f, 25.0f), // Camera position
130 &D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // Look-at target
131 &D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // Up direction
132 g_pD3DDevice->SetTransform(D3DTS_VIEW, &mtxView);
133
134 // Configure projection
135 D3DXMatrixPerspectiveFovLH(&mtxProjection,
136 D3DXToRadian(45), // Horizontal field of view
137 (FLOAT)((FLOAT)g_iWidth/(FLOAT)g_iHeight), // Aspect ratio
138 0.0f, // Near view plane
139 100.0f); // Far view plane
140 g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &mtxProjection);
141
142 return S_OK;
143 }
144
145 // +---------------+
146 // | D3DShutdown() |
147 // +---------------+----------------------+
148 // | Release all created Direct3D objects |
149 // +--------------------------------------+
150 VOID D3DShutdown(VOID)
151 {
152 if(g_pVB != NULL ) g_pVB->Release();
153 if(g_pD3DDevice != NULL) g_pD3DDevice->Release();
154 if(g_pD3D != NULL) g_pD3D->Release();
155 }
156
157 // +--------------+
158 // | CreateCube() |
159 // +--------------+------------------------------+
160 // | Populates a vertex buffer with a cube shape |
161 // +---------------------------------------------+
162 HRESULT CreateCube(VOID)
163 {
164 VOID* pVBVertices = NULL; // Pointer to vertex buffer data
165
166 // Initialize 24 vertices describing the shape of a cube
167 CUSTOMVERTEX cvtxCube[] = {
168 {-5.0f, 5.0f, -5.0f, 0, 0, -1, ARGB_RED,},
169 {5.0f, 5.0f, -5.0f, 0, 0, -1, ARGB_GREEN,},
170 {-5.0f, -5.0f, -5.0f, 0, 0, -1, ARGB_BLUE,},
171 {5.0f, -5.0f, -5.0f, 0, 0, -1, ARGB_CYAN,},
172
173 {-5.0f, 5.0f, 5.0f, 0, 0, 1, ARGB_RED,},
174 {-5.0f, -5.0f, 5.0f, 0, 0, 1, ARGB_GREEN,},
175 {5.0f, 5.0f, 5.0f, 0, 0, 1, ARGB_BLUE,},
176 {5.0f, -5.0f, 5.0f, 0, 0, 1, ARGB_CYAN,},
177
178 {-5.0f, 5.0f, 5.0f, 0, 1, 0, ARGB_RED,},
179 {5.0f, 5.0f, 5.0f, 0, 1, 0, ARGB_GREEN,},
180 {-5.0f, 5.0f, -5.0f, 0, 1, 0, ARGB_BLUE,},
181 {5.0f, 5.0f, -5.0f, 0, 1, 0, ARGB_CYAN,},
182
183 {-5.0f, -5.0f, 5.0f, 0, -1, 0, ARGB_RED,},
184 {-5.0f, -5.0f, -5.0f, 0, -1, 0, ARGB_GREEN,},
185 {5.0f, -5.0f, 5.0f, 0, -1, 0, ARGB_BLUE,},
186 {5.0f, -5.0f, -5.0f, 0, -1, 0, ARGB_CYAN,},
187
188 {5.0f, 5.0f, -5.0f, 1, 0, 0, ARGB_RED,},
189 {5.0f, 5.0f, 5.0f, 1, 0, 0, ARGB_GREEN,},
190 {5.0f, -5.0f, -5.0f, 1, 0, 0, ARGB_BLUE,},
191 {5.0f, -5.0f, 5.0f, 1, 0, 0, ARGB_CYAN,},
192
193 {-5.0f, 5.0f, -5.0f, -1, 0, 0, ARGB_RED,},
194 {-5.0f, -5.0f, -5.0f, -1, 0, 0, ARGB_GREEN,},
195 {-5.0f, 5.0f, 5.0f, -1, 0, 0, ARGB_BLUE,},
196 {-5.0f, -5.0f, 5.0f, -1, 0, 0, ARGB_CYAN,}};
197
198 // Create a vertex buffer to hold the cube data
199 if(FAILED(g_pD3DDevice->CreateVertexBuffer(24*sizeof(CUSTOMVERTEX),
200 0,
201 D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE,
202 D3DPOOL_DEFAULT,
203 &g_pVB,
204 NULL)
205 )) return E_FAIL;
206
207 // Lock the vertex buffer for editing
208 if(FAILED(g_pVB->Lock(0, sizeof(cvtxCube), (VOID**)&pVBVertices, 0))) return E_FAIL;
209
210 // Copy vertex array to vertex buffer
211 memcpy(pVBVertices, cvtxCube, sizeof(cvtxCube));
212
213 // Unlock the vertex buffer
214 g_pVB->Unlock();
215
216 return S_OK;
217 }
218
219 // +----------+
220 // | Render() |
221 // +----------+-------------------------+
222 // | Renders a scene to the back buffer |
223 // +------------------------------------+
224 VOID Render(VOID)
225 {
226 static float fRotator = 0.0f; // Cube rotation factor
227 D3DXMATRIX mtxRotateYPR; // Yaw/Pitch/Roll matrix
228
229 // Sanity check
230 if(g_pD3DDevice == NULL) return;
231
232 // Increment static float
233 fRotator += 0.025f;
234
235 // Rotate the cube using the static float
236 D3DXMatrixRotationYawPitchRoll(&mtxRotateYPR, fRotator, fRotator, fRotator);
237 g_pD3DDevice->SetTransform(D3DTS_WORLD, &mtxRotateYPR);
238
239 // Clear the back buffer and z buffer to transparent
240 g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, ARGB_TRANS, 1.0f, 0);
241
242 // Render scene
243 if(SUCCEEDED(g_pD3DDevice->BeginScene()))
244 {
245 // Draw the cube
246 g_pD3DDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
247 g_pD3DDevice->SetFVF(D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE);
248 g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
249 g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
250 g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 8, 2);
251 g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 12, 2);
252 g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 16, 2);
253 g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 20, 2);
254 g_pD3DDevice->EndScene();
255 }
256
257 // Update display
258 g_pD3DDevice->PresentEx(NULL, NULL, NULL, NULL, NULL);
259 }
260
261 // +--------------+
262 // | WindowProc() |
263 // +--------------+------------------+
264 // | The main window message handler |
265 // +---------------------------------+
266 LRESULT WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
267 {
268 switch(uMsg)
269 {
270 case WM_DESTROY:
271 // Signal application to terminate
272 PostQuitMessage(0);
273 return 0;
274
275 case WM_KEYDOWN:
276 // If ESC has been pressed then signal window should close
277 if (LOWORD(wParam) == VK_ESCAPE) SendMessage(hWnd, WM_CLOSE, NULL, NULL);
278 break;
279
280 case WM_LBUTTONDOWN:
281 // Trick OS into thinking we are dragging on title bar for any clicks on the main window
282 SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
283 return TRUE;
284
285 case WM_ERASEBKGND:
286 // We dont want to call render twice so just force Render() in WM_PAINT to be called
287 SendMessage(hWnd, WM_PAINT, NULL, NULL);
288 return TRUE;
289
290 case WM_PAINT:
291 // Force a render to keep the window updated
292 Render();
293 return 0;
294 }
295
296 return DefWindowProc(hWnd, uMsg, wParam, lParam);
297 }
298
299 // +-----------+
300 // | WinMain() |
301 // +-----------+---------+
302 // | Program entry point |
303 // +---------------------+
304 INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, INT)
305 {
306 HWND hWnd = NULL;
307 MSG uMsg;
308 WNDCLASSEX wc = {sizeof(WNDCLASSEX), // cbSize
309 NULL, // style
310 WindowProc, // lpfnWndProc
311 NULL, // cbClsExtra
312 NULL, // cbWndExtra
313 hInstance, // hInstance
314 LoadIcon(NULL, IDI_APPLICATION), // hIcon
315 LoadCursor(NULL, IDC_ARROW), // hCursor
316 NULL, // hbrBackground
317 NULL, // lpszMenuName
318 g_wcpAppName, // lpszClassName
319 LoadIcon(NULL, IDI_APPLICATION)};// hIconSm
320
321 RegisterClassEx(&wc);
322 hWnd = CreateWindowEx(WS_EX_COMPOSITED, // dwExStyle
323 g_wcpAppName, // lpClassName
324 g_wcpAppName, // lpWindowName
325 WS_POPUP | WS_SIZEBOX, // dwStyle
326 CW_USEDEFAULT, CW_USEDEFAULT, // x, y
327 g_iWidth, g_iHeight, // nWidth, nHeight
328 NULL, // hWndParent
329 NULL, // hMenu
330 hInstance, // hInstance
331 NULL); // lpParam
332
333 // Extend glass to cover whole window
334 DwmExtendFrameIntoClientArea(hWnd, &g_mgDWMMargins);
335
336 // Initialise Direct3D
337 if(SUCCEEDED(D3DStartup(hWnd)))
338 {
339 if(SUCCEEDED(CreateCube()))
340 {
341 // Show the window
342 ShowWindow(hWnd, SW_SHOWDEFAULT);
343 UpdateWindow(hWnd);
344
345 // Enter main loop
346 while(TRUE)
347 {
348 // Check for a message
349 if(PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE))
350 {
351 // Check if the message is WM_QUIT
352 if(uMsg.message == WM_QUIT)
353 {
354 // Break out of main loop
355 break;
356 }
357
358 // Pump the message
359 TranslateMessage(&uMsg);
360 DispatchMessage(&uMsg);
361 }
362
363 // Render a frame
364 Render();
365 }
366 }
367 }
368
369 // Shutdown Direct3D
370 D3DShutdown();
371
372 // Exit application
373 return 0;
374 }