Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3325 lines
118 KiB

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