umvistad3d.cpp
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 }