I’ve had luck with an ATI and an NVIDIA card in the same system.
Here’s the code I use to open up an OpenGL window based on the display #:
#define VC_EXTRALEAN
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
#include "../../gl_lib/src/gl_lib.h"
#include "os_win32.h"
#include "../../Game/src/Common.h"
#include <vector>
#define STRINGIZE(x) #x
#define STRINGIZE_DEF(x) STRINGIZE(x)
void Sys_PrintGamma( WORD *ramp ) {
for( unsigned int i = 0; i < 256; ++i ) {
printf("%u %u %u
", ramp[i], ramp[i+256], ramp[i+512]);
}
}
int Sys_SetGammaRamp( float Scale, float Offset ) {
unsigned short ramp[3][256];
for (int num=0; num<=255; num++)
{
float fnum=static_cast<float>(num);
ramp[0][num]=__min(65535,static_cast<unsigned int>(fnum*256*Scale+Offset));
ramp[1][num]=__min(65535,static_cast<unsigned int>(fnum*256*Scale+Offset));
ramp[2][num]=__min(65535,static_cast<unsigned int>(fnum*256*Scale+Offset));
}
if(!(SetDeviceGammaRamp( appWindow.hDC, ramp))) {
printf("Failed to SetDeviceGammaRamp
");
return 0;
}
return 1;
}
int Sys_GLMakeCurrent( const HDC hdc, const HGLRC hrc ) {
return wglMakeCurrent( hdc, hrc );
}
BOOL Sys_CreateGLRenderContext() {
if (!(appWindow.hRC=wglCreateContext(appWindow.hDC)))
{
printf("Can't Create A GL Rendering Context.
");
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
if(!Sys_GLMakeCurrent(appWindow.hDC,appWindow.hRC))
{
printf("Can't Activate The GL Rendering Context.
");
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
return TRUE;
}
void GL_ReleaseRenderContext(HGLRC hRC) {
if (hRC) // Do We Have A Rendering Context?
{
if (!Sys_GLMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
{
printf("Release Of DC And RC Failed.
");
}
if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
{
printf( "Release Rendering Context Failed.
");
}
hRC=NULL; // Set RC To NULL
}
}
int Sys_DestroyGLWindow(HWND hWnd, HINSTANCE hInstance, HDC hDC) {
// TODO FIX THIS
/*
if (fullscreen)
{
ChangeDisplaySettingsEx(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE);
}
*/
int eventSuccess = 1;
if (hDC && !ReleaseDC(hWnd,hDC))
{
printf( "Release Device Context Failed.
" );
hDC=NULL;
eventSuccess = 0;
}
if (hWnd && !DestroyWindow(hWnd))
{
printf( "Could Not Release hWnd.
" );
hWnd=NULL;
eventSuccess = 0;
}
if (!UnregisterClass("OpenGL",appWindow.hInstance))
{
printf( "Could Not Unregister Class.
" );
hInstance=NULL;
eventSuccess = 0;
}
return eventSuccess;
}
static int GL_GetMultisamplePixelFormatFromDummyWindow(HDC hdc, int suggestedFormat, const int numSamples, int &samplesGiven )
{
HDC hDC = wglGetCurrentDC();
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) wglGetProcAddress("wglGetPixelFormatAttribivARB");
/*
BOOL wglGetPixelFormatAttribivARB(HDC hDC,
int iPixelFormat,
int iLayerPlane,
UINT nAttributes,
int *piAttributes,
int *piValues)
C SPECIFICATION
BOOL wglGetPixelFormatAttribfvARB(HDC hDC,
int iPixelFormat,
int iLayerPlane,
UINT nAttributes,
int *piAttributes,
FLOAT *pfValues)
*/
if (!wglChoosePixelFormatARB) {
printf("No wglChoosePixelFormatARB
");
return suggestedFormat;
}
if (!GL_ExtensionExists("GL_ARB_multisample")) {
printf("No GL_ARB_multisample
");
return suggestedFormat;
}
int pixelFormatList[1];
BOOL bStatus;
UINT numFormats;
float fAttributes[] = {0,0};
int iAttributes[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, // Specifies an ICD driver.
WGL_COLOR_BITS_ARB, 24,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, numSamples,
WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB,
0};
// WGL_SWAP_EXCHANGE_ARB Swapping exchanges the front and back buffer contents.
// WGL_SWAP_COPY_ARB Swapping copies the back buffer contents to the front buffer.
// WGL_SWAP_UNDEFINED_ARB
while( iAttributes[19] > 0 ) {
bStatus = wglChoosePixelFormatARB(hDC,iAttributes,fAttributes,1,&pixelFormatList[0],&numFormats);
if( (bStatus == GL_TRUE) && (numFormats > 0) )
{
printf("Found %d multisample pixel format
", iAttributes[19] );
const int iMainLayerPlane = 0;
const int nQueriedAttributes = 1;
int attributeQueries = WGL_SWAP_METHOD_ARB;
int attributeValues;
wglGetPixelFormatAttribivARB( hDC, pixelFormatList[0], iMainLayerPlane, nQueriedAttributes, &attributeQueries, &attributeValues );
if( attributeValues != WGL_SWAP_EXCHANGE_ARB ) {
common->DPrintf( COM_RED("PixelFormat is not SWAP_EXCHANGE!
") );
}
else {
common->DPrintf( COM_GREEN("PixelFormat is SWAP_EXCHANGE!
") );
}
if( iAttributes[19] != numSamples ) {
printf("Found a lower quality %d multisample pixel format
", iAttributes[19]);
}
samplesGiven = iAttributes[19];
return pixelFormatList[0];
}
else {
// okay, that failed, so try using 1 fewer sample
if( iAttributes[19] > 0 ) {
--iAttributes[19];
}
// bStatus = wglChoosePixelFormatARB(hDC,iAttributes,fAttributes,1,&pixelFormatList[0],&numFormats);
}
}
// failed, return the suggested format and continue
printf("No wglPixelFormat
");
return suggestedFormat;
}
int GL_GetMultisamplePixelFormat(int width, int height, const int samplesReq, int &samplesGiven ) {
samplesGiven = 0;
width = 20;
height = 20;
int dummyPixelFormat;
DEVMODE dm;
// Get the desktop color depth...
memset( &dm, 0, sizeof( dm ) );
HDC hdc = ::GetDC( ::GetDesktopWindow() );
dm.dmSize = sizeof( dm );
dm.dmBitsPerPel = GetDeviceCaps( hdc, BITSPIXEL );
dm.dmFields = DM_BITSPERPEL;
::ReleaseDC( ::GetDesktopWindow(), hdc );
const int accumBufferEnable = 0;
// Dummy window pfd
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER | // double buffered
PFD_TYPE_RGBA, // RGBA type
dm.dmBitsPerPel == 32 ? 24 : 16,// desktop color depth
0, 0, 0, 0, 0, 0, // color bits ignored
dm.dmBitsPerPel == 32 ? 8 : 0, // alpha buffer
0, // shift bit ignored
accumBufferEnable, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
dm.dmBitsPerPel == 32 ? 24 : 16, // z-buffer
dm.dmBitsPerPel == 32 ? 8 : 0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
WNDCLASS wc;
RECT WindowRect;
WindowRect.left = (long)0;
WindowRect.right = (long)width;
WindowRect.top = (long)0;
WindowRect.bottom= (long)height;
bool fullscreen=0;
const char dummyClassName[] = "DummyOpenGL";
//appWindow.hInstance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = NULL;//(WNDPROC) appWindow.wndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = NULL;// appWindow.hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION );
wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = dummyClassName;
if (!RegisterClass(&wc))
{
printf("DummyWindow: Failed To Register The Window Class.
");
return FALSE;
}
printf("...Creating dummy window...");
HWND dummyHwnd =CreateWindow("STATIC", NULL, WS_POPUP|WS_CLIPSIBLINGS|WS_CLIPCHILDREN, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
printf("done.
");
if( !dummyHwnd ) {
printf( "Can't create the dummy window
" );
return 0;
}
HDC dc;
HGLRC hGLRC;
dc = ::GetDC( dummyHwnd );
// Set up OpenGL
dummyPixelFormat = ChoosePixelFormat( dc, &pfd);
if (SetPixelFormat(dc, dummyPixelFormat, &pfd) == FALSE)
{
printf("MSAA: SetPixelFormat failed!
");
return -1;
}
// Create a rendering context and make it current
hGLRC = wglCreateContext(dc);
Sys_GLMakeCurrent(dc, hGLRC);
// And the WGL strings, but for this we need
// the the WGL_ARB_pixel_format entry point...
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
// or the WGL_EXT_pixel_format entry point...
PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT;
wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsString = 0;
if( wglGetExtensionsStringARB )
wglGetExtensionsString = wglGetExtensionsStringARB;
else if( wglGetExtensionsStringEXT )
wglGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetExtensionsStringEXT;
if( !wglGetExtensionsString ) {
printf("No wglGetExtensionsString!
" );
return 0;
}
//printf("WGL_EXTENSIONS: %s
", wglGetExtensionsString(dc) );
int msaaPixelFormat = GL_GetMultisamplePixelFormatFromDummyWindow( dc, dummyPixelFormat, samplesReq, samplesGiven );
// TODO: check for SWAP_EXCHANGE
if( msaaPixelFormat == dummyPixelFormat || msaaPixelFormat == 0 ) {
printf( "No multisample support" );
printf("msaaPixelFormat %d
", msaaPixelFormat );
msaaPixelFormat = 0;
}
/*
...GL_MakeCurrent( NULL, NULL ): success
...deleting GL context: success
...releasing DC: success
...destroying window
...shutting down QGL
...unloading OpenGL DLL
*/
Sys_GLMakeCurrent(NULL, NULL);
wglDeleteContext(hGLRC);
ReleaseDC(dummyHwnd, dc);
DestroyWindow( dummyHwnd );
UnregisterClass( dummyClassName, appWindow.hInstance );
dummyHwnd = 0;
return msaaPixelFormat;
}
//
//
//static void CenterWindow( HWND m_hWnd )
//{
//
// //ASSERT(::IsWindow(m_hWnd));
//
// // determine owner window to center against
// DWORD dwStyle = ::GetWindowLong( m_hWnd, GWL_STYLE );
// //::GetWindowStyle(m_hWnd);//GetStyle();
// HWND pAlternateOwner = NULL;
// // HWND hWndCenter = pAlternateOwner->GetSafeHwnd()
// HWND hWndCenter = NULL;
// if (pAlternateOwner == NULL)
// {
// if (dwStyle & WS_CHILD)
// hWndCenter = ::GetParent(m_hWnd);
// else
// hWndCenter = ::GetWindow(m_hWnd, GW_OWNER);
// if (hWndCenter != NULL)
// {
// // let parent determine alternate center window
// HWND hWndTemp =
// (HWND)::SendMessage(hWndCenter, /* WM_QUERYCENTERWND */0x036B, 0, 0);
// if (hWndTemp != NULL)
// hWndCenter = hWndTemp;
// }
// }
//
// // get coordinates of the window relative to its parent
// ::RECT rcDlg;
// GetWindowRect( m_hWnd, &rcDlg);
// ::RECT rcArea;
// ::RECT rcCenter;
// HWND hWndParent;
// if (!(dwStyle & WS_CHILD))
// {
// // don't center against invisible or minimized windows
// if (hWndCenter != NULL)
// {
// DWORD dwStyle = ::GetWindowLong(hWndCenter, GWL_STYLE);
// if (!(dwStyle & WS_VISIBLE) || (dwStyle & WS_MINIMIZE))
// hWndCenter = NULL;
// }
//
// MONITORINFO mi;
// mi.cbSize = sizeof(mi);
//
// // center within appropriate monitor coordinates
// if (hWndCenter == NULL)
// {
// //HWND hwDefault = AfxGetMainWnd()->GetSafeHwnd();
// HWND hwDefault = ::GetDesktopWindow();
//
// GetMonitorInfo(
// MonitorFromWindow(hwDefault, MONITOR_DEFAULTTOPRIMARY), &mi);
// rcCenter = mi.rcWork;
// rcArea = mi.rcWork;
// }
// else
// {
// ::GetWindowRect(hWndCenter, &rcCenter);
// GetMonitorInfo(
// MonitorFromWindow(hWndCenter, MONITOR_DEFAULTTONEAREST), &mi);
// rcArea = mi.rcWork;
// }
// }
// else
// {
// // center within parent client coordinates
// hWndParent = ::GetParent(m_hWnd);
// assert(::IsWindow(hWndParent));
//
// ::GetClientRect(hWndParent, &rcArea);
// assert(::IsWindow(hWndCenter));
// ::GetClientRect(hWndCenter, &rcCenter);
// ::MapWindowPoints(hWndCenter, hWndParent, (POINT*)&rcCenter, 2);
// }
//
// // find dialog's upper left based on rcCenter
// int height = rcDlg.top - rcDlg.top;
// int xLeft = (rcCenter.left + rcCenter.right) / 2 - (rcDlg.right-rcDlg.left) / 2;
// int yTop = (rcCenter.top + rcCenter.bottom) / 2 - (height) / 2;
//
//
// // if the dialog is outside the screen, move it inside
// if (xLeft < rcArea.left)
// xLeft = rcArea.left;
// else if (xLeft + (rcDlg.right - rcDlg.left) > rcArea.right)
// xLeft = rcArea.right - (rcDlg.right - rcDlg.left);
//
// if (yTop < rcArea.top)
// yTop = rcArea.top;
// else if (yTop + (height) > rcArea.bottom)
// yTop = rcArea.bottom - (height);
//
// // map screen coordinates to child coordinates
// SetWindowPos( m_hWnd, NULL, xLeft, yTop, -1, -1,
// SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
//}
// csz todo
// TODO: This is making the window disappear!
static void CenterWindow(HWND hwnd, HWND hwndParent)
{
int x;
int y;
int cx;
int cy;
HWND hwndDesktop;
RECT rectParent;
RECT rectDialog;
RECT rectDesktop;
//-- need this for the screen size
hwndDesktop = GetDesktopWindow();
//-- as a last resort use the desktop window
hwndParent = (hwndParent == 0) ? hwndDesktop : hwndParent;
//-- Obtain positions of both current window & its parent window
GetWindowRect(hwnd, &rectDialog);
GetWindowRect(hwndParent, &rectParent);
GetWindowRect(hwndDesktop, &rectDesktop);
cx = rectDialog.right - rectDialog.left;
cy = rectDialog.bottom - rectDialog.top;
//-- set dialog window centred within parent window
x = rectParent.left + (rectParent.right - rectParent.left) / 2 -
(cx) / 2;
y = rectParent.top + (rectParent.bottom - rectParent.top ) / 2 -
(cy) / 2;
//-- make sure the dialog stays on the screen
x = (x > 0) ? x : 5;
y = (y > 0) ? y : 5;
x = ((rectDesktop.right - (x + cx)) > 0) ? x : rectDesktop.right -
cx - 5;
y = ((rectDesktop.bottom - (y + cy)) > 0) ? y : rectDesktop.bottom -
cy - 5;
//-- center the dialog
SetWindowPos(hwnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
void EnumerateMonitors() {
#ifndef SM_CMONITORS
typedef HANDLE HMONITOR;
#endif
#ifndef DISPLAY_DEVICE_PRIMARY_DEVICE
typedef struct _DISPLAY_DEVICE {
DWORD cb;
TCHAR DeviceName[32];
TCHAR DeviceString[128];
DWORD StateFlags;
} DISPLAY_DEVICE, *PDISPLAY_DEVICE, *LPDISPLAY_DEVICE;
#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002
#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004
#define DISPLAY_DEVICE_VGA 0x00000010
#endif
int i;
BOOL (WINAPI* pEnumDisplayDevices)(PVOID,DWORD,PVOID,DWORD);
pEnumDisplayDevices = (BOOL (__stdcall *)(PVOID,DWORD,PVOID,DWORD)) GetProcAddress(LoadLibrary("USER32"), "EnumDisplayDevicesA");
if (pEnumDisplayDevices)
{
DISPLAY_DEVICE dd;
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
//printf("*** EnumDisplayDevices
");
for (i=0; (*pEnumDisplayDevices)(NULL, i, &dd, 0); i++)
{
if( !(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ) {
continue;
}
//printf(" DeviceName: '%s'
", dd.DeviceName);
//printf(" DeviceString: '%s'
", dd.DeviceString);
/*printf(" Flags: %08X %s%s
",
dd.StateFlags,
((dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ?
"Desktop " : ""),
((dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) ? "Primary " : ""));*/
}
}
}
struct monitor_s {
HMONITOR handle;
HDC hdc;
int index;
monitor_s *next;
};
static BOOL CALLBACK MonitorEnumProc( HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData ) {
/*
hMonitor
[in] Handle to the display monitor. This value will always be non-NULL.
hdcMonitor
[in] Handle to a device context.
The device context has color attributes that are appropriate for the display monitor identified by hMonitor. The clipping area of the device context is set to the intersection of the visible region of the device context identified by the hdc parameter of EnumDisplayMonitors, the rectangle pointed to by the lprcClip parameter of EnumDisplayMonitors, and the display monitor rectangle.
This value is NULL if the hdc parameter of EnumDisplayMonitors was NULL.
lprcMonitor
[in] Pointer to a RECT structure.
If hdcMonitor is non-NULL, this rectangle is the intersection of the clipping area of the device context identified by hdcMonitor and the display monitor rectangle. The rectangle coordinates are device-context coordinates.
If hdcMonitor is NULL, this rectangle is the display monitor rectangle. The rectangle coordinates are virtual-screen coordinates.
dwData .. from EnumDisplayMonitors
*/
MONITORINFOEX mi;
memset( &mi, 0, sizeof(mi) );
mi.cbSize = sizeof(mi);
GetMonitorInfo( hMonitor, &mi );
//printf( "MONITOR %s", mi.szDevice );
if( mi.dwFlags == MONITORINFOF_PRIMARY ) {
// printf( "(primary)" );
}
//printf("
");
/*monitor_s *monitor = ( monitor_s *)dwData;
monitor->handle = hMonitor;
monitor->hdc = hdcMonitor;
monitor->next = (monitor_s *)malloc( sizeof(monitor_s) );*/
std::vector< monitor_s * > *pVector = ( std::vector< monitor_s * > * )dwData;
monitor_s *monitor = (monitor_s *) malloc( sizeof(monitor_s ) );
monitor->handle = hMonitor;
monitor->hdc = hdcMonitor;
monitor->next = NULL;
pVector->push_back( monitor );
return TRUE;
}
void EnumerateDisplayMonitors() {
HDC allDesktopDisplays = NULL;
//EnumDisplayMonitors( allDesktopDisplays, NULL, MonitorEnumProc, NULL );
}
HMONITOR MultiMonitor_GetMonitorHandle( const int requestedMonitorNumber ) {
HDC allDesktopDisplays = NULL;
std::vector< monitor_s * > monitorList;
EnumDisplayMonitors( allDesktopDisplays, NULL, MonitorEnumProc, (LPARAM)&monitorList );
HMONITOR tempHandle = NULL;
for( size_t i = 0; i < monitorList.size(); ++i ) {
monitor_s *monitor = monitorList[i];
tempHandle = monitor->handle;
if( (i+1) == requestedMonitorNumber ) {
MONITORINFOEX mi;
memset( &mi, 0, sizeof(mi) );
mi.cbSize = sizeof(mi);
GetMonitorInfo( monitor->handle, &mi );
printf("Using monitor %d: %s
", monitor->index, mi.szDevice );
// actualMonitorNumber = requestedMonitorNumber;
return monitor->handle;
}
}
// actualMonitorNumber = 1;
return tempHandle;
}
#define MONITOR_CENTER 0x0001 // center rect to monitor
#define MONITOR_CLIP 0x0000 // clip rect to monitor
#define MONITOR_WORKAREA 0x0002 // use monitor work area
#define MONITOR_AREA 0x0000 // use monitor entire area
void ClipOrCenterRectToMonitor(LPRECT prc, UINT flags)
{
HMONITOR hMonitor;
MONITORINFO mi;
RECT rc;
int w = prc->right - prc->left;
int h = prc->bottom - prc->top;
//
// get the nearest monitor to the passed rect.
//
hMonitor = MonitorFromRect( prc, MONITOR_DEFAULTTONEAREST );
//
// get the work area or entire monitor rect.
//
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
if (flags & MONITOR_WORKAREA)
rc = mi.rcWork;
else
rc = mi.rcMonitor;
//
// center or clip the passed rect to the monitor rect
//
if (flags & MONITOR_CENTER)
{
prc->left = rc.left + (rc.right - rc.left - w) / 2;
prc->top = rc.top + (rc.bottom - rc.top - h) / 2;
prc->right = prc->left + w;
prc->bottom = prc->top + h;
}
else
{
prc->left = max(rc.left, min(rc.right-w, prc->left));
prc->top = max(rc.top, min(rc.bottom-h, prc->top));
prc->right = prc->left + w;
prc->bottom = prc->top + h;
}
}
void ClipOrCenterWindowToMonitor(HWND hwnd, UINT flags)
{
RECT rc;
GetWindowRect( hwnd, &rc);
ClipOrCenterRectToMonitor(&rc, flags);
SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
void MultiMonitor_CenterRectToMonitor( HMONITOR hMonitor, LPRECT prc, UINT flags)
{
//HMONITOR hMonitor;
MONITORINFO mi;
RECT rc;
int w = prc->right - prc->left;
int h = prc->bottom - prc->top;
//
// get the nearest monitor to the passed rect.
//
//hMonitor = MonitorFromRect( prc, MONITOR_DEFAULTTONEAREST );
//
// get the work area or entire monitor rect.
//
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
/*printf("Monitor area:
"
"left: %d
"
"right: %d
"
"top: %d
"
"bottom: %d
",
mi.rcMonitor.left,
mi.rcMonitor.right,
mi.rcMonitor.top,
mi.rcMonitor.bottom ); */
if (flags & MONITOR_WORKAREA)
rc = mi.rcWork;
else
rc = mi.rcMonitor;
//
// center or clip the passed rect to the monitor rect
//
if (flags & MONITOR_CENTER)
{
prc->left = rc.left + (rc.right - rc.left - w) / 2;
prc->top = rc.top + (rc.bottom - rc.top - h) / 2;
prc->right = prc->left + w;
prc->bottom = prc->top + h;
}
else
{
prc->left = max(rc.left, min(rc.right-w, prc->left));
prc->top = max(rc.top, min(rc.bottom-h, prc->top));
prc->right = prc->left + w;
prc->bottom = prc->top + h;
}
}
void MultiMonitor_CenterWindowToMonitor(HMONITOR hMonitor, HWND hwnd, UINT flags)
{
RECT rc;
GetWindowRect( appWindow.hWnd, &rc);
MultiMonitor_CenterRectToMonitor( hMonitor, &rc, flags);
SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
bool RequestFullscreen( const char *deviceName, const int width, const int height, const int colorBits, const int refreshRate ) {
DEVMODE currentMode;
memset( ¤tMode, 0, sizeof(currentMode) );
currentMode.dmSize = sizeof(currentMode);
EnumDisplaySettings( deviceName, ENUM_CURRENT_SETTINGS, ¤tMode );
DEVMODE dmScreenSettings;
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width;
dmScreenSettings.dmPelsHeight = height;
dmScreenSettings.dmBitsPerPel = colorBits;
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
if( refreshRate ) {
dmScreenSettings.dmDisplayFrequency = refreshRate;
dmScreenSettings.dmFields|=DM_DISPLAYFREQUENCY;
}
/*
fixed-resolution displays: LCDs, etc
if( 1 ) {
dmScreenSettings.dmFields |= DM_DISPLAYFIXEDOUTPUT;
dmScreenSettings.dmDisplayFixedOutput = DMDFO_DEFAULT;//DMDFO_CENTER;
}
*/
if( ChangeDisplaySettingsEx( deviceName, &dmScreenSettings, NULL, CDS_FULLSCREEN, NULL )!=DISP_CHANGE_SUCCESSFUL)
{
//DWORD mask = DM_DISPLAYFREQUENCY;
//mask = ~mask;
//dmScreenSettings.dmFields &= mask;
dmScreenSettings.dmDisplayFrequency = currentMode.dmDisplayFrequency;
if( ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) {
if(MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By
Your Video Card. Defaulting to Windowed mode","",MB_OK|MB_ICONEXCLAMATION)==IDYES) {
return false;
}
}
}
return true;
}
BOOL Sys_CreateGLWindow( const int monitor, const char* title, const int width, const int height, const int colorBits, const int depthBits, const int stencilBits, const bool fullscreenflag, const int refreshRate )
{
GLuint PixelFormat;
WNDCLASS wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect;
WindowRect.left = (long)0;
WindowRect.right = (long)width;
WindowRect.top = (long)0;
WindowRect.bottom= (long)height;
bool fullscreen=fullscreenflag;
//appWindow.hInstance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) appWindow.wndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = appWindow.hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION );
wc.hCursor = NULL;//LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";
if (!RegisterClass(&wc))
{
common->RSafePrintf( "Failed To Register The Window Class.
");
return FALSE;
}
HMONITOR hmon = MultiMonitor_GetMonitorHandle( monitor );
MONITORINFOEX mi;
memset( &mi, 0, sizeof(mi) );
mi.cbSize = sizeof(mi);
GetMonitorInfo( hmon, &mi );
if (fullscreen)
{
fullscreen = RequestFullscreen( mi.szDevice, width, height, colorBits, refreshRate );
}
if (fullscreen)
{
dwExStyle=WS_EX_APPWINDOW;
dwStyle=WS_POPUP;
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle=WS_OVERLAPPEDWINDOW;
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
if (!(appWindow.hWnd=CreateWindowEx( dwExStyle,
"OpenGL",
title,
dwStyle |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,
0, 0,
WindowRect.right-WindowRect.left,
WindowRect.bottom-WindowRect.top,
NULL,
NULL,
appWindow.hInstance,
NULL)))
{
common->RSafePrintf( "Window Creation Error." );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
// #error Make sure CreateWindow is called correctly
#pragma message( __FILE__ "(" STRINGIZE_DEF(__LINE__) ")" ": Make sure CreateWindow is called correctly" )
//I had a similar problem a while ago, and I couldn't figure out why my viewport was larger than the window and was being squished to fit (resulting in poor image quality).
// Turns out, I was setting the size of the window itslef, and not the client area. So I would create the window at, say, 640x480, and then the actual client area would be like 636x432. It took me weeks to catch this!
//Here is how you create a window with a specific CLIENT area:
//DWORD style = WS_OVERLAPPEDWINDOW;
//RECT clientArea = {0, 0, Width, Height};
//AdjustWindowRect(&clientArea, style, false);
//hWnd = CreateWindowEx(0, WINDOWCLASS, "", style, CW_USEDEFAULT, CW_USEDEFAULT, clientArea.right-clientArea.left, clientArea.bottom-clientArea.top, ...);
MultiMonitor_CenterWindowToMonitor( hmon, appWindow.hWnd, MONITOR_CENTER );
//if(fullscreen) {
// //HMONITOR m = MultiMonitor_GetMonitorHandle(0);
// //MultiMonitor_CenterWindowToMonitor( m, appWindow.hWnd, MONITOR_CENTER );
// //SetWindowPos( appWindow.hWnd, HWND_TOPMOST, 0, 0, width, height, 0);
//}
//else {
// //SetWindowPos( appWindow.hWnd, HWND_TOPMOST, 0, 0, width, height, 0);
// //CenterWindow( appWindow.hWnd, NULL );
// //ClipOrCenterWindowToMonitor( appWindow.hWnd, NULL );
// //HMONITOR m = MultiMonitor_GetMonitorHandle(0);
// //MultiMonitor_CenterWindowToMonitor( m, appWindow.hWnd, MONITOR_CENTER );
//}
//appWindow.hWnd = GetWindow (GetWindow(FindWindow ("ProgMan", NULL), GW_CHILD), GW_CHILD);
//appWindow.hDC = GetWindowDC(GetDesktopWindow());
const int accumBufferEnable = 0;
PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR),
1, // Version Number
PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER |
PFD_SWAP_EXCHANGE, // Driver hint for SLI
PFD_TYPE_RGBA, // Request An RGBA Format
colorBits, // Select Our Color Depth
8, 0, // Red
8, 0, // Green
8, 0, // Blue
8, 0, // Alpha
accumBufferEnable, // Accumulation Buffer Enable bit
0, 0, 0, 0, // Accumulation Bits Ignored
depthBits, // depth bits
stencilBits, // stencil bits
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
if( !(appWindow.hDC = GetDC(appWindow.hWnd)) )
{
common->RSafePrintf( "Can't Create A GL Device Context.
" );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
if (!(PixelFormat=ChoosePixelFormat(appWindow.hDC,&pfd)))
{
common->RSafePrintf( "Can't Find A Suitable PixelFormat.
" );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
PIXELFORMATDESCRIPTOR actualPFD;
DescribePixelFormat( appWindow.hDC, PixelFormat, sizeof(actualPFD), &actualPFD );
if( (actualPFD.dwFlags & PFD_SWAP_EXCHANGE) == 0 ) {
common->RSafePrintf( COM_RED("PFD_SWAP_EXCHANGE not enabled
") );
}
else {
common->RSafePrintf( COM_EXP("PFD_SWAP_EXCHANGE enabled
") );
}
if(!SetPixelFormat(appWindow.hDC,PixelFormat,&pfd))
{
printf( "Can't Set The PixelFormat.
" );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
ShowWindow( appWindow.hWnd,SW_SHOW );
SetForegroundWindow( appWindow.hWnd );
SetFocus( appWindow.hWnd );
return TRUE;
}
extern void WGL_GetLastErr_internal( const char *, const int );
#define GUARD_WINDOW if( !IsWindow(appWindow.hWnd) ) {printf(__FUNCTION__":%d : appWindow.hWnd = %p, but is not a window
", __LINE__, appWindow.hWnd );exit(0); }
BOOL Sys_CreateGLWindowMultisample( const int monitor,
const char* title, const int width, const int height,
const int colorBits,
const int depthBits,
const int stencilBits,
const bool fullscreen,
const int refreshRate,
const int samplesReq ) {
WNDCLASS wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect;
WindowRect.left = (long)0;
WindowRect.right = (long)width;
WindowRect.top = (long)0;
WindowRect.bottom= (long)height;
bool fullscreenflag = fullscreen;
//appWindow.hInstance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) appWindow.wndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = appWindow.hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION );
wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";
if (!RegisterClass(&wc))
{
MessageBox(NULL,"MS: Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
//return FALSE;
}
WGL_GetLastErr_internal(__FILE__, __LINE__);
HMONITOR hmon = MultiMonitor_GetMonitorHandle( monitor );
MONITORINFOEX mi;
memset( &mi, 0, sizeof(mi) );
mi.cbSize = sizeof(mi);
GetMonitorInfo( hmon, &mi );
if( fullscreenflag ) {
fullscreenflag = RequestFullscreen( mi.szDevice, width, height, colorBits, refreshRate );
}
if( fullscreenflag) {
dwExStyle=WS_EX_APPWINDOW;
dwStyle=WS_POPUP;
}
else {
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle=WS_OVERLAPPEDWINDOW;
}
if(fullscreenflag) {
SetWindowPos( appWindow.hWnd, HWND_TOPMOST, 0, 0, width, height, 0);
}
WGL_GetLastErr_internal(__FILE__, __LINE__);
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
if (!(appWindow.hWnd=CreateWindowEx( dwExStyle,
"OpenGL",
title,
dwStyle |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,
0, 0,
WindowRect.right-WindowRect.left,
WindowRect.bottom-WindowRect.top,
NULL,
NULL,
appWindow.hInstance,
NULL)))
{
printf( "Window Creation Error.
" );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
GUARD_WINDOW
MultiMonitor_CenterWindowToMonitor( hmon, appWindow.hWnd, MONITOR_CENTER );
//appWindow.hWnd = GetWindow (GetWindow(FindWindow ("ProgMan", NULL), GW_CHILD), GW_CHILD);
//appWindow.hDC = GetWindowDC(GetDesktopWindow());
GUARD_WINDOW
if (!(appWindow.hDC=GetDC(appWindow.hWnd)))
{
printf( "Can't Create A GL Device Context.
" );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
GUARD_WINDOW
WGL_GetLastErr_internal(__FILE__, __LINE__);
GUARD_WINDOW
PIXELFORMATDESCRIPTOR pfd;
int samplesGiven = 0;
const int msaaPixelformat = GL_GetMultisamplePixelFormat( width, height, samplesReq, samplesGiven );
int pixelFormat = 0;
GUARD_WINDOW
if( !msaaPixelformat )
{
if( !(pixelFormat=ChoosePixelFormat(appWindow.hDC,&pfd))) {
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
}
else {
pixelFormat = msaaPixelformat;
}
GUARD_WINDOW
WGL_GetLastErr_internal(__FILE__, __LINE__);
if(!SetPixelFormat(appWindow.hDC, pixelFormat,&pfd))
{
printf( "Can't Set The PixelFormat.
" );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}
GUARD_WINDOW
WGL_GetLastErr_internal(__FILE__, __LINE__);
printf("Showing window...
");
ShowWindow( appWindow.hWnd,SW_SHOW );
WGL_GetLastErr_internal(__FILE__, __LINE__);
SetForegroundWindow( appWindow.hWnd );
WGL_GetLastErr_internal(__FILE__, __LINE__);
SetFocus( appWindow.hWnd );
WGL_GetLastErr_internal(__FILE__, __LINE__);
return TRUE;
}