Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3331 lines
122 KiB

//-----------------------------------------------------------------------------
// File: D3DSaver.cpp
//
// Desc: Framework for screensavers that use Direct3D 8.0.
//
// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include <Windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <stdio.h>
#include <tchar.h>
#include <regstr.h>
#define COMPILE_MULTIMON_STUBS
#include <multimon.h>
#include <mmsystem.h>
#include <D3DX8.h>
#include "D3DSaver.h"
#include "dxutil.h"
// Resource IDs. D3DSaver assumes that you will create resources with
// these IDs that it can use. The easiest way to do this is to copy
// the resources from the rc file of an existing D3DSaver-based program.
#define IDI_MAIN_ICON 101
#define IDD_SINGLEMONITORSETTINGS 200
#define IDD_MULTIMONITORSETTINGS 201
#define IDC_MONITORSTAB 2000
#define IDC_TABNAMEFMT 2001
#define IDC_ADAPTERNAME 2002
#define IDC_RENDERING 2003
#define IDC_MOREINFO 2004
#define IDC_DISABLEHW 2005
#define IDC_SCREENUSAGEBOX 2006
#define IDC_RENDER 2007
#define IDC_LEAVEBLACK 2008
#define IDC_DISPLAYMODEBOX 2009
#define IDC_MODESSTATIC 2010
#define IDC_MODESCOMBO 2011
#define IDC_AUTOMATIC 2012
#define IDC_DISPLAYMODENOTE 2013
#define IDC_GENERALBOX 2014
#define IDC_SAME 2015
#define IDC_MODEFMT 2016
#define IDS_ERR_GENERIC 2100
#define IDS_ERR_NODIRECT3D 2101
#define IDS_ERR_NOWINDOWEDHAL 2102
#define IDS_ERR_CREATEDEVICEFAILED 2103
#define IDS_ERR_NOCOMPATIBLEDEVICES 2104
#define IDS_ERR_NOHARDWAREDEVICE 2105
#define IDS_ERR_HALNOTCOMPATIBLE 2106
#define IDS_ERR_NOHALTHISMODE 2107
#define IDS_ERR_MEDIANOTFOUND 2108
#define IDS_ERR_RESIZEFAILED 2109
#define IDS_ERR_OUTOFMEMORY 2110
#define IDS_ERR_OUTOFVIDEOMEMORY 2111
#define IDS_ERR_NOPREVIEW 2112
#define IDS_INFO_GOODHAL 2200
#define IDS_INFO_BADHAL_GOODSW 2201
#define IDS_INFO_BADHAL_BADSW 2202
#define IDS_INFO_BADHAL_NOSW 2203
#define IDS_INFO_NOHAL_GOODSW 2204
#define IDS_INFO_NOHAL_BADSW 2205
#define IDS_INFO_NOHAL_NOSW 2206
#define IDS_INFO_DISABLEDHAL_GOODSW 2207
#define IDS_INFO_DISABLEDHAL_BADSW 2208
#define IDS_INFO_DISABLEDHAL_NOSW 2209
#define IDS_RENDERING_HAL 2210
#define IDS_RENDERING_SW 2211
#define IDS_RENDERING_NONE 2212
// Use the following structure rather than DISPLAY_DEVICE, since some old
// versions of DISPLAY_DEVICE are missing the last two fields and this can
// cause problems with EnumDisplayDevices on Windows 2000.
struct DISPLAY_DEVICE_FULL
{
DWORD cb;
TCHAR DeviceName[32];
TCHAR DeviceString[128];
DWORD StateFlags;
TCHAR DeviceID[128];
TCHAR DeviceKey[128];
};
static CD3DScreensaver* s_pD3DScreensaver = NULL;
//-----------------------------------------------------------------------------
// Name: CD3DScreensaver()
// Desc: Constructor
//-----------------------------------------------------------------------------
CD3DScreensaver::CD3DScreensaver()
{
s_pD3DScreensaver = this;
m_bCheckingSaverPassword = FALSE;
m_bIs9x = FALSE;
m_dwSaverMouseMoveCount = 0;
m_hWndParent = NULL;
m_hPasswordDLL = NULL;
m_hWnd = NULL;
m_VerifySaverPassword = NULL;
m_bAllScreensSame = FALSE;
m_pD3D = NULL;
m_pd3dDevice = NULL;
m_bWindowed = FALSE;
m_bWaitForInputIdle = FALSE;
m_bErrorMode = FALSE;
m_hrError = S_OK;
m_szError[0] = TEXT('\0');
m_fFPS = 0.0f;
m_strDeviceStats[0] = TEXT('\0');
m_strFrameStats[0] = TEXT('\0');
// Note: clients should load a resource into m_strWindowTitle to localize this string
lstrcpy( m_strWindowTitle, TEXT("Screen Saver") );
m_bAllowRef = FALSE;
m_bUseDepthBuffer = FALSE;
m_bMultithreaded = FALSE;
m_bOneScreenOnly = FALSE;
m_strRegPath[0] = TEXT('\0');
m_dwMinDepthBits = 16;
m_dwMinStencilBits = 0;
m_SwapEffectFullscreen = D3DSWAPEFFECT_DISCARD;
m_SwapEffectWindowed = D3DSWAPEFFECT_COPY_VSYNC;
SetRectEmpty( &m_rcRenderTotal );
SetRectEmpty( &m_rcRenderCurDevice );
ZeroMemory( m_Monitors, sizeof(m_Monitors) );
m_dwNumMonitors = 0;
ZeroMemory( m_Adapters, sizeof(m_Adapters) );
m_dwNumAdapters = 0;
ZeroMemory( m_RenderUnits, sizeof(m_RenderUnits) );
m_dwNumRenderUnits = 0;
m_fTime = 0.0f;
}
//-----------------------------------------------------------------------------
// Name: Create()
// Desc: Have the client program call this function before calling Run().
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::Create( HINSTANCE hInstance )
{
HRESULT hr;
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_IDLE );
m_hInstance = hInstance;
// Parse the command line and do the appropriate thing
TCHAR* pstrCmdLine = GetCommandLine();
m_SaverMode = ParseCommandLine( pstrCmdLine );
EnumMonitors();
// Create the screen saver window(s)
if( m_SaverMode == sm_preview ||
m_SaverMode == sm_test ||
m_SaverMode == sm_full )
{
if( FAILED( hr = CreateSaverWindow() ) )
{
m_bErrorMode = TRUE;
m_hrError = hr;
}
}
if( m_SaverMode == sm_preview )
{
// In preview mode, "pause" (enter a limited message loop) briefly
// before proceeding, so the display control panel knows to update itself.
m_bWaitForInputIdle = TRUE;
// Post a message to mark the end of the initial group of window messages
PostMessage( m_hWnd, WM_USER, 0, 0 );
MSG msg;
while( m_bWaitForInputIdle )
{
// If GetMessage returns FALSE, it's quitting time.
if( !GetMessage( &msg, m_hWnd, 0, 0 ) )
{
// Post the quit message to handle it later
PostQuitMessage(0);
break;
}
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
// Create Direct3D object
if( (m_pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) == NULL )
{
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_NODIRECT3D;
return S_OK;
}
// Give the app the opportunity to register a pluggable SW D3D Device.
if( FAILED( hr = RegisterSoftwareDevice() ) )
{
m_bErrorMode = TRUE;
m_hrError = hr;
return S_OK;
}
// Build a list of Direct3D adapters, modes and devices. The
// ConfirmDevice() callback is used to confirm that only devices that
// meet the app's requirements are considered.
if( FAILED( hr = BuildDeviceList() ) )
{
m_bErrorMode = TRUE;
m_hrError = hr;
return S_OK;
}
// Make sure that at least one valid usable D3D device was found
BOOL bCompatibleDeviceFound = FALSE;
for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
{
if( m_Adapters[iAdapter]->bHasAppCompatHAL ||
m_Adapters[iAdapter]->bHasAppCompatSW )
{
bCompatibleDeviceFound = TRUE;
break;
}
}
if( !bCompatibleDeviceFound )
{
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_NOCOMPATIBLEDEVICES;
return S_OK;
}
// Read any settings we need
ReadSettings();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: EnumMonitors()
// Desc: Determine HMONITOR, desktop rect, and other info for each monitor.
// Note that EnumDisplayDevices enumerates monitors in the order
// indicated on the Settings page of the Display control panel, which
// is the order we want to list monitors in, as opposed to the order
// used by D3D's GetAdapterInfo.
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::EnumMonitors( VOID )
{
DWORD iDevice = 0;
DISPLAY_DEVICE_FULL dispdev;
DISPLAY_DEVICE_FULL dispdev2;
DEVMODE devmode;
dispdev.cb = sizeof(dispdev);
dispdev2.cb = sizeof(dispdev2);
devmode.dmSize = sizeof(devmode);
devmode.dmDriverExtra = 0;
MonitorInfo* pMonitorInfoNew;
while( EnumDisplayDevices(NULL, iDevice, (DISPLAY_DEVICE*)&dispdev, 0) )
{
// Ignore NetMeeting's mirrored displays
if( (dispdev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0 )
{
// To get monitor info for a display device, call EnumDisplayDevices
// a second time, passing dispdev.DeviceName (from the first call) as
// the first parameter.
EnumDisplayDevices(dispdev.DeviceName, 0, (DISPLAY_DEVICE*)&dispdev2, 0);
pMonitorInfoNew = &m_Monitors[m_dwNumMonitors];
ZeroMemory( pMonitorInfoNew, sizeof(MonitorInfo) );
lstrcpy( pMonitorInfoNew->strDeviceName, dispdev.DeviceString );
lstrcpy( pMonitorInfoNew->strMonitorName, dispdev2.DeviceString );
pMonitorInfoNew->iAdapter = NO_ADAPTER;
if( dispdev.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP )
{
EnumDisplaySettings( dispdev.DeviceName, ENUM_CURRENT_SETTINGS, &devmode );
if( dispdev.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE )
{
// For some reason devmode.dmPosition is not always (0, 0)
// for the primary display, so force it.
pMonitorInfoNew->rcScreen.left = 0;
pMonitorInfoNew->rcScreen.top = 0;
}
else
{
pMonitorInfoNew->rcScreen.left = devmode.dmPosition.x;
pMonitorInfoNew->rcScreen.top = devmode.dmPosition.y;
}
pMonitorInfoNew->rcScreen.right = pMonitorInfoNew->rcScreen.left + devmode.dmPelsWidth;
pMonitorInfoNew->rcScreen.bottom = pMonitorInfoNew->rcScreen.top + devmode.dmPelsHeight;
pMonitorInfoNew->hMonitor = MonitorFromRect( &pMonitorInfoNew->rcScreen, MONITOR_DEFAULTTONULL );
}
m_dwNumMonitors++;
if( m_dwNumMonitors == MAX_DISPLAYS )
break;
}
iDevice++;
}
}
//-----------------------------------------------------------------------------
// Name: Run()
// Desc: Starts main execution of the screen saver.
//-----------------------------------------------------------------------------
INT CD3DScreensaver::Run()
{
HRESULT hr;
// Parse the command line and do the appropriate thing
switch ( m_SaverMode )
{
case sm_config:
{
if( m_bErrorMode )
{
DisplayErrorMsg( m_hrError, 0 );
}
else
{
DoConfig();
}
break;
}
case sm_preview:
case sm_test:
case sm_full:
{
if( FAILED( hr = DoSaver() ) )
DisplayErrorMsg( hr, 0 );
break;
}
case sm_passwordchange:
{
ChangePassword();
break;
}
}
for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
SAFE_DELETE( m_Adapters[iAdapter] );
SAFE_RELEASE( m_pD3D );
return 0;
}
//-----------------------------------------------------------------------------
// Name: ParseCommandLine()
// Desc: Interpret command-line parameters passed to this app.
//-----------------------------------------------------------------------------
SaverMode CD3DScreensaver::ParseCommandLine( TCHAR* pstrCommandLine )
{
m_hWndParent = NULL;
// Skip the first part of the command line, which is the full path
// to the exe. If it contains spaces, it will be contained in quotes.
if (*pstrCommandLine == TEXT('\"'))
{
pstrCommandLine++;
while (*pstrCommandLine != TEXT('\0') && *pstrCommandLine != TEXT('\"'))
pstrCommandLine++;
if( *pstrCommandLine == TEXT('\"') )
pstrCommandLine++;
}
else
{
while (*pstrCommandLine != TEXT('\0') && *pstrCommandLine != TEXT(' '))
pstrCommandLine++;
if( *pstrCommandLine == TEXT(' ') )
pstrCommandLine++;
}
// Skip along to the first option delimiter "/" or "-"
while ( *pstrCommandLine != TEXT('\0') && *pstrCommandLine != TEXT('/') && *pstrCommandLine != TEXT('-') )
pstrCommandLine++;
// If there wasn't one, then must be config mode
if ( *pstrCommandLine == TEXT('\0') )
return sm_config;
// Otherwise see what the option was
switch ( *(++pstrCommandLine) )
{
case 'c':
case 'C':
pstrCommandLine++;
while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
pstrCommandLine++;
if ( isdigit(*pstrCommandLine) )
{
#ifdef _WIN64
CHAR strCommandLine[2048];
DXUtil_ConvertGenericStringToAnsi(strCommandLine, pstrCommandLine, 2048);
m_hWndParent = HWND(_atoi64(strCommandLine));
#else
m_hWndParent = HWND(_ttol(pstrCommandLine));
#endif
}
else
{
m_hWndParent = NULL;
}
return sm_config;
case 't':
case 'T':
return sm_test;
case 'p':
case 'P':
// Preview-mode, so option is followed by the parent HWND in decimal
pstrCommandLine++;
while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
pstrCommandLine++;
if ( isdigit(*pstrCommandLine) )
{
#ifdef _WIN64
CHAR strCommandLine[2048];
DXUtil_ConvertGenericStringToAnsi(strCommandLine, pstrCommandLine, 2048);
m_hWndParent = HWND(_atoi64(strCommandLine));
#else
m_hWndParent = HWND(_ttol(pstrCommandLine));
#endif
}
return sm_preview;
case 'a':
case 'A':
// Password change mode, so option is followed by parent HWND in decimal
pstrCommandLine++;
while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
pstrCommandLine++;
if ( isdigit(*pstrCommandLine) )
{
#ifdef _WIN64
CHAR strCommandLine[2048];
DXUtil_ConvertGenericStringToAnsi(strCommandLine, pstrCommandLine, 2048);
m_hWndParent = HWND(_atoi64(strCommandLine));
#else
m_hWndParent = HWND(_ttol(pstrCommandLine));
#endif
}
return sm_passwordchange;
default:
// All other options => run the screensaver (typically this is "/s")
return sm_full;
}
}
//-----------------------------------------------------------------------------
// Name: CreateSaverWindow
// Desc: Register and create the appropriate window(s)
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::CreateSaverWindow()
{
/*
// Uncomment this code to allow stepping thru code in the preview case
if( m_SaverMode == sm_preview )
{
WNDCLASS cls;
cls.hCursor = NULL;
cls.hIcon = NULL;
cls.lpszMenuName = NULL;
cls.lpszClassName = TEXT("Parent");
cls.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
cls.hInstance = m_hInstance;
cls.style = CS_VREDRAW|CS_HREDRAW|CS_SAVEBITS|CS_DBLCLKS;
cls.lpfnWndProc = DefWindowProc;
cls.cbWndExtra = 0;
cls.cbClsExtra = 0;
RegisterClass( &cls );
// Create the window
RECT rect;
HWND hwnd;
rect.left = rect.top = 40;
rect.right = rect.left+200;
rect.bottom = rect.top+200;
AdjustWindowRect( &rect, WS_VISIBLE|WS_OVERLAPPED|WS_CAPTION|WS_POPUP, FALSE );
hwnd = CreateWindow( TEXT("Parent"), TEXT("FakeShell"),
WS_VISIBLE|WS_OVERLAPPED|WS_CAPTION|WS_POPUP, rect.left, rect.top,
rect.right-rect.left, rect.bottom-rect.top, NULL,
NULL, m_hInstance, NULL );
m_hWndParent = hwnd;
}
*/
// Register an appropriate window class
WNDCLASS cls;
cls.hCursor = LoadCursor( NULL, IDC_ARROW );
cls.hIcon = LoadIcon( m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) );
cls.lpszMenuName = NULL;
cls.lpszClassName = TEXT("D3DSaverWndClass");
cls.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
cls.hInstance = m_hInstance;
cls.style = CS_VREDRAW|CS_HREDRAW;
cls.lpfnWndProc = SaverProcStub;
cls.cbWndExtra = 0;
cls.cbClsExtra = 0;
RegisterClass( &cls );
// Create the window
RECT rc;
DWORD dwStyle;
switch ( m_SaverMode )
{
case sm_preview:
GetClientRect( m_hWndParent, &rc );
dwStyle = WS_VISIBLE | WS_CHILD;
AdjustWindowRect( &rc, dwStyle, FALSE );
m_hWnd = CreateWindow( TEXT("D3DSaverWndClass"), m_strWindowTitle, dwStyle,
rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
m_hWndParent, NULL, m_hInstance, this );
m_Monitors[0].hWnd = m_hWnd;
GetClientRect( m_hWnd, &m_rcRenderTotal );
GetClientRect( m_hWnd, &m_rcRenderCurDevice );
break;
case sm_test:
rc.left = rc.top = 50;
rc.right = rc.left+600;
rc.bottom = rc.top+400;
dwStyle = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
AdjustWindowRect( &rc, dwStyle, FALSE );
m_hWnd = CreateWindow( TEXT("D3DSaverWndClass"), m_strWindowTitle, dwStyle,
rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
NULL, NULL, m_hInstance, this );
m_Monitors[0].hWnd = m_hWnd;
GetClientRect( m_hWnd, &m_rcRenderTotal );
GetClientRect( m_hWnd, &m_rcRenderCurDevice );
break;
case sm_full:
// Create windows for each monitor. Note that m_hWnd is NULL when CreateWindowEx
// is called for the first monitor, so that window has no parent. Windows for
// additional monitors are created as children of the window for the first monitor.
dwStyle = WS_VISIBLE | WS_POPUP;
m_hWnd = NULL;
for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
{
MonitorInfo* pMonitorInfo;
pMonitorInfo = &m_Monitors[iMonitor];
if( pMonitorInfo->hMonitor == NULL )
continue;
rc = pMonitorInfo->rcScreen;
pMonitorInfo->hWnd = CreateWindowEx( WS_EX_TOPMOST, TEXT("D3DSaverWndClass"),
m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right - rc.left,
rc.bottom - rc.top, m_hWnd, NULL, m_hInstance, this );
if( pMonitorInfo->hWnd == NULL )
return E_FAIL;
if( m_hWnd == NULL )
m_hWnd = pMonitorInfo->hWnd;
}
}
if ( m_hWnd == NULL )
return E_FAIL;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DoSaver()
// Desc: Run the screensaver graphics - may be preview, test or full-on mode
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::DoSaver()
{
HRESULT hr;
// Figure out if we're on Win9x
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx( &osvi );
m_bIs9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
// If we're in full on mode, and on 9x, then need to load the password DLL
if ( m_SaverMode == sm_full && m_bIs9x )
{
// Only do this if the password is set - check registry:
HKEY hKey;
if ( RegOpenKey( HKEY_CURRENT_USER , REGSTR_PATH_SCREENSAVE , &hKey ) == ERROR_SUCCESS )
{
DWORD dwVal;
DWORD dwSize = sizeof(dwVal);
if ( (RegQueryValueEx( hKey, REGSTR_VALUE_USESCRPASSWORD, NULL, NULL,
(BYTE *)&dwVal, &dwSize ) == ERROR_SUCCESS) && dwVal )
{
m_hPasswordDLL = LoadLibrary( TEXT("PASSWORD.CPL") );
if ( m_hPasswordDLL )
m_VerifySaverPassword = (VERIFYPWDPROC)GetProcAddress( m_hPasswordDLL, "VerifyScreenSavePwd" );
RegCloseKey( hKey );
}
}
}
// Initialize the application timer
DXUtil_Timer( TIMER_START );
if( !m_bErrorMode )
{
// Initialize the app's custom scene stuff
if( FAILED( hr = OneTimeSceneInit() ) )
return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
// Do graphical init stuff
if ( FAILED(hr = Initialize3DEnvironment()) )
return hr;
}
// Flag as screensaver running if in full on mode
if ( m_SaverMode == sm_full )
{
BOOL bUnused;
SystemParametersInfo( SPI_SCREENSAVERRUNNING, TRUE, &bUnused, 0 );
}
// Message pump
BOOL bGotMsg;
MSG msg;
msg.message = WM_NULL;
while ( msg.message != WM_QUIT )
{
bGotMsg = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
if( bGotMsg )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Sleep(10);
if( m_bErrorMode )
{
UpdateErrorBox();
}
else
{
Render3DEnvironment();
}
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: ShutdownSaver()
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::ShutdownSaver()
{
// Unflag screensaver running if in full on mode
if ( m_SaverMode == sm_full )
{
BOOL bUnused;
SystemParametersInfo( SPI_SCREENSAVERRUNNING, FALSE, &bUnused, 0 );
}
// Kill graphical stuff
Cleanup3DEnvironment();
// Let client app clean up its resources
FinalCleanup();
// Unload the password DLL (if we loaded it)
if ( m_hPasswordDLL != NULL )
{
FreeLibrary( m_hPasswordDLL );
m_hPasswordDLL = NULL;
}
// Post message to drop out of message loop
PostQuitMessage( 0 );
}
//-----------------------------------------------------------------------------
// Name: SaverProcStub()
// Desc: This function forwards all window messages to SaverProc, which has
// access to the "this" pointer.
//-----------------------------------------------------------------------------
LRESULT CALLBACK CD3DScreensaver::SaverProcStub( HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
return s_pD3DScreensaver->SaverProc( hWnd, uMsg, wParam, lParam );
}
//-----------------------------------------------------------------------------
// Name: SaverProc()
// Desc: Handle window messages for main screensaver windows (one per screen).
//-----------------------------------------------------------------------------
LRESULT CD3DScreensaver::SaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch ( uMsg )
{
case WM_USER:
// All initialization messages have gone through. Allow
// 500ms of idle time, then proceed with initialization.
SetTimer( hWnd, 1, 500, NULL );
break;
case WM_TIMER:
// Initial idle time is done, proceed with initialization.
m_bWaitForInputIdle = FALSE;
KillTimer( hWnd, 1 );
break;
case WM_DESTROY:
if( m_SaverMode == sm_preview || m_SaverMode == sm_test )
ShutdownSaver();
break;
case WM_SETCURSOR:
if ( m_SaverMode == sm_full && !m_bCheckingSaverPassword )
{
// Hide cursor
SetCursor( NULL );
return TRUE;
}
break;
case WM_PAINT:
{
// Show error message, if there is one
PAINTSTRUCT ps;
BeginPaint( hWnd, &ps );
// In preview mode, just fill
// the preview window with black.
if( !m_bErrorMode && m_SaverMode == sm_preview )
{
RECT rc;
GetClientRect(hWnd,&rc);
HBRUSH hbrBlack = (HBRUSH)GetStockObject(BLACK_BRUSH);
if( hbrBlack != NULL )
FillRect(ps.hdc, &rc, hbrBlack );
}
else
{
DoPaint( hWnd, ps.hdc );
}
EndPaint( hWnd, &ps );
return 0;
}
case WM_ERASEBKGND:
// Erase background if checking password or if window is not
// assigned to a render unit
if( !m_bCheckingSaverPassword )
{
RenderUnit* pRenderUnit;
D3DAdapterInfo* pD3DAdapterInfo;
for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
pD3DAdapterInfo = m_Adapters[pRenderUnit->iAdapter];
if( pD3DAdapterInfo->hWndDevice == hWnd )
return TRUE; // don't erase this window
}
}
break;
case WM_MOUSEMOVE:
if( m_SaverMode != sm_test )
{
static INT xPrev = -1;
static INT yPrev = -1;
INT xCur = GET_X_LPARAM(lParam);
INT yCur = GET_Y_LPARAM(lParam);
if( xCur != xPrev || yCur != yPrev )
{
xPrev = xCur;
yPrev = yCur;
m_dwSaverMouseMoveCount++;
if ( m_dwSaverMouseMoveCount > 5 )
InterruptSaver();
}
}
break;
case WM_KEYDOWN:
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
if( m_SaverMode != sm_test )
InterruptSaver();
break;
case WM_ACTIVATEAPP:
if( wParam == FALSE && m_SaverMode != sm_test )
InterruptSaver();
break;
case WM_POWERBROADCAST:
if( wParam == PBT_APMSUSPEND && m_VerifySaverPassword == NULL )
InterruptSaver();
break;
case WM_SYSCOMMAND:
if ( m_SaverMode == sm_full )
{
switch ( wParam )
{
case SC_NEXTWINDOW:
case SC_PREVWINDOW:
case SC_SCREENSAVE:
case SC_CLOSE:
return FALSE;
break;
case SC_MONITORPOWER:
//
// The monitor is shutting down. Tell our client that he needs to
// cleanup and exit.
//
InterruptSaver();
break;
};
}
break;
}
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
//-----------------------------------------------------------------------------
// Name: InterruptSaver()
// Desc: A message was received (mouse move, keydown, etc.) that may mean
// the screen saver should show the password dialog and/or shut down.
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::InterruptSaver()
{
HRESULT hr;
DWORD iRenderUnit;
RenderUnit* pRenderUnit;
BOOL bPasswordOkay = FALSE;
if( m_SaverMode == sm_test ||
m_SaverMode == sm_full && !m_bCheckingSaverPassword )
{
if( m_bIs9x && m_SaverMode == sm_full )
{
// If no VerifyPassword function, then no password is set
// or we're not on 9x.
if ( m_VerifySaverPassword != NULL )
{
// Shut down all D3D devices so we can show a Windows dialog
for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
SwitchToRenderUnit(iRenderUnit);
if( pRenderUnit->bDeviceObjectsRestored )
{
InvalidateDeviceObjects();
pRenderUnit->bDeviceObjectsRestored = FALSE;
}
if( pRenderUnit->bDeviceObjectsInited )
{
DeleteDeviceObjects();
pRenderUnit->bDeviceObjectsInited = FALSE;
}
SAFE_RELEASE(pRenderUnit->pd3dDevice);
}
// Make sure all adapter windows cover the whole screen,
// even after deleting D3D devices (which may have caused
// mode changes)
D3DAdapterInfo* pD3DAdapterInfo;
for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
{
pD3DAdapterInfo = m_Adapters[iAdapter];
ShowWindow( pD3DAdapterInfo->hWndDevice, SW_RESTORE );
ShowWindow( pD3DAdapterInfo->hWndDevice, SW_MAXIMIZE );
}
m_bCheckingSaverPassword = TRUE;
bPasswordOkay = m_VerifySaverPassword( m_hWnd );
m_bCheckingSaverPassword = FALSE;
if ( bPasswordOkay )
{
// D3D devices are all torn down, so it's safe
// to discard all render units now (so we don't
// try to clean them up again later).
m_dwNumRenderUnits = 0;
}
else
{
// Back to screen saving...
SetCursor( NULL );
m_dwSaverMouseMoveCount = 0;
// Recreate all D3D devices
for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
hr = m_pD3D->CreateDevice(pRenderUnit->iAdapter,
pRenderUnit->DeviceType, m_hWnd,
pRenderUnit->dwBehavior, &pRenderUnit->d3dpp,
&pRenderUnit->pd3dDevice );
if( FAILED( hr ) )
{
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
}
else
{
SwitchToRenderUnit(iRenderUnit);
if( FAILED(hr = InitDeviceObjects() ) )
{
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
}
else
{
pRenderUnit->bDeviceObjectsInited = TRUE;
if( FAILED(hr = RestoreDeviceObjects() ) )
{
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
}
else
{
pRenderUnit->bDeviceObjectsRestored = TRUE;
}
}
}
}
return;
}
}
}
ShutdownSaver();
}
}
//-----------------------------------------------------------------------------
// Name: Initialize3DEnvironment()
// Desc: Set up D3D device(s)
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::Initialize3DEnvironment()
{
HRESULT hr;
DWORD iAdapter;
DWORD iMonitor;
D3DAdapterInfo* pD3DAdapterInfo;
MonitorInfo* pMonitorInfo;
DWORD iRenderUnit;
RenderUnit* pRenderUnit;
MONITORINFO monitorInfo;
if ( m_SaverMode == sm_full )
{
// Fullscreen mode. Create a RenderUnit for each monitor (unless
// the user wants it black)
m_bWindowed = FALSE;
if( m_bOneScreenOnly )
{
// Set things up to only create a RenderUnit on the best device
for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
{
pD3DAdapterInfo = m_Adapters[iAdapter];
pD3DAdapterInfo->bLeaveBlack = TRUE;
}
GetBestAdapter( &iAdapter );
if( iAdapter == NO_ADAPTER )
{
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_NOCOMPATIBLEDEVICES;
}
else
{
pD3DAdapterInfo = m_Adapters[iAdapter];
pD3DAdapterInfo->bLeaveBlack = FALSE;
}
}
for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
{
pMonitorInfo = &m_Monitors[iMonitor];
iAdapter = pMonitorInfo->iAdapter;
if( iAdapter == NO_ADAPTER )
continue;
pD3DAdapterInfo = m_Adapters[iAdapter];
if( !pD3DAdapterInfo->bLeaveBlack && pD3DAdapterInfo->dwNumDevices > 0 )
{
pD3DAdapterInfo->hWndDevice = pMonitorInfo->hWnd;
pRenderUnit = &m_RenderUnits[m_dwNumRenderUnits++];
ZeroMemory( pRenderUnit, sizeof(RenderUnit) );
pRenderUnit->iAdapter = iAdapter;
if( FAILED( hr = CreateFullscreenRenderUnit( pRenderUnit ) ) )
{
// skip this render unit and leave screen blank
m_dwNumRenderUnits--;
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
}
}
}
}
else
{
// Windowed mode, for test mode or preview window. Just need one RenderUnit.
m_bWindowed = TRUE;
GetClientRect( m_hWnd, &m_rcRenderTotal );
GetClientRect( m_hWnd, &m_rcRenderCurDevice );
GetBestAdapter( &iAdapter );
if( iAdapter == NO_ADAPTER )
{
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
}
else
{
pD3DAdapterInfo = m_Adapters[iAdapter];
pD3DAdapterInfo->hWndDevice = m_hWnd;
}
if( !m_bErrorMode )
{
pRenderUnit = &m_RenderUnits[m_dwNumRenderUnits++];
ZeroMemory( pRenderUnit, sizeof(RenderUnit) );
pRenderUnit->iAdapter = iAdapter;
if( FAILED( hr = CreateWindowedRenderUnit( pRenderUnit ) ) )
{
m_dwNumRenderUnits--;
m_bErrorMode = TRUE;
if( m_SaverMode == sm_preview )
m_hrError = D3DAPPERR_NOPREVIEW;
else
m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
}
}
}
// Once all mode changes are done, (re-)determine coordinates of all
// screens, and make sure windows still cover each screen
for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
{
pMonitorInfo = &m_Monitors[iMonitor];
monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo( pMonitorInfo->hMonitor, &monitorInfo );
pMonitorInfo->rcScreen = monitorInfo.rcMonitor;
if( !m_bWindowed )
{
SetWindowPos( pMonitorInfo->hWnd, HWND_TOPMOST, monitorInfo.rcMonitor.left,
monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, SWP_NOACTIVATE );
}
}
// For fullscreen, determine bounds of the virtual screen containing all
// screens that are rendering. Don't just use SM_XVIRTUALSCREEN, because
// we don't want to count screens that are just black
if( !m_bWindowed )
{
for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
pMonitorInfo = &m_Monitors[pRenderUnit->iMonitor];
UnionRect( &m_rcRenderTotal, &m_rcRenderTotal, &pMonitorInfo->rcScreen );
}
}
if( !m_bErrorMode )
{
// Initialize D3D devices for all render units
for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
SwitchToRenderUnit( iRenderUnit );
if ( FAILED(hr = InitDeviceObjects() ) )
{
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
}
else
{
pRenderUnit->bDeviceObjectsInited = TRUE;
if ( FAILED(hr = RestoreDeviceObjects() ) )
{
m_bErrorMode = TRUE;
m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
}
else
{
pRenderUnit->bDeviceObjectsRestored = TRUE;
}
}
}
UpdateDeviceStats();
}
// Make sure all those display changes don't count as user mouse moves
m_dwSaverMouseMoveCount = 0;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GetBestAdapter()
// Desc: To decide which adapter to use, loop through monitors until you find
// one whose adapter has a compatible HAL. If none, use the first
// monitor that has an compatible SW device.
//-----------------------------------------------------------------------------
BOOL CD3DScreensaver::GetBestAdapter( DWORD* piAdapter )
{
DWORD iAdapterBest = NO_ADAPTER;
DWORD iAdapter;
DWORD iMonitor;
MonitorInfo* pMonitorInfo;
D3DAdapterInfo* pD3DAdapterInfo;
for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
{
pMonitorInfo = &m_Monitors[iMonitor];
iAdapter = pMonitorInfo->iAdapter;
if( iAdapter == NO_ADAPTER )
continue;
pD3DAdapterInfo = m_Adapters[iAdapter];
if( pD3DAdapterInfo->bHasAppCompatHAL )
{
iAdapterBest = iAdapter;
break;
}
if( pD3DAdapterInfo->bHasAppCompatSW )
{
iAdapterBest = iAdapter;
// but keep looking...
}
}
*piAdapter = iAdapterBest;
return (iAdapterBest != NO_ADAPTER);
}
//-----------------------------------------------------------------------------
// Name: CreateFullscreenRenderUnit()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::CreateFullscreenRenderUnit( RenderUnit* pRenderUnit )
{
HRESULT hr;
UINT iAdapter = pRenderUnit->iAdapter;
D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
DWORD iMonitor = pD3DAdapterInfo->iMonitor;
D3DDeviceInfo* pD3DDeviceInfo;
D3DModeInfo* pD3DModeInfo;
DWORD dwCurrentDevice;
D3DDEVTYPE curType;
if( iAdapter >= m_dwNumAdapters )
return E_FAIL;
if( pD3DAdapterInfo->dwNumDevices == 0 )
return E_FAIL;
// Find the best device for the adapter. Use HAL
// if it's there, otherwise SW, otherwise REF.
dwCurrentDevice = 0xffff;
curType = D3DDEVTYPE_FORCE_DWORD;
for( DWORD iDevice = 0; iDevice < pD3DAdapterInfo->dwNumDevices; iDevice++)
{
pD3DDeviceInfo = &pD3DAdapterInfo->devices[iDevice];
if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_HAL && !pD3DAdapterInfo->bDisableHW )
{
dwCurrentDevice = iDevice;
curType = D3DDEVTYPE_HAL;
break; // stop looking
}
else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW )
{
dwCurrentDevice = iDevice;
curType = D3DDEVTYPE_SW;
// but keep looking
}
else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_REF && m_bAllowRef && curType != D3DDEVTYPE_SW )
{
dwCurrentDevice = iDevice;
curType = D3DDEVTYPE_REF;
// but keep looking
}
}
if( dwCurrentDevice == 0xffff )
return D3DAPPERR_NOHARDWAREDEVICE;
pD3DDeviceInfo = &pD3DAdapterInfo->devices[dwCurrentDevice];
pD3DDeviceInfo->dwCurrentMode = 0xffff;
if( pD3DAdapterInfo->dwUserPrefWidth != 0 )
{
// Try to find mode that matches user preference
for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
{
pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
if( pD3DModeInfo->Width == pD3DAdapterInfo->dwUserPrefWidth &&
pD3DModeInfo->Height == pD3DAdapterInfo->dwUserPrefHeight &&
pD3DModeInfo->Format == pD3DAdapterInfo->d3dfmtUserPrefFormat )
{
pD3DDeviceInfo->dwCurrentMode = iMode;
break;
}
}
}
// If user-preferred mode is not specified or not found,
// use "Automatic" technique:
if( pD3DDeviceInfo->dwCurrentMode == 0xffff )
{
if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW )
{
// If using a SW rast then try to find a low resolution and 16-bpp.
BOOL bFound16BitMode = FALSE;
DWORD dwSmallestHeight = -1;
pD3DDeviceInfo->dwCurrentMode = 0; // unless we find something better
for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
{
pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
// Skip 640x400 because 640x480 is better
if( pD3DModeInfo->Height == 400 )
continue;
if( pD3DModeInfo->Height < dwSmallestHeight ||
(pD3DModeInfo->Height == dwSmallestHeight && !bFound16BitMode) )
{
dwSmallestHeight = pD3DModeInfo->Height;
pD3DDeviceInfo->dwCurrentMode = iMode;
bFound16BitMode = FALSE;
if( ( pD3DModeInfo->Format == D3DFMT_R5G6B5 ||
pD3DModeInfo->Format == D3DFMT_X1R5G5B5 ||
pD3DModeInfo->Format == D3DFMT_A1R5G5B5 ||
pD3DModeInfo->Format == D3DFMT_A4R4G4B4 ||
pD3DModeInfo->Format == D3DFMT_X4R4G4B4 ) )
{
bFound16BitMode = TRUE;
}
}
}
}
else
{
// Try to find mode matching desktop resolution and 32-bpp.
BOOL bMatchedSize = FALSE;
BOOL bGot32Bit = FALSE;
pD3DDeviceInfo->dwCurrentMode = 0; // unless we find something better
for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
{
pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
if( pD3DModeInfo->Width == pD3DAdapterInfo->d3ddmDesktop.Width &&
pD3DModeInfo->Height == pD3DAdapterInfo->d3ddmDesktop.Height )
{
if( !bMatchedSize )
pD3DDeviceInfo->dwCurrentMode = iMode;
bMatchedSize = TRUE;
if( !bGot32Bit &&
( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
pD3DModeInfo->Format == D3DFMT_A8R8G8B8 ) )
{
pD3DDeviceInfo->dwCurrentMode = iMode;
bGot32Bit = TRUE;
break;
}
}
}
}
}
// If desktop mode not found, pick highest mode available
if( pD3DDeviceInfo->dwCurrentMode == 0xffff )
{
DWORD dwWidthMax = 0;
DWORD dwHeightMax = 0;
DWORD dwBppMax = 0;
DWORD dwWidthCur = 0;
DWORD dwHeightCur = 0;
DWORD dwBppCur = 0;
for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
{
pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
dwWidthCur = pD3DModeInfo->Width;
dwHeightCur = pD3DModeInfo->Height;
if( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
pD3DModeInfo->Format == D3DFMT_A8R8G8B8 )
{
dwBppCur = 32;
}
else
{
dwBppCur = 16;
}
if( dwWidthCur > dwWidthMax ||
dwHeightCur > dwHeightMax ||
dwWidthCur == dwWidthMax && dwHeightCur == dwHeightMax && dwBppCur > dwBppMax )
{
dwWidthMax = dwWidthCur;
dwHeightMax = dwHeightCur;
dwBppMax = dwBppCur;
pD3DDeviceInfo->dwCurrentMode = iMode;
}
}
}
// Try to create the D3D device, falling back to lower-res modes if it fails
BOOL bAtLeastOneFailure = FALSE;
while( TRUE )
{
pD3DModeInfo = &pD3DDeviceInfo->modes[pD3DDeviceInfo->dwCurrentMode];
pRenderUnit->DeviceType = pD3DDeviceInfo->DeviceType;
pRenderUnit->dwBehavior = pD3DModeInfo->dwBehavior;
pRenderUnit->iMonitor = iMonitor;
pRenderUnit->d3dpp.BackBufferFormat = pD3DModeInfo->Format;
pRenderUnit->d3dpp.BackBufferWidth = pD3DModeInfo->Width;
pRenderUnit->d3dpp.BackBufferHeight = pD3DModeInfo->Height;
pRenderUnit->d3dpp.Windowed = FALSE;
pRenderUnit->d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
pRenderUnit->d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
pRenderUnit->d3dpp.AutoDepthStencilFormat = pD3DModeInfo->DepthStencilFormat;
pRenderUnit->d3dpp.BackBufferCount = 1;
pRenderUnit->d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
pRenderUnit->d3dpp.SwapEffect = m_SwapEffectFullscreen;
pRenderUnit->d3dpp.hDeviceWindow = pD3DAdapterInfo->hWndDevice;
pRenderUnit->d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
pRenderUnit->d3dpp.Flags = 0;
// Create device
hr = m_pD3D->CreateDevice( iAdapter, pRenderUnit->DeviceType,
m_hWnd, // (this is the focus window)
pRenderUnit->dwBehavior, &pRenderUnit->d3dpp,
&pRenderUnit->pd3dDevice );
if( SUCCEEDED( hr ) )
{
// Give the client app an opportunity to reject this mode
// due to not enough video memory, or any other reason
if( SUCCEEDED( hr = ConfirmMode( pRenderUnit->pd3dDevice ) ) )
break;
else
SAFE_RELEASE( pRenderUnit->pd3dDevice );
}
// If we get here, remember that CreateDevice or ConfirmMode failed, so
// we can change the default mode next time
bAtLeastOneFailure = TRUE;
if( !FindNextLowerMode( pD3DDeviceInfo ) )
break;
}
if( SUCCEEDED( hr ) && bAtLeastOneFailure && m_strRegPath[0] != TEXT('\0') )
{
// Record the mode that succeeded in the registry so we can
// default to it next time
TCHAR strKey[100];
HKEY hkeyParent;
HKEY hkey;
pD3DAdapterInfo->dwUserPrefWidth = pRenderUnit->d3dpp.BackBufferWidth;
pD3DAdapterInfo->dwUserPrefHeight = pRenderUnit->d3dpp.BackBufferHeight;
pD3DAdapterInfo->d3dfmtUserPrefFormat = pRenderUnit->d3dpp.BackBufferFormat;
if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, m_strRegPath,
0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyParent, NULL ) )
{
wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey,
0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
{
RegSetValueEx( hkey, TEXT("Width"), NULL, REG_DWORD,
(BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, sizeof(DWORD) );
RegSetValueEx( hkey, TEXT("Height"), NULL, REG_DWORD,
(BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, sizeof(DWORD) );
RegSetValueEx( hkey, TEXT("Format"), NULL, REG_DWORD,
(BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, sizeof(DWORD) );
RegSetValueEx( hkey, TEXT("Adapter ID"), NULL, REG_BINARY,
(BYTE*)&pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier, sizeof(GUID) );
RegCloseKey( hkey );
}
RegCloseKey( hkeyParent );
}
}
return hr;
}
//-----------------------------------------------------------------------------
// Name: FindNextLowerMode()
// Desc:
//-----------------------------------------------------------------------------
BOOL CD3DScreensaver::FindNextLowerMode( D3DDeviceInfo* pD3DDeviceInfo )
{
DWORD iModeCur = pD3DDeviceInfo->dwCurrentMode;
D3DModeInfo* pD3DModeInfoCur = &pD3DDeviceInfo->modes[iModeCur];
DWORD dwWidthCur = pD3DModeInfoCur->Width;
DWORD dwHeightCur = pD3DModeInfoCur->Height;
DWORD dwNumPixelsCur = dwWidthCur * dwHeightCur;
D3DFORMAT d3dfmtCur = pD3DModeInfoCur->Format;
BOOL b32BitCur = (d3dfmtCur == D3DFMT_A8R8G8B8 ||
d3dfmtCur == D3DFMT_X8R8G8B8);
DWORD iModeNew;
D3DModeInfo* pD3DModeInfoNew;
DWORD dwWidthNew;
DWORD dwHeightNew;
DWORD dwNumPixelsNew;
D3DFORMAT d3dfmtNew = D3DFMT_UNKNOWN;
BOOL b32BitNew;
DWORD dwWidthBest = 0;
DWORD dwHeightBest = 0;
DWORD dwNumPixelsBest = 0;
BOOL b32BitBest = FALSE;
DWORD iModeBest = 0xffff;
for( iModeNew = 0; iModeNew < pD3DDeviceInfo->dwNumModes; iModeNew++ )
{
// Don't pick the same mode we currently have
if( iModeNew == iModeCur )
continue;
// Get info about new mode
pD3DModeInfoNew = &pD3DDeviceInfo->modes[iModeNew];
dwWidthNew = pD3DModeInfoNew->Width;
dwHeightNew = pD3DModeInfoNew->Height;
dwNumPixelsNew = dwWidthNew * dwHeightNew;
d3dfmtNew = pD3DModeInfoNew->Format;
b32BitNew = (d3dfmtNew == D3DFMT_A8R8G8B8 ||
d3dfmtNew == D3DFMT_X8R8G8B8);
// If we're currently 32-bit and new mode is same width/height and 16-bit, take it
if( b32BitCur &&
!b32BitNew &&
pD3DModeInfoNew->Width == dwWidthCur &&
pD3DModeInfoNew->Height == dwHeightCur)
{
pD3DDeviceInfo->dwCurrentMode = iModeNew;
return TRUE;
}
// If new mode is smaller than current mode, see if it's our best so far
if( dwNumPixelsNew < dwNumPixelsCur )
{
// If current best is 32-bit, new mode needs to be bigger to be best
if( b32BitBest && (dwNumPixelsNew < dwNumPixelsBest ) )
continue;
// If new mode is bigger or equal to best, make it the best
if( (dwNumPixelsNew > dwNumPixelsBest) ||
(!b32BitBest && b32BitNew) )
{
dwWidthBest = dwWidthNew;
dwHeightBest = dwHeightNew;
dwNumPixelsBest = dwNumPixelsNew;
iModeBest = iModeNew;
b32BitBest = b32BitNew;
}
}
}
if( iModeBest == 0xffff )
return FALSE; // no smaller mode found
pD3DDeviceInfo->dwCurrentMode = iModeBest;
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: CreateWindowedRenderUnit()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::CreateWindowedRenderUnit( RenderUnit* pRenderUnit )
{
HRESULT hr;
UINT iAdapter = pRenderUnit->iAdapter;
D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
DWORD iMonitor = pD3DAdapterInfo->iMonitor;
D3DDeviceInfo* pD3DDeviceInfo;
D3DDEVTYPE curType;
// Find the best device for the primary adapter. Use HAL
// if it's there, otherwise SW, otherwise REF.
pD3DAdapterInfo->dwCurrentDevice = 0xffff; // unless we find something better
curType = D3DDEVTYPE_FORCE_DWORD;
for( DWORD iDevice = 0; iDevice < pD3DAdapterInfo->dwNumDevices; iDevice++)
{
pD3DDeviceInfo = &pD3DAdapterInfo->devices[iDevice];
if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_HAL && !pD3DAdapterInfo->bDisableHW &&
pD3DDeviceInfo->bCanDoWindowed )
{
pD3DAdapterInfo->dwCurrentDevice = iDevice;
curType = D3DDEVTYPE_HAL;
break;
}
else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW &&
pD3DDeviceInfo->bCanDoWindowed )
{
pD3DAdapterInfo->dwCurrentDevice = iDevice;
curType = D3DDEVTYPE_SW;
// but keep looking
}
else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_REF && m_bAllowRef && curType != D3DDEVTYPE_SW )
{
pD3DAdapterInfo->dwCurrentDevice = iDevice;
curType = D3DDEVTYPE_REF;
// but keep looking
}
}
if( pD3DAdapterInfo->dwCurrentDevice == 0xffff )
return D3DAPPERR_NOHARDWAREDEVICE;
pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
D3DWindowedModeInfo D3DWindowedModeInfo;
D3DWindowedModeInfo.DisplayFormat = pD3DAdapterInfo->d3ddmDesktop.Format;
D3DWindowedModeInfo.BackBufferFormat = pD3DAdapterInfo->d3ddmDesktop.Format;
if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
{
D3DWindowedModeInfo.BackBufferFormat = D3DFMT_A8R8G8B8;
if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
{
D3DWindowedModeInfo.BackBufferFormat = D3DFMT_X8R8G8B8;
if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
{
D3DWindowedModeInfo.BackBufferFormat = D3DFMT_A1R5G5B5;
if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
{
D3DWindowedModeInfo.BackBufferFormat = D3DFMT_R5G6B5;
if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
{
return E_FAIL;
}
}
}
}
}
pRenderUnit->DeviceType = pD3DDeviceInfo->DeviceType;
pRenderUnit->dwBehavior = D3DWindowedModeInfo.dwBehavior;
pRenderUnit->iMonitor = iMonitor;
pRenderUnit->d3dpp.BackBufferWidth = 0;
pRenderUnit->d3dpp.BackBufferHeight = 0;
pRenderUnit->d3dpp.Windowed = TRUE;
pRenderUnit->d3dpp.FullScreen_RefreshRateInHz = 0;
pRenderUnit->d3dpp.FullScreen_PresentationInterval = 0;
pRenderUnit->d3dpp.BackBufferFormat = D3DWindowedModeInfo.BackBufferFormat;
pRenderUnit->d3dpp.AutoDepthStencilFormat = D3DWindowedModeInfo.DepthStencilFormat;
pRenderUnit->d3dpp.BackBufferCount = 1;
pRenderUnit->d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
pRenderUnit->d3dpp.SwapEffect = m_SwapEffectWindowed;
pRenderUnit->d3dpp.hDeviceWindow = pD3DAdapterInfo->hWndDevice;
pRenderUnit->d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
pRenderUnit->d3dpp.Flags = 0;
// Create device
hr = m_pD3D->CreateDevice( iAdapter, pRenderUnit->DeviceType, m_hWnd,
pRenderUnit->dwBehavior, &pRenderUnit->d3dpp, &pRenderUnit->pd3dDevice );
if ( FAILED(hr) )
{
return hr;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: UpdateDeviceStats()
// Desc: Store device description
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::UpdateDeviceStats()
{
DWORD iRenderUnit;
RenderUnit* pRenderUnit;
for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
if( pRenderUnit->DeviceType == D3DDEVTYPE_REF )
lstrcpy( pRenderUnit->strDeviceStats, TEXT("REF") );
else if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
lstrcpy( pRenderUnit->strDeviceStats, TEXT("HAL") );
else if( pRenderUnit->DeviceType == D3DDEVTYPE_SW )
lstrcpy( pRenderUnit->strDeviceStats, TEXT("SW") );
if( pRenderUnit->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
pRenderUnit->dwBehavior & D3DCREATE_PUREDEVICE )
{
if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
lstrcat( pRenderUnit->strDeviceStats, TEXT(" (pure hw vp)") );
else
lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated pure hw vp)") );
}
else if( pRenderUnit->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING )
{
if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
lstrcat( pRenderUnit->strDeviceStats, TEXT(" (hw vp)") );
else
lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated hw vp)") );
}
else if( pRenderUnit->dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING )
{
if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
lstrcat( pRenderUnit->strDeviceStats, TEXT(" (mixed vp)") );
else
lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated mixed vp)") );
}
else if( pRenderUnit->dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
{
lstrcat( pRenderUnit->strDeviceStats, TEXT(" (sw vp)") );
}
if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
{
lstrcat( pRenderUnit->strDeviceStats, TEXT(": ") );
TCHAR szDescription[300];
DXUtil_ConvertAnsiStringToGeneric( szDescription,
m_Adapters[pRenderUnit->iAdapter]->d3dAdapterIdentifier.Description, 300 );
lstrcat( pRenderUnit->strDeviceStats, szDescription );
}
}
}
//-----------------------------------------------------------------------------
// Name: SwitchToRenderUnit()
// Desc: Updates internal variables and notifies client that we are switching
// to a new RenderUnit / D3D device.
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::SwitchToRenderUnit( UINT iRenderUnit )
{
RenderUnit* pRenderUnit = &m_RenderUnits[iRenderUnit];
MonitorInfo* pMonitorInfo = &m_Monitors[pRenderUnit->iMonitor];
m_pd3dDevice = pRenderUnit->pd3dDevice;
if( !m_bWindowed )
m_rcRenderCurDevice = pMonitorInfo->rcScreen;
if( m_pd3dDevice != NULL )
{
// Store render target surface desc
LPDIRECT3DSURFACE8 pBackBuffer;
m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
pBackBuffer->Release();
}
lstrcpy( m_strDeviceStats, pRenderUnit->strDeviceStats );
lstrcpy( m_strFrameStats, pRenderUnit->strFrameStats );
// Notify the client to switch to this device
SetDevice(iRenderUnit);
}
//-----------------------------------------------------------------------------
// Name: SetProjectionMatrix()
// Desc: This function sets up an appropriate projection matrix to support
// rendering the appropriate parts of the scene to each screen.
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::SetProjectionMatrix( FLOAT fNear, FLOAT fFar )
{
D3DXMATRIX mat;
INT cx, cy;
INT dx, dy;
INT dd;
FLOAT l,r,t,b;
if( m_bAllScreensSame )
{
cx = (m_rcRenderCurDevice.right + m_rcRenderCurDevice.left) / 2;
cy = (m_rcRenderCurDevice.bottom + m_rcRenderCurDevice.top) / 2;
dx = m_rcRenderCurDevice.right - m_rcRenderCurDevice.left;
dy = m_rcRenderCurDevice.bottom - m_rcRenderCurDevice.top;
}
else
{
cx = (m_rcRenderTotal.right + m_rcRenderTotal.left) / 2;
cy = (m_rcRenderTotal.bottom + m_rcRenderTotal.top) / 2;
dx = m_rcRenderTotal.right - m_rcRenderTotal.left;
dy = m_rcRenderTotal.bottom - m_rcRenderTotal.top;
}
dd = (dx > dy ? dy : dx);
l = FLOAT(m_rcRenderCurDevice.left - cx) / (FLOAT)(dd);
r = FLOAT(m_rcRenderCurDevice.right - cx) / (FLOAT)(dd);
t = FLOAT(m_rcRenderCurDevice.top - cy) / (FLOAT)(dd);
b = FLOAT(m_rcRenderCurDevice.bottom - cy) / (FLOAT)(dd);
l = fNear * l;
r = fNear * r;
t = fNear * t;
b = fNear * b;
D3DXMatrixPerspectiveOffCenterLH( &mat, l, r, t, b, fNear, fFar );
return m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &mat );
}
//-----------------------------------------------------------------------------
// Name: SortModesCallback()
// Desc: Callback function for sorting display modes (used by BuildDeviceList).
//-----------------------------------------------------------------------------
static int SortModesCallback( const VOID* arg1, const VOID* arg2 )
{
D3DDISPLAYMODE* p1 = (D3DDISPLAYMODE*)arg1;
D3DDISPLAYMODE* p2 = (D3DDISPLAYMODE*)arg2;
if( p1->Width < p2->Width ) return -1;
if( p1->Width > p2->Width ) return +1;
if( p1->Height < p2->Height ) return -1;
if( p1->Height > p2->Height ) return +1;
if( p1->Format > p2->Format ) return -1;
if( p1->Format < p2->Format ) return +1;
return 0;
}
//-----------------------------------------------------------------------------
// Name: BuildDeviceList()
// Desc: Builds a list of all available adapters, devices, and modes.
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::BuildDeviceList()
{
DWORD dwNumDeviceTypes;
const TCHAR* strDeviceDescs[] = { TEXT("HAL"), TEXT("SW"), TEXT("REF") };
const D3DDEVTYPE DeviceTypes[] = { D3DDEVTYPE_HAL, D3DDEVTYPE_SW, D3DDEVTYPE_REF };
if( m_bAllowRef )
dwNumDeviceTypes = 3;
else
dwNumDeviceTypes = 2;
HMONITOR hMonitor = NULL;
BOOL bHALExists = FALSE;
BOOL bHALIsWindowedCompatible = FALSE;
BOOL bHALIsDesktopCompatible = FALSE;
BOOL bHALIsSampleCompatible = FALSE;
// Loop through all the adapters on the system (usually, there's just one
// unless more than one graphics card is present).
for( UINT iAdapter = 0; iAdapter < m_pD3D->GetAdapterCount(); iAdapter++ )
{
// Fill in adapter info
if( m_Adapters[m_dwNumAdapters] == NULL )
{
m_Adapters[m_dwNumAdapters] = new D3DAdapterInfo;
if( m_Adapters[m_dwNumAdapters] == NULL )
return E_OUTOFMEMORY;
ZeroMemory( m_Adapters[m_dwNumAdapters], sizeof(D3DAdapterInfo) );
}
D3DAdapterInfo* pAdapter = m_Adapters[m_dwNumAdapters];
m_pD3D->GetAdapterIdentifier( iAdapter, D3DENUM_NO_WHQL_LEVEL, &pAdapter->d3dAdapterIdentifier );
m_pD3D->GetAdapterDisplayMode( iAdapter, &pAdapter->d3ddmDesktop );
pAdapter->dwNumDevices = 0;
pAdapter->dwCurrentDevice = 0;
pAdapter->bLeaveBlack = FALSE;
pAdapter->iMonitor = NO_MONITOR;
// Find the MonitorInfo that corresponds to this adapter. If the monitor
// is disabled, the adapter has a NULL HMONITOR and we cannot find the
// corresponding MonitorInfo. (Well, if one monitor was disabled, we
// could link the one MonitorInfo with a NULL HMONITOR to the one
// D3DAdapterInfo with a NULL HMONITOR, but if there are more than one,
// we can't link them, so it's safer not to ever try.)
hMonitor = m_pD3D->GetAdapterMonitor( iAdapter );
if( hMonitor != NULL )
{
for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
{
MonitorInfo* pMonitorInfo;
pMonitorInfo = &m_Monitors[iMonitor];
if( pMonitorInfo->hMonitor == hMonitor )
{
pAdapter->iMonitor = iMonitor;
pMonitorInfo->iAdapter = iAdapter;
break;
}
}
}
// Enumerate all display modes on this adapter
D3DDISPLAYMODE modes[100];
D3DFORMAT formats[20];
DWORD dwNumFormats = 0;
DWORD dwNumModes = 0;
DWORD dwNumAdapterModes = m_pD3D->GetAdapterModeCount( iAdapter );
// Add the adapter's current desktop format to the list of formats
formats[dwNumFormats++] = pAdapter->d3ddmDesktop.Format;
for( UINT iMode = 0; iMode < dwNumAdapterModes; iMode++ )
{
// Get the display mode attributes
D3DDISPLAYMODE DisplayMode;
m_pD3D->EnumAdapterModes( iAdapter, iMode, &DisplayMode );
// Filter out low-resolution modes
if( DisplayMode.Width < 640 || DisplayMode.Height < 400 )
continue;
// Check if the mode already exists (to filter out refresh rates)
for( DWORD m=0L; m<dwNumModes; m++ )
{
if( ( modes[m].Width == DisplayMode.Width ) &&
( modes[m].Height == DisplayMode.Height ) &&
( modes[m].Format == DisplayMode.Format ) )
break;
}
// If we found a new mode, add it to the list of modes
if( m == dwNumModes )
{
modes[dwNumModes].Width = DisplayMode.Width;
modes[dwNumModes].Height = DisplayMode.Height;
modes[dwNumModes].Format = DisplayMode.Format;
modes[dwNumModes].RefreshRate = 0;
dwNumModes++;
// Check if the mode's format already exists
for( DWORD f=0; f<dwNumFormats; f++ )
{
if( DisplayMode.Format == formats[f] )
break;
}
// If the format is new, add it to the list
if( f== dwNumFormats )
formats[dwNumFormats++] = DisplayMode.Format;
}
}
// Sort the list of display modes (by format, then width, then height)
qsort( modes, dwNumModes, sizeof(D3DDISPLAYMODE), SortModesCallback );
// Add devices to adapter
for( UINT iDevice = 0; iDevice < dwNumDeviceTypes; iDevice++ )
{
// Fill in device info
D3DDeviceInfo* pDevice;
pDevice = &pAdapter->devices[pAdapter->dwNumDevices];
pDevice->DeviceType = DeviceTypes[iDevice];
m_pD3D->GetDeviceCaps( iAdapter, DeviceTypes[iDevice], &pDevice->d3dCaps );
pDevice->strDesc = strDeviceDescs[iDevice];
pDevice->dwNumModes = 0;
pDevice->dwCurrentMode = 0;
pDevice->bCanDoWindowed = FALSE;
pDevice->bWindowed = FALSE;
pDevice->MultiSampleType = D3DMULTISAMPLE_NONE;
// Examine each format supported by the adapter to see if it will
// work with this device and meets the needs of the application.
BOOL bFormatConfirmed[20];
DWORD dwBehavior[20];
D3DFORMAT fmtDepthStencil[20];
for( DWORD f=0; f<dwNumFormats; f++ )
{
bFormatConfirmed[f] = FALSE;
fmtDepthStencil[f] = D3DFMT_UNKNOWN;
// Skip formats that cannot be used as render targets on this device
if( FAILED( m_pD3D->CheckDeviceType( iAdapter, pDevice->DeviceType,
formats[f], formats[f], FALSE ) ) )
continue;
if( pDevice->DeviceType == D3DDEVTYPE_SW )
{
// This system has a SW device
pAdapter->bHasSW = TRUE;
}
if( pDevice->DeviceType == D3DDEVTYPE_HAL )
{
// This system has a HAL device
bHALExists = TRUE;
pAdapter->bHasHAL = TRUE;
if( pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED )
{
// HAL can run in a window for some mode
bHALIsWindowedCompatible = TRUE;
if( f == 0 )
{
// HAL can run in a window for the current desktop mode
bHALIsDesktopCompatible = TRUE;
}
}
}
// Confirm the device/format for HW vertex processing
if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
{
if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
{
dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING |
D3DCREATE_PUREDEVICE;
if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
formats[f] ) ) )
bFormatConfirmed[f] = TRUE;
}
if ( FALSE == bFormatConfirmed[f] )
{
dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING;
if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
formats[f] ) ) )
bFormatConfirmed[f] = TRUE;
}
if ( FALSE == bFormatConfirmed[f] )
{
dwBehavior[f] = D3DCREATE_MIXED_VERTEXPROCESSING;
if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
formats[f] ) ) )
bFormatConfirmed[f] = TRUE;
}
}
// Confirm the device/format for SW vertex processing
if( FALSE == bFormatConfirmed[f] )
{
dwBehavior[f] = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
formats[f] ) ) )
bFormatConfirmed[f] = TRUE;
}
if( bFormatConfirmed[f] && m_bMultithreaded )
{
dwBehavior[f] |= D3DCREATE_MULTITHREADED;
}
// Find a suitable depth/stencil buffer format for this device/format
if( bFormatConfirmed[f] && m_bUseDepthBuffer )
{
if( !FindDepthStencilFormat( iAdapter, pDevice->DeviceType,
formats[f], &fmtDepthStencil[f] ) )
{
bFormatConfirmed[f] = FALSE;
}
}
}
// Add all enumerated display modes with confirmed formats to the
// device's list of valid modes
for( DWORD m=0L; m<dwNumModes; m++ )
{
for( DWORD f=0; f<dwNumFormats; f++ )
{
if( modes[m].Format == formats[f] )
{
if( bFormatConfirmed[f] == TRUE )
{
// Add this mode to the device's list of valid modes
pDevice->modes[pDevice->dwNumModes].Width = modes[m].Width;
pDevice->modes[pDevice->dwNumModes].Height = modes[m].Height;
pDevice->modes[pDevice->dwNumModes].Format = modes[m].Format;
pDevice->modes[pDevice->dwNumModes].dwBehavior = dwBehavior[f];
pDevice->modes[pDevice->dwNumModes].DepthStencilFormat = fmtDepthStencil[f];
pDevice->dwNumModes++;
if( pDevice->DeviceType == D3DDEVTYPE_HAL )
bHALIsSampleCompatible = TRUE;
}
}
}
}
// Select any 640x480 mode for default (but prefer a 16-bit mode)
for( m=0; m<pDevice->dwNumModes; m++ )
{
if( pDevice->modes[m].Width==640 && pDevice->modes[m].Height==480 )
{
pDevice->dwCurrentMode = m;
if( pDevice->modes[m].Format == D3DFMT_R5G6B5 ||
pDevice->modes[m].Format == D3DFMT_X1R5G5B5 ||
pDevice->modes[m].Format == D3DFMT_A1R5G5B5 )
{
break;
}
}
}
// Check if the device is compatible with the desktop display mode
// (which was added initially as formats[0])
if( bFormatConfirmed[0] && (pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) )
{
pDevice->bCanDoWindowed = TRUE;
pDevice->bWindowed = TRUE;
}
// If valid modes were found, keep this device
if( pDevice->dwNumModes > 0 )
{
pAdapter->dwNumDevices++;
if( pDevice->DeviceType == D3DDEVTYPE_SW )
pAdapter->bHasAppCompatSW = TRUE;
else if( pDevice->DeviceType == D3DDEVTYPE_HAL )
pAdapter->bHasAppCompatHAL = TRUE;
}
}
// If valid devices were found, keep this adapter
// Count adapters even if no devices, so we can throw up blank windows on them
// if( pAdapter->dwNumDevices > 0 )
m_dwNumAdapters++;
}
/*
// Return an error if no compatible devices were found
if( 0L == m_dwNumAdapters )
return D3DAPPERR_NOCOMPATIBLEDEVICES;
// Pick a default device that can render into a window
// (This code assumes that the HAL device comes before the REF
// device in the device array).
for( DWORD a=0; a<m_dwNumAdapters; a++ )
{
for( DWORD d=0; d < m_Adapters[a]->dwNumDevices; d++ )
{
if( m_Adapters[a]->devices[d].bWindowed )
{
m_Adapters[a]->dwCurrentDevice = d;
m_dwAdapter = a;
m_bWindowed = TRUE;
// Display a warning message
if( m_Adapters[a]->devices[d].DeviceType == D3DDEVTYPE_REF )
{
if( !bHALExists )
DisplayErrorMsg( D3DAPPERR_NOHARDWAREDEVICE, MSGWARN_SWITCHEDTOREF );
else if( !bHALIsSampleCompatible )
DisplayErrorMsg( D3DAPPERR_HALNOTCOMPATIBLE, MSGWARN_SWITCHEDTOREF );
else if( !bHALIsWindowedCompatible )
DisplayErrorMsg( D3DAPPERR_NOWINDOWEDHAL, MSGWARN_SWITCHEDTOREF );
else if( !bHALIsDesktopCompatible )
DisplayErrorMsg( D3DAPPERR_NODESKTOPHAL, MSGWARN_SWITCHEDTOREF );
else // HAL is desktop compatible, but not sample compatible
DisplayErrorMsg( D3DAPPERR_NOHALTHISMODE, MSGWARN_SWITCHEDTOREF );
}
return S_OK;
}
}
}
return D3DAPPERR_NOWINDOWABLEDEVICES;
*/
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: CheckWindowedFormat()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::CheckWindowedFormat( UINT iAdapter, D3DWindowedModeInfo* pD3DWindowedModeInfo )
{
HRESULT hr;
D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
D3DDeviceInfo* pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
BOOL bFormatConfirmed = FALSE;
if( FAILED( hr = m_pD3D->CheckDeviceType( iAdapter, pD3DDeviceInfo->DeviceType,
pD3DAdapterInfo->d3ddmDesktop.Format, pD3DWindowedModeInfo->BackBufferFormat, TRUE ) ) )
{
return hr;
}
// Confirm the device/format for HW vertex processing
if( pD3DDeviceInfo->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
{
if( pD3DDeviceInfo->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
{
pD3DWindowedModeInfo->dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING |
D3DCREATE_PUREDEVICE;
if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
pD3DWindowedModeInfo->BackBufferFormat ) ) )
bFormatConfirmed = TRUE;
}
if ( !bFormatConfirmed )
{
pD3DWindowedModeInfo->dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
pD3DWindowedModeInfo->BackBufferFormat ) ) )
bFormatConfirmed = TRUE;
}
if ( !bFormatConfirmed )
{
pD3DWindowedModeInfo->dwBehavior = D3DCREATE_MIXED_VERTEXPROCESSING;
if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
pD3DWindowedModeInfo->BackBufferFormat ) ) )
bFormatConfirmed = TRUE;
}
}
// Confirm the device/format for SW vertex processing
if( !bFormatConfirmed )
{
pD3DWindowedModeInfo->dwBehavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
pD3DWindowedModeInfo->BackBufferFormat ) ) )
bFormatConfirmed = TRUE;
}
if( bFormatConfirmed && m_bMultithreaded )
{
pD3DWindowedModeInfo->dwBehavior |= D3DCREATE_MULTITHREADED;
}
// Find a suitable depth/stencil buffer format for this device/format
if( bFormatConfirmed && m_bUseDepthBuffer )
{
if( !FindDepthStencilFormat( iAdapter, pD3DDeviceInfo->DeviceType,
pD3DWindowedModeInfo->BackBufferFormat, &pD3DWindowedModeInfo->DepthStencilFormat ) )
{
bFormatConfirmed = FALSE;
}
}
if( !bFormatConfirmed )
return E_FAIL;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: FindDepthStencilFormat()
// Desc: Finds a depth/stencil format for the given device that is compatible
// with the render target format and meets the needs of the app.
//-----------------------------------------------------------------------------
BOOL CD3DScreensaver::FindDepthStencilFormat( UINT iAdapter, D3DDEVTYPE DeviceType,
D3DFORMAT TargetFormat, D3DFORMAT* pDepthStencilFormat )
{
if( m_dwMinDepthBits <= 16 && m_dwMinStencilBits == 0 )
{
if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
{
if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
TargetFormat, TargetFormat, D3DFMT_D16 ) ) )
{
*pDepthStencilFormat = D3DFMT_D16;
return TRUE;
}
}
}
if( m_dwMinDepthBits <= 15 && m_dwMinStencilBits <= 1 )
{
if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 ) ) )
{
if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
TargetFormat, TargetFormat, D3DFMT_D15S1 ) ) )
{
*pDepthStencilFormat = D3DFMT_D15S1;
return TRUE;
}
}
}
if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits == 0 )
{
if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 ) ) )
{
if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
TargetFormat, TargetFormat, D3DFMT_D24X8 ) ) )
{
*pDepthStencilFormat = D3DFMT_D24X8;
return TRUE;
}
}
}
if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 8 )
{
if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) )
{
if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
TargetFormat, TargetFormat, D3DFMT_D24S8 ) ) )
{
*pDepthStencilFormat = D3DFMT_D24S8;
return TRUE;
}
}
}
if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 4 )
{
if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 ) ) )
{
if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
TargetFormat, TargetFormat, D3DFMT_D24X4S4 ) ) )
{
*pDepthStencilFormat = D3DFMT_D24X4S4;
return TRUE;
}
}
}
if( m_dwMinDepthBits <= 32 && m_dwMinStencilBits == 0 )
{
if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D32 ) ) )
{
if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
TargetFormat, TargetFormat, D3DFMT_D32 ) ) )
{
*pDepthStencilFormat = D3DFMT_D32;
return TRUE;
}
}
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name: Cleanup3DEnvironment()
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::Cleanup3DEnvironment()
{
RenderUnit* pRenderUnit;
for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
SwitchToRenderUnit( iRenderUnit );
if( pRenderUnit->bDeviceObjectsRestored )
{
InvalidateDeviceObjects();
pRenderUnit->bDeviceObjectsRestored = FALSE;
}
if( pRenderUnit->bDeviceObjectsInited )
{
DeleteDeviceObjects();
pRenderUnit->bDeviceObjectsInited = FALSE;
}
SAFE_RELEASE(m_pd3dDevice);
}
m_dwNumRenderUnits = 0;
SAFE_RELEASE(m_pD3D);
}
//-----------------------------------------------------------------------------
// Name: Render3DEnvironment()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::Render3DEnvironment()
{
HRESULT hr;
RenderUnit* pRenderUnit;
D3DAdapterInfo* pAdapterInfo;
m_fTime = DXUtil_Timer( TIMER_GETAPPTIME );
m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
// Tell client to update the world
FrameMove();
UpdateFrameStats();
for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
pAdapterInfo = m_Adapters[pRenderUnit->iAdapter];
SwitchToRenderUnit( iRenderUnit );
if( m_pd3dDevice == NULL )
continue;
// Test the cooperative level to see if it's okay to render
if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
{
// If the device was lost, do not render until we get it back
if( D3DERR_DEVICELOST == hr )
return S_OK;
// Check if the device needs to be reset.
if( D3DERR_DEVICENOTRESET == hr )
{
// If we are windowed, read the desktop mode and use the same format for
// the back buffer
if( m_bWindowed )
{
m_pD3D->GetAdapterDisplayMode( pRenderUnit->iAdapter, &pAdapterInfo->d3ddmDesktop );
// m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
}
if( pRenderUnit->bDeviceObjectsRestored )
{
InvalidateDeviceObjects();
pRenderUnit->bDeviceObjectsRestored = FALSE;
}
if( FAILED( hr = m_pd3dDevice->Reset( &pRenderUnit->d3dpp ) ) )
{
m_bErrorMode = TRUE;
}
else
{
if( FAILED( hr = RestoreDeviceObjects() ) )
{
m_bErrorMode = TRUE;
}
else
{
pRenderUnit->bDeviceObjectsRestored = TRUE;
}
}
}
}
// Tell client to render using the current device
Render();
}
// Call Present() in a separate loop once all rendering is done
// so multiple monitors are as closely synced visually as possible
for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
SwitchToRenderUnit( iRenderUnit );
// Present the results of the rendering to the screen
m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: UpdateErrorBox()
// Desc: Update the box that shows the error message
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::UpdateErrorBox()
{
MonitorInfo* pMonitorInfo;
HWND hwnd;
RECT rcBounds;
static DWORD dwTimeLast = 0;
DWORD dwTimeNow;
FLOAT fTimeDelta;
// Make sure all the RenderUnits / D3D devices have been torn down
// so the error box is visible
if( m_bErrorMode && m_dwNumRenderUnits > 0 )
{
Cleanup3DEnvironment();
}
// Update timing to determine how much to move error box
if( dwTimeLast == 0 )
dwTimeLast = timeGetTime();
dwTimeNow = timeGetTime();
fTimeDelta = (FLOAT)(dwTimeNow - dwTimeLast) / 1000.0f;
dwTimeLast = dwTimeNow;
// Load error string if necessary
if( m_szError[0] == TEXT('\0') )
{
GetTextForError( m_hrError, m_szError, sizeof(m_szError) / sizeof(TCHAR) );
}
for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
{
pMonitorInfo = &m_Monitors[iMonitor];
hwnd = pMonitorInfo->hWnd;
if( hwnd == NULL )
continue;
if( m_SaverMode == sm_full )
{
rcBounds = pMonitorInfo->rcScreen;
ScreenToClient( hwnd, (POINT*)&rcBounds.left );
ScreenToClient( hwnd, (POINT*)&rcBounds.right );
}
else
{
rcBounds = m_rcRenderTotal;
}
if( pMonitorInfo->widthError == 0 )
{
if( m_SaverMode == sm_preview )
{
pMonitorInfo->widthError = (float) (rcBounds.right - rcBounds.left);
pMonitorInfo->heightError = (float) (rcBounds.bottom - rcBounds.top);
pMonitorInfo->xError = 0.0f;
pMonitorInfo->yError = 0.0f;
pMonitorInfo->xVelError = 0.0f;
pMonitorInfo->yVelError = 0.0f;
InvalidateRect( hwnd, NULL, FALSE ); // Invalidate the hwnd so it gets drawn
UpdateWindow( hwnd );
}
else
{
pMonitorInfo->widthError = 300;
pMonitorInfo->heightError = 150;
pMonitorInfo->xError = (rcBounds.right + rcBounds.left - pMonitorInfo->widthError) / 2.0f;
pMonitorInfo->yError = (rcBounds.bottom + rcBounds.top - pMonitorInfo->heightError) / 2.0f;
pMonitorInfo->xVelError = (rcBounds.right - rcBounds.left) / 10.0f;
pMonitorInfo->yVelError = (rcBounds.bottom - rcBounds.top) / 20.0f;
}
}
else
{
if( m_SaverMode != sm_preview )
{
RECT rcOld;
RECT rcNew;
SetRect( &rcOld, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
(INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
(INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
// Update rect velocity
if( (pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta +
pMonitorInfo->widthError > rcBounds.right && pMonitorInfo->xVelError > 0.0f) ||
(pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta <
rcBounds.left && pMonitorInfo->xVelError < 0.0f) )
{
pMonitorInfo->xVelError = -pMonitorInfo->xVelError;
}
if( (pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta +
pMonitorInfo->heightError > rcBounds.bottom && pMonitorInfo->yVelError > 0.0f) ||
(pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta <
rcBounds.top && pMonitorInfo->yVelError < 0.0f) )
{
pMonitorInfo->yVelError = -pMonitorInfo->yVelError;
}
// Update rect position
pMonitorInfo->xError += pMonitorInfo->xVelError * fTimeDelta;
pMonitorInfo->yError += pMonitorInfo->yVelError * fTimeDelta;
SetRect( &rcNew, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
(INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
(INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
if( rcOld.left != rcNew.left || rcOld.top != rcNew.top )
{
InvalidateRect( hwnd, &rcOld, FALSE ); // Invalidate old rect so it gets erased
InvalidateRect( hwnd, &rcNew, FALSE ); // Invalidate new rect so it gets drawn
UpdateWindow( hwnd );
}
}
}
}
}
//-----------------------------------------------------------------------------
// Name: GetTextForError()
// Desc: Translate an HRESULT error code into a string that can be displayed
// to explain the error. A class derived from CD3DScreensaver can
// provide its own version of this function that provides app-specific
// error translation instead of or in addition to calling this function.
// This function returns TRUE if a specific error was translated, or
// FALSE if no specific translation for the HRESULT was found (though
// it still puts a generic string into pszError).
//-----------------------------------------------------------------------------
BOOL CD3DScreensaver::GetTextForError( HRESULT hr, TCHAR* pszError,
DWORD dwNumChars )
{
const DWORD dwErrorMap[][2] =
{
// HRESULT, stringID
E_FAIL, IDS_ERR_GENERIC,
D3DAPPERR_NODIRECT3D, IDS_ERR_NODIRECT3D,
D3DAPPERR_NOWINDOWEDHAL, IDS_ERR_NOWINDOWEDHAL,
D3DAPPERR_CREATEDEVICEFAILED, IDS_ERR_CREATEDEVICEFAILED,
D3DAPPERR_NOCOMPATIBLEDEVICES, IDS_ERR_NOCOMPATIBLEDEVICES,
D3DAPPERR_NOHARDWAREDEVICE, IDS_ERR_NOHARDWAREDEVICE,
D3DAPPERR_HALNOTCOMPATIBLE, IDS_ERR_HALNOTCOMPATIBLE,
D3DAPPERR_NOHALTHISMODE, IDS_ERR_NOHALTHISMODE,
D3DAPPERR_MEDIANOTFOUND, IDS_ERR_MEDIANOTFOUND,
D3DAPPERR_RESIZEFAILED, IDS_ERR_RESIZEFAILED,
E_OUTOFMEMORY, IDS_ERR_OUTOFMEMORY,
D3DERR_OUTOFVIDEOMEMORY, IDS_ERR_OUTOFVIDEOMEMORY,
D3DAPPERR_NOPREVIEW, IDS_ERR_NOPREVIEW
};
const DWORD dwErrorMapSize = sizeof(dwErrorMap) / sizeof(DWORD[2]);
DWORD iError;
DWORD resid = 0;
for( iError = 0; iError < dwErrorMapSize; iError++ )
{
if( hr == (HRESULT)dwErrorMap[iError][0] )
{
resid = dwErrorMap[iError][1];
}
}
if( resid == 0 )
{
resid = IDS_ERR_GENERIC;
}
LoadString( NULL, resid, pszError, dwNumChars );
if( resid == IDS_ERR_GENERIC )
return FALSE;
else
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: UpdateFrameStats()
// Desc: Keep track of the frame count
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::UpdateFrameStats()
{
UINT iRenderUnit;
RenderUnit* pRenderUnit;
UINT iAdapter;
static FLOAT fLastTime = 0.0f;
static DWORD dwFrames = 0L;
FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
++dwFrames;
// Update the scene stats once per second
if( fTime - fLastTime > 1.0f )
{
m_fFPS = dwFrames / (fTime - fLastTime);
fLastTime = fTime;
dwFrames = 0L;
for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
{
pRenderUnit = &m_RenderUnits[iRenderUnit];
iAdapter = pRenderUnit->iAdapter;
// Get adapter's current mode so we can report
// bit depth (back buffer depth may be unknown)
D3DDISPLAYMODE mode;
m_pD3D->GetAdapterDisplayMode( iAdapter, &mode );
_stprintf( pRenderUnit->strFrameStats, TEXT("%.02f fps (%dx%dx%d)"), m_fFPS,
mode.Width, mode.Height,
mode.Format==D3DFMT_X8R8G8B8?32:16 );
if( m_bUseDepthBuffer )
{
D3DAdapterInfo* pAdapterInfo = m_Adapters[iAdapter];
D3DDeviceInfo* pDeviceInfo = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
D3DModeInfo* pModeInfo = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
switch( pModeInfo->DepthStencilFormat )
{
case D3DFMT_D16:
lstrcat( pRenderUnit->strFrameStats, TEXT(" (D16)") );
break;
case D3DFMT_D15S1:
lstrcat( pRenderUnit->strFrameStats, TEXT(" (D15S1)") );
break;
case D3DFMT_D24X8:
lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24X8)") );
break;
case D3DFMT_D24S8:
lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24S8)") );
break;
case D3DFMT_D24X4S4:
lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24X4S4)") );
break;
case D3DFMT_D32:
lstrcat( pRenderUnit->strFrameStats, TEXT(" (D32)") );
break;
}
}
}
}
}
//-----------------------------------------------------------------------------
// Name: DoPaint()
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::DoPaint(HWND hwnd, HDC hdc)
{
HMONITOR hMonitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST );
MonitorInfo* pMonitorInfo = NULL;
for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++)
{
pMonitorInfo = &m_Monitors[iMonitor];
if( pMonitorInfo->hMonitor == hMonitor )
break;
}
if( pMonitorInfo == NULL || iMonitor == m_dwNumMonitors )
return;
// Draw the error message box
HBRUSH hbrBlack = (HBRUSH)GetStockObject(BLACK_BRUSH);
RECT rc;
SetRect( &rc, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
(INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
(INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
FillRect(hdc, &rc, (HBRUSH)(COLOR_WINDOW+1));
if( hbrBlack != NULL )
FrameRect(hdc, &rc, hbrBlack);
RECT rc2;
int height;
rc2 = rc;
height = DrawText(hdc, m_szError, -1, &rc, DT_WORDBREAK | DT_CENTER | DT_CALCRECT );
rc = rc2;
rc2.top = (rc.bottom + rc.top - height) / 2;
DrawText(hdc, m_szError, -1, &rc2, DT_WORDBREAK | DT_CENTER );
// Erase everywhere except the error message box
ExcludeClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom );
rc = pMonitorInfo->rcScreen;
ScreenToClient( hwnd, (POINT*)&rc.left );
ScreenToClient( hwnd, (POINT*)&rc.right );
if( hbrBlack != NULL )
FillRect(hdc, &rc, hbrBlack );
}
//-----------------------------------------------------------------------------
// Name: ChangePassword()
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::ChangePassword()
{
// Load the password change DLL
HINSTANCE mpr = LoadLibrary( TEXT("MPR.DLL") );
if ( mpr != NULL )
{
// Grab the password change function from it
typedef DWORD (PASCAL *PWCHGPROC)( LPCSTR, HWND, DWORD, LPVOID );
PWCHGPROC pwd = (PWCHGPROC)GetProcAddress( mpr, "PwdChangePasswordA" );
// Do the password change
if ( pwd != NULL )
pwd( "SCRSAVE", m_hWndParent, 0, NULL );
// Free the library
FreeLibrary( mpr );
}
}
//-----------------------------------------------------------------------------
// Name: DisplayErrorMsg()
// Desc: Displays error messages in a message box
//-----------------------------------------------------------------------------
HRESULT CD3DScreensaver::DisplayErrorMsg( HRESULT hr, DWORD dwType )
{
TCHAR strMsg[512];
GetTextForError( hr, strMsg, 512 );
MessageBox( m_hWnd, strMsg, m_strWindowTitle, MB_ICONERROR | MB_OK );
return hr;
}
//-----------------------------------------------------------------------------
// Name: ReadScreenSettings()
// Desc: Read the registry settings that affect how the screens are set up and
// used.
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::ReadScreenSettings( HKEY hkeyParent )
{
TCHAR strKey[100];
DWORD iMonitor;
MonitorInfo* pMonitorInfo;
DWORD iAdapter;
D3DAdapterInfo* pD3DAdapterInfo;
HKEY hkey;
DWORD dwType = REG_DWORD;
DWORD dwLength = sizeof(DWORD);
DWORD dwLength2 = sizeof(GUID);
GUID guidAdapterID;
GUID guidZero;
ZeroMemory( &guidAdapterID, sizeof(GUID) );
ZeroMemory( &guidZero, sizeof(GUID) );
RegQueryValueEx( hkeyParent, TEXT("AllScreensSame"), NULL, &dwType,
(BYTE*)&m_bAllScreensSame, &dwLength);
for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
{
pMonitorInfo = &m_Monitors[iMonitor];
iAdapter = pMonitorInfo->iAdapter;
if( iAdapter == NO_ADAPTER )
continue;
pD3DAdapterInfo = m_Adapters[iAdapter];
wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey,
0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
{
RegQueryValueEx( hkey, TEXT("Adapter ID"), NULL, &dwType,
(BYTE*)&guidAdapterID, &dwLength2);
RegQueryValueEx( hkey, TEXT("Leave Black"), NULL, &dwType,
(BYTE*)&pD3DAdapterInfo->bLeaveBlack, &dwLength);
if( guidAdapterID == pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier ||
guidAdapterID == guidZero )
{
RegQueryValueEx( hkey, TEXT("Disable Hardware"), NULL, &dwType,
(BYTE*)&pD3DAdapterInfo->bDisableHW, &dwLength);
RegQueryValueEx( hkey, TEXT("Width"), NULL, &dwType,
(BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, &dwLength);
RegQueryValueEx( hkey, TEXT("Height"), NULL, &dwType,
(BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, &dwLength);
RegQueryValueEx( hkey, TEXT("Format"), NULL, &dwType,
(BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, &dwLength);
}
RegCloseKey( hkey);
}
}
}
//-----------------------------------------------------------------------------
// Name: WriteScreenSettings()
// Desc: Write the registry settings that affect how the screens are set up and
// used.
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::WriteScreenSettings( HKEY hkeyParent )
{
TCHAR strKey[100];
DWORD iMonitor;
MonitorInfo* pMonitorInfo;
DWORD iAdapter;
D3DAdapterInfo* pD3DAdapterInfo;
HKEY hkey;
RegSetValueEx( hkeyParent, TEXT("AllScreensSame"), NULL, REG_DWORD,
(BYTE*)&m_bAllScreensSame, sizeof(DWORD) );
for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
{
pMonitorInfo = &m_Monitors[iMonitor];
iAdapter = pMonitorInfo->iAdapter;
if( iAdapter == NO_ADAPTER )
continue;
pD3DAdapterInfo = m_Adapters[iAdapter];
wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey,
0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
{
RegSetValueEx( hkey, TEXT("Leave Black"), NULL, REG_DWORD,
(BYTE*)&pD3DAdapterInfo->bLeaveBlack, sizeof(DWORD) );
RegSetValueEx( hkey, TEXT("Disable Hardware"), NULL, REG_DWORD,
(BYTE*)&pD3DAdapterInfo->bDisableHW, sizeof(DWORD) );
RegSetValueEx( hkey, TEXT("Width"), NULL, REG_DWORD,
(BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, sizeof(DWORD) );
RegSetValueEx( hkey, TEXT("Height"), NULL, REG_DWORD,
(BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, sizeof(DWORD) );
RegSetValueEx( hkey, TEXT("Format"), NULL, REG_DWORD,
(BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, sizeof(DWORD) );
RegSetValueEx( hkey, TEXT("Adapter ID"), NULL, REG_BINARY,
(BYTE*)&pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier, sizeof(GUID) );
RegCloseKey( hkey);
}
}
}
//-----------------------------------------------------------------------------
// Name: DoScreenSettingsDialog()
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::DoScreenSettingsDialog( HWND hwndParent )
{
LPCTSTR pstrTemplate;
if( m_dwNumAdapters > 1 && !m_bOneScreenOnly )
pstrTemplate = MAKEINTRESOURCE( IDD_MULTIMONITORSETTINGS );
else
pstrTemplate = MAKEINTRESOURCE( IDD_SINGLEMONITORSETTINGS );
DialogBox(m_hInstance, pstrTemplate, hwndParent, ScreenSettingsDlgProcStub );
}
//-----------------------------------------------------------------------------
// Name: ScreenSettingsDlgProcStub()
// Desc:
//-----------------------------------------------------------------------------
INT_PTR CALLBACK CD3DScreensaver::ScreenSettingsDlgProcStub( HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
return s_pD3DScreensaver->ScreenSettingsDlgProc( hWnd, uMsg, wParam, lParam );
}
// We need to store a copy of the original screen settings so that the user
// can modify those settings in the dialog, then hit Cancel and have the
// original settings restored.
static D3DAdapterInfo* s_AdaptersSave[9];
static BOOL s_bAllScreensSameSave;
//-----------------------------------------------------------------------------
// Name: ScreenSettingsDlgProc()
// Desc:
//-----------------------------------------------------------------------------
INT_PTR CD3DScreensaver::ScreenSettingsDlgProc( HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
HWND hwndTabs = GetDlgItem(hWnd, IDC_MONITORSTAB);
HWND hwndModeList = GetDlgItem(hWnd, IDC_MODESCOMBO);
DWORD iMonitor;
MonitorInfo* pMonitorInfo;
DWORD iAdapter;
switch (uMsg)
{
case WM_INITDIALOG:
{
INT i = 0;
TC_ITEM tie;
TCHAR szFmt[100];
TCHAR sz[100];
GetWindowText(GetDlgItem(hWnd, IDC_TABNAMEFMT), szFmt, 100);
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
{
wsprintf(sz, szFmt, iMonitor + 1);
tie.pszText = sz;
TabCtrl_InsertItem(hwndTabs, i++, &tie);
}
for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
{
s_AdaptersSave[iAdapter] = new D3DAdapterInfo;
if( s_AdaptersSave[iAdapter] != NULL )
*s_AdaptersSave[iAdapter] = *m_Adapters[iAdapter];
}
s_bAllScreensSameSave = m_bAllScreensSame;
SetupAdapterPage(hWnd);
CheckDlgButton(hWnd, IDC_SAME, (m_bAllScreensSame ? BST_CHECKED : BST_UNCHECKED));
}
return TRUE;
case WM_NOTIFY:
{
NMHDR* pnmh = (LPNMHDR)lParam;
UINT code = pnmh->code;
if (code == TCN_SELCHANGE)
{
SetupAdapterPage(hWnd);
}
}
return TRUE;
case WM_COMMAND:
switch( LOWORD( wParam ) )
{
case IDC_SAME:
m_bAllScreensSame = (IsDlgButtonChecked(hWnd, IDC_SAME) == BST_CHECKED);
break;
case IDC_LEAVEBLACK:
case IDC_RENDER:
if( m_bOneScreenOnly )
{
GetBestAdapter( &iAdapter );
iMonitor = m_Adapters[iAdapter]->iMonitor;
}
else
{
iMonitor = TabCtrl_GetCurSel(hwndTabs);
}
pMonitorInfo = &m_Monitors[iMonitor];
iAdapter = pMonitorInfo->iAdapter;
if( IsDlgButtonChecked(hWnd, IDC_LEAVEBLACK) == BST_CHECKED )
{
m_Adapters[iAdapter]->bLeaveBlack = TRUE;
EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), FALSE);
}
else
{
m_Adapters[iAdapter]->bLeaveBlack = FALSE;
EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), TRUE);
}
break;
case IDC_MODESCOMBO:
if (HIWORD(wParam) == CBN_SELCHANGE)
{
DWORD iSel;
DWORD iMode;
if( m_bOneScreenOnly )
{
GetBestAdapter( &iAdapter );
iMonitor = m_Adapters[iAdapter]->iMonitor;
}
else
{
iMonitor = TabCtrl_GetCurSel(hwndTabs);
}
pMonitorInfo = &m_Monitors[iMonitor];
iAdapter = pMonitorInfo->iAdapter;
iSel = ComboBox_GetCurSel( hwndModeList );
if( iSel == 0 )
{
// "Automatic"
m_Adapters[iAdapter]->dwUserPrefWidth = 0;
m_Adapters[iAdapter]->dwUserPrefHeight = 0;
m_Adapters[iAdapter]->d3dfmtUserPrefFormat = D3DFMT_UNKNOWN;
}
else
{
D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
D3DDeviceInfo* pD3DDeviceInfo;
D3DModeInfo* pD3DModeInfo;
pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
iMode = (DWORD)ComboBox_GetItemData( hwndModeList, iSel );
pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
m_Adapters[iAdapter]->dwUserPrefWidth = pD3DModeInfo->Width;
m_Adapters[iAdapter]->dwUserPrefHeight = pD3DModeInfo->Height;
m_Adapters[iAdapter]->d3dfmtUserPrefFormat = pD3DModeInfo->Format;
}
}
break;
case IDC_DISABLEHW:
if( m_bOneScreenOnly )
{
GetBestAdapter( &iAdapter );
iMonitor = m_Adapters[iAdapter]->iMonitor;
}
else
{
iMonitor = TabCtrl_GetCurSel(hwndTabs);
}
pMonitorInfo = &m_Monitors[iMonitor];
iAdapter = pMonitorInfo->iAdapter;
if( IsDlgButtonChecked( hWnd, IDC_DISABLEHW ) == BST_CHECKED )
m_Adapters[iAdapter]->bDisableHW = TRUE;
else
m_Adapters[iAdapter]->bDisableHW = FALSE;
SetupAdapterPage( hWnd );
break;
case IDC_MOREINFO:
{
if( m_bOneScreenOnly )
{
GetBestAdapter( &iAdapter );
iMonitor = m_Adapters[iAdapter]->iMonitor;
}
else
{
iMonitor = TabCtrl_GetCurSel(hwndTabs);
}
pMonitorInfo = &m_Monitors[iMonitor];
iAdapter = pMonitorInfo->iAdapter;
D3DAdapterInfo* pD3DAdapterInfo;
TCHAR szText[500];
if( pMonitorInfo->hMonitor == NULL )
pD3DAdapterInfo = NULL;
else
pD3DAdapterInfo = m_Adapters[pMonitorInfo->iAdapter];
// Accelerated / Unaccelerated settings
BOOL bHasHAL = FALSE;
BOOL bHasAppCompatHAL = FALSE;
BOOL bDisabledHAL = FALSE;
BOOL bHasSW = FALSE;
BOOL bHasAppCompatSW = FALSE;
if( pD3DAdapterInfo != NULL )
{
bHasHAL = pD3DAdapterInfo->bHasHAL;
bHasAppCompatHAL = pD3DAdapterInfo->bHasAppCompatHAL;
bDisabledHAL = pD3DAdapterInfo->bDisableHW;
bHasSW = pD3DAdapterInfo->bHasSW;
bHasAppCompatSW = pD3DAdapterInfo->bHasAppCompatSW;
}
if( bHasHAL && !bDisabledHAL && bHasAppCompatHAL )
{
// Good HAL
LoadString( NULL, IDS_INFO_GOODHAL, szText, 500 );
}
else if( bHasHAL && bDisabledHAL )
{
// Disabled HAL
if( bHasSW && bHasAppCompatSW )
LoadString( NULL, IDS_INFO_DISABLEDHAL_GOODSW, szText, 500 );
else if( bHasSW )
LoadString( NULL, IDS_INFO_DISABLEDHAL_BADSW, szText, 500 );
else
LoadString( NULL, IDS_INFO_DISABLEDHAL_NOSW, szText, 500 );
}
else if( bHasHAL && !bHasAppCompatHAL )
{
// Bad HAL
if( bHasSW && bHasAppCompatSW )
LoadString( NULL, IDS_INFO_BADHAL_GOODSW, szText, 500 );
else if( bHasSW )
LoadString( NULL, IDS_INFO_BADHAL_BADSW, szText, 500 );
else
LoadString( NULL, IDS_INFO_BADHAL_NOSW, szText, 500 );
}
else
{
// No HAL
if( bHasSW && bHasAppCompatSW )
LoadString( NULL, IDS_INFO_NOHAL_GOODSW, szText, 500 );
else if( bHasSW )
LoadString( NULL, IDS_INFO_NOHAL_BADSW, szText, 500 );
else
LoadString( NULL, IDS_INFO_NOHAL_NOSW, szText, 500 );
}
MessageBox( hWnd, szText, pMonitorInfo->strDeviceName, MB_OK | MB_ICONINFORMATION );
break;
}
case IDOK:
for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
{
SAFE_DELETE( s_AdaptersSave[iAdapter] );
}
EndDialog(hWnd, IDOK);
break;
case IDCANCEL:
// Restore member values to original state
for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
{
if( s_AdaptersSave[iAdapter] != NULL )
*m_Adapters[iAdapter] = *s_AdaptersSave[iAdapter];
SAFE_DELETE( s_AdaptersSave[iAdapter] );
}
m_bAllScreensSame = s_bAllScreensSameSave;
EndDialog(hWnd, IDCANCEL);
break;
}
return TRUE;
default:
return FALSE;
}
}
//-----------------------------------------------------------------------------
// Name: SetupAdapterPage()
// Desc: Set up the controls for a given page in the Screen Settings dialog.
//-----------------------------------------------------------------------------
VOID CD3DScreensaver::SetupAdapterPage( HWND hWnd )
{
HWND hwndTabs = GetDlgItem(hWnd, IDC_MONITORSTAB);
HWND hwndModeList = GetDlgItem(hWnd, IDC_MODESCOMBO);
UINT iPage = TabCtrl_GetCurFocus(hwndTabs);
HWND hwndDesc = GetDlgItem(hWnd, IDC_ADAPTERNAME);
MonitorInfo* pMonitorInfo;
D3DAdapterInfo* pD3DAdapterInfo;
D3DDeviceInfo* pD3DDeviceInfo;
D3DModeInfo* pD3DModeInfo;
if( m_bOneScreenOnly )
{
DWORD iAdapter;
GetBestAdapter( &iAdapter );
if( iAdapter != NO_ADAPTER )
{
pD3DAdapterInfo = m_Adapters[iAdapter];
iPage = pD3DAdapterInfo->iMonitor;
}
}
pMonitorInfo = &m_Monitors[iPage];
SetWindowText( hwndDesc, pMonitorInfo->strDeviceName );
if( pMonitorInfo->iAdapter == NO_ADAPTER )
pD3DAdapterInfo = NULL;
else
pD3DAdapterInfo = m_Adapters[pMonitorInfo->iAdapter];
// Accelerated / Unaccelerated settings
BOOL bHasHAL = FALSE;
BOOL bHasAppCompatHAL = FALSE;
BOOL bDisabledHAL = FALSE;
BOOL bHasSW = FALSE;
BOOL bHasAppCompatSW = FALSE;
if( pD3DAdapterInfo != NULL )
{
bHasHAL = pD3DAdapterInfo->bHasHAL;
bHasAppCompatHAL = pD3DAdapterInfo->bHasAppCompatHAL;
bDisabledHAL = pD3DAdapterInfo->bDisableHW;
bHasSW = pD3DAdapterInfo->bHasSW;
bHasAppCompatSW = pD3DAdapterInfo->bHasAppCompatSW;
}
TCHAR szStatus[200];
if( bHasHAL && !bDisabledHAL && bHasAppCompatHAL )
{
LoadString( NULL, IDS_RENDERING_HAL, szStatus, 200 );
}
else if( bHasSW && bHasAppCompatSW )
{
LoadString( NULL, IDS_RENDERING_SW, szStatus, 200 );
}
else
{
LoadString( NULL, IDS_RENDERING_NONE, szStatus, 200 );
}
SetWindowText( GetDlgItem( hWnd, IDC_RENDERING ), szStatus );
if( bHasHAL && bHasAppCompatHAL )
{
EnableWindow( GetDlgItem( hWnd, IDC_DISABLEHW ), TRUE );
CheckDlgButton( hWnd, IDC_DISABLEHW,
pD3DAdapterInfo->bDisableHW ? BST_CHECKED : BST_UNCHECKED );
}
else
{
EnableWindow( GetDlgItem( hWnd, IDC_DISABLEHW ), FALSE );
CheckDlgButton( hWnd, IDC_DISABLEHW, BST_UNCHECKED );
}
if( bHasAppCompatHAL || bHasAppCompatSW )
{
if( pD3DAdapterInfo->bLeaveBlack )
CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_LEAVEBLACK);
else
CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_RENDER);
EnableWindow(GetDlgItem(hWnd, IDC_LEAVEBLACK), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_RENDER), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_SCREENUSAGEBOX), TRUE);
}
else
{
CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_LEAVEBLACK);
EnableWindow(GetDlgItem(hWnd, IDC_LEAVEBLACK), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_RENDER), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_SCREENUSAGEBOX), FALSE);
}
if( IsDlgButtonChecked(hWnd, IDC_LEAVEBLACK) == BST_CHECKED )
{
EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), FALSE);
}
else
{
EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), TRUE);
}
// Mode list
ComboBox_ResetContent( hwndModeList );
if( pD3DAdapterInfo == NULL )
return;
TCHAR strAutomatic[100];
GetWindowText(GetDlgItem(hWnd, IDC_AUTOMATIC), strAutomatic, 100);
ComboBox_AddString( hwndModeList, strAutomatic );
ComboBox_SetItemData( hwndModeList, 0, -1 );
pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
DWORD iSelInitial = 0;
TCHAR strModeFmt[100];
GetWindowText(GetDlgItem(hWnd, IDC_MODEFMT), strModeFmt, 100);
for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++ )
{
DWORD dwBitDepth;
TCHAR strMode[80];
DWORD dwItem;
pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
dwBitDepth = 16;
if( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
pD3DModeInfo->Format == D3DFMT_A8R8G8B8 ||
pD3DModeInfo->Format == D3DFMT_R8G8B8 )
{
dwBitDepth = 32;
}
wsprintf( strMode, strModeFmt, pD3DModeInfo->Width,
pD3DModeInfo->Height, dwBitDepth );
dwItem = ComboBox_AddString( hwndModeList, strMode );
ComboBox_SetItemData( hwndModeList, dwItem, iMode );
if( pD3DModeInfo->Width == pD3DAdapterInfo->dwUserPrefWidth &&
pD3DModeInfo->Height == pD3DAdapterInfo->dwUserPrefHeight &&
pD3DModeInfo->Format == pD3DAdapterInfo->d3dfmtUserPrefFormat )
{
iSelInitial = dwItem;
}
}
ComboBox_SetCurSel( hwndModeList, iSelInitial );
}