d3dsaver.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:123k
源码类别:

游戏

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // File: D3DSaver.cpp
  3. //
  4. // Desc: Framework for screensavers that use Direct3D.
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #include <Windows.h>
  9. #include <windowsx.h>
  10. #include <commctrl.h>
  11. #include <stdio.h>
  12. #include <tchar.h>
  13. #include <regstr.h>
  14. #define COMPILE_MULTIMON_STUBS
  15. #include <multimon.h>
  16. #include <mmsystem.h>
  17. #include <D3DX9.h>
  18. #include "D3DSaver.h"
  19. #include "dxutil.h"
  20. // Resource IDs.  D3DSaver assumes that you will create resources with
  21. // these IDs that it can use.  The easiest way to do this is to copy
  22. // the resources from the rc file of an existing D3DSaver-based program.
  23. #define IDI_MAIN_ICON                   101
  24. #define IDD_SINGLEMONITORSETTINGS       200
  25. #define IDD_MULTIMONITORSETTINGS        201
  26. #define IDC_MONITORSTAB                 2000
  27. #define IDC_TABNAMEFMT                  2001
  28. #define IDC_ADAPTERNAME                 2002
  29. #define IDC_RENDERING                   2003
  30. #define IDC_MOREINFO                    2004
  31. #define IDC_DISABLEHW                   2005
  32. #define IDC_SCREENUSAGEBOX              2006
  33. #define IDC_RENDER                      2007
  34. #define IDC_LEAVEBLACK                  2008
  35. #define IDC_DISPLAYMODEBOX              2009
  36. #define IDC_MODESSTATIC                 2010
  37. #define IDC_MODESCOMBO                  2011
  38. #define IDC_AUTOMATIC                   2012
  39. #define IDC_DISPLAYMODENOTE             2013
  40. #define IDC_GENERALBOX                  2014
  41. #define IDC_SAME                        2015
  42. #define IDC_MODEFMT                     2016
  43. #define IDS_ERR_GENERIC                 2100
  44. #define IDS_ERR_NODIRECT3D              2101
  45. #define IDS_ERR_NOWINDOWEDHAL           2102
  46. #define IDS_ERR_CREATEDEVICEFAILED      2103
  47. #define IDS_ERR_NOCOMPATIBLEDEVICES     2104
  48. #define IDS_ERR_NOHARDWAREDEVICE        2105
  49. #define IDS_ERR_HALNOTCOMPATIBLE        2106
  50. #define IDS_ERR_NOHALTHISMODE           2107
  51. #define IDS_ERR_MEDIANOTFOUND           2108
  52. #define IDS_ERR_RESIZEFAILED            2109
  53. #define IDS_ERR_OUTOFMEMORY             2110
  54. #define IDS_ERR_OUTOFVIDEOMEMORY        2111
  55. #define IDS_ERR_NOPREVIEW               2112
  56. #define IDS_INFO_GOODHAL                2200
  57. #define IDS_INFO_BADHAL_GOODSW          2201
  58. #define IDS_INFO_BADHAL_BADSW           2202
  59. #define IDS_INFO_BADHAL_NOSW            2203
  60. #define IDS_INFO_NOHAL_GOODSW           2204
  61. #define IDS_INFO_NOHAL_BADSW            2205
  62. #define IDS_INFO_NOHAL_NOSW             2206
  63. #define IDS_INFO_DISABLEDHAL_GOODSW     2207
  64. #define IDS_INFO_DISABLEDHAL_BADSW      2208
  65. #define IDS_INFO_DISABLEDHAL_NOSW       2209
  66. #define IDS_RENDERING_HAL               2210
  67. #define IDS_RENDERING_SW                2211
  68. #define IDS_RENDERING_NONE              2212
  69. // Use the following structure rather than DISPLAY_DEVICE, since some old 
  70. // versions of DISPLAY_DEVICE are missing the last two fields and this can
  71. // cause problems with EnumDisplayDevices on Windows 2000.
  72. struct DISPLAY_DEVICE_FULL
  73. {
  74.     DWORD  cb;
  75.     TCHAR  DeviceName[32];
  76.     TCHAR  DeviceString[128];
  77.     DWORD  StateFlags;
  78.     TCHAR  DeviceID[128];
  79.     TCHAR  DeviceKey[128];
  80. };
  81. static CD3DScreensaver* s_pD3DScreensaver = NULL;
  82. //-----------------------------------------------------------------------------
  83. // Name: CD3DScreensaver()
  84. // Desc: Constructor
  85. //-----------------------------------------------------------------------------
  86. CD3DScreensaver::CD3DScreensaver()
  87. {
  88.     s_pD3DScreensaver = this;
  89.     m_bCheckingSaverPassword = FALSE;
  90.     m_bIs9x = FALSE;
  91.     m_dwSaverMouseMoveCount = 0;
  92.     m_hWndParent = NULL;
  93.     m_hPasswordDLL = NULL;
  94.     m_hWnd = NULL;
  95.     m_VerifySaverPassword = NULL;
  96.     
  97.     m_bAllScreensSame = FALSE;
  98.     m_pD3D = NULL;
  99.     m_pd3dDevice = NULL;
  100.     m_bWindowed = FALSE;
  101.     m_bWaitForInputIdle = FALSE;
  102.     m_bErrorMode = FALSE;
  103.     m_hrError = S_OK;
  104.     m_szError[0] = TEXT('');
  105.     m_fFPS              = 0.0f;
  106.     m_strDeviceStats[0] = TEXT('');
  107.     m_strFrameStats[0]  = TEXT('');
  108.     // Note: clients should load a resource into m_strWindowTitle to localize this string
  109.     lstrcpy( m_strWindowTitle, TEXT("Screen Saver") );
  110.     m_bAllowRef = FALSE;
  111.     m_bUseDepthBuffer = FALSE;
  112.     m_bMultithreaded = FALSE;
  113.     m_bOneScreenOnly = FALSE;
  114.     m_strRegPath[0] = TEXT('');
  115.     m_dwMinDepthBits = 16;
  116.     m_dwMinStencilBits = 0;
  117.     m_SwapEffectFullscreen = D3DSWAPEFFECT_DISCARD;
  118.     m_SwapEffectWindowed = D3DSWAPEFFECT_COPY;
  119.     SetRectEmpty( &m_rcRenderTotal );
  120.     SetRectEmpty( &m_rcRenderCurDevice );
  121.     ZeroMemory( m_Monitors, sizeof(m_Monitors) );
  122.     m_dwNumMonitors = 0;
  123.     ZeroMemory( m_Adapters, sizeof(m_Adapters) );
  124.     m_dwNumAdapters = 0;
  125.     ZeroMemory( m_RenderUnits, sizeof(m_RenderUnits) );
  126.     m_dwNumRenderUnits = 0;
  127.     m_fTime = 0.0f;
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Name: Create()
  131. // Desc: Have the client program call this function before calling Run().
  132. //-----------------------------------------------------------------------------
  133. HRESULT CD3DScreensaver::Create( HINSTANCE hInstance )
  134. {
  135.     HRESULT hr;
  136.     SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_IDLE );
  137.     m_hInstance = hInstance;
  138.     // Parse the command line and do the appropriate thing
  139.     TCHAR* pstrCmdLine = GetCommandLine();
  140.     m_SaverMode = ParseCommandLine( pstrCmdLine );
  141.     EnumMonitors();
  142.     // Create the screen saver window(s)
  143.     if( m_SaverMode == sm_preview || 
  144.         m_SaverMode == sm_test    || 
  145.         m_SaverMode == sm_full )
  146.     {
  147.         if( FAILED( hr = CreateSaverWindow() ) )
  148.         {
  149.             m_bErrorMode = TRUE;
  150.             m_hrError = hr;
  151.         }
  152.     }
  153.     if( m_SaverMode == sm_preview )
  154.     {
  155.         // In preview mode, "pause" (enter a limited message loop) briefly 
  156.         // before proceeding, so the display control panel knows to update itself.
  157.         m_bWaitForInputIdle = TRUE;
  158.         // Post a message to mark the end of the initial group of window messages
  159.         PostMessage( m_hWnd, WM_USER, 0, 0 );
  160.         MSG msg;
  161.         while( m_bWaitForInputIdle )
  162.         {
  163.             // If GetMessage returns FALSE, it's quitting time.
  164.             if( !GetMessage( &msg, m_hWnd, 0, 0 ) )
  165.             {
  166.                 // Post the quit message to handle it later
  167.                 PostQuitMessage(0);
  168.                 break;
  169.             }
  170.             TranslateMessage( &msg );
  171.             DispatchMessage( &msg );
  172.         }
  173.     }
  174.     // Create Direct3D object
  175.     if( (m_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) == NULL )
  176.     {
  177.         m_bErrorMode = TRUE;
  178.         m_hrError = D3DAPPERR_NODIRECT3D;
  179.         return S_OK;
  180.     }
  181.     // Give the app the opportunity to register a pluggable SW D3D Device.
  182.     if( FAILED( hr = RegisterSoftwareDevice() ) )
  183.     {
  184.         m_bErrorMode = TRUE;
  185.         m_hrError = hr;
  186.         return S_OK;
  187.     }
  188.     // Build a list of Direct3D adapters, modes and devices. The
  189.     // ConfirmDevice() callback is used to confirm that only devices that
  190.     // meet the app's requirements are considered.
  191.     if( FAILED( hr = BuildDeviceList() ) )
  192.     {
  193.         m_bErrorMode = TRUE;
  194.         m_hrError = hr;
  195.         return S_OK;
  196.     }
  197.     // Make sure that at least one valid usable D3D device was found
  198.     BOOL bCompatibleDeviceFound = FALSE;
  199.     for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  200.     {
  201.         if( m_Adapters[iAdapter]->bHasAppCompatHAL || 
  202.             m_Adapters[iAdapter]->bHasAppCompatSW )
  203.         {
  204.             bCompatibleDeviceFound = TRUE;
  205.             break;
  206.         }
  207.     }
  208.     if( !bCompatibleDeviceFound )
  209.     {
  210.         m_bErrorMode = TRUE;
  211.         m_hrError = D3DAPPERR_NOCOMPATIBLEDEVICES;
  212.         return S_OK;
  213.     }
  214.     // Read any settings we need
  215.     ReadSettings();
  216.     return S_OK;
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Name: EnumMonitors()
  220. // Desc: Determine HMONITOR, desktop rect, and other info for each monitor.  
  221. //       Note that EnumDisplayDevices enumerates monitors in the order 
  222. //       indicated on the Settings page of the Display control panel, which 
  223. //       is the order we want to list monitors in, as opposed to the order 
  224. //       used by D3D's GetAdapterInfo.
  225. //-----------------------------------------------------------------------------
  226. VOID CD3DScreensaver::EnumMonitors( VOID )
  227. {
  228.     DWORD iDevice = 0;
  229.     DISPLAY_DEVICE_FULL dispdev;
  230.     DISPLAY_DEVICE_FULL dispdev2;
  231.     DEVMODE devmode;
  232.     dispdev.cb = sizeof(dispdev);
  233.     dispdev2.cb = sizeof(dispdev2);
  234.     devmode.dmSize = sizeof(devmode);
  235.     devmode.dmDriverExtra = 0;
  236.     MonitorInfo* pMonitorInfoNew;
  237.     while( EnumDisplayDevices(NULL, iDevice, (DISPLAY_DEVICE*)&dispdev, 0) )
  238.     {
  239.         // Ignore NetMeeting's mirrored displays
  240.         if( (dispdev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0 )
  241.         {
  242.             // To get monitor info for a display device, call EnumDisplayDevices
  243.             // a second time, passing dispdev.DeviceName (from the first call) as
  244.             // the first parameter.
  245.             EnumDisplayDevices(dispdev.DeviceName, 0, (DISPLAY_DEVICE*)&dispdev2, 0);
  246.             pMonitorInfoNew = &m_Monitors[m_dwNumMonitors];
  247.             ZeroMemory( pMonitorInfoNew, sizeof(MonitorInfo) );
  248.             lstrcpy( pMonitorInfoNew->strDeviceName, dispdev.DeviceString );
  249.             lstrcpy( pMonitorInfoNew->strMonitorName, dispdev2.DeviceString );
  250.             pMonitorInfoNew->iAdapter = NO_ADAPTER;
  251.             
  252.             if( dispdev.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP )
  253.             {
  254.                 EnumDisplaySettings( dispdev.DeviceName, ENUM_CURRENT_SETTINGS, &devmode );
  255.                 if( dispdev.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE )
  256.                 {
  257.                     // For some reason devmode.dmPosition is not always (0, 0)
  258.                     // for the primary display, so force it.
  259.                     pMonitorInfoNew->rcScreen.left = 0;
  260.                     pMonitorInfoNew->rcScreen.top = 0;
  261.                 }
  262.                 else
  263.                 {
  264.                     pMonitorInfoNew->rcScreen.left = devmode.dmPosition.x;
  265.                     pMonitorInfoNew->rcScreen.top = devmode.dmPosition.y;
  266.                 }
  267.                 pMonitorInfoNew->rcScreen.right = pMonitorInfoNew->rcScreen.left + devmode.dmPelsWidth;
  268.                 pMonitorInfoNew->rcScreen.bottom = pMonitorInfoNew->rcScreen.top + devmode.dmPelsHeight;
  269.                 pMonitorInfoNew->hMonitor = MonitorFromRect( &pMonitorInfoNew->rcScreen, MONITOR_DEFAULTTONULL );
  270.             }
  271.             m_dwNumMonitors++;
  272.             if( m_dwNumMonitors == MAX_DISPLAYS )
  273.                 break;
  274.         }
  275.         iDevice++;
  276.     }
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Name: Run()
  280. // Desc: Starts main execution of the screen saver.
  281. //-----------------------------------------------------------------------------
  282. INT CD3DScreensaver::Run()
  283. {
  284.     HRESULT hr;
  285.     // Parse the command line and do the appropriate thing
  286.     switch ( m_SaverMode )
  287.     {
  288.         case sm_config:
  289.         {
  290.             if( m_bErrorMode )
  291.             {
  292.                 DisplayErrorMsg( m_hrError, 0 );
  293.             }
  294.             else
  295.             {
  296.                 DoConfig();
  297.             }
  298.             break;
  299.         }
  300.         
  301.         case sm_preview:
  302.         case sm_test:
  303.         case sm_full:
  304.         {
  305.             if( FAILED( hr = DoSaver() ) )
  306.                 DisplayErrorMsg( hr, 0 );
  307.             break;
  308.         }
  309.         
  310.         case sm_passwordchange:
  311.         {
  312.             ChangePassword();
  313.             break;
  314.         }
  315.     }
  316.     for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  317.         SAFE_DELETE( m_Adapters[iAdapter] );
  318.     SAFE_RELEASE( m_pD3D );
  319.     return 0;
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Name: ParseCommandLine()
  323. // Desc: Interpret command-line parameters passed to this app.
  324. //-----------------------------------------------------------------------------
  325. SaverMode CD3DScreensaver::ParseCommandLine( LPCTSTR pstrCommandLine )
  326. {
  327.     m_hWndParent = NULL;
  328.     // Skip the first part of the command line, which is the full path 
  329.     // to the exe.  If it contains spaces, it will be contained in quotes.
  330.     if (*pstrCommandLine == TEXT('"'))
  331.     {
  332.         pstrCommandLine++;
  333.         while (*pstrCommandLine != TEXT('') && *pstrCommandLine != TEXT('"'))
  334.             pstrCommandLine++;
  335.         if( *pstrCommandLine == TEXT('"') )
  336.             pstrCommandLine++;
  337.     }
  338.     else
  339.     {
  340.         while (*pstrCommandLine != TEXT('') && *pstrCommandLine != TEXT(' '))
  341.             pstrCommandLine++;
  342.         if( *pstrCommandLine == TEXT(' ') )
  343.             pstrCommandLine++;
  344.     }
  345.     // Skip along to the first option delimiter "/" or "-"
  346.     while ( *pstrCommandLine != TEXT('') && *pstrCommandLine != TEXT('/') && *pstrCommandLine != TEXT('-') )
  347.         pstrCommandLine++;
  348.     // If there wasn't one, then must be config mode
  349.     if ( *pstrCommandLine == TEXT('') )
  350.         return sm_config;
  351.     // Otherwise see what the option was
  352.     switch ( *(++pstrCommandLine) )
  353.     {
  354.         case 'c':
  355.         case 'C':
  356.             pstrCommandLine++;
  357.             while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
  358.                 pstrCommandLine++;
  359.             if ( isdigit(*pstrCommandLine) )
  360.             {
  361. #ifdef _WIN64
  362.                 CHAR strCommandLine[2048];
  363.                 DXUtil_ConvertGenericStringToAnsiCb( strCommandLine, pstrCommandLine, sizeof(strCommandLine) );
  364.                 m_hWndParent = (HWND)(_atoi64(strCommandLine));
  365. #else
  366.                 m_hWndParent = (HWND)LongToHandle(_ttol(pstrCommandLine));
  367. #endif
  368.             }
  369.             else
  370.             {
  371.                 m_hWndParent = NULL;
  372.             }
  373.             return sm_config;
  374.         case 't':
  375.         case 'T':
  376.             return sm_test;
  377.         case 'p':
  378.         case 'P':
  379.             // Preview-mode, so option is followed by the parent HWND in decimal
  380.             pstrCommandLine++;
  381.             while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
  382.                 pstrCommandLine++;
  383.             if ( isdigit(*pstrCommandLine) )
  384.             {
  385. #ifdef _WIN64
  386.                 CHAR strCommandLine[2048];
  387.                 DXUtil_ConvertGenericStringToAnsiCb(strCommandLine, pstrCommandLine, sizeof(strCommandLine));
  388.                 m_hWndParent = (HWND)(_atoi64(strCommandLine));
  389. #else
  390.                 m_hWndParent = (HWND)LongToHandle(_ttol(pstrCommandLine));
  391. #endif
  392.             }
  393.             return sm_preview;
  394.         case 'a':
  395.         case 'A':
  396.             // Password change mode, so option is followed by parent HWND in decimal
  397.             pstrCommandLine++;
  398.             while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
  399.                 pstrCommandLine++;
  400.             if ( isdigit(*pstrCommandLine) )
  401.             {
  402. #ifdef _WIN64
  403.                 CHAR strCommandLine[2048];
  404.                 DXUtil_ConvertGenericStringToAnsiCb(strCommandLine, pstrCommandLine, sizeof(strCommandLine));
  405.                 m_hWndParent = (HWND)(_atoi64(strCommandLine));
  406. #else
  407.                 m_hWndParent = (HWND)LongToHandle(_ttol(pstrCommandLine));
  408. #endif
  409.             }
  410.             return sm_passwordchange;
  411.         default:
  412.             // All other options => run the screensaver (typically this is "/s")
  413.             return sm_full;
  414.     }
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Name: CreateSaverWindow
  418. // Desc: Register and create the appropriate window(s)
  419. //-----------------------------------------------------------------------------
  420. HRESULT CD3DScreensaver::CreateSaverWindow()
  421. {
  422. /*
  423.     // Uncomment this code to allow stepping thru code in the preview case
  424.     if( m_SaverMode == sm_preview )
  425.     {
  426.         WNDCLASS cls;
  427.         cls.hCursor        = NULL; 
  428.         cls.hIcon          = NULL; 
  429.         cls.lpszMenuName   = NULL;
  430.         cls.lpszClassName  = TEXT("Parent"); 
  431.         cls.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
  432.         cls.hInstance      = m_hInstance; 
  433.         cls.style          = CS_VREDRAW|CS_HREDRAW|CS_SAVEBITS|CS_DBLCLKS;
  434.         cls.lpfnWndProc    = DefWindowProc;
  435.         cls.cbWndExtra     = 0; 
  436.         cls.cbClsExtra     = 0; 
  437.         RegisterClass( &cls );
  438.         // Create the window
  439.         RECT rect;
  440.         HWND hwnd;
  441.         rect.left = rect.top = 40;
  442.         rect.right = rect.left+200;
  443.         rect.bottom = rect.top+200;
  444.         AdjustWindowRect( &rect, WS_VISIBLE|WS_OVERLAPPED|WS_CAPTION|WS_POPUP, FALSE );
  445.         hwnd = CreateWindow( TEXT("Parent"), TEXT("FakeShell"),
  446.             WS_VISIBLE|WS_OVERLAPPED|WS_CAPTION|WS_POPUP, rect.left, rect.top,
  447.             rect.right-rect.left, rect.bottom-rect.top, NULL,
  448.             NULL, m_hInstance, NULL );
  449.         m_hWndParent = hwnd;
  450.     }
  451. */
  452.     
  453.     // Register an appropriate window class
  454.     WNDCLASS    cls;
  455.     cls.hCursor        = LoadCursor( NULL, IDC_ARROW );
  456.     cls.hIcon          = LoadIcon( m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ); 
  457.     cls.lpszMenuName   = NULL;
  458.     cls.lpszClassName  = TEXT("D3DSaverWndClass");
  459.     cls.hbrBackground  = (HBRUSH) GetStockObject(BLACK_BRUSH);
  460.     cls.hInstance      = m_hInstance; 
  461.     cls.style          = CS_VREDRAW|CS_HREDRAW;
  462.     cls.lpfnWndProc    = SaverProcStub;
  463.     cls.cbWndExtra     = 0; 
  464.     cls.cbClsExtra     = 0; 
  465.     RegisterClass( &cls );
  466.     // Create the window
  467.     RECT rc;
  468.     DWORD dwStyle;
  469.     switch ( m_SaverMode )
  470.     {
  471.         case sm_preview:
  472.             GetClientRect( m_hWndParent, &rc );
  473.             dwStyle = WS_VISIBLE | WS_CHILD;
  474.             AdjustWindowRect( &rc, dwStyle, FALSE );
  475.             m_hWnd = CreateWindow( TEXT("D3DSaverWndClass"), m_strWindowTitle, dwStyle, 
  476.                                     rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 
  477.                                     m_hWndParent, NULL, m_hInstance, this );
  478.             m_Monitors[0].hWnd = m_hWnd;
  479.             GetClientRect( m_hWnd, &m_rcRenderTotal );
  480.             GetClientRect( m_hWnd, &m_rcRenderCurDevice );
  481.             break;
  482.         case sm_test:
  483.             rc.left = rc.top = 50;
  484.             rc.right = rc.left+600;
  485.             rc.bottom = rc.top+400;
  486.             dwStyle = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
  487.             AdjustWindowRect( &rc, dwStyle, FALSE );
  488.             m_hWnd = CreateWindow( TEXT("D3DSaverWndClass"), m_strWindowTitle, dwStyle, 
  489.                                    rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 
  490.                                    NULL, NULL, m_hInstance, this );
  491.             m_Monitors[0].hWnd = m_hWnd;
  492.             GetClientRect( m_hWnd, &m_rcRenderTotal );
  493.             GetClientRect( m_hWnd, &m_rcRenderCurDevice );
  494.             break;
  495.         case sm_full:
  496.             // Create windows for each monitor.  Note that m_hWnd is NULL when CreateWindowEx
  497.             // is called for the first monitor, so that window has no parent.  Windows for
  498.             // additional monitors are created as children of the window for the first monitor.
  499.             dwStyle = WS_VISIBLE | WS_POPUP;
  500.             m_hWnd = NULL;
  501.             for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  502.             {
  503.                 MonitorInfo* pMonitorInfo;
  504.                 pMonitorInfo = &m_Monitors[iMonitor];
  505.                 if( pMonitorInfo->hMonitor == NULL )
  506.                     continue;
  507.                 rc = pMonitorInfo->rcScreen;
  508.                 pMonitorInfo->hWnd = CreateWindowEx( WS_EX_TOPMOST, TEXT("D3DSaverWndClass"), 
  509.                     m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right - rc.left, 
  510.                     rc.bottom - rc.top, m_hWnd, NULL, m_hInstance, this );
  511.                 if( pMonitorInfo->hWnd == NULL )
  512.                     return E_FAIL;
  513.                 if( m_hWnd == NULL )
  514.                     m_hWnd = pMonitorInfo->hWnd;
  515.             }
  516.     }
  517.     if ( m_hWnd == NULL )
  518.         return E_FAIL;
  519.     return S_OK;
  520. }
  521. //-----------------------------------------------------------------------------
  522. // Name: DoSaver()
  523. // Desc: Run the screensaver graphics - may be preview, test or full-on mode
  524. //-----------------------------------------------------------------------------
  525. HRESULT CD3DScreensaver::DoSaver()
  526. {
  527.     HRESULT hr;
  528.     // Figure out if we're on Win9x
  529.     OSVERSIONINFO osvi; 
  530.     osvi.dwOSVersionInfoSize = sizeof(osvi);
  531.     GetVersionEx( &osvi );
  532.     m_bIs9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
  533.     // If we're in full on mode, and on 9x, then need to load the password DLL
  534.     if ( m_SaverMode == sm_full && m_bIs9x )
  535.     {
  536.         // Only do this if the password is set - check registry:
  537.         HKEY hKey; 
  538.         if ( RegCreateKeyEx( HKEY_CURRENT_USER, REGSTR_PATH_SCREENSAVE, 0, NULL, 0, KEY_READ, NULL, &hKey, NULL ) == ERROR_SUCCESS ) 
  539.         { 
  540.             DWORD dwVal;
  541.             DWORD dwSize = sizeof(dwVal); 
  542.  
  543.             if ( (RegQueryValueEx( hKey, REGSTR_VALUE_USESCRPASSWORD, NULL, NULL,
  544.                                    (BYTE *)&dwVal, &dwSize ) == ERROR_SUCCESS) && dwVal ) 
  545.             { 
  546.                 m_hPasswordDLL = LoadLibrary( TEXT("PASSWORD.CPL") );
  547.                 if ( m_hPasswordDLL )
  548.                     m_VerifySaverPassword = (VERIFYPWDPROC)GetProcAddress( m_hPasswordDLL, "VerifyScreenSavePwd" );
  549.                 RegCloseKey( hKey );
  550.             }
  551.         }
  552.     }
  553.     // Initialize the application timer
  554.     DXUtil_Timer( TIMER_START );
  555.     if( !m_bErrorMode )
  556.     {
  557.         // Initialize the app's custom scene stuff
  558.         if( FAILED( hr = OneTimeSceneInit() ) )
  559.             return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  560.         // Do graphical init stuff
  561.         if ( FAILED(hr = Initialize3DEnvironment()) )
  562.             return hr;
  563.     }
  564.     // Flag as screensaver running if in full on mode
  565.     if ( m_SaverMode == sm_full )
  566.     {
  567.         BOOL bUnused;
  568.         SystemParametersInfo( SPI_SCREENSAVERRUNNING, TRUE, &bUnused, 0 );
  569.     }
  570.     // Message pump
  571.     BOOL bGotMsg;
  572.     MSG msg;
  573.     msg.message = WM_NULL;
  574.     while ( msg.message != WM_QUIT )
  575.     {
  576.         bGotMsg = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
  577.         if( bGotMsg )
  578.         {
  579.             TranslateMessage( &msg );
  580.             DispatchMessage( &msg );
  581.         }
  582.         else
  583.         {
  584.             Sleep(10);
  585.             if( m_bErrorMode )
  586.             {
  587.                 UpdateErrorBox();
  588.             }
  589.             else
  590.             {
  591.                 Render3DEnvironment();
  592.             }
  593.         }
  594.     }
  595.     return S_OK;
  596. }
  597. //-----------------------------------------------------------------------------
  598. // Name: ShutdownSaver()
  599. // Desc: 
  600. //-----------------------------------------------------------------------------
  601. VOID CD3DScreensaver::ShutdownSaver()
  602. {
  603.     // Unflag screensaver running if in full on mode
  604.     if ( m_SaverMode == sm_full )
  605.     {
  606.         BOOL bUnused;
  607.         SystemParametersInfo( SPI_SCREENSAVERRUNNING, FALSE, &bUnused, 0 );
  608.     }
  609.     // Kill graphical stuff
  610.     Cleanup3DEnvironment();
  611.     // Let client app clean up its resources
  612.     FinalCleanup();
  613.     // Unload the password DLL (if we loaded it)
  614.     if ( m_hPasswordDLL != NULL )
  615.     {
  616.         FreeLibrary( m_hPasswordDLL );
  617.         m_hPasswordDLL = NULL;
  618.     }
  619.     // Post message to drop out of message loop
  620.     PostQuitMessage( 0 );
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Name: SaverProcStub()
  624. // Desc: This function forwards all window messages to SaverProc, which has
  625. //       access to the "this" pointer.
  626. //-----------------------------------------------------------------------------
  627. LRESULT CALLBACK CD3DScreensaver::SaverProcStub( HWND hWnd, UINT uMsg,
  628.                                                  WPARAM wParam, LPARAM lParam )
  629. {
  630.     return s_pD3DScreensaver->SaverProc( hWnd, uMsg, wParam, lParam );
  631. }
  632. //-----------------------------------------------------------------------------
  633. // Name: SaverProc()
  634. // Desc: Handle window messages for main screensaver windows (one per screen).
  635. //-----------------------------------------------------------------------------
  636. LRESULT CD3DScreensaver::SaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  637. {
  638.     switch ( uMsg )
  639.         {
  640.         case WM_USER:
  641.             // All initialization messages have gone through.  Allow
  642.             // 500ms of idle time, then proceed with initialization.
  643.             SetTimer( hWnd, 1, 500, NULL );
  644.             break;
  645.         case WM_TIMER:
  646.             // Initial idle time is done, proceed with initialization.
  647.             m_bWaitForInputIdle = FALSE;
  648.             KillTimer( hWnd, 1 );
  649.             break;
  650.         case WM_DESTROY:
  651.             ShutdownSaver();
  652.             break;
  653.         case WM_SETCURSOR:
  654.             if ( m_SaverMode == sm_full && !m_bCheckingSaverPassword )
  655.             {
  656.                 // Hide cursor
  657.                 SetCursor( NULL );
  658.                 return TRUE;
  659.             }
  660.             break;
  661.         case WM_PAINT:
  662.         {
  663.             // Show error message, if there is one
  664.             PAINTSTRUCT ps;
  665.             BeginPaint( hWnd, &ps );
  666.             // In preview mode, just fill 
  667.             // the preview window with black. 
  668.             if( !m_bErrorMode && m_SaverMode == sm_preview )
  669.             {
  670.                 RECT rc;
  671.                 GetClientRect(hWnd,&rc);
  672.                 FillRect(ps.hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH) );
  673.             }
  674.             else
  675.             {
  676.                 DoPaint( hWnd, ps.hdc );
  677.             }
  678.             EndPaint( hWnd, &ps );
  679.             return 0;
  680.         }
  681.         case WM_ERASEBKGND:
  682.             // Erase background if checking password or if window is not
  683.             // assigned to a render unit
  684.             if( !m_bCheckingSaverPassword )
  685.             {
  686.                 RenderUnit* pRenderUnit;
  687.                 D3DAdapterInfo* pD3DAdapterInfo;
  688.                 for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  689.                 {
  690.                     pRenderUnit = &m_RenderUnits[iRenderUnit];
  691.                     pD3DAdapterInfo = m_Adapters[pRenderUnit->iAdapter];
  692.                     if( pD3DAdapterInfo->hWndDevice == hWnd )
  693.                         return TRUE; // don't erase this window
  694.                 }
  695.             }
  696.             break;
  697.         case WM_MOUSEMOVE:
  698.             if( m_SaverMode != sm_test )
  699.             {
  700.                 static INT xPrev = -1;
  701.                 static INT yPrev = -1;
  702.                 INT xCur = GET_X_LPARAM(lParam);
  703.                 INT yCur = GET_Y_LPARAM(lParam);
  704.                 if( xCur != xPrev || yCur != yPrev )
  705.                 {
  706.                     xPrev = xCur;
  707.                     yPrev = yCur;
  708.                     m_dwSaverMouseMoveCount++;
  709.                     if ( m_dwSaverMouseMoveCount > 5 )
  710.                         InterruptSaver();
  711.                 }
  712.             }
  713.             break;
  714.         case WM_KEYDOWN:
  715.         case WM_LBUTTONDOWN:
  716.         case WM_RBUTTONDOWN:
  717.         case WM_MBUTTONDOWN:
  718.             if( m_SaverMode != sm_test )
  719.                 InterruptSaver();
  720.             break;
  721.         case WM_ACTIVATEAPP:
  722.             if( wParam == FALSE && m_SaverMode != sm_test )
  723.                 InterruptSaver();
  724.             break;
  725.         case WM_POWERBROADCAST:
  726.             if( wParam == PBT_APMSUSPEND && m_VerifySaverPassword == NULL )
  727.                 InterruptSaver();
  728.             break;
  729.         case WM_SYSCOMMAND: 
  730.             if ( m_SaverMode == sm_full )
  731.             {
  732.                 switch ( wParam )
  733.                 {
  734.                     case SC_NEXTWINDOW:
  735.                     case SC_PREVWINDOW:
  736.                     case SC_SCREENSAVE:
  737.                     case SC_CLOSE:
  738.                         return FALSE;
  739.                 };
  740.             }
  741.             break;
  742.     }
  743.     return DefWindowProc( hWnd, uMsg, wParam, lParam );
  744. }
  745. //-----------------------------------------------------------------------------
  746. // Name: InterruptSaver()
  747. // Desc: A message was received (mouse move, keydown, etc.) that may mean
  748. //       the screen saver should show the password dialog and/or shut down.
  749. //-----------------------------------------------------------------------------
  750. VOID CD3DScreensaver::InterruptSaver()
  751. {
  752.     HRESULT hr;
  753.     DWORD iRenderUnit;
  754.     RenderUnit* pRenderUnit;
  755.     BOOL bPasswordOkay = FALSE;
  756.     if( m_SaverMode == sm_test ||
  757.         m_SaverMode == sm_full && !m_bCheckingSaverPassword )
  758.     {
  759.         if( m_bIs9x && m_SaverMode == sm_full )
  760.         {
  761.             // If no VerifyPassword function, then no password is set 
  762.             // or we're not on 9x. 
  763.             if ( m_VerifySaverPassword != NULL )
  764.             {
  765.                 // Shut down all D3D devices so we can show a Windows dialog
  766.                 for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  767.                 {
  768.                     pRenderUnit = &m_RenderUnits[iRenderUnit];
  769.                     SwitchToRenderUnit(iRenderUnit);
  770.                     if( pRenderUnit->bDeviceObjectsRestored )
  771.                     {
  772.                         InvalidateDeviceObjects();
  773.                         pRenderUnit->bDeviceObjectsRestored = FALSE;
  774.                     }
  775.                     if( pRenderUnit->bDeviceObjectsInited )
  776.                     {
  777.                         DeleteDeviceObjects();
  778.                         pRenderUnit->bDeviceObjectsInited = FALSE;
  779.                     }
  780.                     SAFE_RELEASE(pRenderUnit->pd3dDevice);
  781.                 }
  782.                 // Make sure all adapter windows cover the whole screen,
  783.                 // even after deleting D3D devices (which may have caused
  784.                 // mode changes)
  785.                 D3DAdapterInfo* pD3DAdapterInfo;
  786.                 for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  787.                 {
  788.                     pD3DAdapterInfo = m_Adapters[iAdapter];
  789.                     ShowWindow( pD3DAdapterInfo->hWndDevice, SW_RESTORE );
  790.                     ShowWindow( pD3DAdapterInfo->hWndDevice, SW_MAXIMIZE );
  791.                 }
  792.                 m_bCheckingSaverPassword = TRUE;
  793.                 bPasswordOkay = m_VerifySaverPassword( m_hWnd );
  794.                 m_bCheckingSaverPassword = FALSE;
  795.                 if ( bPasswordOkay )
  796.                 {
  797.                     // D3D devices are all torn down, so it's safe
  798.                     // to discard all render units now (so we don't
  799.                     // try to clean them up again later).
  800.                     m_dwNumRenderUnits = 0;
  801.                 }
  802.                 else
  803.                 {
  804.                     // Back to screen saving...
  805.                     SetCursor( NULL );
  806.                     m_dwSaverMouseMoveCount = 0;
  807.                     // Recreate all D3D devices
  808.                     for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  809.                     {
  810.                         pRenderUnit = &m_RenderUnits[iRenderUnit];
  811.                         hr = m_pD3D->CreateDevice(pRenderUnit->iAdapter, 
  812.                             pRenderUnit->DeviceType, m_hWnd, 
  813.                             pRenderUnit->dwBehavior, &pRenderUnit->d3dpp, 
  814.                             &pRenderUnit->pd3dDevice );
  815.                         if( FAILED( hr ) )
  816.                         {
  817.                             m_bErrorMode = TRUE;
  818.                             m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  819.                         }
  820.                         else
  821.                         {
  822.                             SwitchToRenderUnit(iRenderUnit);
  823.                             if( FAILED(hr = InitDeviceObjects() ) )
  824.                             {
  825.                                 m_bErrorMode = TRUE;
  826.                                 m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  827.                             }
  828.                             else 
  829.                             {
  830.                                 pRenderUnit->bDeviceObjectsInited = TRUE;
  831.                                 if( FAILED(hr = RestoreDeviceObjects() ) )
  832.                                 {
  833.                                     m_bErrorMode = TRUE;
  834.                                     m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  835.                                 }
  836.                                 else
  837.                                 {
  838.                                     pRenderUnit->bDeviceObjectsRestored = TRUE;
  839.                                 }
  840.                             }
  841.                         }
  842.                     }
  843.                     return;
  844.                 }
  845.             }
  846.         }
  847.         ShutdownSaver();
  848.     }
  849. }
  850. //-----------------------------------------------------------------------------
  851. // Name: Initialize3DEnvironment()
  852. // Desc: Set up D3D device(s)
  853. //-----------------------------------------------------------------------------
  854. HRESULT CD3DScreensaver::Initialize3DEnvironment()
  855. {
  856.     HRESULT hr;
  857.     DWORD iAdapter;
  858.     DWORD iMonitor;
  859.     D3DAdapterInfo* pD3DAdapterInfo;
  860.     MonitorInfo* pMonitorInfo;
  861.     DWORD iRenderUnit;
  862.     RenderUnit* pRenderUnit;
  863.     MONITORINFO monitorInfo;
  864.     if ( m_SaverMode == sm_full )
  865.     {
  866.         // Fullscreen mode.  Create a RenderUnit for each monitor (unless 
  867.         // the user wants it black)
  868.         m_bWindowed = FALSE;
  869.         if( m_bOneScreenOnly )
  870.         {
  871.             // Set things up to only create a RenderUnit on the best device
  872.             for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  873.             {
  874.                 pD3DAdapterInfo = m_Adapters[iAdapter];
  875.                 pD3DAdapterInfo->bLeaveBlack = TRUE;
  876.             }
  877.             GetBestAdapter( &iAdapter );
  878.             if( iAdapter == NO_ADAPTER )
  879.             {
  880.                 m_bErrorMode = TRUE;
  881.                 m_hrError = D3DAPPERR_NOCOMPATIBLEDEVICES;
  882.             }
  883.             else
  884.             {
  885.                 pD3DAdapterInfo = m_Adapters[iAdapter];
  886.                 pD3DAdapterInfo->bLeaveBlack = FALSE;
  887.             }
  888.         }
  889.         for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  890.         {
  891.             pMonitorInfo = &m_Monitors[iMonitor];
  892.             iAdapter = pMonitorInfo->iAdapter;
  893.             if( iAdapter == NO_ADAPTER )
  894.                 continue; 
  895.             pD3DAdapterInfo = m_Adapters[iAdapter];
  896.             if( pD3DAdapterInfo->bDisableHW && !pD3DAdapterInfo->bHasAppCompatSW &&
  897.                 !m_bAllowRef )
  898.             {
  899.                 pD3DAdapterInfo->bLeaveBlack = TRUE;
  900.             }
  901.             if( !pD3DAdapterInfo->bLeaveBlack && pD3DAdapterInfo->dwNumDevices > 0 )
  902.             {
  903.                 pD3DAdapterInfo->hWndDevice = pMonitorInfo->hWnd;
  904.                 pRenderUnit = &m_RenderUnits[m_dwNumRenderUnits++];
  905.                 ZeroMemory( pRenderUnit, sizeof(RenderUnit) );
  906.                 pRenderUnit->iAdapter = iAdapter;
  907.                 if( FAILED( hr = CreateFullscreenRenderUnit( pRenderUnit ) ) )
  908.                 {
  909.                     // skip this render unit and leave screen blank
  910.                     m_dwNumRenderUnits--;
  911.                     m_bErrorMode = TRUE;
  912.                     m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  913.                 }
  914.             }
  915.         }
  916.     }
  917.     else 
  918.     {
  919.         // Windowed mode, for test mode or preview window.  Just need one RenderUnit.
  920.         m_bWindowed = TRUE;
  921.         GetClientRect( m_hWnd, &m_rcRenderTotal );
  922.         GetClientRect( m_hWnd, &m_rcRenderCurDevice );
  923.         GetBestAdapter( &iAdapter );
  924.         if( iAdapter == NO_ADAPTER )
  925.         {
  926.             m_bErrorMode = TRUE;
  927.             m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  928.         }
  929.         else
  930.         {
  931.             pD3DAdapterInfo = m_Adapters[iAdapter];
  932.             pD3DAdapterInfo->hWndDevice = m_hWnd;
  933.         }
  934.         if( !m_bErrorMode )
  935.         {
  936.             pRenderUnit = &m_RenderUnits[m_dwNumRenderUnits++];
  937.             ZeroMemory( pRenderUnit, sizeof(RenderUnit) );
  938.             pRenderUnit->iAdapter = iAdapter;
  939.             if( FAILED( hr = CreateWindowedRenderUnit( pRenderUnit ) ) )
  940.             {
  941.                 m_dwNumRenderUnits--;
  942.                 m_bErrorMode = TRUE;
  943.                 if( m_SaverMode == sm_preview )
  944.                     m_hrError = D3DAPPERR_NOPREVIEW;
  945.                 else
  946.                     m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  947.             }
  948.         }
  949.     }
  950.     // Once all mode changes are done, (re-)determine coordinates of all 
  951.     // screens, and make sure windows still cover each screen
  952.     for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  953.     {
  954.         pMonitorInfo = &m_Monitors[iMonitor];
  955.         monitorInfo.cbSize = sizeof(MONITORINFO);
  956.         GetMonitorInfo( pMonitorInfo->hMonitor, &monitorInfo );
  957.         pMonitorInfo->rcScreen = monitorInfo.rcMonitor;
  958.         if( !m_bWindowed )
  959.         {
  960.             SetWindowPos( pMonitorInfo->hWnd, HWND_TOPMOST, monitorInfo.rcMonitor.left, 
  961.                 monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, 
  962.                 monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, SWP_NOACTIVATE );
  963.         }
  964.     }
  965.     // For fullscreen, determine bounds of the virtual screen containing all 
  966.     // screens that are rendering.  Don't just use SM_XVIRTUALSCREEN, because 
  967.     // we don't want to count screens that are just black
  968.     if( !m_bWindowed )
  969.     {
  970.         for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  971.         {
  972.             pRenderUnit = &m_RenderUnits[iRenderUnit];
  973.             pMonitorInfo = &m_Monitors[pRenderUnit->iMonitor];
  974.             UnionRect( &m_rcRenderTotal, &m_rcRenderTotal, &pMonitorInfo->rcScreen );
  975.         }
  976.     }
  977.     if( !m_bErrorMode )
  978.     {
  979.         // Initialize D3D devices for all render units
  980.         for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  981.         {
  982.             pRenderUnit = &m_RenderUnits[iRenderUnit];
  983.             SwitchToRenderUnit( iRenderUnit );
  984.             if ( FAILED(hr = InitDeviceObjects() ) )
  985.             {
  986.                 m_bErrorMode = TRUE;
  987.                 m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  988.             }
  989.             else 
  990.             {
  991.                 pRenderUnit->bDeviceObjectsInited = TRUE;
  992.                 if ( FAILED(hr = RestoreDeviceObjects() ) )
  993.                 {
  994.                     m_bErrorMode = TRUE;
  995.                     m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  996.                 }
  997.                 else
  998.                 {
  999.                     pRenderUnit->bDeviceObjectsRestored = TRUE;
  1000.                 }
  1001.             }
  1002.         }
  1003.         UpdateDeviceStats(); 
  1004.     }
  1005.     // Make sure all those display changes don't count as user mouse moves
  1006.     m_dwSaverMouseMoveCount = 0;
  1007.     return S_OK;
  1008. }
  1009. //-----------------------------------------------------------------------------
  1010. // Name: GetBestAdapter()
  1011. // Desc: To decide which adapter to use, loop through monitors until you find
  1012. //       one whose adapter has a compatible HAL.  If none, use the first 
  1013. //       monitor that has an compatible SW device.
  1014. //-----------------------------------------------------------------------------
  1015. BOOL CD3DScreensaver::GetBestAdapter( DWORD* piAdapter )
  1016. {
  1017.     DWORD iAdapterBest = NO_ADAPTER;
  1018.     DWORD iAdapter;
  1019.     DWORD iMonitor;
  1020.     MonitorInfo* pMonitorInfo;
  1021.     D3DAdapterInfo* pD3DAdapterInfo;
  1022.     for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  1023.     {
  1024.         pMonitorInfo = &m_Monitors[iMonitor];
  1025.         iAdapter = pMonitorInfo->iAdapter;
  1026.         if( iAdapter == NO_ADAPTER )
  1027.             continue; 
  1028.         pD3DAdapterInfo = m_Adapters[iAdapter];
  1029.         if( pD3DAdapterInfo->bHasAppCompatHAL )
  1030.         {
  1031.             iAdapterBest = iAdapter;
  1032.             break;
  1033.         }
  1034.         if( pD3DAdapterInfo->bHasAppCompatSW )
  1035.         {
  1036.             iAdapterBest = iAdapter;
  1037.             // but keep looking...
  1038.         }
  1039.     }
  1040.     *piAdapter = iAdapterBest;
  1041.     return (iAdapterBest != NO_ADAPTER);
  1042. }
  1043. //-----------------------------------------------------------------------------
  1044. // Name: CreateFullscreenRenderUnit()
  1045. // Desc: 
  1046. //-----------------------------------------------------------------------------
  1047. HRESULT CD3DScreensaver::CreateFullscreenRenderUnit( RenderUnit* pRenderUnit )
  1048. {
  1049.     HRESULT hr;
  1050.     UINT iAdapter = pRenderUnit->iAdapter;
  1051.     D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  1052.     DWORD iMonitor = pD3DAdapterInfo->iMonitor;
  1053.     D3DDeviceInfo* pD3DDeviceInfo;
  1054.     D3DModeInfo* pD3DModeInfo;
  1055.     DWORD dwCurrentDevice;
  1056.     D3DDEVTYPE curType;
  1057.     if( iAdapter >= m_dwNumAdapters )
  1058.         return E_FAIL;
  1059.     if( pD3DAdapterInfo->dwNumDevices == 0 )
  1060.         return E_FAIL;
  1061.     // Find the best device for the adapter.  Use HAL
  1062.     // if it's there, otherwise SW, otherwise REF.
  1063.     dwCurrentDevice = 0xffff;
  1064.     curType = D3DDEVTYPE_FORCE_DWORD;
  1065.     for( DWORD iDevice = 0; iDevice < pD3DAdapterInfo->dwNumDevices; iDevice++)
  1066.     {
  1067.         pD3DDeviceInfo = &pD3DAdapterInfo->devices[iDevice];
  1068.         if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_HAL && !pD3DAdapterInfo->bDisableHW )
  1069.         {
  1070.             dwCurrentDevice = iDevice;
  1071.             curType = D3DDEVTYPE_HAL;
  1072.             break; // stop looking
  1073.         }
  1074.         else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW )
  1075.         {
  1076.             dwCurrentDevice = iDevice;
  1077.             curType = D3DDEVTYPE_SW;
  1078.             // but keep looking
  1079.         }
  1080.         else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_REF && m_bAllowRef && curType != D3DDEVTYPE_SW )
  1081.         {
  1082.             dwCurrentDevice = iDevice;
  1083.             curType = D3DDEVTYPE_REF;
  1084.             // but keep looking
  1085.         }
  1086.     }
  1087.     if( dwCurrentDevice == 0xffff )
  1088.         return D3DAPPERR_NOHARDWAREDEVICE;
  1089.     pD3DDeviceInfo = &pD3DAdapterInfo->devices[dwCurrentDevice];
  1090.     pD3DDeviceInfo->dwCurrentMode = 0xffff;
  1091.     if( pD3DAdapterInfo->dwUserPrefWidth != 0 )
  1092.     {
  1093.         // Try to find mode that matches user preference
  1094.         for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1095.         {
  1096.             pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1097.             if( pD3DModeInfo->Width == pD3DAdapterInfo->dwUserPrefWidth &&
  1098.                 pD3DModeInfo->Height == pD3DAdapterInfo->dwUserPrefHeight &&
  1099.                 pD3DModeInfo->Format == pD3DAdapterInfo->d3dfmtUserPrefFormat )
  1100.             {
  1101.                 pD3DDeviceInfo->dwCurrentMode = iMode;
  1102.                 break;
  1103.             }
  1104.         }
  1105.     }
  1106.     // If user-preferred mode is not specified or not found,
  1107.     // use "Automatic" technique: 
  1108.     if( pD3DDeviceInfo->dwCurrentMode == 0xffff )
  1109.     {
  1110.         if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW )
  1111.         {
  1112.             // If using a SW rast then try to find a low resolution and 16-bpp.
  1113.             BOOL bFound16BitMode = FALSE;            
  1114.             DWORD dwSmallestHeight = 0;
  1115.             pD3DDeviceInfo->dwCurrentMode = 0; // unless we find something better
  1116.             for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1117.             {
  1118.                 pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1119.                 // Skip 640x400 because 640x480 is better
  1120.                 if( pD3DModeInfo->Height == 400 )
  1121.                     continue; 
  1122.                 if( pD3DModeInfo->Height < dwSmallestHeight || 
  1123.                     (pD3DModeInfo->Height == dwSmallestHeight && !bFound16BitMode) )
  1124.                 {
  1125.                     dwSmallestHeight = pD3DModeInfo->Height;
  1126.                     pD3DDeviceInfo->dwCurrentMode = iMode;
  1127.                     bFound16BitMode = FALSE;
  1128.                     if( ( pD3DModeInfo->Format == D3DFMT_R5G6B5 ||
  1129.                           pD3DModeInfo->Format == D3DFMT_X1R5G5B5 || 
  1130.                           pD3DModeInfo->Format == D3DFMT_A1R5G5B5 || 
  1131.                           pD3DModeInfo->Format == D3DFMT_A4R4G4B4 || 
  1132.                           pD3DModeInfo->Format == D3DFMT_X4R4G4B4 ) )
  1133.                     {
  1134.                         bFound16BitMode = TRUE;
  1135.                     }
  1136.                 }
  1137.             }
  1138.         }
  1139.         else
  1140.         {
  1141.             // Try to find mode matching desktop resolution and 32-bpp.
  1142.             BOOL bMatchedSize = FALSE;
  1143.             BOOL bGot32Bit = FALSE;
  1144.             pD3DDeviceInfo->dwCurrentMode = 0; // unless we find something better
  1145.             for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1146.             {
  1147.                 pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1148.                 if( pD3DModeInfo->Width == pD3DAdapterInfo->d3ddmDesktop.Width &&
  1149.                     pD3DModeInfo->Height == pD3DAdapterInfo->d3ddmDesktop.Height )
  1150.                 {
  1151.                     if( !bMatchedSize )
  1152.                         pD3DDeviceInfo->dwCurrentMode = iMode;
  1153.                     bMatchedSize = TRUE;
  1154.                     if( !bGot32Bit &&
  1155.                         ( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
  1156.                           pD3DModeInfo->Format == D3DFMT_A8R8G8B8 ) )
  1157.                     {
  1158.                         pD3DDeviceInfo->dwCurrentMode = iMode;
  1159.                         bGot32Bit = TRUE;
  1160.                         break;
  1161.                     }
  1162.                 }
  1163.             }
  1164.         }
  1165.     }
  1166.     // If desktop mode not found, pick highest mode available
  1167.     if( pD3DDeviceInfo->dwCurrentMode == 0xffff )
  1168.     {
  1169.         DWORD dwWidthMax = 0;
  1170.         DWORD dwHeightMax = 0;
  1171.         DWORD dwBppMax = 0;
  1172.         DWORD dwWidthCur = 0;
  1173.         DWORD dwHeightCur = 0;
  1174.         DWORD dwBppCur = 0;
  1175.         for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1176.         {
  1177.             pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1178.             dwWidthCur = pD3DModeInfo->Width;
  1179.             dwHeightCur = pD3DModeInfo->Height;
  1180.             if( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
  1181.                 pD3DModeInfo->Format == D3DFMT_A8R8G8B8 )
  1182.             {
  1183.                 dwBppCur = 32;
  1184.             }
  1185.             else
  1186.             {
  1187.                 dwBppCur = 16;
  1188.             }
  1189.             if( dwWidthCur > dwWidthMax ||
  1190.                 dwHeightCur > dwHeightMax ||
  1191.                 dwWidthCur == dwWidthMax && dwHeightCur == dwHeightMax && dwBppCur > dwBppMax )
  1192.             {
  1193.                 dwWidthMax = dwWidthCur;
  1194.                 dwHeightMax = dwHeightCur;
  1195.                 dwBppMax = dwBppCur;
  1196.                 pD3DDeviceInfo->dwCurrentMode = iMode;
  1197.             }
  1198.         }
  1199.     }
  1200.     // Try to create the D3D device, falling back to lower-res modes if it fails
  1201.     BOOL bAtLeastOneFailure = FALSE;
  1202.     for( ; ; )
  1203.     {
  1204.         pD3DModeInfo = &pD3DDeviceInfo->modes[pD3DDeviceInfo->dwCurrentMode];
  1205.         pRenderUnit->DeviceType = pD3DDeviceInfo->DeviceType;
  1206.         pRenderUnit->dwBehavior = pD3DModeInfo->dwBehavior;
  1207.         pRenderUnit->iMonitor = iMonitor;
  1208.         pRenderUnit->d3dpp.BackBufferFormat = pD3DModeInfo->Format;
  1209.         pRenderUnit->d3dpp.BackBufferWidth = pD3DModeInfo->Width;
  1210.         pRenderUnit->d3dpp.BackBufferHeight = pD3DModeInfo->Height;
  1211.         pRenderUnit->d3dpp.Windowed = FALSE;
  1212.         pRenderUnit->d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  1213.         pRenderUnit->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  1214.         pRenderUnit->d3dpp.AutoDepthStencilFormat = pD3DModeInfo->DepthStencilFormat;
  1215.         pRenderUnit->d3dpp.BackBufferCount = 1;
  1216.         pRenderUnit->d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
  1217.         pRenderUnit->d3dpp.SwapEffect = m_SwapEffectFullscreen;
  1218.         pRenderUnit->d3dpp.hDeviceWindow = pD3DAdapterInfo->hWndDevice;
  1219.         pRenderUnit->d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
  1220.         pRenderUnit->d3dpp.Flags = 0;
  1221.         // Create device
  1222.         hr = m_pD3D->CreateDevice( iAdapter, pRenderUnit->DeviceType, 
  1223.                                    m_hWnd, // (this is the focus window)
  1224.                                    pRenderUnit->dwBehavior, &pRenderUnit->d3dpp, 
  1225.                                    &pRenderUnit->pd3dDevice );
  1226.         if( SUCCEEDED( hr ) )
  1227.         {
  1228.             // Give the client app an opportunity to reject this mode
  1229.             // due to not enough video memory, or any other reason
  1230.             if( SUCCEEDED( hr = ConfirmMode( pRenderUnit->pd3dDevice ) ) )
  1231.                 break;
  1232.             else
  1233.                 SAFE_RELEASE( pRenderUnit->pd3dDevice );
  1234.         }
  1235.         // If we get here, remember that CreateDevice or ConfirmMode failed, so
  1236.         // we can change the default mode next time
  1237.         bAtLeastOneFailure = TRUE;
  1238.         if( !FindNextLowerMode( pD3DDeviceInfo ) )
  1239.             break;
  1240.     }
  1241.     if( SUCCEEDED( hr ) && bAtLeastOneFailure && m_strRegPath[0] != TEXT('') )
  1242.     {
  1243.         // Record the mode that succeeded in the registry so we can 
  1244.         // default to it next time
  1245.         TCHAR strKey[100];
  1246.         HKEY hkeyParent;
  1247.         HKEY hkey;
  1248.         pD3DAdapterInfo->dwUserPrefWidth = pRenderUnit->d3dpp.BackBufferWidth;
  1249.         pD3DAdapterInfo->dwUserPrefHeight = pRenderUnit->d3dpp.BackBufferHeight;
  1250.         pD3DAdapterInfo->d3dfmtUserPrefFormat = pRenderUnit->d3dpp.BackBufferFormat;
  1251.         if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, m_strRegPath, 
  1252.             0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyParent, NULL ) )
  1253.         {
  1254.             wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
  1255.             if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey, 
  1256.                 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  1257.             {
  1258.                 RegSetValueEx( hkey, TEXT("Width"), NULL, REG_DWORD, 
  1259.                     (BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, sizeof(DWORD) );
  1260.                 RegSetValueEx( hkey, TEXT("Height"), NULL, REG_DWORD, 
  1261.                     (BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, sizeof(DWORD) );
  1262.                 RegSetValueEx( hkey, TEXT("Format"), NULL, REG_DWORD, 
  1263.                     (BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, sizeof(DWORD) );
  1264.                 RegSetValueEx( hkey, TEXT("Adapter ID"), NULL, REG_BINARY, 
  1265.                     (BYTE*)&pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier, sizeof(GUID) );
  1266.                 RegCloseKey( hkey );
  1267.             }
  1268.             RegCloseKey( hkeyParent );
  1269.         }
  1270.     }
  1271.     return hr;
  1272. }
  1273. //-----------------------------------------------------------------------------
  1274. // Name: FindNextLowerMode()
  1275. // Desc: 
  1276. //-----------------------------------------------------------------------------
  1277. BOOL CD3DScreensaver::FindNextLowerMode( D3DDeviceInfo* pD3DDeviceInfo )
  1278. {
  1279.     DWORD iModeCur = pD3DDeviceInfo->dwCurrentMode;
  1280.     D3DModeInfo* pD3DModeInfoCur = &pD3DDeviceInfo->modes[iModeCur];
  1281.     DWORD dwWidthCur = pD3DModeInfoCur->Width;
  1282.     DWORD dwHeightCur = pD3DModeInfoCur->Height;
  1283.     DWORD dwNumPixelsCur = dwWidthCur * dwHeightCur;
  1284.     D3DFORMAT d3dfmtCur = pD3DModeInfoCur->Format;
  1285.     BOOL b32BitCur = (d3dfmtCur == D3DFMT_A8R8G8B8 ||
  1286.                       d3dfmtCur == D3DFMT_X8R8G8B8);
  1287.     DWORD iModeNew;
  1288.     D3DModeInfo* pD3DModeInfoNew;
  1289.     DWORD dwWidthNew;
  1290.     DWORD dwHeightNew;
  1291.     DWORD dwNumPixelsNew;
  1292.     D3DFORMAT d3dfmtNew = D3DFMT_UNKNOWN;
  1293.     BOOL b32BitNew;
  1294.     DWORD dwWidthBest = 0;
  1295.     DWORD dwHeightBest = 0;
  1296.     DWORD dwNumPixelsBest = 0;
  1297.     BOOL b32BitBest = FALSE;
  1298.     DWORD iModeBest = 0xffff;
  1299.     for( iModeNew = 0; iModeNew < pD3DDeviceInfo->dwNumModes; iModeNew++ )
  1300.     {
  1301.         // Don't pick the same mode we currently have
  1302.         if( iModeNew == iModeCur )
  1303.             continue;
  1304.         // Get info about new mode
  1305.         pD3DModeInfoNew = &pD3DDeviceInfo->modes[iModeNew];
  1306.         dwWidthNew = pD3DModeInfoNew->Width;
  1307.         dwHeightNew = pD3DModeInfoNew->Height;
  1308.         dwNumPixelsNew = dwWidthNew * dwHeightNew;
  1309.         d3dfmtNew = pD3DModeInfoNew->Format;
  1310.         b32BitNew = (d3dfmtNew == D3DFMT_A8R8G8B8 ||
  1311.                      d3dfmtNew == D3DFMT_X8R8G8B8);
  1312.         // If we're currently 32-bit and new mode is same width/height and 16-bit, take it
  1313.         if( b32BitCur && 
  1314.             !b32BitNew &&
  1315.             pD3DModeInfoNew->Width == dwWidthCur &&
  1316.             pD3DModeInfoNew->Height == dwHeightCur)
  1317.         {
  1318.             pD3DDeviceInfo->dwCurrentMode = iModeNew;
  1319.             return TRUE;
  1320.         }
  1321.         // If new mode is smaller than current mode, see if it's our best so far
  1322.         if( dwNumPixelsNew < dwNumPixelsCur )
  1323.         {
  1324.             // If current best is 32-bit, new mode needs to be bigger to be best
  1325.             if( b32BitBest && (dwNumPixelsNew < dwNumPixelsBest ) )
  1326.                 continue;
  1327.             // If new mode is bigger or equal to best, make it the best
  1328.             if( (dwNumPixelsNew > dwNumPixelsBest) || 
  1329.                 (!b32BitBest && b32BitNew) )
  1330.             {
  1331.                 dwWidthBest = dwWidthNew;
  1332.                 dwHeightBest = dwHeightNew;
  1333.                 dwNumPixelsBest = dwNumPixelsNew;
  1334.                 iModeBest = iModeNew;
  1335.                 b32BitBest = b32BitNew;
  1336.             }
  1337.         }
  1338.     }
  1339.     if( iModeBest == 0xffff )
  1340.         return FALSE; // no smaller mode found
  1341.     pD3DDeviceInfo->dwCurrentMode = iModeBest;
  1342.     return TRUE;
  1343. }
  1344. //-----------------------------------------------------------------------------
  1345. // Name: CreateWindowedRenderUnit()
  1346. // Desc: 
  1347. //-----------------------------------------------------------------------------
  1348. HRESULT CD3DScreensaver::CreateWindowedRenderUnit( RenderUnit* pRenderUnit )
  1349. {
  1350.     HRESULT hr;
  1351.     UINT iAdapter = pRenderUnit->iAdapter;
  1352.     D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  1353.     DWORD iMonitor = pD3DAdapterInfo->iMonitor;
  1354.     D3DDeviceInfo* pD3DDeviceInfo;
  1355.     D3DDEVTYPE curType;
  1356.     // Find the best device for the primary adapter.  Use HAL
  1357.     // if it's there, otherwise SW, otherwise REF.
  1358.     pD3DAdapterInfo->dwCurrentDevice = 0xffff; // unless we find something better
  1359.     curType = D3DDEVTYPE_FORCE_DWORD;
  1360.     for( DWORD iDevice = 0; iDevice < pD3DAdapterInfo->dwNumDevices; iDevice++)
  1361.     {
  1362.         pD3DDeviceInfo = &pD3DAdapterInfo->devices[iDevice];
  1363.         if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_HAL && !pD3DAdapterInfo->bDisableHW &&
  1364.             pD3DDeviceInfo->bCanDoWindowed )
  1365.         {
  1366.             pD3DAdapterInfo->dwCurrentDevice = iDevice;
  1367.             curType = D3DDEVTYPE_HAL;
  1368.             break;
  1369.         }
  1370.         else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW &&
  1371.             pD3DDeviceInfo->bCanDoWindowed )
  1372.         {
  1373.             pD3DAdapterInfo->dwCurrentDevice = iDevice;
  1374.             curType = D3DDEVTYPE_SW;
  1375.             // but keep looking
  1376.         }
  1377.         else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_REF && m_bAllowRef && curType != D3DDEVTYPE_SW )
  1378.         {
  1379.             pD3DAdapterInfo->dwCurrentDevice = iDevice;
  1380.             curType = D3DDEVTYPE_REF;
  1381.             // but keep looking
  1382.         }
  1383.     }
  1384.     if( pD3DAdapterInfo->dwCurrentDevice == 0xffff )
  1385.         return D3DAPPERR_NOHARDWAREDEVICE;
  1386.     pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  1387.     D3DWindowedModeInfo D3DWindowedModeInfo;
  1388.     D3DWindowedModeInfo.DisplayFormat = pD3DAdapterInfo->d3ddmDesktop.Format;
  1389.     D3DWindowedModeInfo.BackBufferFormat = pD3DAdapterInfo->d3ddmDesktop.Format;
  1390.     if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1391.     {
  1392.         D3DWindowedModeInfo.BackBufferFormat = D3DFMT_A8R8G8B8;
  1393.         if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1394.         {
  1395.             D3DWindowedModeInfo.BackBufferFormat = D3DFMT_X8R8G8B8;
  1396.             if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1397.             {
  1398.                 D3DWindowedModeInfo.BackBufferFormat = D3DFMT_A1R5G5B5;
  1399.                 if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1400.                 {
  1401.                     D3DWindowedModeInfo.BackBufferFormat = D3DFMT_R5G6B5;
  1402.                     if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1403.                     {
  1404.                         return E_FAIL;
  1405.                     }
  1406.                 }
  1407.             }
  1408.         }
  1409.     }
  1410.     pRenderUnit->DeviceType = pD3DDeviceInfo->DeviceType;
  1411.     pRenderUnit->dwBehavior = D3DWindowedModeInfo.dwBehavior;
  1412.     pRenderUnit->iMonitor = iMonitor;
  1413.     pRenderUnit->d3dpp.BackBufferWidth = 0;
  1414.     pRenderUnit->d3dpp.BackBufferHeight = 0;
  1415.     pRenderUnit->d3dpp.Windowed = TRUE;
  1416.     pRenderUnit->d3dpp.FullScreen_RefreshRateInHz = 0;
  1417.     pRenderUnit->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  1418.     pRenderUnit->d3dpp.BackBufferFormat = D3DWindowedModeInfo.BackBufferFormat;
  1419.     pRenderUnit->d3dpp.AutoDepthStencilFormat = D3DWindowedModeInfo.DepthStencilFormat;
  1420.     pRenderUnit->d3dpp.BackBufferCount = 1;
  1421.     pRenderUnit->d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
  1422.     pRenderUnit->d3dpp.SwapEffect = m_SwapEffectWindowed;
  1423.     pRenderUnit->d3dpp.hDeviceWindow = pD3DAdapterInfo->hWndDevice;
  1424.     pRenderUnit->d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
  1425.     pRenderUnit->d3dpp.Flags = 0;
  1426.     // Create device
  1427.     hr = m_pD3D->CreateDevice( iAdapter, pRenderUnit->DeviceType, m_hWnd,
  1428.                                pRenderUnit->dwBehavior, &pRenderUnit->d3dpp, &pRenderUnit->pd3dDevice );
  1429.     if ( FAILED(hr) )
  1430.     {
  1431.         return hr;
  1432.     }
  1433.     return S_OK;
  1434. }
  1435. //-----------------------------------------------------------------------------
  1436. // Name: UpdateDeviceStats()
  1437. // Desc: Store device description
  1438. //-----------------------------------------------------------------------------
  1439. VOID CD3DScreensaver::UpdateDeviceStats()
  1440. {
  1441.     DWORD iRenderUnit;
  1442.     RenderUnit* pRenderUnit; 
  1443.     for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  1444.     {
  1445.         pRenderUnit = &m_RenderUnits[iRenderUnit];
  1446.         if( pRenderUnit->DeviceType == D3DDEVTYPE_REF )
  1447.             lstrcpy( pRenderUnit->strDeviceStats, TEXT("REF") );
  1448.         else if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1449.             lstrcpy( pRenderUnit->strDeviceStats, TEXT("HAL") );
  1450.         else if( pRenderUnit->DeviceType == D3DDEVTYPE_SW )
  1451.             lstrcpy( pRenderUnit->strDeviceStats, TEXT("SW") );
  1452.         if( pRenderUnit->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  1453.             pRenderUnit->dwBehavior & D3DCREATE_PUREDEVICE )
  1454.         {
  1455.             if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1456.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (pure hw vp)") );
  1457.             else
  1458.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated pure hw vp)") );
  1459.         }
  1460.         else if( pRenderUnit->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  1461.         {
  1462.             if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1463.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (hw vp)") );
  1464.             else
  1465.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated hw vp)") );
  1466.         }
  1467.         else if( pRenderUnit->dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING )
  1468.         {
  1469.             if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1470.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (mixed vp)") );
  1471.             else
  1472.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated mixed vp)") );
  1473.         }
  1474.         else if( pRenderUnit->dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  1475.         {
  1476.             lstrcat( pRenderUnit->strDeviceStats, TEXT(" (sw vp)") );
  1477.         }
  1478.         if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1479.         {
  1480.             // Be sure not to overflow m_strDeviceStats when appending the adapter 
  1481.             // description, since it can be long.  Note that the adapter description
  1482.             // is initially CHAR and must be converted to TCHAR.
  1483.             lstrcat( pRenderUnit->strDeviceStats, TEXT(": ") );
  1484.             const int cchDesc = sizeof(m_Adapters[pRenderUnit->iAdapter]->d3dAdapterIdentifier.Description);
  1485.             TCHAR szDescription[cchDesc];
  1486.             DXUtil_ConvertAnsiStringToGenericCch( szDescription, 
  1487.                 m_Adapters[pRenderUnit->iAdapter]->d3dAdapterIdentifier.Description, cchDesc );
  1488.             lstrcat( pRenderUnit->strDeviceStats, szDescription );
  1489.             int maxAppend = sizeof(m_strDeviceStats) / sizeof(TCHAR) -
  1490.                 lstrlen( m_strDeviceStats ) - 1;
  1491.             _tcsncat( m_strDeviceStats, szDescription, maxAppend );
  1492.         }
  1493.     }
  1494. }
  1495. //-----------------------------------------------------------------------------
  1496. // Name: SwitchToRenderUnit()
  1497. // Desc: Updates internal variables and notifies client that we are switching
  1498. //       to a new RenderUnit / D3D device.
  1499. //-----------------------------------------------------------------------------
  1500. VOID CD3DScreensaver::SwitchToRenderUnit( UINT iRenderUnit )
  1501. {
  1502.     RenderUnit* pRenderUnit = &m_RenderUnits[iRenderUnit];
  1503.     MonitorInfo* pMonitorInfo = &m_Monitors[pRenderUnit->iMonitor];
  1504.     m_pd3dDevice = pRenderUnit->pd3dDevice;
  1505.     if( !m_bWindowed )
  1506.         m_rcRenderCurDevice = pMonitorInfo->rcScreen;
  1507.     if( m_pd3dDevice != NULL && !m_bErrorMode )
  1508.     {
  1509.         // Store render target surface desc
  1510.         LPDIRECT3DSURFACE9 pBackBuffer;
  1511.         m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  1512.         pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  1513.         pBackBuffer->Release();
  1514.     }
  1515.     lstrcpy( m_strDeviceStats, pRenderUnit->strDeviceStats );
  1516.     lstrcpy( m_strFrameStats, pRenderUnit->strFrameStats );
  1517.     // Notify the client to switch to this device
  1518.     SetDevice(iRenderUnit);
  1519. }
  1520. //-----------------------------------------------------------------------------
  1521. // Name: BuildProjectionMatrix()
  1522. // Desc: This function sets up an appropriate projection matrix to support 
  1523. //       rendering the appropriate parts of the scene to each screen.
  1524. //-----------------------------------------------------------------------------
  1525. VOID CD3DScreensaver::BuildProjectionMatrix( FLOAT fNear, FLOAT fFar, D3DXMATRIX* pMatrix )
  1526. {
  1527.     D3DXMATRIX mat;
  1528.     INT cx, cy;
  1529.     INT dx, dy;
  1530.     INT dd;
  1531.     FLOAT l,r,t,b;
  1532.     if( m_bAllScreensSame )
  1533.     {
  1534.         cx = (m_rcRenderCurDevice.right + m_rcRenderCurDevice.left) / 2;
  1535.         cy = (m_rcRenderCurDevice.bottom + m_rcRenderCurDevice.top) / 2;
  1536.         dx = m_rcRenderCurDevice.right - m_rcRenderCurDevice.left;
  1537.         dy = m_rcRenderCurDevice.bottom - m_rcRenderCurDevice.top;
  1538.     }
  1539.     else
  1540.     {
  1541.         cx = (m_rcRenderTotal.right + m_rcRenderTotal.left) / 2;
  1542.         cy = (m_rcRenderTotal.bottom + m_rcRenderTotal.top) / 2;
  1543.         dx = m_rcRenderTotal.right - m_rcRenderTotal.left;
  1544.         dy = m_rcRenderTotal.bottom - m_rcRenderTotal.top;
  1545.     }
  1546.     dd = (dx > dy ? dy : dx);
  1547.     l = FLOAT(m_rcRenderCurDevice.left - cx) / (FLOAT)(dd);
  1548.     r = FLOAT(m_rcRenderCurDevice.right - cx) / (FLOAT)(dd);
  1549.     t = FLOAT(m_rcRenderCurDevice.top - cy) / (FLOAT)(dd);
  1550.     b = FLOAT(m_rcRenderCurDevice.bottom - cy) / (FLOAT)(dd);
  1551.     l = fNear * l;
  1552.     r = fNear * r;
  1553.     t = fNear * t;
  1554.     b = fNear * b;
  1555.     D3DXMatrixPerspectiveOffCenterLH( &mat, l, r, t, b, fNear, fFar );
  1556.     *pMatrix = mat;
  1557. }
  1558. //-----------------------------------------------------------------------------
  1559. // Name: SetProjectionMatrix()
  1560. // Desc: This function sets up an appropriate projection matrix to support 
  1561. //       rendering the appropriate parts of the scene to each screen.
  1562. //-----------------------------------------------------------------------------
  1563. HRESULT CD3DScreensaver::SetProjectionMatrix( FLOAT fNear, FLOAT fFar )
  1564. {
  1565.     D3DXMATRIX mat;
  1566.     BuildProjectionMatrix( fNear, fFar, &mat );
  1567.     return m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &mat );
  1568. }
  1569. //-----------------------------------------------------------------------------
  1570. // Name: SortModesCallback()
  1571. // Desc: Callback function for sorting display modes (used by BuildDeviceList).
  1572. //-----------------------------------------------------------------------------
  1573. static int __cdecl SortModesCallback( const VOID* arg1, const VOID* arg2 )
  1574. {
  1575.     D3DDISPLAYMODE* p1 = (D3DDISPLAYMODE*)arg1;
  1576.     D3DDISPLAYMODE* p2 = (D3DDISPLAYMODE*)arg2;
  1577.     if( p1->Width  < p2->Width )    return -1;
  1578.     if( p1->Width  > p2->Width )    return +1;
  1579.     if( p1->Height < p2->Height )   return -1;
  1580.     if( p1->Height > p2->Height )   return +1;
  1581.     if( p1->Format > p2->Format )   return -1;
  1582.     if( p1->Format < p2->Format )   return +1;
  1583.     return 0;
  1584. }
  1585. //-----------------------------------------------------------------------------
  1586. // Name: BuildDeviceList()
  1587. // Desc: Builds a list of all available adapters, devices, and modes.
  1588. //-----------------------------------------------------------------------------
  1589. HRESULT CD3DScreensaver::BuildDeviceList()
  1590. {
  1591.     DWORD dwNumDeviceTypes;
  1592.     const TCHAR* strDeviceDescs[] = { TEXT("HAL"), TEXT("SW"), TEXT("REF") };
  1593.     const D3DDEVTYPE DeviceTypes[] = { D3DDEVTYPE_HAL, D3DDEVTYPE_SW, D3DDEVTYPE_REF };
  1594.     if( m_bAllowRef )
  1595.         dwNumDeviceTypes = 3;
  1596.     else
  1597.         dwNumDeviceTypes = 2;
  1598.     HMONITOR hMonitor = NULL;
  1599.     BOOL bHALExists = FALSE;
  1600.     BOOL bHALIsWindowedCompatible = FALSE;
  1601.     BOOL bHALIsDesktopCompatible = FALSE;
  1602.     BOOL bHALIsSampleCompatible = FALSE;
  1603.     // Loop through all the adapters on the system (usually, there's just one
  1604.     // unless more than one graphics card is present).
  1605.     for( UINT iAdapter = 0; iAdapter < m_pD3D->GetAdapterCount(); iAdapter++ )
  1606.     {
  1607.         // Fill in adapter info
  1608.         if( m_Adapters[m_dwNumAdapters] == NULL )
  1609.         {
  1610.             m_Adapters[m_dwNumAdapters] = new D3DAdapterInfo;
  1611.             if( m_Adapters[m_dwNumAdapters] == NULL )
  1612.                 return E_OUTOFMEMORY;
  1613.             ZeroMemory( m_Adapters[m_dwNumAdapters], sizeof(D3DAdapterInfo) );
  1614.         }
  1615.         D3DAdapterInfo* pAdapter  = m_Adapters[m_dwNumAdapters];
  1616.         m_pD3D->GetAdapterIdentifier( iAdapter, 0, &pAdapter->d3dAdapterIdentifier );
  1617.         m_pD3D->GetAdapterDisplayMode( iAdapter, &pAdapter->d3ddmDesktop );
  1618.         pAdapter->dwNumDevices    = 0;
  1619.         pAdapter->dwCurrentDevice = 0;
  1620.         pAdapter->bLeaveBlack = FALSE;
  1621.         pAdapter->iMonitor = NO_MONITOR;
  1622.         // Find the MonitorInfo that corresponds to this adapter.  If the monitor
  1623.         // is disabled, the adapter has a NULL HMONITOR and we cannot find the 
  1624.         // corresponding MonitorInfo.  (Well, if one monitor was disabled, we
  1625.         // could link the one MonitorInfo with a NULL HMONITOR to the one
  1626.         // D3DAdapterInfo with a NULL HMONITOR, but if there are more than one,
  1627.         // we can't link them, so it's safer not to ever try.)
  1628.         hMonitor = m_pD3D->GetAdapterMonitor( iAdapter );
  1629.         if( hMonitor != NULL )
  1630.         {
  1631.             for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  1632.             {
  1633.                 MonitorInfo* pMonitorInfo;
  1634.                 pMonitorInfo = &m_Monitors[iMonitor];
  1635.                 if( pMonitorInfo->hMonitor == hMonitor )
  1636.                 {
  1637.                     pAdapter->iMonitor = iMonitor;
  1638.                     pMonitorInfo->iAdapter = iAdapter;
  1639.                     break;
  1640.                 }
  1641.             }
  1642.         }
  1643.         // Enumerate all display modes on this adapter
  1644.         D3DDISPLAYMODE modes[100];
  1645.         D3DFORMAT      AllowedAdapterFormatArray[] = 
  1646.             { D3DFMT_X8R8G8B8, D3DFMT_X1R5G5B5, D3DFMT_R5G6B5 };
  1647.         DWORD AllowedAdapterFormatArraySize = sizeof(AllowedAdapterFormatArray) / sizeof(AllowedAdapterFormatArray[0]);
  1648.         D3DFORMAT AdapterFormat;
  1649.         D3DFORMAT      formats[20];
  1650.         DWORD dwNumFormats      = 0;
  1651.         DWORD dwNumModes        = 0;
  1652.         DWORD dwNumAdapterModes = 0;
  1653.         // Add the adapter's current desktop format to the list of formats
  1654.         formats[dwNumFormats++] = pAdapter->d3ddmDesktop.Format;
  1655.         for( UINT iaaf = 0; iaaf < AllowedAdapterFormatArraySize; iaaf++ )
  1656.         {
  1657.             AdapterFormat = AllowedAdapterFormatArray[iaaf];
  1658.             dwNumAdapterModes = m_pD3D->GetAdapterModeCount( iAdapter, AdapterFormat );
  1659.             for( UINT iMode = 0; iMode < dwNumAdapterModes; iMode++ )
  1660.             {
  1661.                 // Get the display mode attributes
  1662.                 D3DDISPLAYMODE DisplayMode;
  1663.                 m_pD3D->EnumAdapterModes( iAdapter, AdapterFormat, iMode, &DisplayMode );
  1664.                 // Filter out low-resolution modes
  1665.                 if( DisplayMode.Width  < 640 || DisplayMode.Height < 400 )
  1666.                     continue;
  1667.                 // Check if the mode already exists (to filter out refresh rates)
  1668.                 for( DWORD m=0L; m<dwNumModes; m++ )
  1669.                 {
  1670.                     if( ( modes[m].Width  == DisplayMode.Width  ) &&
  1671.                         ( modes[m].Height == DisplayMode.Height ) &&
  1672.                         ( modes[m].Format == DisplayMode.Format ) )
  1673.                         break;
  1674.                 }
  1675.                 // If we found a new mode, add it to the list of modes
  1676.                 if( m == dwNumModes && dwNumModes < 99 )
  1677.                 {
  1678.                     modes[dwNumModes].Width       = DisplayMode.Width;
  1679.                     modes[dwNumModes].Height      = DisplayMode.Height;
  1680.                     modes[dwNumModes].Format      = DisplayMode.Format;
  1681.                     modes[dwNumModes].RefreshRate = 0;
  1682.                     dwNumModes++;
  1683.                     // Check if the mode's format already exists
  1684.                     for( DWORD f=0; f<dwNumFormats; f++ )
  1685.                     {
  1686.                         if( DisplayMode.Format == formats[f] )
  1687.                             break;
  1688.                     }
  1689.                     // If the format is new, add it to the list
  1690.                     if( f== dwNumFormats && dwNumFormats < 19)
  1691.                         formats[dwNumFormats++] = DisplayMode.Format;
  1692.                 }
  1693.             }
  1694.         }
  1695.         // Sort the list of display modes (by format, then width, then height)
  1696.         qsort( modes, dwNumModes, sizeof(D3DDISPLAYMODE), SortModesCallback );
  1697.         // Add devices to adapter
  1698.         for( UINT iDevice = 0; iDevice < dwNumDeviceTypes; iDevice++ )
  1699.         {
  1700.             // Fill in device info
  1701.             D3DDeviceInfo* pDevice;
  1702.             pDevice                 = &pAdapter->devices[pAdapter->dwNumDevices];
  1703.             pDevice->DeviceType     = DeviceTypes[iDevice];
  1704.             m_pD3D->GetDeviceCaps( iAdapter, DeviceTypes[iDevice], &pDevice->d3dCaps );
  1705.             pDevice->strDesc        = strDeviceDescs[iDevice];
  1706.             pDevice->dwNumModes     = 0;
  1707.             pDevice->dwCurrentMode  = 0;
  1708.             pDevice->bCanDoWindowed = FALSE;
  1709.             pDevice->bWindowed      = FALSE;
  1710.             pDevice->MultiSampleType = D3DMULTISAMPLE_NONE;
  1711.             // Examine each format supported by the adapter to see if it will
  1712.             // work with this device and meets the needs of the application.
  1713.             BOOL  bFormatConfirmed[20];
  1714.             DWORD dwBehavior[20];
  1715.             D3DFORMAT fmtDepthStencil[20];
  1716.             for( DWORD f=0; f<dwNumFormats; f++ )
  1717.             {
  1718.                 bFormatConfirmed[f] = FALSE;
  1719.                 fmtDepthStencil[f] = D3DFMT_UNKNOWN;
  1720.                 // Skip formats that cannot be used as render targets on this device
  1721.                 if( FAILED( m_pD3D->CheckDeviceType( iAdapter, pDevice->DeviceType,
  1722.                                                      formats[f], formats[f], FALSE ) ) )
  1723.                     continue;
  1724.                 if( pDevice->DeviceType == D3DDEVTYPE_SW )
  1725.                 {
  1726.                     // This system has a SW device
  1727.                     pAdapter->bHasSW = TRUE;
  1728.                 }
  1729.                 if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  1730.                 {
  1731.                     // This system has a HAL device
  1732.                     bHALExists = TRUE;
  1733.                     pAdapter->bHasHAL = TRUE;
  1734.                     // HAL can run in a window for some mode
  1735.                     bHALIsWindowedCompatible = TRUE;
  1736.                     if( f == 0 )
  1737.                     {
  1738.                         // HAL can run in a window for the current desktop mode
  1739.                         bHALIsDesktopCompatible = TRUE;
  1740.                     }
  1741.                 }
  1742.                 // Confirm the device/format for HW vertex processing
  1743.                 if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
  1744.                 {
  1745.                     if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
  1746.                     {
  1747.                         dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING |
  1748.                                         D3DCREATE_PUREDEVICE;
  1749.                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1750.                                                       formats[f] ) ) )
  1751.                             bFormatConfirmed[f] = TRUE;
  1752.                     }
  1753.                     if ( FALSE == bFormatConfirmed[f] )
  1754.                     {
  1755.                         dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1756.                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1757.                                                       formats[f] ) ) )
  1758.                             bFormatConfirmed[f] = TRUE;
  1759.                     }
  1760.                     if ( FALSE == bFormatConfirmed[f] )
  1761.                     {
  1762.                         dwBehavior[f] = D3DCREATE_MIXED_VERTEXPROCESSING;
  1763.                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1764.                                                       formats[f] ) ) )
  1765.                             bFormatConfirmed[f] = TRUE;
  1766.                     }
  1767.                 }
  1768.                 // Confirm the device/format for SW vertex processing
  1769.                 if( FALSE == bFormatConfirmed[f] )
  1770.                 {
  1771.                     dwBehavior[f] = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1772.                     if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1773.                                                   formats[f] ) ) )
  1774.                         bFormatConfirmed[f] = TRUE;
  1775.                 }
  1776.                 if( bFormatConfirmed[f] && m_bMultithreaded )
  1777.                 {
  1778.                     dwBehavior[f] |= D3DCREATE_MULTITHREADED;
  1779.                 }
  1780.                 // Find a suitable depth/stencil buffer format for this device/format
  1781.                 if( bFormatConfirmed[f] && m_bUseDepthBuffer )
  1782.                 {
  1783.                     if( !FindDepthStencilFormat( iAdapter, pDevice->DeviceType,
  1784.                         formats[f], &fmtDepthStencil[f] ) )
  1785.                     {
  1786.                         bFormatConfirmed[f] = FALSE;
  1787.                     }
  1788.                 }
  1789.             }
  1790.             // Add all enumerated display modes with confirmed formats to the
  1791.             // device's list of valid modes
  1792.             for( DWORD m=0L; m<dwNumModes; m++ )
  1793.             {
  1794.                 for( DWORD f=0; f<dwNumFormats; f++ )
  1795.                 {
  1796.                     if( modes[m].Format == formats[f] )
  1797.                     {
  1798.                         if( bFormatConfirmed[f] == TRUE )
  1799.                         {
  1800.                             // Add this mode to the device's list of valid modes
  1801.                             pDevice->modes[pDevice->dwNumModes].Width      = modes[m].Width;
  1802.                             pDevice->modes[pDevice->dwNumModes].Height     = modes[m].Height;
  1803.                             pDevice->modes[pDevice->dwNumModes].Format     = modes[m].Format;
  1804.                             pDevice->modes[pDevice->dwNumModes].dwBehavior = dwBehavior[f];
  1805.                             pDevice->modes[pDevice->dwNumModes].DepthStencilFormat = fmtDepthStencil[f];
  1806.                             pDevice->dwNumModes++;
  1807.                             if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  1808.                                 bHALIsSampleCompatible = TRUE;
  1809.                         }
  1810.                     }
  1811.                 }
  1812.             }
  1813.             // Select any 640x480 mode for default (but prefer a 16-bit mode)
  1814.             for( m=0; m<pDevice->dwNumModes; m++ )
  1815.             {
  1816.                 if( pDevice->modes[m].Width==640 && pDevice->modes[m].Height==480 )
  1817.                 {
  1818.                     pDevice->dwCurrentMode = m;
  1819.                     if( pDevice->modes[m].Format == D3DFMT_R5G6B5 ||
  1820.                         pDevice->modes[m].Format == D3DFMT_X1R5G5B5 ||
  1821.                         pDevice->modes[m].Format == D3DFMT_A1R5G5B5 )
  1822.                     {
  1823.                         break;
  1824.                     }
  1825.                 }
  1826.             }
  1827.             // Check if the device is compatible with the desktop display mode
  1828.             // (which was added initially as formats[0])
  1829.             if( bFormatConfirmed[0] )
  1830.             {
  1831.                 pDevice->bCanDoWindowed = TRUE;
  1832.                 pDevice->bWindowed      = TRUE;
  1833.             }
  1834.             // If valid modes were found, keep this device
  1835.             if( pDevice->dwNumModes > 0 )
  1836.             {
  1837.                 pAdapter->dwNumDevices++;
  1838.                 if( pDevice->DeviceType == D3DDEVTYPE_SW )
  1839.                     pAdapter->bHasAppCompatSW = TRUE;
  1840.                 else if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  1841.                     pAdapter->bHasAppCompatHAL = TRUE;
  1842.             }
  1843.         }
  1844.         // If valid devices were found, keep this adapter
  1845. // Count adapters even if no devices, so we can throw up blank windows on them
  1846. //        if( pAdapter->dwNumDevices > 0 )
  1847.             m_dwNumAdapters++;
  1848.     }
  1849. /*
  1850.     // Return an error if no compatible devices were found
  1851.     if( 0L == m_dwNumAdapters )
  1852.         return D3DAPPERR_NOCOMPATIBLEDEVICES;
  1853.     // Pick a default device that can render into a window
  1854.     // (This code assumes that the HAL device comes before the REF
  1855.     // device in the device array).
  1856.     for( DWORD a=0; a<m_dwNumAdapters; a++ )
  1857.     {
  1858.         for( DWORD d=0; d < m_Adapters[a]->dwNumDevices; d++ )
  1859.         {
  1860.             if( m_Adapters[a]->devices[d].bWindowed )
  1861.             {
  1862.                 m_Adapters[a]->dwCurrentDevice = d;
  1863.                 m_dwAdapter = a;
  1864.                 m_bWindowed = TRUE;
  1865.                 // Display a warning message
  1866.                 if( m_Adapters[a]->devices[d].DeviceType == D3DDEVTYPE_REF )
  1867.                 {
  1868.                     if( !bHALExists )
  1869.                         DisplayErrorMsg( D3DAPPERR_NOHARDWAREDEVICE, MSGWARN_SWITCHEDTOREF );
  1870.                     else if( !bHALIsSampleCompatible )
  1871.                         DisplayErrorMsg( D3DAPPERR_HALNOTCOMPATIBLE, MSGWARN_SWITCHEDTOREF );
  1872.                     else if( !bHALIsWindowedCompatible )
  1873.                         DisplayErrorMsg( D3DAPPERR_NOWINDOWEDHAL, MSGWARN_SWITCHEDTOREF );
  1874.                     else if( !bHALIsDesktopCompatible )
  1875.                         DisplayErrorMsg( D3DAPPERR_NODESKTOPHAL, MSGWARN_SWITCHEDTOREF );
  1876.                     else // HAL is desktop compatible, but not sample compatible
  1877.                         DisplayErrorMsg( D3DAPPERR_NOHALTHISMODE, MSGWARN_SWITCHEDTOREF );
  1878.                 }
  1879.                 return S_OK;
  1880.             }
  1881.         }
  1882.     }
  1883.     return D3DAPPERR_NOWINDOWABLEDEVICES;
  1884. */
  1885.     return S_OK;
  1886. }
  1887. //-----------------------------------------------------------------------------
  1888. // Name: CheckWindowedFormat()
  1889. // Desc: 
  1890. //-----------------------------------------------------------------------------
  1891. HRESULT CD3DScreensaver::CheckWindowedFormat( UINT iAdapter, D3DWindowedModeInfo* pD3DWindowedModeInfo )
  1892. {
  1893.     HRESULT hr;
  1894.     D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  1895.     D3DDeviceInfo* pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  1896.     BOOL bFormatConfirmed = FALSE;
  1897.     if( FAILED( hr = m_pD3D->CheckDeviceType( iAdapter, pD3DDeviceInfo->DeviceType,
  1898.         pD3DAdapterInfo->d3ddmDesktop.Format, pD3DWindowedModeInfo->BackBufferFormat, TRUE ) ) )
  1899.     {
  1900.         return hr;
  1901.     }
  1902.     // Confirm the device/format for HW vertex processing
  1903.     if( pD3DDeviceInfo->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
  1904.     {
  1905.         if( pD3DDeviceInfo->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
  1906.         {
  1907.             pD3DWindowedModeInfo->dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING |
  1908.                             D3DCREATE_PUREDEVICE;
  1909.             if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  1910.                                           pD3DWindowedModeInfo->BackBufferFormat ) ) )
  1911.                 bFormatConfirmed = TRUE;
  1912.         }
  1913.         if ( !bFormatConfirmed )
  1914.         {
  1915.             pD3DWindowedModeInfo->dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1916.             if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  1917.                                           pD3DWindowedModeInfo->BackBufferFormat ) ) )
  1918.                 bFormatConfirmed = TRUE;
  1919.         }
  1920.         if ( !bFormatConfirmed )
  1921.         {
  1922.             pD3DWindowedModeInfo->dwBehavior = D3DCREATE_MIXED_VERTEXPROCESSING;
  1923.             if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  1924.                                           pD3DWindowedModeInfo->BackBufferFormat ) ) )
  1925.                 bFormatConfirmed = TRUE;
  1926.         }
  1927.     }
  1928.     // Confirm the device/format for SW vertex processing
  1929.     if( !bFormatConfirmed )
  1930.     {
  1931.         pD3DWindowedModeInfo->dwBehavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1932.         if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  1933.                                       pD3DWindowedModeInfo->BackBufferFormat ) ) )
  1934.             bFormatConfirmed = TRUE;
  1935.     }
  1936.     if( bFormatConfirmed && m_bMultithreaded )
  1937.     {
  1938.         pD3DWindowedModeInfo->dwBehavior |= D3DCREATE_MULTITHREADED;
  1939.     }
  1940.     // Find a suitable depth/stencil buffer format for this device/format
  1941.     if( bFormatConfirmed && m_bUseDepthBuffer )
  1942.     {
  1943.         if( !FindDepthStencilFormat( iAdapter, pD3DDeviceInfo->DeviceType,
  1944.             pD3DWindowedModeInfo->BackBufferFormat, &pD3DWindowedModeInfo->DepthStencilFormat ) )
  1945.         {
  1946.             bFormatConfirmed = FALSE;
  1947.         }
  1948.     }
  1949.     if( !bFormatConfirmed )
  1950.         return E_FAIL;
  1951.     return S_OK;
  1952. }
  1953. //-----------------------------------------------------------------------------
  1954. // Name: FindDepthStencilFormat()
  1955. // Desc: Finds a depth/stencil format for the given device that is compatible
  1956. //       with the render target format and meets the needs of the app.
  1957. //-----------------------------------------------------------------------------
  1958. BOOL CD3DScreensaver::FindDepthStencilFormat( UINT iAdapter, D3DDEVTYPE DeviceType,
  1959.     D3DFORMAT TargetFormat, D3DFORMAT* pDepthStencilFormat )
  1960. {
  1961.     if( m_dwMinDepthBits <= 16 && m_dwMinStencilBits == 0 )
  1962.     {
  1963.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  1964.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
  1965.         {
  1966.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  1967.                 TargetFormat, TargetFormat, D3DFMT_D16 ) ) )
  1968.             {
  1969.                 *pDepthStencilFormat = D3DFMT_D16;
  1970.                 return TRUE;
  1971.             }
  1972.         }
  1973.     }
  1974.     if( m_dwMinDepthBits <= 15 && m_dwMinStencilBits <= 1 )
  1975.     {
  1976.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  1977.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 ) ) )
  1978.         {
  1979.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  1980.                 TargetFormat, TargetFormat, D3DFMT_D15S1 ) ) )
  1981.             {
  1982.                 *pDepthStencilFormat = D3DFMT_D15S1;
  1983.                 return TRUE;
  1984.             }
  1985.         }
  1986.     }
  1987.     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits == 0 )
  1988.     {
  1989.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  1990.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 ) ) )
  1991.         {
  1992.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  1993.                 TargetFormat, TargetFormat, D3DFMT_D24X8 ) ) )
  1994.             {
  1995.                 *pDepthStencilFormat = D3DFMT_D24X8;
  1996.                 return TRUE;
  1997.             }
  1998.         }
  1999.     }
  2000.     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 8 )
  2001.     {
  2002.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2003.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) )
  2004.         {
  2005.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2006.                 TargetFormat, TargetFormat, D3DFMT_D24S8 ) ) )
  2007.             {
  2008.                 *pDepthStencilFormat = D3DFMT_D24S8;
  2009.                 return TRUE;
  2010.             }
  2011.         }
  2012.     }
  2013.     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 4 )
  2014.     {
  2015.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2016.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 ) ) )
  2017.         {
  2018.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2019.                 TargetFormat, TargetFormat, D3DFMT_D24X4S4 ) ) )
  2020.             {
  2021.                 *pDepthStencilFormat = D3DFMT_D24X4S4;
  2022.                 return TRUE;
  2023.             }
  2024.         }
  2025.     }
  2026.     if( m_dwMinDepthBits <= 32 && m_dwMinStencilBits == 0 )
  2027.     {
  2028.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2029.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D32 ) ) )
  2030.         {
  2031.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2032.                 TargetFormat, TargetFormat, D3DFMT_D32 ) ) )
  2033.             {
  2034.                 *pDepthStencilFormat = D3DFMT_D32;
  2035.                 return TRUE;
  2036.             }
  2037.         }
  2038.     }
  2039.     return FALSE;
  2040. }
  2041. //-----------------------------------------------------------------------------
  2042. // Name: Cleanup3DEnvironment()
  2043. // Desc: 
  2044. //-----------------------------------------------------------------------------
  2045. VOID CD3DScreensaver::Cleanup3DEnvironment()
  2046. {
  2047.     RenderUnit* pRenderUnit;
  2048.     for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2049.     {
  2050.         pRenderUnit = &m_RenderUnits[iRenderUnit];
  2051.         SwitchToRenderUnit( iRenderUnit );
  2052.         if( pRenderUnit->bDeviceObjectsRestored )
  2053.         {
  2054.             InvalidateDeviceObjects();
  2055.             pRenderUnit->bDeviceObjectsRestored = FALSE;
  2056.         }
  2057.         if( pRenderUnit->bDeviceObjectsInited )
  2058.         {
  2059.             DeleteDeviceObjects();
  2060.             pRenderUnit->bDeviceObjectsInited = FALSE;
  2061.         }
  2062.         SAFE_RELEASE(m_pd3dDevice);
  2063.     }
  2064.     m_dwNumRenderUnits = 0;
  2065.     SAFE_RELEASE(m_pD3D);
  2066. }
  2067. //-----------------------------------------------------------------------------
  2068. // Name: Render3DEnvironment()
  2069. // Desc: 
  2070. //-----------------------------------------------------------------------------
  2071. HRESULT CD3DScreensaver::Render3DEnvironment()
  2072. {
  2073.     HRESULT hr;
  2074.     RenderUnit* pRenderUnit;
  2075.     D3DAdapterInfo* pAdapterInfo;
  2076.     m_fTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  2077.     m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  2078.     // Tell client to update the world
  2079.     FrameMove();
  2080.     UpdateFrameStats();
  2081.     for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2082.     {
  2083.         pRenderUnit = &m_RenderUnits[iRenderUnit];
  2084.         pAdapterInfo = m_Adapters[pRenderUnit->iAdapter];
  2085.         SwitchToRenderUnit( iRenderUnit );
  2086.         if( m_pd3dDevice == NULL )
  2087.             continue;
  2088.         // Test the cooperative level to see if it's okay to render
  2089.         if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
  2090.         {
  2091.             // If the device was lost, do not render until we get it back
  2092.             if( D3DERR_DEVICELOST == hr )
  2093.                 return S_OK;
  2094.             // Check if the device needs to be reset.
  2095.             if( D3DERR_DEVICENOTRESET == hr )
  2096.             {
  2097.                 // If we are windowed, read the desktop mode and use the same format for
  2098.                 // the back buffer
  2099.                 if( m_bWindowed )
  2100.                 {
  2101.                     m_pD3D->GetAdapterDisplayMode( pRenderUnit->iAdapter, &pAdapterInfo->d3ddmDesktop );
  2102. //                    m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
  2103.                 }
  2104.                 if( pRenderUnit->bDeviceObjectsRestored )
  2105.                 {
  2106.                     InvalidateDeviceObjects();
  2107.                     pRenderUnit->bDeviceObjectsRestored = FALSE;
  2108.                 }
  2109.                 if( FAILED( hr = m_pd3dDevice->Reset( &pRenderUnit->d3dpp ) ) )
  2110.                 {
  2111.                     m_bErrorMode = TRUE;
  2112.                 }
  2113.                 else
  2114.                 {
  2115.                     if( FAILED( hr = RestoreDeviceObjects() ) )
  2116.                     {
  2117.                         m_bErrorMode = TRUE;
  2118.                     }
  2119.                     else
  2120.                     {
  2121.                         pRenderUnit->bDeviceObjectsRestored = TRUE;
  2122.                     }
  2123.                 }
  2124.             }
  2125.         }
  2126.         if( !m_bErrorMode )
  2127.         {
  2128.             // Tell client to render using the current device
  2129.             Render();
  2130.         }
  2131.     }
  2132.     if( !m_bErrorMode )
  2133.     {
  2134.         // Call Present() in a separate loop once all rendering is done
  2135.         // so multiple monitors are as closely synced visually as possible
  2136.         for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2137.         {
  2138.             pRenderUnit = &m_RenderUnits[iRenderUnit];
  2139.             SwitchToRenderUnit( iRenderUnit );
  2140.             // Present the results of the rendering to the screen
  2141.             m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  2142.         }
  2143.     }
  2144.     return S_OK;
  2145. }
  2146. //-----------------------------------------------------------------------------
  2147. // Name: UpdateErrorBox()
  2148. // Desc: Update the box that shows the error message
  2149. //-----------------------------------------------------------------------------
  2150. VOID CD3DScreensaver::UpdateErrorBox()
  2151. {
  2152.     MonitorInfo* pMonitorInfo;
  2153.     HWND hwnd;
  2154.     RECT rcBounds;
  2155.     static DWORD dwTimeLast = 0;
  2156.     DWORD dwTimeNow;
  2157.     FLOAT fTimeDelta;
  2158.     // Make sure all the RenderUnits / D3D devices have been torn down
  2159.     // so the error box is visible
  2160.     if( m_bErrorMode && m_dwNumRenderUnits > 0 )
  2161.     {
  2162.         Cleanup3DEnvironment();
  2163.     }
  2164.     // Update timing to determine how much to move error box
  2165.     if( dwTimeLast == 0 )
  2166.         dwTimeLast = timeGetTime();
  2167.     dwTimeNow = timeGetTime();
  2168.     fTimeDelta = (FLOAT)(dwTimeNow - dwTimeLast) / 1000.0f;
  2169.     dwTimeLast = dwTimeNow;
  2170.     // Load error string if necessary
  2171.     if( m_szError[0] == TEXT('') )
  2172.     {
  2173.         GetTextForError( m_hrError, m_szError, sizeof(m_szError) / sizeof(TCHAR) );
  2174.     }
  2175.     for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2176.     {
  2177.         pMonitorInfo = &m_Monitors[iMonitor];
  2178.         hwnd = pMonitorInfo->hWnd;
  2179.         if( hwnd == NULL )
  2180.             continue;
  2181.         if( m_SaverMode == sm_full )
  2182.         {
  2183.             rcBounds = pMonitorInfo->rcScreen;
  2184.             ScreenToClient( hwnd, (POINT*)&rcBounds.left );
  2185.             ScreenToClient( hwnd, (POINT*)&rcBounds.right );
  2186.         }
  2187.         else
  2188.         {
  2189.             rcBounds = m_rcRenderTotal;
  2190.         }
  2191.         if( pMonitorInfo->widthError == 0 )
  2192.         {
  2193.             if( m_SaverMode == sm_preview )                
  2194.             {
  2195.                 pMonitorInfo->widthError = (float) (rcBounds.right - rcBounds.left);
  2196.                 pMonitorInfo->heightError = (float) (rcBounds.bottom - rcBounds.top);
  2197.                 pMonitorInfo->xError = 0.0f;
  2198.                 pMonitorInfo->yError = 0.0f;
  2199.                 pMonitorInfo->xVelError = 0.0f;
  2200.                 pMonitorInfo->yVelError = 0.0f;
  2201.                 InvalidateRect( hwnd, NULL, FALSE );    // Invalidate the hwnd so it gets drawn
  2202.                 UpdateWindow( hwnd );
  2203.             }
  2204.             else
  2205.             {
  2206.                 pMonitorInfo->widthError = 300;
  2207.                 pMonitorInfo->heightError = 150;
  2208.                 pMonitorInfo->xError = (rcBounds.right + rcBounds.left - pMonitorInfo->widthError) / 2.0f;
  2209.                 pMonitorInfo->yError = (rcBounds.bottom + rcBounds.top - pMonitorInfo->heightError) / 2.0f;
  2210.                 pMonitorInfo->xVelError = (rcBounds.right - rcBounds.left) / 10.0f;
  2211.                 pMonitorInfo->yVelError = (rcBounds.bottom - rcBounds.top) / 20.0f;
  2212.             }
  2213.         }
  2214.         else
  2215.         {
  2216.             if( m_SaverMode != sm_preview )
  2217.             {
  2218.                 RECT rcOld;
  2219.                 RECT rcNew;
  2220.                 SetRect( &rcOld, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
  2221.                     (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
  2222.                     (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
  2223.                 // Update rect velocity
  2224.                 if( (pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta + 
  2225.                     pMonitorInfo->widthError > rcBounds.right && pMonitorInfo->xVelError > 0.0f) ||
  2226.                     (pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta < 
  2227.                     rcBounds.left && pMonitorInfo->xVelError < 0.0f) )
  2228.                 {
  2229.                     pMonitorInfo->xVelError = -pMonitorInfo->xVelError;
  2230.                 }
  2231.                 if( (pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta + 
  2232.                     pMonitorInfo->heightError > rcBounds.bottom && pMonitorInfo->yVelError > 0.0f) ||
  2233.                     (pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta < 
  2234.                     rcBounds.top && pMonitorInfo->yVelError < 0.0f) )
  2235.                 {
  2236.                     pMonitorInfo->yVelError = -pMonitorInfo->yVelError;
  2237.                 }
  2238.                 // Update rect position
  2239.                 pMonitorInfo->xError += pMonitorInfo->xVelError * fTimeDelta;
  2240.                 pMonitorInfo->yError += pMonitorInfo->yVelError * fTimeDelta;
  2241.             
  2242.                 SetRect( &rcNew, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
  2243.                     (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
  2244.                     (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
  2245.                 if( rcOld.left != rcNew.left || rcOld.top != rcNew.top )
  2246.                 {
  2247.                     InvalidateRect( hwnd, &rcOld, FALSE );    // Invalidate old rect so it gets erased
  2248.                     InvalidateRect( hwnd, &rcNew, FALSE );    // Invalidate new rect so it gets drawn
  2249.                     UpdateWindow( hwnd );
  2250.                 }
  2251.             }
  2252.         }
  2253.     }
  2254. }
  2255. //-----------------------------------------------------------------------------
  2256. // Name: GetTextForError()
  2257. // Desc: Translate an HRESULT error code into a string that can be displayed
  2258. //       to explain the error.  A class derived from CD3DScreensaver can 
  2259. //       provide its own version of this function that provides app-specific
  2260. //       error translation instead of or in addition to calling this function.
  2261. //       This function returns TRUE if a specific error was translated, or
  2262. //       FALSE if no specific translation for the HRESULT was found (though
  2263. //       it still puts a generic string into pszError).
  2264. //-----------------------------------------------------------------------------
  2265. BOOL CD3DScreensaver::GetTextForError( HRESULT hr, TCHAR* pszError, 
  2266.                                        DWORD dwNumChars )
  2267. {
  2268.     const DWORD dwErrorMap[][2] = 
  2269.     {
  2270.     //  HRESULT, stringID
  2271.         (DWORD)E_FAIL, IDS_ERR_GENERIC,
  2272.         D3DAPPERR_NODIRECT3D, IDS_ERR_NODIRECT3D,
  2273.         D3DAPPERR_NOWINDOWEDHAL, IDS_ERR_NOWINDOWEDHAL,
  2274.         D3DAPPERR_CREATEDEVICEFAILED, IDS_ERR_CREATEDEVICEFAILED,
  2275.         D3DAPPERR_NOCOMPATIBLEDEVICES, IDS_ERR_NOCOMPATIBLEDEVICES,
  2276.         D3DAPPERR_NOHARDWAREDEVICE, IDS_ERR_NOHARDWAREDEVICE,
  2277.         D3DAPPERR_HALNOTCOMPATIBLE, IDS_ERR_HALNOTCOMPATIBLE,
  2278.         D3DAPPERR_NOHALTHISMODE, IDS_ERR_NOHALTHISMODE,   
  2279.         D3DAPPERR_MEDIANOTFOUND, IDS_ERR_MEDIANOTFOUND,   
  2280.         D3DAPPERR_RESIZEFAILED, IDS_ERR_RESIZEFAILED,    
  2281.         (DWORD)E_OUTOFMEMORY, IDS_ERR_OUTOFMEMORY,     
  2282.         (DWORD)D3DERR_OUTOFVIDEOMEMORY, IDS_ERR_OUTOFVIDEOMEMORY,
  2283.         D3DAPPERR_NOPREVIEW, IDS_ERR_NOPREVIEW
  2284.     };
  2285.     const DWORD dwErrorMapSize = sizeof(dwErrorMap) / sizeof(DWORD[2]);
  2286.     DWORD iError;
  2287.     DWORD resid = 0;
  2288.     for( iError = 0; iError < dwErrorMapSize; iError++ )
  2289.     {
  2290.         if( hr == (HRESULT)dwErrorMap[iError][0] )
  2291.         {
  2292.             resid = dwErrorMap[iError][1];
  2293.         }
  2294.     }
  2295.     if( resid == 0 )
  2296.     {
  2297.         resid = IDS_ERR_GENERIC;
  2298.     }
  2299.     LoadString( NULL, resid, pszError, dwNumChars );
  2300.     if( resid == IDS_ERR_GENERIC )
  2301.         return FALSE;
  2302.     else
  2303.         return TRUE;
  2304. }
  2305. //-----------------------------------------------------------------------------
  2306. // Name: UpdateFrameStats()
  2307. // Desc: Keep track of the frame count
  2308. //-----------------------------------------------------------------------------
  2309. VOID CD3DScreensaver::UpdateFrameStats()
  2310. {
  2311.     UINT iRenderUnit;
  2312.     RenderUnit* pRenderUnit;
  2313.     UINT iAdapter;
  2314.     static FLOAT fLastTime = 0.0f;
  2315.     static DWORD dwFrames  = 0L;
  2316.     FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
  2317.     ++dwFrames;
  2318.     // Update the scene stats once per second
  2319.     if( fTime - fLastTime > 1.0f )
  2320.     {
  2321.         m_fFPS    = dwFrames / (fTime - fLastTime);
  2322.         fLastTime = fTime;
  2323.         dwFrames  = 0L;
  2324.         for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2325.         {
  2326.             pRenderUnit = &m_RenderUnits[iRenderUnit];
  2327.             iAdapter = pRenderUnit->iAdapter;
  2328.             // Get adapter's current mode so we can report
  2329.             // bit depth (back buffer depth may be unknown)
  2330.             D3DDISPLAYMODE mode;
  2331.             m_pD3D->GetAdapterDisplayMode( iAdapter, &mode );
  2332.             _stprintf( pRenderUnit->strFrameStats, TEXT("%.02f fps (%dx%dx%d)"), m_fFPS,
  2333.                        mode.Width, mode.Height,
  2334.                        mode.Format==D3DFMT_X8R8G8B8?32:16 );
  2335.             if( m_bUseDepthBuffer )
  2336.             {
  2337.                 D3DAdapterInfo* pAdapterInfo = m_Adapters[iAdapter];
  2338.                 D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
  2339.                 D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
  2340.                 switch( pModeInfo->DepthStencilFormat )
  2341.                 {
  2342.                 case D3DFMT_D16:
  2343.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D16)") );
  2344.                     break;
  2345.                 case D3DFMT_D15S1:
  2346.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D15S1)") );
  2347.                     break;
  2348.                 case D3DFMT_D24X8:
  2349.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24X8)") );
  2350.                     break;
  2351.                 case D3DFMT_D24S8:
  2352.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24S8)") );
  2353.                     break;
  2354.                 case D3DFMT_D24X4S4:
  2355.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24X4S4)") );
  2356.                     break;
  2357.                 case D3DFMT_D32:
  2358.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D32)") );
  2359.                     break;
  2360.                 }
  2361.             }
  2362.         }
  2363.     }
  2364. }
  2365. //-----------------------------------------------------------------------------
  2366. // Name: DoPaint()
  2367. // Desc: 
  2368. //-----------------------------------------------------------------------------
  2369. VOID CD3DScreensaver::DoPaint(HWND hwnd, HDC hdc)
  2370. {
  2371.     HMONITOR hMonitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST );
  2372.     MonitorInfo* pMonitorInfo = NULL;
  2373.     for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++)
  2374.     {
  2375.         pMonitorInfo = &m_Monitors[iMonitor];
  2376.         if( pMonitorInfo->hMonitor == hMonitor )
  2377.             break;
  2378.     }
  2379.     if( iMonitor == m_dwNumMonitors )
  2380.         return;
  2381.     // Draw the error message box
  2382.     RECT rc;
  2383.     SetRect( &rc, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
  2384.         (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
  2385.         (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
  2386.     FillRect(hdc, &rc, (HBRUSH)(COLOR_WINDOW+1));
  2387.     FrameRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
  2388.     RECT rc2;
  2389.     int height;
  2390.     rc2 = rc;
  2391.     height = DrawText(hdc, m_szError, -1, &rc, DT_WORDBREAK | DT_CENTER | DT_CALCRECT );
  2392.     rc = rc2;
  2393.     rc2.top = (rc.bottom + rc.top - height) / 2;
  2394.     DrawText(hdc, m_szError, -1, &rc2, DT_WORDBREAK | DT_CENTER );
  2395.     // Erase everywhere except the error message box
  2396.     ExcludeClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom );
  2397.     rc = pMonitorInfo->rcScreen;
  2398.     ScreenToClient( hwnd, (POINT*)&rc.left );
  2399.     ScreenToClient( hwnd, (POINT*)&rc.right );
  2400.     FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH) );
  2401. }
  2402. //-----------------------------------------------------------------------------
  2403. // Name: ChangePassword()
  2404. // Desc:
  2405. //-----------------------------------------------------------------------------
  2406. VOID CD3DScreensaver::ChangePassword()
  2407. {
  2408.     // Load the password change DLL
  2409.     HINSTANCE mpr = LoadLibrary( TEXT("MPR.DLL") );
  2410.     if ( mpr != NULL )
  2411.     {
  2412.         // Grab the password change function from it
  2413.         typedef DWORD (PASCAL *PWCHGPROC)( LPCSTR, HWND, DWORD, LPVOID );
  2414.         PWCHGPROC pwd = (PWCHGPROC)GetProcAddress( mpr, "PwdChangePasswordA" );
  2415.         // Do the password change
  2416.         if ( pwd != NULL )
  2417.             pwd( "SCRSAVE", m_hWndParent, 0, NULL );
  2418.         // Free the library
  2419.         FreeLibrary( mpr );
  2420.     }
  2421. }
  2422. //-----------------------------------------------------------------------------
  2423. // Name: DisplayErrorMsg()
  2424. // Desc: Displays error messages in a message box
  2425. //-----------------------------------------------------------------------------
  2426. HRESULT CD3DScreensaver::DisplayErrorMsg( HRESULT hr, DWORD dwType )
  2427. {
  2428.     TCHAR strMsg[512];
  2429.     GetTextForError( hr, strMsg, 512 );
  2430.     MessageBox( m_hWnd, strMsg, m_strWindowTitle, MB_ICONERROR | MB_OK );
  2431.     return hr;
  2432. }
  2433. //-----------------------------------------------------------------------------
  2434. // Name: ReadScreenSettings()
  2435. // Desc: Read the registry settings that affect how the screens are set up and
  2436. //       used.
  2437. //-----------------------------------------------------------------------------
  2438. VOID CD3DScreensaver::ReadScreenSettings( HKEY hkeyParent )
  2439. {
  2440.     TCHAR strKey[100];
  2441.     DWORD iMonitor;
  2442.     MonitorInfo* pMonitorInfo;
  2443.     DWORD iAdapter;
  2444.     D3DAdapterInfo* pD3DAdapterInfo;
  2445.     HKEY hkey;
  2446.     DWORD dwType = REG_DWORD;
  2447.     DWORD dwLength;
  2448.     GUID guidAdapterID;
  2449.     GUID guidZero;
  2450.     ZeroMemory( &guidAdapterID, sizeof(GUID) );
  2451.     ZeroMemory( &guidZero, sizeof(GUID) );
  2452.     dwLength = sizeof(DWORD);
  2453.     RegQueryValueEx( hkeyParent, TEXT("AllScreensSame"), NULL, &dwType, 
  2454.         (BYTE*)&m_bAllScreensSame, &dwLength);
  2455.     for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2456.     {
  2457.         pMonitorInfo = &m_Monitors[iMonitor];
  2458.         iAdapter = pMonitorInfo->iAdapter;
  2459.         if( iAdapter == NO_ADAPTER )
  2460.             continue; 
  2461.         pD3DAdapterInfo = m_Adapters[iAdapter];
  2462.         wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
  2463.         if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey, 
  2464.             0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  2465.         {
  2466.             dwLength = sizeof(GUID);
  2467.             RegQueryValueEx( hkey, TEXT("Adapter ID"), NULL, &dwType, 
  2468.                 (BYTE*)&guidAdapterID, &dwLength);
  2469.             dwLength = sizeof(DWORD);
  2470.             RegQueryValueEx( hkey, TEXT("Leave Black"), NULL, &dwType, 
  2471.                 (BYTE*)&pD3DAdapterInfo->bLeaveBlack, &dwLength);
  2472.             if( guidAdapterID == pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier ||
  2473.                 guidAdapterID == guidZero )
  2474.             {
  2475.                 dwLength = sizeof(DWORD);
  2476.                 RegQueryValueEx( hkey, TEXT("Disable Hardware"), NULL, &dwType, 
  2477.                     (BYTE*)&pD3DAdapterInfo->bDisableHW, &dwLength);
  2478.                 dwLength = sizeof(DWORD);
  2479.                 RegQueryValueEx( hkey, TEXT("Width"), NULL, &dwType, 
  2480.                     (BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, &dwLength);
  2481.                 dwLength = sizeof(DWORD);
  2482.                 RegQueryValueEx( hkey, TEXT("Height"), NULL, &dwType, 
  2483.                     (BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, &dwLength);
  2484.                 dwLength = sizeof(DWORD);
  2485.                 RegQueryValueEx( hkey, TEXT("Format"), NULL, &dwType, 
  2486.                     (BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, &dwLength);
  2487.             }
  2488.             RegCloseKey( hkey);
  2489.         }
  2490.     }
  2491. }
  2492. //-----------------------------------------------------------------------------
  2493. // Name: WriteScreenSettings()
  2494. // Desc: Write the registry settings that affect how the screens are set up and
  2495. //       used.
  2496. //-----------------------------------------------------------------------------
  2497. VOID CD3DScreensaver::WriteScreenSettings( HKEY hkeyParent )
  2498. {
  2499.     TCHAR strKey[100];
  2500.     DWORD iMonitor;
  2501.     MonitorInfo* pMonitorInfo;
  2502.     DWORD iAdapter;
  2503.     D3DAdapterInfo* pD3DAdapterInfo;
  2504.     HKEY hkey;
  2505.     RegSetValueEx( hkeyParent, TEXT("AllScreensSame"), NULL, REG_DWORD, 
  2506.         (BYTE*)&m_bAllScreensSame, sizeof(DWORD) );
  2507.     for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2508.     {
  2509.         pMonitorInfo = &m_Monitors[iMonitor];
  2510.         iAdapter = pMonitorInfo->iAdapter;
  2511.         if( iAdapter == NO_ADAPTER )
  2512.             continue; 
  2513.         pD3DAdapterInfo = m_Adapters[iAdapter];
  2514.         wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
  2515.         if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey, 
  2516.             0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  2517.         {
  2518.             RegSetValueEx( hkey, TEXT("Leave Black"), NULL, REG_DWORD, 
  2519.                 (BYTE*)&pD3DAdapterInfo->bLeaveBlack, sizeof(DWORD) );
  2520.             RegSetValueEx( hkey, TEXT("Disable Hardware"), NULL, REG_DWORD, 
  2521.                 (BYTE*)&pD3DAdapterInfo->bDisableHW, sizeof(DWORD) );
  2522.             RegSetValueEx( hkey, TEXT("Width"), NULL, REG_DWORD, 
  2523.                 (BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, sizeof(DWORD) );
  2524.             RegSetValueEx( hkey, TEXT("Height"), NULL, REG_DWORD, 
  2525.                 (BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, sizeof(DWORD) );
  2526.             RegSetValueEx( hkey, TEXT("Format"), NULL, REG_DWORD, 
  2527.                 (BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, sizeof(DWORD) );
  2528.             RegSetValueEx( hkey, TEXT("Adapter ID"), NULL, REG_BINARY, 
  2529.                 (BYTE*)&pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier, sizeof(GUID) );
  2530.             RegCloseKey( hkey);
  2531.         }
  2532.     }
  2533. }
  2534. //-----------------------------------------------------------------------------
  2535. // Name: DoScreenSettingsDialog()
  2536. // Desc: 
  2537. //-----------------------------------------------------------------------------
  2538. VOID CD3DScreensaver::DoScreenSettingsDialog( HWND hwndParent )
  2539. {
  2540.     LPCTSTR pstrTemplate;
  2541.     if( m_dwNumAdapters > 1 && !m_bOneScreenOnly )
  2542.         pstrTemplate = MAKEINTRESOURCE( IDD_MULTIMONITORSETTINGS );
  2543.     else
  2544.         pstrTemplate = MAKEINTRESOURCE( IDD_SINGLEMONITORSETTINGS );
  2545.     DialogBox(m_hInstance, pstrTemplate, hwndParent, ScreenSettingsDlgProcStub );
  2546. }
  2547. //-----------------------------------------------------------------------------
  2548. // Name: ScreenSettingsDlgProcStub()
  2549. // Desc:
  2550. //-----------------------------------------------------------------------------
  2551. INT_PTR CALLBACK CD3DScreensaver::ScreenSettingsDlgProcStub( HWND hWnd, UINT uMsg,
  2552.                                                  WPARAM wParam, LPARAM lParam )
  2553. {
  2554.     return s_pD3DScreensaver->ScreenSettingsDlgProc( hWnd, uMsg, wParam, lParam );
  2555. }
  2556. // We need to store a copy of the original screen settings so that the user
  2557. // can modify those settings in the dialog, then hit Cancel and have the
  2558. // original settings restored.
  2559. static D3DAdapterInfo* s_AdaptersSave[9];
  2560. static BOOL s_bAllScreensSameSave;
  2561. //-----------------------------------------------------------------------------
  2562. // Name: ScreenSettingsDlgProc()
  2563. // Desc:
  2564. //-----------------------------------------------------------------------------
  2565. INT_PTR CD3DScreensaver::ScreenSettingsDlgProc( HWND hWnd, UINT uMsg, 
  2566.                                                 WPARAM wParam, LPARAM lParam )
  2567. {
  2568.     HWND hwndTabs = GetDlgItem(hWnd, IDC_MONITORSTAB);
  2569.     HWND hwndModeList = GetDlgItem(hWnd, IDC_MODESCOMBO);
  2570.     DWORD iMonitor;
  2571.     MonitorInfo* pMonitorInfo;
  2572.     DWORD iAdapter;
  2573.     switch (uMsg)
  2574.     {
  2575.     case WM_INITDIALOG:
  2576.         {
  2577.             INT i = 0;
  2578.             TC_ITEM tie; 
  2579.             TCHAR szFmt[100];
  2580.             TCHAR sz[100];
  2581.             GetWindowText(GetDlgItem(hWnd, IDC_TABNAMEFMT), szFmt, 100);
  2582.             tie.mask = TCIF_TEXT | TCIF_IMAGE; 
  2583.             tie.iImage = -1; 
  2584.             for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2585.             {
  2586.                 wsprintf(sz, szFmt, iMonitor + 1);
  2587.                 tie.pszText = sz; 
  2588.                 TabCtrl_InsertItem(hwndTabs, i++, &tie);
  2589.             }
  2590.             for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  2591.             {
  2592.                 s_AdaptersSave[iAdapter] = new D3DAdapterInfo;
  2593.                 if( s_AdaptersSave[iAdapter] != NULL )
  2594.                     *s_AdaptersSave[iAdapter] = *m_Adapters[iAdapter];
  2595.             }
  2596.             s_bAllScreensSameSave = m_bAllScreensSame;
  2597.             SetupAdapterPage(hWnd);
  2598.             CheckDlgButton(hWnd, IDC_SAME, (m_bAllScreensSame ? BST_CHECKED : BST_UNCHECKED));
  2599.         }
  2600.         return TRUE;
  2601.  
  2602.     case WM_NOTIFY:
  2603.         {
  2604.             NMHDR* pnmh = (LPNMHDR)lParam;
  2605.             UINT code = pnmh->code;
  2606.             if (code == TCN_SELCHANGE)
  2607.             {
  2608.                 SetupAdapterPage(hWnd);
  2609.             }
  2610.         }
  2611.         return TRUE;
  2612.     case WM_COMMAND:
  2613.         switch( LOWORD( wParam ) )
  2614.         {
  2615.         case IDC_SAME:
  2616.             m_bAllScreensSame = (IsDlgButtonChecked(hWnd, IDC_SAME) == BST_CHECKED);
  2617.             break;
  2618.         case IDC_LEAVEBLACK:
  2619.         case IDC_RENDER:
  2620.             if( m_bOneScreenOnly )
  2621.             {
  2622.                 GetBestAdapter( &iAdapter );
  2623.                 iMonitor = m_Adapters[iAdapter]->iMonitor;
  2624.             }
  2625.             else
  2626.             {
  2627.                 iMonitor = TabCtrl_GetCurSel(hwndTabs);
  2628.             }
  2629.             pMonitorInfo = &m_Monitors[iMonitor];
  2630.             iAdapter = pMonitorInfo->iAdapter;
  2631.             if( IsDlgButtonChecked(hWnd, IDC_LEAVEBLACK) == BST_CHECKED )
  2632.             {
  2633.                 m_Adapters[iAdapter]->bLeaveBlack = TRUE;
  2634.                 EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), FALSE);
  2635.                 EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), FALSE);
  2636.                 EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), FALSE);
  2637.                 EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), FALSE);
  2638.             }
  2639.             else
  2640.             {
  2641.                 m_Adapters[iAdapter]->bLeaveBlack = FALSE;
  2642.                 EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), TRUE);
  2643.                 EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), TRUE);
  2644.                 EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), TRUE);
  2645.                 EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), TRUE);
  2646.             }
  2647.             break;
  2648.         case IDC_MODESCOMBO:
  2649.             if (HIWORD(wParam) == CBN_SELCHANGE)
  2650.             {
  2651.                 DWORD iSel;
  2652.                 DWORD iMode;
  2653.                 if( m_bOneScreenOnly )
  2654.                 {
  2655.                     GetBestAdapter( &iAdapter );
  2656.                     iMonitor = m_Adapters[iAdapter]->iMonitor;
  2657.                 }
  2658.                 else
  2659.                 {
  2660.                     iMonitor = TabCtrl_GetCurSel(hwndTabs);
  2661.                 }
  2662.                 pMonitorInfo = &m_Monitors[iMonitor];
  2663.                 iAdapter = pMonitorInfo->iAdapter;
  2664.                 iSel = ComboBox_GetCurSel( hwndModeList );
  2665.                 if( iSel == 0 )
  2666.                 {
  2667.                     // "Automatic"
  2668.                     m_Adapters[iAdapter]->dwUserPrefWidth = 0;
  2669.                     m_Adapters[iAdapter]->dwUserPrefHeight = 0;
  2670.                     m_Adapters[iAdapter]->d3dfmtUserPrefFormat = D3DFMT_UNKNOWN;
  2671.                 }
  2672.                 else
  2673.                 {
  2674.                     D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  2675.                     D3DDeviceInfo* pD3DDeviceInfo;
  2676.                     D3DModeInfo* pD3DModeInfo;
  2677.                     pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  2678.                     iMode = (DWORD)ComboBox_GetItemData( hwndModeList, iSel );
  2679.                     pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  2680.                     m_Adapters[iAdapter]->dwUserPrefWidth = pD3DModeInfo->Width;
  2681.                     m_Adapters[iAdapter]->dwUserPrefHeight = pD3DModeInfo->Height;
  2682.                     m_Adapters[iAdapter]->d3dfmtUserPrefFormat = pD3DModeInfo->Format;
  2683.                 }
  2684.             }
  2685.             break;
  2686.         case IDC_DISABLEHW:
  2687.             if( m_bOneScreenOnly )
  2688.             {
  2689.                 GetBestAdapter( &iAdapter );
  2690.                 iMonitor = m_Adapters[iAdapter]->iMonitor;
  2691.             }
  2692.             else
  2693.             {
  2694.                 iMonitor = TabCtrl_GetCurSel(hwndTabs);
  2695.             }
  2696.             pMonitorInfo = &m_Monitors[iMonitor];
  2697.             iAdapter = pMonitorInfo->iAdapter;
  2698.             if( IsDlgButtonChecked( hWnd, IDC_DISABLEHW ) == BST_CHECKED )
  2699.                 m_Adapters[iAdapter]->bDisableHW = TRUE;
  2700.             else
  2701.                 m_Adapters[iAdapter]->bDisableHW = FALSE;
  2702.             SetupAdapterPage( hWnd );
  2703.             break;
  2704.         case IDC_MOREINFO:
  2705.             {
  2706.                 if( m_bOneScreenOnly )
  2707.                 {
  2708.                     GetBestAdapter( &iAdapter );
  2709.                     iMonitor = m_Adapters[iAdapter]->iMonitor;
  2710.                 }
  2711.                 else
  2712.                 {
  2713.                     iMonitor = TabCtrl_GetCurSel(hwndTabs);
  2714.                 }
  2715.                 pMonitorInfo = &m_Monitors[iMonitor];
  2716.                 iAdapter = pMonitorInfo->iAdapter;
  2717.                 D3DAdapterInfo* pD3DAdapterInfo;
  2718.                 TCHAR szText[500];
  2719.                 if( pMonitorInfo->hMonitor == NULL )
  2720.                     pD3DAdapterInfo = NULL;
  2721.                 else
  2722.                     pD3DAdapterInfo = m_Adapters[pMonitorInfo->iAdapter];
  2723.                 // Accelerated / Unaccelerated settings
  2724.                 BOOL bHasHAL = FALSE;
  2725.                 BOOL bHasAppCompatHAL = FALSE;
  2726.                 BOOL bDisabledHAL = FALSE;
  2727.                 BOOL bHasSW = FALSE;
  2728.                 BOOL bHasAppCompatSW = FALSE;
  2729.     
  2730.                 if( pD3DAdapterInfo != NULL )
  2731.                 {
  2732.                     bHasHAL = pD3DAdapterInfo->bHasHAL;
  2733.                     bHasAppCompatHAL = pD3DAdapterInfo->bHasAppCompatHAL;
  2734.                     bDisabledHAL = pD3DAdapterInfo->bDisableHW;
  2735.                     bHasSW = pD3DAdapterInfo->bHasSW;
  2736.                     bHasAppCompatSW = pD3DAdapterInfo->bHasAppCompatSW;
  2737.                 }
  2738.                 if( bHasHAL && !bDisabledHAL && bHasAppCompatHAL )
  2739.                 {
  2740.                     // Good HAL
  2741.                     LoadString( NULL, IDS_INFO_GOODHAL, szText, 500 );
  2742.                 }
  2743.                 else if( bHasHAL && bDisabledHAL )
  2744.                 {
  2745.                     // Disabled HAL
  2746.                     if( bHasSW && bHasAppCompatSW )
  2747.                         LoadString( NULL, IDS_INFO_DISABLEDHAL_GOODSW, szText, 500 );
  2748.                     else if( bHasSW )
  2749.                         LoadString( NULL, IDS_INFO_DISABLEDHAL_BADSW, szText, 500 );
  2750.                     else 
  2751.                         LoadString( NULL, IDS_INFO_DISABLEDHAL_NOSW, szText, 500 );
  2752.                 }
  2753.                 else if( bHasHAL && !bHasAppCompatHAL )
  2754.                 {
  2755.                     // Bad HAL
  2756.                     if( bHasSW && bHasAppCompatSW )
  2757.                         LoadString( NULL, IDS_INFO_BADHAL_GOODSW, szText, 500 );
  2758.                     else if( bHasSW )
  2759.                         LoadString( NULL, IDS_INFO_BADHAL_BADSW, szText, 500 );
  2760.                     else 
  2761.                         LoadString( NULL, IDS_INFO_BADHAL_NOSW, szText, 500 );
  2762.                 }
  2763.                 else 
  2764.                 {
  2765.                     // No HAL
  2766.                     if( bHasSW && bHasAppCompatSW )
  2767.                         LoadString( NULL, IDS_INFO_NOHAL_GOODSW, szText, 500 );
  2768.                     else if( bHasSW  )
  2769.                         LoadString( NULL, IDS_INFO_NOHAL_BADSW, szText, 500 );
  2770.                     else 
  2771.                         LoadString( NULL, IDS_INFO_NOHAL_NOSW, szText, 500 );
  2772.                 }
  2773.                 MessageBox( hWnd, szText, pMonitorInfo->strDeviceName, MB_OK | MB_ICONINFORMATION );
  2774.                 break;
  2775.             }
  2776.         case IDOK:
  2777.             for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  2778.             {
  2779.                 SAFE_DELETE( s_AdaptersSave[iAdapter] );
  2780.             }
  2781.             EndDialog(hWnd, IDOK);
  2782.             break;
  2783.         case IDCANCEL:
  2784.             // Restore member values to original state
  2785.             for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  2786.             {
  2787.                 if( s_AdaptersSave[iAdapter] != NULL )
  2788.                     *m_Adapters[iAdapter] = *s_AdaptersSave[iAdapter];
  2789.                 SAFE_DELETE( s_AdaptersSave[iAdapter] );
  2790.             }
  2791.             m_bAllScreensSame = s_bAllScreensSameSave;
  2792.             EndDialog(hWnd, IDCANCEL);
  2793.             break;
  2794.         }
  2795.         return TRUE;
  2796.     default:
  2797.         return FALSE;
  2798.     }
  2799. }
  2800. //-----------------------------------------------------------------------------
  2801. // Name: SetupAdapterPage()
  2802. // Desc: Set up the controls for a given page in the Screen Settings dialog.
  2803. //-----------------------------------------------------------------------------
  2804. VOID CD3DScreensaver::SetupAdapterPage( HWND hWnd )
  2805. {
  2806.     HWND hwndTabs = GetDlgItem(hWnd, IDC_MONITORSTAB);
  2807.     HWND hwndModeList = GetDlgItem(hWnd, IDC_MODESCOMBO);
  2808.     UINT iPage = TabCtrl_GetCurFocus(hwndTabs);
  2809.     HWND hwndDesc = GetDlgItem(hWnd, IDC_ADAPTERNAME);
  2810.     MonitorInfo* pMonitorInfo;
  2811.     D3DAdapterInfo* pD3DAdapterInfo;
  2812.     D3DDeviceInfo* pD3DDeviceInfo;
  2813.     D3DModeInfo* pD3DModeInfo;
  2814.     if( m_bOneScreenOnly )
  2815.     {
  2816.         DWORD iAdapter;
  2817.         GetBestAdapter( &iAdapter );
  2818.         if( iAdapter != NO_ADAPTER )
  2819.         {
  2820.             pD3DAdapterInfo = m_Adapters[iAdapter];
  2821.             iPage = pD3DAdapterInfo->iMonitor;
  2822.         }
  2823.     }
  2824.     pMonitorInfo = &m_Monitors[iPage];
  2825.     SetWindowText( hwndDesc, pMonitorInfo->strDeviceName );
  2826.     if( pMonitorInfo->iAdapter == NO_ADAPTER )
  2827.         pD3DAdapterInfo = NULL;
  2828.     else
  2829.         pD3DAdapterInfo = m_Adapters[pMonitorInfo->iAdapter];
  2830.     // Accelerated / Unaccelerated settings
  2831.     BOOL bHasHAL = FALSE;
  2832.     BOOL bHasAppCompatHAL = FALSE;
  2833.     BOOL bDisabledHAL = FALSE;
  2834.     BOOL bHasSW = FALSE;
  2835.     BOOL bHasAppCompatSW = FALSE;
  2836.     
  2837.     if( pD3DAdapterInfo != NULL )
  2838.     {
  2839.         bHasHAL = pD3DAdapterInfo->bHasHAL;
  2840.         bHasAppCompatHAL = pD3DAdapterInfo->bHasAppCompatHAL;
  2841.         bDisabledHAL = pD3DAdapterInfo->bDisableHW;
  2842.         bHasSW = pD3DAdapterInfo->bHasSW;
  2843.         bHasAppCompatSW = pD3DAdapterInfo->bHasAppCompatSW;
  2844.     }
  2845.     TCHAR szStatus[200];
  2846.     if( bHasHAL && !bDisabledHAL && bHasAppCompatHAL )
  2847.     {
  2848.         LoadString( NULL, IDS_RENDERING_HAL, szStatus, 200 );
  2849.     }
  2850.     else if( bHasSW && bHasAppCompatSW )
  2851.     {
  2852.         LoadString( NULL, IDS_RENDERING_SW, szStatus, 200 );
  2853.     }
  2854.     else
  2855.     {
  2856.         LoadString( NULL, IDS_RENDERING_NONE, szStatus, 200 );
  2857.     }
  2858.     SetWindowText( GetDlgItem( hWnd, IDC_RENDERING ), szStatus );
  2859.     if( bHasHAL && bHasAppCompatHAL )
  2860.     {
  2861.         EnableWindow( GetDlgItem( hWnd, IDC_DISABLEHW ), TRUE );
  2862.         CheckDlgButton( hWnd, IDC_DISABLEHW, 
  2863.             pD3DAdapterInfo->bDisableHW ? BST_CHECKED : BST_UNCHECKED );
  2864.     }
  2865.     else
  2866.     {
  2867.         EnableWindow( GetDlgItem( hWnd, IDC_DISABLEHW ), FALSE );
  2868.         CheckDlgButton( hWnd, IDC_DISABLEHW, BST_UNCHECKED );
  2869.     }
  2870.     if( ( bHasAppCompatHAL && !bDisabledHAL ) || bHasAppCompatSW )
  2871.     {
  2872.         if( pD3DAdapterInfo->bLeaveBlack )
  2873.             CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_LEAVEBLACK);
  2874.         else
  2875.             CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_RENDER);
  2876.         EnableWindow(GetDlgItem(hWnd, IDC_LEAVEBLACK), TRUE);
  2877.         EnableWindow(GetDlgItem(hWnd, IDC_RENDER), TRUE);
  2878.         EnableWindow(GetDlgItem(hWnd, IDC_SCREENUSAGEBOX), TRUE);
  2879.     }
  2880.     else
  2881.     {
  2882.         CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_LEAVEBLACK);
  2883.         EnableWindow(GetDlgItem(hWnd, IDC_LEAVEBLACK), FALSE);
  2884.         EnableWindow(GetDlgItem(hWnd, IDC_RENDER), FALSE);
  2885.         EnableWindow(GetDlgItem(hWnd, IDC_SCREENUSAGEBOX), FALSE);
  2886.     }
  2887.     if( IsDlgButtonChecked(hWnd, IDC_LEAVEBLACK) == BST_CHECKED )
  2888.     {
  2889.         EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), FALSE);
  2890.         EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), FALSE);
  2891.         EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), FALSE);
  2892.         EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), FALSE);
  2893.     }
  2894.     else
  2895.     {
  2896.         EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), TRUE);
  2897.         EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), TRUE);
  2898.         EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), TRUE);
  2899.         EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), TRUE);
  2900.     }
  2901.     // Mode list
  2902.     ComboBox_ResetContent( hwndModeList );
  2903.     if( pD3DAdapterInfo == NULL )
  2904.         return;
  2905.     TCHAR strAutomatic[100];
  2906.     GetWindowText(GetDlgItem(hWnd, IDC_AUTOMATIC), strAutomatic, 100);
  2907.     ComboBox_AddString( hwndModeList, strAutomatic );
  2908.     ComboBox_SetItemData( hwndModeList, 0, -1 );
  2909.     pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  2910.     DWORD iSelInitial = 0;
  2911.     TCHAR strModeFmt[100];
  2912.     GetWindowText(GetDlgItem(hWnd, IDC_MODEFMT), strModeFmt, 100);
  2913.     for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++ )
  2914.     {
  2915.         DWORD dwBitDepth;
  2916.         TCHAR strMode[80];
  2917.         DWORD dwItem;
  2918.         pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  2919.         dwBitDepth = 16;
  2920.         if( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
  2921.             pD3DModeInfo->Format == D3DFMT_A8R8G8B8 ||
  2922.             pD3DModeInfo->Format == D3DFMT_R8G8B8 )
  2923.         {
  2924.             dwBitDepth = 32;
  2925.         }
  2926.         wsprintf( strMode, strModeFmt, pD3DModeInfo->Width,
  2927.                   pD3DModeInfo->Height, dwBitDepth );
  2928.         dwItem = ComboBox_AddString( hwndModeList, strMode );
  2929.         ComboBox_SetItemData( hwndModeList, dwItem, iMode );
  2930.         if( pD3DModeInfo->Width == pD3DAdapterInfo->dwUserPrefWidth &&
  2931.             pD3DModeInfo->Height == pD3DAdapterInfo->dwUserPrefHeight &&
  2932.             pD3DModeInfo->Format == pD3DAdapterInfo->d3dfmtUserPrefFormat )
  2933.         {
  2934.             iSelInitial = dwItem;
  2935.         }
  2936.     }
  2937.     ComboBox_SetCurSel( hwndModeList, iSelInitial );
  2938. }