1 //-----------------------------------------------------------------------------
4 // Desc: Windows code for Direct3D samples
6 // This code uses the Direct3D sample framework.
9 // Copyright (c) 1996-1998 Microsoft Corporation. All rights reserved.
10 //-----------------------------------------------------------------------------
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;
36 enum APPMSGTYPE { MSG_NONE, MSGERR_APPMUSTEXIT, MSGWARN_SWITCHTOSOFTWARE };
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 );
52 VOID AppOutputText( LPDIRECT3DDEVICE3, DWORD, DWORD, CHAR* );
53 VOID AppPause( BOOL );
58 //-----------------------------------------------------------------------------
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 )
64 extern "C" INT InitMain ()
66 HINSTANCE hInst = GetModuleHandle (NULL);
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 );
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 );
83 if (GetClientRect (g_hWnd, &rect))
85 int cx = 320 + (300 - rect.right);
86 int cy = 200 + (300 - rect.bottom);
88 SetWindowPos (g_hWnd, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
91 ShowWindow( g_hWnd, SW_SHOWNORMAL );
92 UpdateWindow( g_hWnd );
94 // Save the window size/pos for switching modes
95 GetWindowRect( g_hWnd, &g_rcWindow );
97 // Load keyboard accelerators
98 g_hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
100 // Enumerate available D3D devices, passing a callback that allows devices
101 // to be accepted/rejected based on what capabilities the app requires.
103 if( FAILED( hr = D3DEnum_EnumerateDevices( App_ConfirmDevice ) ) )
105 DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
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 )
116 Cleanup3DEnvironment();
117 DisplayFrameworkError( D3DFWERR_INVALIDMODE, MSGERR_APPMUSTEXIT );
121 // Initialize the 3D environment for the app
122 if( FAILED( hr = Initialize3DEnvironment( g_hWnd ) ) )
124 Cleanup3DEnvironment();
125 DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
134 void PumpMessages (void)
137 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
140 if (msg.message == WM_QUIT)
145 if (!TranslateAccelerator (g_hWnd, g_hAccel, &msg))
147 TranslateMessage (&msg);
148 DispatchMessage (&msg);
156 //-----------------------------------------------------------------------------
158 // Desc: This is the basic Windows-programming function that processes
159 // Windows messages. We need to handle window movement, painting,
161 //-----------------------------------------------------------------------------
162 LRESULT CALLBACK WndProc( HWND g_hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
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();
179 if( g_bActive && g_bReady && g_bWindowed )
181 GetWindowRect( g_hWnd, &g_rcWindow );
182 g_pFramework->Move( (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) );
187 // Check to see if we are losing our window...
188 if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
190 else g_bActive = TRUE;
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 )
197 GetWindowRect( g_hWnd, &g_rcWindow );
198 Change3DEnvironment( g_hWnd );
203 case WM_GETMINMAXINFO:
204 ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
205 ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
209 if( g_bActive && g_bReady && (!g_bWindowed) )
217 DestroyWindow( g_hWnd );
221 Cleanup3DEnvironment();
225 case WM_ENTERMENULOOP:
229 case WM_EXITMENULOOP:
235 HMENU hMenu = LoadMenu( 0, MAKEINTRESOURCE(IDR_POPUP) );
236 TrackPopupMenuEx( GetSubMenu( hMenu, 0 ),
237 TPM_VERTICAL, LOWORD(lParam),
238 HIWORD(lParam), g_hWnd, NULL );
243 switch( LOWORD(wParam) )
245 case SC_MONITORPOWER:
246 // Prevent potential crashes when the monitor powers down
249 case IDM_TOGGLESTART:
250 g_bFrameMoving = !g_bFrameMoving;
254 g_bSingleStep = TRUE;
257 case IDM_CHANGEDEVICE:
258 // Display the driver-selection dialog box.
259 if( g_bActive && g_bReady )
263 GetWindowRect( g_hWnd, &g_rcWindow );
266 if( IDOK == D3DEnum_UserDlgSelectDriver( hWnd, g_bWindowed ) )
268 D3DEnum_DriverInfo* pDriverInfo;
269 D3DEnum_DeviceInfo* pDeviceInfo;
270 D3DEnum_GetSelectedDriver( &pDriverInfo, &pDeviceInfo );
271 g_bWindowed = pDeviceInfo->bWindowed;
273 Change3DEnvironment( g_hWnd );
279 case IDM_TOGGLEFULLSCREEN:
280 // Toggle the fullscreen/window mode
281 if( g_bActive && g_bReady )
285 GetWindowRect( g_hWnd, &g_rcWindow );
286 g_bWindowed = !g_bWindowed;
287 Change3DEnvironment( g_hWnd );
294 DialogBox( (HINSTANCE)GetWindowLong( g_hWnd, GWL_HINSTANCE ),
295 MAKEINTRESOURCE(IDD_ABOUT), g_hWnd, (DLGPROC)AboutProc );
300 // Recieved key/menu command to exit app
301 SendMessage( g_hWnd, WM_CLOSE, 0, 0 );
307 return DefWindowProc( g_hWnd, uMsg, wParam, lParam );
313 //-----------------------------------------------------------------------------
315 // Desc: Minimal message proc function for the about box
316 //-----------------------------------------------------------------------------
317 BOOL CALLBACK AboutProc( HWND g_hWnd, UINT uMsg, WPARAM wParam, LPARAM )
319 if( WM_COMMAND == uMsg )
320 if( IDOK == LOWORD(wParam) || IDCANCEL == LOWORD(wParam) )
321 EndDialog (g_hWnd, TRUE);
323 return ( WM_INITDIALOG == uMsg ) ? TRUE : FALSE;
329 //-----------------------------------------------------------------------------
330 // Note: From this point on, the code is DirectX specific support for the app.
331 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
342 HRESULT AppInitialize( HWND g_hWnd )
344 D3DEnum_DriverInfo* pDriverInfo;
345 D3DEnum_DeviceInfo* pDeviceInfo;
346 DWORD dwFrameworkFlags = 0L;
349 D3DEnum_GetSelectedDriver( &pDriverInfo, &pDeviceInfo );
351 dwFrameworkFlags |= (!g_bWindowed ? D3DFW_FULLSCREEN : 0L );
352 dwFrameworkFlags |= ( g_bAppUseZBuffer ? D3DFW_ZBUFFER : 0L );
353 dwFrameworkFlags |= ( g_bAppUseBackBuffer ? D3DFW_BACKBUFFER : 0L );
355 // Initialize the D3D framework
356 if( SUCCEEDED( hr = g_pFramework->Initialize( g_hWnd, &pDriverInfo->guid,
357 &pDeviceInfo->guid, &pDeviceInfo->pCurrentMode->ddsd,
358 dwFrameworkFlags ) ) )
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() ) ) )
366 App_DeleteDeviceObjects( g_pFramework->GetD3DDevice(),
367 g_pFramework->GetViewport() );
368 g_pFramework->DestroyObjects();
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 )
376 // Try again with a software rasterizer
377 DisplayFrameworkError( hr, MSGWARN_SWITCHTOSOFTWARE );
378 D3DEnum_SelectDefaultDriver( D3DENUM_SOFTWAREONLY );
379 return AppInitialize( g_hWnd );
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 //-----------------------------------------------------------------------------
393 HRESULT Initialize3DEnvironment( HWND g_hWnd )
397 // Initialize the app
398 if( FAILED( hr = App_OneTimeSceneInit( g_hWnd ) ) )
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;
406 // Finally, initialize the framework and scene.
407 return AppInitialize( g_hWnd );
413 //-----------------------------------------------------------------------------
414 // Name: Change3DEnvironment()
415 // Desc: Handles driver, device, and/or mode changes for the app.
416 //-----------------------------------------------------------------------------
417 HRESULT Change3DEnvironment( HWND g_hWnd )
421 // Release all objects that need to be re-created for the new device
422 App_DeleteDeviceObjects( g_pFramework->GetD3DDevice(),
423 g_pFramework->GetViewport() );
425 // Release the current framework objects (they will be recreated later on)
426 if( FAILED( hr = g_pFramework->DestroyObjects() ) )
428 DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
429 DestroyWindow( g_hWnd );
433 // In case we're coming from a fullscreen mode, restore the window size
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 );
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 ) ) )
445 DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
446 DestroyWindow( g_hWnd );
450 // Trigger the rendering of a frame and return
451 g_bSingleStep = TRUE;
457 extern "C" HRESULT Win32_start_frame ()
459 // Check the cooperative level before rendering
460 if( FAILED( g_pFramework->GetDirectDraw()->TestCooperativeLevel() ) )
463 // Get the current time
464 g_fTime = GetTickCount() * 0.001f;
466 return App_StartFrame( g_pFramework->GetD3DDevice(),
467 g_pFramework->GetViewport(),
468 (D3DRECT*)g_pFramework->GetViewportRect() );
471 extern "C" HRESULT Win32_end_frame ()
473 // Show the frame rate, etc.
477 return App_EndFrame ();
480 extern "C" HRESULT Win32_flip_screens ()
482 // Show the frame on the primary surface.
483 if( DDERR_SURFACELOST == g_pFramework->ShowFrame() )
485 g_pFramework->RestoreSurfaces();
486 App_RestoreSurfaces();
493 //-----------------------------------------------------------------------------
494 // Name: Cleanup3DEnvironment()
495 // Desc: Cleanup scene objects
496 //-----------------------------------------------------------------------------
497 VOID Cleanup3DEnvironment()
501 App_FinalCleanup( g_pFramework->GetD3DDevice(),
502 g_pFramework->GetViewport() );
504 SAFE_DELETE( g_pFramework );
513 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
519 VOID AppPause( BOOL bPause )
521 static DWORD dwAppPausedCount = 0L;
523 if( bPause && 0 == dwAppPausedCount )
525 g_pFramework->FlipToGDISurface( TRUE );
527 dwAppPausedCount += ( bPause ? +1 : -1 );
529 g_bReady = (0==dwAppPausedCount);
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 //-----------------------------------------------------------------------------
542 static FLOAT fFPS = 0.0f;
543 static FLOAT fLastTime = 0.0f;
544 static DWORD dwFrames = 0L;
546 // Keep track of the time lapse and frame count
547 FLOAT fTime = GetTickCount() * 0.001f; // Get current time in seconds
550 // Update the frame rate once per second
551 if( fTime - fLastTime > 1.0f )
553 fFPS = dwFrames / (fTime - fLastTime);
558 // Get dimensions of the render surface
560 ddsd.dwSize = sizeof(DDSURFACEDESC2);
561 g_pFramework->GetRenderSurface()->GetSurfaceDesc(&ddsd);
563 // Setup the text buffer to write out
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 );
573 //-----------------------------------------------------------------------------
574 // Name: AppOutputText()
575 // Desc: Draws text on the window.
576 //-----------------------------------------------------------------------------
577 VOID AppOutputText( LPDIRECT3DDEVICE3 pd3dDevice, DWORD x, DWORD y, CHAR* str )
579 LPDIRECTDRAWSURFACE4 pddsRenderSurface;
580 if( FAILED( pd3dDevice->GetRenderTarget( &pddsRenderSurface ) ) )
583 // Get a DC for the surface. Then, write out the buffer
585 if( SUCCEEDED( pddsRenderSurface->GetDC(&hDC) ) )
587 SetTextColor( hDC, RGB(255,255,0) );
588 SetBkMode( hDC, TRANSPARENT );
589 ExtTextOut( hDC, x, y, 0, NULL, str, strlen(str), NULL );
591 pddsRenderSurface->ReleaseDC(hDC);
593 pddsRenderSurface->Release();
599 //-----------------------------------------------------------------------------
600 // Name: DisplayFrameworkError()
601 // Desc: Displays error messages in a message box
602 //-----------------------------------------------------------------------------
603 VOID DisplayFrameworkError( HRESULT hr, APPMSGTYPE errType )
609 case D3DENUMERR_NOCOMPATIBLEDEVICES:
610 strcpy( strMsg, TEXT("Could not find any compatible Direct3D\n"
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.") );
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") );
622 case D3DFWERR_INITIALIZATIONFAILED:
623 strcpy( strMsg, TEXT("Generic initialization error.\n\nEnable "
624 "debug output for detailed information.") );
626 case D3DFWERR_NODIRECTDRAW:
627 strcpy( strMsg, TEXT("No DirectDraw") );
629 case D3DFWERR_NODIRECT3D:
630 strcpy( strMsg, TEXT("No Direct3D") );
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.") );
637 case D3DFWERR_COULDNTSETCOOPLEVEL:
638 strcpy( strMsg, TEXT("Could not set Cooperative Level") );
640 case D3DFWERR_NO3DDEVICE:
641 strcpy( strMsg, TEXT("No 3D Device") );
643 case D3DFWERR_NOZBUFFER:
644 strcpy( strMsg, TEXT("No ZBuffer") );
646 case D3DFWERR_NOVIEWPORT:
647 strcpy( strMsg, TEXT("No Viewport") );
649 case D3DFWERR_NOPRIMARY:
650 strcpy( strMsg, TEXT("No primary") );
652 case D3DFWERR_NOCLIPPER:
653 strcpy( strMsg, TEXT("No Clipper") );
655 case D3DFWERR_BADDISPLAYMODE:
656 strcpy( strMsg, TEXT("Bad display mode") );
658 case D3DFWERR_NOBACKBUFFER:
659 strcpy( strMsg, TEXT("No backbuffer") );
661 case D3DFWERR_NONZEROREFCOUNT:
662 strcpy( strMsg, TEXT("Nonzerorefcount") );
664 case D3DFWERR_NORENDERTARGET:
665 strcpy( strMsg, TEXT("No render target") );
668 strcpy( strMsg, TEXT("Not enough memory!") );
670 case DDERR_OUTOFVIDEOMEMORY:
671 strcpy( strMsg, TEXT("There was insufficient video memory "
672 "to use the\nhardware device.") );
675 strcpy( strMsg, TEXT("Generic application error.\n\nEnable "
676 "debug output for detailed information.") );
679 if( MSGERR_APPMUSTEXIT == errType )
681 strcat( strMsg, TEXT("\n\nThis sample will now exit.") );
682 MessageBox( NULL, strMsg, g_strAppTitle, MB_ICONERROR|MB_OK );
686 if( MSGWARN_SWITCHTOSOFTWARE == errType )
687 strcat( strMsg, TEXT("\n\nSwitching to software rasterizer.") );
688 MessageBox( NULL, strMsg, g_strAppTitle, MB_ICONWARNING|MB_OK );