1 //-----------------------------------------------------------------------------
2 // File: WinMain.cpp
3 //
4 // Desc: Windows code for Direct3D samples
5 //
6 //       This code uses the Direct3D sample framework.
7 //
8 //
9 // Copyright (c) 1996-1998 Microsoft Corporation. All rights reserved.
10 //-----------------------------------------------------------------------------
11 
12 #include "pch.h"
13 #include "WinMain.h"
14 #include "D3DFrame.h"
15 #include "D3DEnum.h"
16 #include "D3DUtil.h"
17 #include "resource.h"
18 
19 #include "scene.h"
20 
21 
22 //-----------------------------------------------------------------------------
23 // Global variables for using the D3D sample framework class
24 //-----------------------------------------------------------------------------
25 CD3DFramework* g_pFramework        = NULL;
26 BOOL           g_bActive           = FALSE;
27 BOOL           g_bReady            = FALSE;
28 BOOL           g_bFrameMoving      = TRUE;
29 BOOL           g_bSingleStep       = FALSE;
30 BOOL           g_bWindowed         = TRUE;
31 BOOL           g_bShowStats        = TRUE;
32 RECT           g_rcWindow;
33 HACCEL         g_hAccel;
34 HWND g_hWnd;
35 
36 enum APPMSGTYPE { MSG_NONE, MSGERR_APPMUSTEXIT, MSGWARN_SWITCHTOSOFTWARE };
37 
38 
39 
40 
41 //-----------------------------------------------------------------------------
42 // Local function-prototypes
43 //-----------------------------------------------------------------------------
44 INT     CALLBACK AboutProc( HWND, UINT, WPARAM, LPARAM );
45 LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
46 HRESULT Initialize3DEnvironment( HWND );
47 HRESULT Change3DEnvironment( HWND );
48 HRESULT Render3DEnvironment();
49 VOID    Cleanup3DEnvironment();
50 VOID    DisplayFrameworkError( HRESULT, APPMSGTYPE );
51 VOID    AppShowStats();
52 VOID    AppOutputText( LPDIRECT3DDEVICE3, DWORD, DWORD, CHAR* );
53 VOID    AppPause( BOOL );
54 
55 
56 
57 
58 //-----------------------------------------------------------------------------
59 // Name: WinMain()
60 // Desc: Entry point to the program. Initializes everything, and goes into a
61 //       message-processing loop. Idle time is used to render the scene.
62 //-----------------------------------------------------------------------------
63 //INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
InitMain()64 extern "C" INT InitMain ()
65 {
66 	HINSTANCE hInst = GetModuleHandle (NULL);
67 
68 	// Register the window class
69     WNDCLASS wndClass = { CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInst,
70                           LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN_ICON)),
71                           LoadCursor(NULL, IDC_ARROW),
72                           (HBRUSH)GetStockObject(WHITE_BRUSH),
73 						  MAKEINTRESOURCE(IDR_MENU),
74                           TEXT("Render Window") };
75     RegisterClass( &wndClass );
76 
77     // Create our main window
78     g_hWnd = CreateWindow( TEXT("Render Window"), g_strAppTitle,
79                               WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
80                               CW_USEDEFAULT, 300, 300, 0L, 0L, hInst, 0L );
81 
82 	RECT rect;
83 	if (GetClientRect (g_hWnd, &rect))
84 	{
85 		int cx = 320 + (300 - rect.right);
86 		int cy = 200 + (300 - rect.bottom);
87 
88 		SetWindowPos (g_hWnd, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
89 	}
90 
91     ShowWindow( g_hWnd, SW_SHOWNORMAL );
92     UpdateWindow( g_hWnd );
93 
94 	// Save the window size/pos for switching modes
95 	GetWindowRect( g_hWnd, &g_rcWindow );
96 
97     // Load keyboard accelerators
98     g_hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
99 
100 	// Enumerate available D3D devices, passing a callback that allows devices
101 	// to be accepted/rejected based on what capabilities the app requires.
102 	HRESULT hr;
103 	if( FAILED( hr = D3DEnum_EnumerateDevices( App_ConfirmDevice ) ) )
104 	{
105 		DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
106         return 0;
107 	}
108 
109 	// Check if we could not get a device that renders into a window, which
110 	// means the display must be 16- or 256-color mode. If so, let's bail.
111 	D3DEnum_DriverInfo* pDriverInfo;
112 	D3DEnum_DeviceInfo* pDeviceInfo;
113     D3DEnum_GetSelectedDriver( &pDriverInfo, &pDeviceInfo );
114 	if( FALSE == pDeviceInfo->bWindowed )
115     {
116 		Cleanup3DEnvironment();
117 		DisplayFrameworkError( D3DFWERR_INVALIDMODE, MSGERR_APPMUSTEXIT );
118 		return 0;
119     }
120 
121 	// Initialize the 3D environment for the app
122     if( FAILED( hr = Initialize3DEnvironment( g_hWnd ) ) )
123     {
124 	    Cleanup3DEnvironment();
125 		DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
126         return 0;
127     }
128 
129 	g_bReady = TRUE;
130 
131 	return 1;
132 }
133 
PumpMessages(void)134 void PumpMessages (void)
135 {
136 	MSG msg;
137 	while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
138     {
139         // Exit App ?!?
140         if (msg.message == WM_QUIT)
141         {
142             return;
143         }
144 
145 		if (!TranslateAccelerator (g_hWnd, g_hAccel, &msg))
146 		{
147 			TranslateMessage (&msg);
148 			DispatchMessage (&msg);
149 		}
150     }
151 }
152 
153 
154 
155 
156 //-----------------------------------------------------------------------------
157 // Name: WndProc()
158 // Desc: This is the basic Windows-programming function that processes
159 //       Windows messages. We need to handle window movement, painting,
160 //       and destruction.
161 //-----------------------------------------------------------------------------
WndProc(HWND g_hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)162 LRESULT CALLBACK WndProc( HWND g_hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
163 {
164     switch( uMsg )
165     {
166         case WM_PAINT:
167             if( g_pFramework )
168 			{
169 				// If we are paused, and in fullscreen mode, give the dialogs
170 				// a GDI surface to draw on.
171 				if( !g_bReady && !g_bWindowed)
172 					g_pFramework->FlipToGDISurface( TRUE );
173 				else // Simply repaint the frame's contents
174 					g_pFramework->ShowFrame();
175 			}
176             break;
177 
178         case WM_MOVE:
179             if( g_bActive && g_bReady && g_bWindowed )
180 			{
181 			    GetWindowRect( g_hWnd, &g_rcWindow );
182                 g_pFramework->Move( (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) );
183 			}
184             break;
185 
186         case WM_SIZE:
187             // Check to see if we are losing our window...
188             if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
189                 g_bActive = FALSE;
190 			else g_bActive = TRUE;
191 
192             // A new window size will require a new viewport and backbuffer
193             // size, so the 3D structures must be changed accordingly.
194             if( g_bActive && g_bReady && g_bWindowed )
195 			{
196 				g_bReady = FALSE;
197 				GetWindowRect( g_hWnd, &g_rcWindow );
198 				Change3DEnvironment( g_hWnd );
199 				g_bReady = TRUE;
200 			}
201             break;
202 
203 		case WM_GETMINMAXINFO:
204 			((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
205 			((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
206 			break;
207 
208         case WM_SETCURSOR:
209             if( g_bActive && g_bReady && (!g_bWindowed) )
210             {
211                 SetCursor(NULL);
212                 return TRUE;
213             }
214             break;
215 
216         case WM_CLOSE:
217             DestroyWindow( g_hWnd );
218             return 0;
219 
220         case WM_DESTROY:
221             Cleanup3DEnvironment();
222             PostQuitMessage(0);
223             return 0L;
224 
225 		case WM_ENTERMENULOOP:
226 			AppPause(TRUE);
227 			break;
228 
229 		case WM_EXITMENULOOP:
230 			AppPause(FALSE);
231 			break;
232 
233 		case WM_CONTEXTMENU:
234 			{
235 				HMENU hMenu = LoadMenu( 0, MAKEINTRESOURCE(IDR_POPUP) );
236 				TrackPopupMenuEx( GetSubMenu( hMenu, 0 ),
237 								  TPM_VERTICAL, LOWORD(lParam),
238 								  HIWORD(lParam), g_hWnd, NULL );
239 			}
240 			break;
241 
242         case WM_COMMAND:
243             switch( LOWORD(wParam) )
244             {
245 				case SC_MONITORPOWER:
246 					// Prevent potential crashes when the monitor powers down
247 					return 1;
248 
249 				case IDM_TOGGLESTART:
250 					g_bFrameMoving = !g_bFrameMoving;
251 					break;
252 
253 				case IDM_SINGLESTEP:
254 					g_bSingleStep = TRUE;
255 					break;
256 
257                 case IDM_CHANGEDEVICE:
258                     // Display the driver-selection dialog box.
259 		            if( g_bActive && g_bReady )
260 					{
261 						AppPause(TRUE);
262 						if( g_bWindowed )
263 							GetWindowRect( g_hWnd, &g_rcWindow );
264 
265 						HWND hWnd = g_hWnd;
266 						if( IDOK == D3DEnum_UserDlgSelectDriver( hWnd, g_bWindowed ) )
267 						{
268 							D3DEnum_DriverInfo* pDriverInfo;
269 							D3DEnum_DeviceInfo* pDeviceInfo;
270 							D3DEnum_GetSelectedDriver( &pDriverInfo, &pDeviceInfo );
271 							g_bWindowed = pDeviceInfo->bWindowed;
272 
273 							Change3DEnvironment( g_hWnd );
274 						}
275 						AppPause(FALSE);
276 					}
277                     return 0;
278 
279                 case IDM_TOGGLEFULLSCREEN:
280                     // Toggle the fullscreen/window mode
281 		            if( g_bActive && g_bReady )
282 					{
283 						g_bReady = FALSE;
284 						if( g_bWindowed )
285 							GetWindowRect( g_hWnd, &g_rcWindow );
286 			            g_bWindowed = !g_bWindowed;
287 						Change3DEnvironment( g_hWnd );
288 						g_bReady = TRUE;
289 					}
290 					return 0;
291 
292                 case IDM_HELP:
293 					AppPause(TRUE);
294                     DialogBox( (HINSTANCE)GetWindowLong( g_hWnd, GWL_HINSTANCE ),
295                                MAKEINTRESOURCE(IDD_ABOUT), g_hWnd, (DLGPROC)AboutProc );
296 					AppPause(FALSE);
297                     return 0;
298 
299                 case IDM_EXIT:
300                     // Recieved key/menu command to exit app
301                     SendMessage( g_hWnd, WM_CLOSE, 0, 0 );
302                     return 0;
303             }
304             break;
305     }
306 
307     return DefWindowProc( g_hWnd, uMsg, wParam, lParam );
308 }
309 
310 
311 
312 
313 //-----------------------------------------------------------------------------
314 // Name: AboutProc()
315 // Desc: Minimal message proc function for the about box
316 //-----------------------------------------------------------------------------
AboutProc(HWND g_hWnd,UINT uMsg,WPARAM wParam,LPARAM)317 BOOL CALLBACK AboutProc( HWND g_hWnd, UINT uMsg, WPARAM wParam, LPARAM )
318 {
319     if( WM_COMMAND == uMsg )
320 		if( IDOK == LOWORD(wParam) || IDCANCEL == LOWORD(wParam) )
321 			EndDialog (g_hWnd, TRUE);
322 
323     return ( WM_INITDIALOG == uMsg ) ? TRUE : FALSE;
324 }
325 
326 
327 
328 
329 //-----------------------------------------------------------------------------
330 // Note: From this point on, the code is DirectX specific support for the app.
331 //-----------------------------------------------------------------------------
332 
333 
334 
335 
336 //-----------------------------------------------------------------------------
337 // Name: AppInitialize()
338 // Desc: Initializes the sample framework, then calls the app-specific function
339 //       to initialize device specific objects. This code is structured to
340 //       handled any errors that may occur duing initialization
341 //-----------------------------------------------------------------------------
AppInitialize(HWND g_hWnd)342 HRESULT AppInitialize( HWND g_hWnd )
343 {
344 	D3DEnum_DriverInfo* pDriverInfo;
345 	D3DEnum_DeviceInfo* pDeviceInfo;
346     DWORD   dwFrameworkFlags = 0L;
347 	HRESULT hr;
348 
349     D3DEnum_GetSelectedDriver( &pDriverInfo, &pDeviceInfo );
350 
351     dwFrameworkFlags |= (!g_bWindowed         ? D3DFW_FULLSCREEN : 0L );
352     dwFrameworkFlags |= ( g_bAppUseZBuffer    ? D3DFW_ZBUFFER    : 0L );
353     dwFrameworkFlags |= ( g_bAppUseBackBuffer ? D3DFW_BACKBUFFER : 0L );
354 
355 	// Initialize the D3D framework
356     if( SUCCEEDED( hr = g_pFramework->Initialize( g_hWnd, &pDriverInfo->guid,
357 		               &pDeviceInfo->guid, &pDeviceInfo->pCurrentMode->ddsd,
358 		               dwFrameworkFlags ) ) )
359 	{
360 		// Let the app run its startup code which creates the 3d scene.
361 		if( SUCCEEDED( hr = App_InitDeviceObjects( g_pFramework->GetD3DDevice(),
362 			                                    g_pFramework->GetViewport() ) ) )
363 			return S_OK;
364 		else
365 		{
366 			App_DeleteDeviceObjects( g_pFramework->GetD3DDevice(),
367 		                             g_pFramework->GetViewport() );
368 			g_pFramework->DestroyObjects();
369 		}
370 	}
371 
372 	// If we get here, the first initialization passed failed. If that was with a
373 	// hardware device, try again using a software rasterizer instead.
374 	if( pDeviceInfo->bIsHardware )
375 	{
376 		// Try again with a software rasterizer
377 		DisplayFrameworkError( hr, MSGWARN_SWITCHTOSOFTWARE );
378 		D3DEnum_SelectDefaultDriver( D3DENUM_SOFTWAREONLY );
379 		return AppInitialize( g_hWnd );
380 	}
381 
382 	return hr;
383 }
384 
385 
386 
387 
388 //-----------------------------------------------------------------------------
389 // Name: Initialize3DEnvironment()
390 // Desc: Called when the app window is initially created, this triggers
391 //       creation of the remaining portion (the 3D stuff) of the app.
392 //-----------------------------------------------------------------------------
Initialize3DEnvironment(HWND g_hWnd)393 HRESULT Initialize3DEnvironment( HWND g_hWnd )
394 {
395 	HRESULT hr;
396 
397 	// Initialize the app
398 	if( FAILED( hr = App_OneTimeSceneInit( g_hWnd ) ) )
399 		return E_FAIL;
400 
401     // Create a new CD3DFramework class. This class does all of our D3D
402     // initialization and manages the common D3D objects.
403     if( NULL == ( g_pFramework = new CD3DFramework() ) )
404 		return E_OUTOFMEMORY;
405 
406 	// Finally, initialize the framework and scene.
407 	return AppInitialize( g_hWnd );
408 }
409 
410 
411 
412 
413 //-----------------------------------------------------------------------------
414 // Name: Change3DEnvironment()
415 // Desc: Handles driver, device, and/or mode changes for the app.
416 //-----------------------------------------------------------------------------
Change3DEnvironment(HWND g_hWnd)417 HRESULT Change3DEnvironment( HWND g_hWnd )
418 {
419 	HRESULT hr;
420 
421     // Release all objects that need to be re-created for the new device
422     App_DeleteDeviceObjects( g_pFramework->GetD3DDevice(),
423                              g_pFramework->GetViewport() );
424 
425 	// Release the current framework objects (they will be recreated later on)
426 	if( FAILED( hr = g_pFramework->DestroyObjects() ) )
427 	{
428 		DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
429         DestroyWindow( g_hWnd );
430 		return hr;
431 	}
432 
433 	// In case we're coming from a fullscreen mode, restore the window size
434 	if( g_bWindowed )
435 	{
436 		SetWindowPos( g_hWnd, HWND_NOTOPMOST, g_rcWindow.left, g_rcWindow.top,
437                       ( g_rcWindow.right - g_rcWindow.left ),
438                       ( g_rcWindow.bottom - g_rcWindow.top ), SWP_SHOWWINDOW );
439 	}
440 
441     // Inform the framework class of the driver change. It will internally
442     // re-create valid surfaces, a d3ddevice, and a viewport.
443 	if( FAILED( hr = AppInitialize( g_hWnd ) ) )
444 	{
445 		DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
446 		DestroyWindow( g_hWnd );
447 		return hr;
448 	}
449 
450 	// Trigger the rendering of a frame and return
451 	g_bSingleStep = TRUE;
452 	return S_OK;
453 }
454 
455 FLOAT g_fTime;
456 
Win32_start_frame()457 extern "C" HRESULT Win32_start_frame ()
458 {
459 	// Check the cooperative level before rendering
460 	if( FAILED( g_pFramework->GetDirectDraw()->TestCooperativeLevel() ) )
461 		return S_OK;
462 
463 	// Get the current time
464 	g_fTime = GetTickCount() * 0.001f;
465 
466 	return App_StartFrame( g_pFramework->GetD3DDevice(),
467 		                   g_pFramework->GetViewport(),
468                            (D3DRECT*)g_pFramework->GetViewportRect() );
469 }
470 
Win32_end_frame()471 extern "C" HRESULT Win32_end_frame ()
472 {
473 	// Show the frame rate, etc.
474 	if( g_bShowStats )
475 		AppShowStats();
476 
477 	return App_EndFrame ();
478 }
479 
Win32_flip_screens()480 extern "C" HRESULT Win32_flip_screens ()
481 {
482     // Show the frame on the primary surface.
483     if( DDERR_SURFACELOST == g_pFramework->ShowFrame() )
484     {
485 		g_pFramework->RestoreSurfaces();
486 		App_RestoreSurfaces();
487 	}
488 	return S_OK;
489 }
490 
491 
492 
493 //-----------------------------------------------------------------------------
494 // Name: Cleanup3DEnvironment()
495 // Desc: Cleanup scene objects
496 //-----------------------------------------------------------------------------
Cleanup3DEnvironment()497 VOID Cleanup3DEnvironment()
498 {
499     if( g_pFramework )
500     {
501         App_FinalCleanup( g_pFramework->GetD3DDevice(),
502                           g_pFramework->GetViewport() );
503 
504         SAFE_DELETE( g_pFramework );
505     }
506 	g_bActive = FALSE;
507 	g_bReady  = FALSE;
508 }
509 
510 
511 
512 
513 //-----------------------------------------------------------------------------
514 // Name: AppPause()
515 // Desc: Called in to toggle the pause state of the app. This function
516 //       brings the GDI surface to the front of the display, so drawing
517 //       output like message boxes and menus may be displayed.
518 //-----------------------------------------------------------------------------
AppPause(BOOL bPause)519 VOID AppPause( BOOL bPause )
520 {
521     static DWORD dwAppPausedCount = 0L;
522 
523     if( bPause && 0 == dwAppPausedCount )
524         if( g_pFramework )
525             g_pFramework->FlipToGDISurface( TRUE );
526 
527     dwAppPausedCount += ( bPause ? +1 : -1 );
528 
529     g_bReady = (0==dwAppPausedCount);
530 }
531 
532 
533 
534 
535 //-----------------------------------------------------------------------------
536 // Name: AppShowStats()
537 // Desc: Shows frame rate and dimensions of the rendering device. Note: a
538 //       "real" app wouldn't query the surface dimensions each frame.
539 //-----------------------------------------------------------------------------
AppShowStats()540 VOID AppShowStats()
541 {
542     static FLOAT fFPS      = 0.0f;
543     static FLOAT fLastTime = 0.0f;
544     static DWORD dwFrames  = 0L;
545 
546 	// Keep track of the time lapse and frame count
547 	FLOAT fTime = GetTickCount() * 0.001f; // Get current time in seconds
548 	++dwFrames;
549 
550 	// Update the frame rate once per second
551 	if( fTime - fLastTime > 1.0f )
552     {
553         fFPS      = dwFrames / (fTime - fLastTime);
554         fLastTime = fTime;
555         dwFrames  = 0L;
556     }
557 
558     // Get dimensions of the render surface
559     DDSURFACEDESC2 ddsd;
560     ddsd.dwSize = sizeof(DDSURFACEDESC2);
561     g_pFramework->GetRenderSurface()->GetSurfaceDesc(&ddsd);
562 
563     // Setup the text buffer to write out
564     CHAR buffer[80];
565     sprintf( buffer, "%7.02f fps (%dx%dx%d)", fFPS, ddsd.dwWidth,
566              ddsd.dwHeight, ddsd.ddpfPixelFormat.dwRGBBitCount );
567     AppOutputText( g_pFramework->GetD3DDevice(), 0, 0, buffer );
568 }
569 
570 
571 
572 
573 //-----------------------------------------------------------------------------
574 // Name: AppOutputText()
575 // Desc: Draws text on the window.
576 //-----------------------------------------------------------------------------
AppOutputText(LPDIRECT3DDEVICE3 pd3dDevice,DWORD x,DWORD y,CHAR * str)577 VOID AppOutputText( LPDIRECT3DDEVICE3 pd3dDevice, DWORD x, DWORD y, CHAR* str )
578 {
579     LPDIRECTDRAWSURFACE4 pddsRenderSurface;
580     if( FAILED( pd3dDevice->GetRenderTarget( &pddsRenderSurface ) ) )
581         return;
582 
583     // Get a DC for the surface. Then, write out the buffer
584     HDC hDC;
585     if( SUCCEEDED( pddsRenderSurface->GetDC(&hDC) ) )
586     {
587         SetTextColor( hDC, RGB(255,255,0) );
588         SetBkMode( hDC, TRANSPARENT );
589         ExtTextOut( hDC, x, y, 0, NULL, str, strlen(str), NULL );
590 
591         pddsRenderSurface->ReleaseDC(hDC);
592     }
593     pddsRenderSurface->Release();
594 }
595 
596 
597 
598 
599 //-----------------------------------------------------------------------------
600 // Name: DisplayFrameworkError()
601 // Desc: Displays error messages in a message box
602 //-----------------------------------------------------------------------------
DisplayFrameworkError(HRESULT hr,APPMSGTYPE errType)603 VOID DisplayFrameworkError( HRESULT hr, APPMSGTYPE errType )
604 {
605 	CHAR strMsg[512];
606 
607 	switch( hr )
608 	{
609 		case D3DENUMERR_NOCOMPATIBLEDEVICES:
610 			strcpy( strMsg, TEXT("Could not find any compatible Direct3D\n"
611 				    "devices.") );
612 			break;
613 		case D3DENUMERR_SUGGESTREFRAST:
614 			strcpy( strMsg, TEXT("Could not find any compatible devices.\n\n"
615 		            "Try enabling the reference rasterizer using\n"
616 					"EnableRefRast.reg.") );
617 			break;
618 		case D3DENUMERR_ENUMERATIONFAILED:
619 			strcpy( strMsg, TEXT("Enumeration failed. Your system may be in an\n"
620 					"unstable state and need to be rebooted") );
621 			break;
622 		case D3DFWERR_INITIALIZATIONFAILED:
623 			strcpy( strMsg, TEXT("Generic initialization error.\n\nEnable "
624 				    "debug output for detailed information.") );
625 			break;
626 		case D3DFWERR_NODIRECTDRAW:
627 			strcpy( strMsg, TEXT("No DirectDraw") );
628 			break;
629 		case D3DFWERR_NODIRECT3D:
630 			strcpy( strMsg, TEXT("No Direct3D") );
631 			break;
632 		case D3DFWERR_INVALIDMODE:
633 			strcpy( strMsg, TEXT("This sample requires a 16-bit (or higher) "
634 			        "display mode\nto run in a window.\n\nPlease switch "
635 				    "your desktop settings accordingly.") );
636 			break;
637 		case D3DFWERR_COULDNTSETCOOPLEVEL:
638 			strcpy( strMsg, TEXT("Could not set Cooperative Level") );
639 			break;
640 		case D3DFWERR_NO3DDEVICE:
641 			strcpy( strMsg, TEXT("No 3D Device") );
642 			break;
643 		case D3DFWERR_NOZBUFFER:
644 			strcpy( strMsg, TEXT("No ZBuffer") );
645 			break;
646 		case D3DFWERR_NOVIEWPORT:
647 			strcpy( strMsg, TEXT("No Viewport") );
648 			break;
649 		case D3DFWERR_NOPRIMARY:
650 			strcpy( strMsg, TEXT("No primary") );
651 			break;
652 		case D3DFWERR_NOCLIPPER:
653 			strcpy( strMsg, TEXT("No Clipper") );
654 			break;
655 		case D3DFWERR_BADDISPLAYMODE:
656 			strcpy( strMsg, TEXT("Bad display mode") );
657 			break;
658 		case D3DFWERR_NOBACKBUFFER:
659 			strcpy( strMsg, TEXT("No backbuffer") );
660 			break;
661 		case D3DFWERR_NONZEROREFCOUNT:
662 			strcpy( strMsg, TEXT("Nonzerorefcount") );
663 			break;
664 		case D3DFWERR_NORENDERTARGET:
665 			strcpy( strMsg, TEXT("No render target") );
666 			break;
667 		case E_OUTOFMEMORY:
668 			strcpy( strMsg, TEXT("Not enough memory!") );
669 			break;
670 		case DDERR_OUTOFVIDEOMEMORY:
671 			strcpy( strMsg, TEXT("There was insufficient video memory "
672 					"to use the\nhardware device.") );
673 			break;
674 		default:
675 			strcpy( strMsg, TEXT("Generic application error.\n\nEnable "
676 			        "debug output for detailed information.") );
677 	}
678 
679 	if( MSGERR_APPMUSTEXIT == errType )
680 	{
681 		strcat( strMsg, TEXT("\n\nThis sample will now exit.") );
682 		MessageBox( NULL, strMsg, g_strAppTitle, MB_ICONERROR|MB_OK );
683 	}
684 	else
685 	{
686 		if( MSGWARN_SWITCHTOSOFTWARE == errType )
687 			strcat( strMsg, TEXT("\n\nSwitching to software rasterizer.") );
688 		MessageBox( NULL, strMsg, g_strAppTitle, MB_ICONWARNING|MB_OK );
689 	}
690 }
691