PDA

View Full Version : Detect openGL version on a multi-graphic board system



toxnico
11-22-2006, 12:51 AM
Hello,

In my application I have to detect OpenGL version on a three-screens system.

The PC contains one AGP graphic board, which does not support OpenGL greater than 1.1.0 (one screen connected on it), AND a PCIe dual head graphic board which may support OpenGL 1.3 (two screens connected on it).

I use the function glGetString(GL_VERSION) but it only returns the version of the AGP (primary) graphic board : 1.1.0.
Is it possible to get OpenGL informations for the two graphic boards?

Thanks for your help,

Nico

Robert Osfield
11-22-2006, 01:45 AM
Hi Nico,

You'll need to open up a graphics context on each card and querry the OpenGL version for each context.

Robert.

toxnico
11-22-2006, 01:54 AM
Hi Robert, thanks for your answer.

So I'm going to try this, and I'll give you feedback when it's done (and when it works! (: )

Nico

toxnico
11-22-2006, 09:49 PM
Hi,

I tried to create openGL context on my two graphic cards, but it seems that openGL returns only the infos from the card where is connected the screen declared as the main monitor ( I'm working on MS Windows with QT library).

Nico

Robert Osfield
11-22-2006, 11:03 PM
Hi Nico,


Originally posted by toxnico:
Hi,
I tried to create openGL context on my two graphic cards, but it seems that openGL returns only the infos from the card where is connected the screen declared as the main monitor ( I'm working on MS Windows with QT library).

Nico I'm a unix hack myself, so can't provide specific points to Windows.

In theory, if you can get Qt to open up a graphics window on the screen you want, then this should have the appropriate driver info. This certainly works just fine under X11, but alas this doesn't help you too much.

Robert.

toxnico
11-22-2006, 11:58 PM
Hi Robert,

One more time Unix and X11 proved their superiority... ;) I sent a mail to Qt support this morning, and I hope they will be able to give me a solution under windows...

Nevertheless, thank you very much for your help!

Nico

knackered
11-23-2006, 12:12 PM
No chance. Due to a limitation of the ICD, a GL context can be created from the primary display device only.
Unless you can get the driver to go into span mode across all your cards, you're screwed....

CatAtWork
11-24-2006, 04:25 PM
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\n", 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\n");
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.\n");
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.\n");
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.\n");
}

if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
{
printf( "Release Rendering Context Failed.\n");
}
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 &amp;&amp; !ReleaseDC(hWnd,hDC))
{
printf( "Release Device Context Failed.\n" );
hDC=NULL;
eventSuccess = 0;
}

if (hWnd &amp;&amp; !DestroyWindow(hWnd))
{
printf( "Could Not Release hWnd.\n" );
hWnd=NULL;
eventSuccess = 0;
}

if (!UnregisterClass("OpenGL",appWindow.hInstance))
{
printf( "Could Not Unregister Class.\n" );
hInstance=NULL;
eventSuccess = 0;
}

return eventSuccess;

}









static int GL_GetMultisamplePixelFormatFromDummyWindow(HDC hdc, int suggestedFormat, const int numSamples, int &amp;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\n");
return suggestedFormat;
}

if (!GL_ExtensionExists("GL_ARB_multisample")) {
printf("No GL_ARB_multisample\n");
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,fAttribute s,1,&amp;pixelFormatList[0],&amp;numFormats);

if( (bStatus == GL_TRUE) &amp;&amp; (numFormats > 0) )
{
printf("Found %d multisample pixel format\n", iAttributes[19] );
const int iMainLayerPlane = 0;
const int nQueriedAttributes = 1;
int attributeQueries = WGL_SWAP_METHOD_ARB;
int attributeValues;
wglGetPixelFormatAttribivARB( hDC, pixelFormatList[0], iMainLayerPlane, nQueriedAttributes, &amp;attributeQueries, &amp;attributeValues );

if( attributeValues != WGL_SWAP_EXCHANGE_ARB ) {
common->DPrintf( COM_RED("PixelFormat is not SWAP_EXCHANGE!\n") );
}
else {
common->DPrintf( COM_GREEN("PixelFormat is SWAP_EXCHANGE!\n") );
}

if( iAttributes[19] != numSamples ) {
printf("Found a lower quality %d multisample pixel format\n", 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,fAttribute s,1,&amp;pixelFormatList[0],&amp;numFormats);
}
}

// failed, return the suggested format and continue
printf("No wglPixelFormat\n");
return suggestedFormat;
}


int GL_GetMultisamplePixelFormat(int width, int height, const int samplesReq, int &amp;samplesGiven ) {

samplesGiven = 0;

width = 20;
height = 20;

int dummyPixelFormat;
DEVMODE dm;

// Get the desktop color depth...
memset( &amp;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(&amp;wc))
{
printf("DummyWindow: Failed To Register The Window Class.\n");
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.\n");

if( !dummyHwnd ) {
printf( "Can't create the dummy window\n" );
return 0;
}





HDC dc;
HGLRC hGLRC;
dc = ::GetDC( dummyHwnd );

// Set up OpenGL
dummyPixelFormat = ChoosePixelFormat( dc, &amp;pfd);
if (SetPixelFormat(dc, dummyPixelFormat, &amp;pfd) == FALSE)
{
printf("MSAA: SetPixelFormat failed!\n");
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)wglGetProcAddres s("wglGetExtensionsStringARB");

// or the WGL_EXT_pixel_format entry point...
PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT;
wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddres s("wglGetExtensionsStringEXT");

PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsString = 0;

if( wglGetExtensionsStringARB )
wglGetExtensionsString = wglGetExtensionsStringARB;
else if( wglGetExtensionsStringEXT )
wglGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetExtensionsStringEXT;

if( !wglGetExtensionsString ) {
printf("No wglGetExtensionsString!\n" );
return 0;
}

//printf("WGL_EXTENSIONS: %s\n\n", wglGetExtensionsString(dc) );

int msaaPixelFormat = GL_GetMultisamplePixelFormatFromDummyWindow( dc, dummyPixelFormat, samplesReq, samplesGiven );


// TODO: check for SWAP_EXCHANGE
if( msaaPixelFormat == dummyPixelFormat &amp;#0124;&amp;#0124; msaaPixelFormat == 0 ) {
printf( "No multisample support" );
printf("msaaPixelFormat %d\n", 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, &amp;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) &amp;#0124;&amp;#0124; (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), &amp;mi);
// rcCenter = mi.rcWork;
// rcArea = mi.rcWork;
// }
// else
// {
// ::GetWindowRect(hWndCenter, &amp;rcCenter);
// GetMonitorInfo(
// MonitorFromWindow(hWndCenter, MONITOR_DEFAULTTONEAREST), &amp;mi);
// rcArea = mi.rcWork;
// }
// }
// else
// {
// // center within parent client coordinates
// hWndParent = ::GetParent(m_hWnd);
// assert(::IsWindow(hWndParent));
//
// ::GetClientRect(hWndParent, &amp;rcArea);
// assert(::IsWindow(hWndCenter));
// ::GetClientRect(hWndCenter, &amp;rcCenter);
// ::MapWindowPoints(hWndCenter, hWndParent, (POINT*)&amp;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, &amp;rectDialog);
GetWindowRect(hwndParent, &amp;rectParent);
GetWindowRect(hwndDesktop, &amp;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(&amp;dd, sizeof(dd));
dd.cb = sizeof(dd);

//printf("*** EnumDisplayDevices\n");

for (i=0; (*pEnumDisplayDevices)(NULL, i, &amp;dd, 0); i++)
{
if( !(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ) {
continue;
}
//printf(" DeviceName: '%s'\n", dd.DeviceName);
//printf(" DeviceString: '%s'\n", dd.DeviceString);
/*printf(" Flags: %08X %s%s\n",
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( &amp;mi, 0, sizeof(mi) );
mi.cbSize = sizeof(mi);

GetMonitorInfo( hMonitor, &amp;mi );
//printf( "MONITOR %s", mi.szDevice );
if( mi.dwFlags == MONITORINFOF_PRIMARY ) {
// printf( "(primary)" );
}
//printf("\n");



/*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)&amp;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( &amp;mi, 0, sizeof(mi) );
mi.cbSize = sizeof(mi);
GetMonitorInfo( monitor->handle, &amp;mi );
printf("Using monitor %d: %s\n", 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, &amp;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, &amp;rc);
ClipOrCenterRectToMonitor(&amp;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, &amp;mi);


/*printf("Monitor area:\n"
"left: %d\n"
"right: %d\n"
"top: %d\n"
"bottom: %d\n",
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, &amp;rc);
MultiMonitor_CenterRectToMonitor( hMonitor, &amp;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( &amp;currentMode, 0, sizeof(currentMode) );
currentMode.dmSize = sizeof(currentMode);
EnumDisplaySettings( deviceName, ENUM_CURRENT_SETTINGS, &amp;currentMode );

DEVMODE dmScreenSettings;
memset(&amp;dmScreenSettings,0,sizeof(dmScreenSettings ));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width;
dmScreenSettings.dmPelsHeight = height;
dmScreenSettings.dmBitsPerPel = colorBits;
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWID TH|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, &amp;dmScreenSettings, NULL, CDS_FULLSCREEN, NULL )!=DISP_CHANGE_SUCCESSFUL)
{
//DWORD mask = DM_DISPLAYFREQUENCY;
//mask = ~mask;
//dmScreenSettings.dmFields &amp;= mask;
dmScreenSettings.dmDisplayFrequency = currentMode.dmDisplayFrequency;
if( ChangeDisplaySettings(&amp;dmScreenSettings,CDS_FULLSC REEN)!=DISP_CHANGE_SUCCESSFUL) {
if(MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour 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(&amp;wc))
{
common->RSafePrintf( "Failed To Register The Window Class.\n");
return FALSE;
}


HMONITOR hmon = MultiMonitor_GetMonitorHandle( monitor );
MONITORINFOEX mi;
memset( &amp;mi, 0, sizeof(mi) );
mi.cbSize = sizeof(mi);
GetMonitorInfo( hmon, &amp;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(&amp;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(&amp;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.\n" );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}


if (!(PixelFormat=ChoosePixelFormat(appWindow.hDC,&amp;pf d)))
{

common->RSafePrintf( "Can't Find A Suitable PixelFormat.\n" );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}

PIXELFORMATDESCRIPTOR actualPFD;
DescribePixelFormat( appWindow.hDC, PixelFormat, sizeof(actualPFD), &amp;actualPFD );
if( (actualPFD.dwFlags & PFD_SWAP_EXCHANGE) == 0 ) {
common->RSafePrintf( COM_RED("PFD_SWAP_EXCHANGE not enabled\n") );
}
else {
common->RSafePrintf( COM_EXP("PFD_SWAP_EXCHANGE enabled\n") );
}

if(!SetPixelFormat(appWindow.hDC,PixelFormat,&amp;pfd) )
{

printf( "Can't Set The PixelFormat.\n" );
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\n", __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(&amp;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) &amp;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( &amp;mi, 0, sizeof(mi) );
mi.cbSize = sizeof(mi);
GetMonitorInfo( hmon, &amp;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(&amp;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.\n" );
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.\n" );
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,&amp;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,&amp;pfd))
{

printf( "Can't Set The PixelFormat.\n" );
Sys_DestroyGLWindow( appWindow.hWnd, appWindow.hInstance, appWindow.hDC );
return FALSE;
}

GUARD_WINDOW

WGL_GetLastErr_internal(__FILE__, __LINE__);

printf("Showing window...\n");
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;
}