Detect openGL version on a multi-graphic board system

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

Hi Nico,

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

Robert.

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

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

Hi Nico,

Originally posted by toxnico:
[b] 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 [/b]
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.

Hi Robert,

One more time Unix and X11 proved their superiority… :wink: 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

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…

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 &#0124;&#0124; 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) &#0124;&#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), &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( &currentMode, 0, sizeof(currentMode) );
	currentMode.dmSize = sizeof(currentMode);
	EnumDisplaySettings( deviceName, ENUM_CURRENT_SETTINGS, &currentMode );
	
	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;									
}