/*
								+---------------------------------+
								|                                 |
								|  ***   OpenGL 4.0 driver   ***  |
								|                                 |
								|  Copyright  © -tHE SWINe- 2009  |
								|                                 |
								|         OpenGL40Drv.cpp         |
								|                                 |
								+---------------------------------+
*/

/**
 *	@file gl4/OpenGL40Drv.cpp
 *	@author -tHE SWINe-
 *	@date 2009
 *	@brief (Windows) OpenGL 4.0 driver
 */

#include "../NewFix.h"
#include "../CallStack.h"
#include <stdio.h>
#include "OpenGL40Drv.h"

#if defined(_WIN32) || defined(_WIN64)

/*
 *								=== WGL_ARB_create_context ===
 */

#ifndef WGL_ARB_create_context
#define WGL_ARB_create_context 1
#define __GENERATE_WGL_ARB_create_context__

extern HGLRC (GLApi *wglCreateContextAttribsARB_ptr)(HDC, HGLRC, const int*);

#define wglCreateContextAttribsARB wglCreateContextAttribsARB_ptr

#define WGL_CONTEXT_MAJOR_VERSION_ARB				0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB				0x2092
#define WGL_CONTEXT_LAYER_PLANE_ARB					0x2093
#define WGL_CONTEXT_FLAGS_ARB						0x2094
#define WGL_CONTEXT_PROFILE_MASK_ARB				0x9126
#define WGL_CONTEXT_DEBUG_BIT_ARB					0x0001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB		0x0002

#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB			0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB	0x00000002

#define GL_ERROR_INVALID_VERSION_ARB				0x2095
#define GL_ERROR_INVALID_PROFILE_ARB				0x2096

#endif // WGL_ARB_create_context

/*
 *								=== ~WGL_ARB_create_context ===
 */

/*
 *								=== WGL_EXT_swap_control ===
 */

#ifndef WGL_EXT_swap_control
#define WGL_EXT_swap_control 1
#define __GENERATE_WGL_EXT_swap_control__

extern BOOL (GLApi *wglSwapIntervalEXT_ptr)(int interval);
extern int (GLApi *wglGetSwapIntervalEXT_ptr)(void);

#define wglSwapIntervalEXT wglSwapIntervalEXT_ptr
#define wglGetSwapIntervalEXT wglGetSwapIntervalEXT_ptr

// no new tokens

#endif // WGL_EXT_swap_control

/*
 *								=== ~WGL_EXT_swap_control ===
 */

/*
 *								=== WGL_ARB_pixel_format ===
 */

#ifndef WGL_ARB_pixel_format
#define WGL_ARB_pixel_format 1
#define __GENERATE_WGL_ARB_pixel_format__

#define WGL_NUMBER_PIXEL_FORMATS_ARB         0x2000
#define WGL_DRAW_TO_WINDOW_ARB               0x2001
#define WGL_DRAW_TO_BITMAP_ARB               0x2002
#define WGL_ACCELERATION_ARB                 0x2003
#define WGL_NEED_PALETTE_ARB                 0x2004
#define WGL_NEED_SYSTEM_PALETTE_ARB          0x2005
#define WGL_SWAP_LAYER_BUFFERS_ARB           0x2006
#define WGL_SWAP_METHOD_ARB                  0x2007
#define WGL_NUMBER_OVERLAYS_ARB              0x2008
#define WGL_NUMBER_UNDERLAYS_ARB             0x2009
#define WGL_TRANSPARENT_ARB                  0x200A
#define WGL_TRANSPARENT_VALUE_ARB            0x200B
#define WGL_SHARE_DEPTH_ARB                  0x200C
#define WGL_SHARE_STENCIL_ARB                0x200D
#define WGL_SHARE_ACCUM_ARB                  0x200E
#define WGL_SUPPORT_GDI_ARB                  0x200F
#define WGL_SUPPORT_OPENGL_ARB               0x2010
#define WGL_DOUBLE_BUFFER_ARB                0x2011
#define WGL_STEREO_ARB                       0x2012
#define WGL_PIXEL_TYPE_ARB                   0x2013
#define WGL_COLOR_BITS_ARB                   0x2014
#define WGL_RED_BITS_ARB                     0x2015
#define WGL_RED_SHIFT_ARB                    0x2016
#define WGL_GREEN_BITS_ARB                   0x2017
#define WGL_GREEN_SHIFT_ARB                  0x2018
#define WGL_BLUE_BITS_ARB                    0x2019
#define WGL_BLUE_SHIFT_ARB                   0x201A
#define WGL_ALPHA_BITS_ARB                   0x201B
#define WGL_ALPHA_SHIFT_ARB                  0x201C
#define WGL_ACCUM_BITS_ARB                   0x201D
#define WGL_ACCUM_RED_BITS_ARB               0x201E
#define WGL_ACCUM_GREEN_BITS_ARB             0x201F
#define WGL_ACCUM_BLUE_BITS_ARB              0x2020
#define WGL_ACCUM_ALPHA_BITS_ARB             0x2021
#define WGL_DEPTH_BITS_ARB                   0x2022
#define WGL_STENCIL_BITS_ARB                 0x2023
#define WGL_AUX_BUFFERS_ARB                  0x2024
#define WGL_NO_ACCELERATION_ARB              0x2025
#define WGL_GENERIC_ACCELERATION_ARB         0x2026
#define WGL_FULL_ACCELERATION_ARB            0x2027
#define WGL_SWAP_EXCHANGE_ARB                0x2028
#define WGL_SWAP_COPY_ARB                    0x2029
#define WGL_SWAP_UNDEFINED_ARB               0x202A
#define WGL_TYPE_RGBA_ARB                    0x202B
#define WGL_TYPE_COLORINDEX_ARB              0x202C


extern BOOL (GLApi *wglGetPixelFormatAttribivARB_ptr)(HDC hdc,
                                      int iPixelFormat,
                                      int iLayerPlane,
                                      UINT nAttributes,
                                      int *piAttributes,
                                      int *piValues);
extern BOOL (GLApi *wglGetPixelFormatAttribfvARB_ptr)(HDC hdc,
                                      int iPixelFormat,
                                      int iLayerPlane,
                                      UINT nAttributes,
                                      int *piAttributes,
                                      FLOAT *pfValues);
extern BOOL (GLApi *wglChoosePixelFormatARB_ptr)(HDC hdc,
                                 const int *piAttribIList,
                                 const FLOAT *pfAttribFList,
                                 UINT nMaxFormats,
                                 int *piFormats,
                                 UINT *nNumFormats);

#define wglGetPixelFormatAttribivARB wglGetPixelFormatAttribivARB_ptr
#define wglGetPixelFormatAttribfvARB wglGetPixelFormatAttribfvARB_ptr
#define wglChoosePixelFormatARB wglChoosePixelFormatARB_ptr

#endif // WGL_ARB_pixel_format

/*
 *								=== ~WGL_ARB_pixel_format ===
 */

/*
 *								=== WGL_ARB_multisample ===
 */

#ifndef WGL_ARB_multisample
#define WGL_ARB_multisample 1
#define __GENERATE_WGL_ARB_multisample__

#define WGL_SAMPLE_BUFFERS_ARB				0x2041
#define WGL_SAMPLES_ARB						0x2042

// no new procedures or functions

#endif // WGL_ARB_multisample

/*
 *								=== ~WGL_ARB_multisample ===
 */

#else // _WIN32 || _WIN64

// @todo - GLX_ARB_create_context

/*
 *								=== GLX_SGI_swap_control ===
 */

#ifndef GLX_SGI_swap_control
#define GLX_SGI_swap_control 1
#define __GENERATE_GLX_SGI_swap_control__

extern int (GLApi *glXSwapIntervalSGI_ptr)(int interval);

#define glXSwapIntervalSGI glXSwapIntervalSGI_ptr

// no new tokens

#endif // GLX_SGI_swap_control

/*
 *								=== ~GLX_SGI_swap_control ===
 */

/*
 *								=== GLX_ARB_multisample ===
 */

#ifndef WGL_ARB_multisample
#define WGL_ARB_multisample 1
#define __GENERATE_WGL_ARB_multisample__

#define GLX_SAMPLE_BUFFERS_ARB               100000
#define GLX_SAMPLES_ARB                      100001

// no new procedures or functions

#endif // WGL_ARB_multisample

/*
 *								=== ~GLX_ARB_multisample ===
 */

#endif // _WIN32 || _WIN64

/*
 *								=== CGL4Driver ===
 */

#ifdef __GENERATE_WGL_ARB_create_context__

HGLRC (GLApi *wglCreateContextAttribsARB_ptr)(HDC, HGLRC, const int*) = 0;

#endif // __GENERATE_WGL_ARB_create_context__

int CGL4Driver::n_GetCreateContextARBFuncPointers()
{
	int n_failed_functions = 1;

#ifdef __GENERATE_WGL_ARB_create_context__

	n_failed_functions = 0;

	if(!(wglCreateContextAttribsARB_ptr = (HGLRC(GLApi*)(HDC, HGLRC, const int*))wglGetProcAddress("wglCreateContextAttribsARB"))) ++ n_failed_functions;

#endif // __GENERATE_WGL_ARB_create_context__

	return n_failed_functions;
}

#ifdef __GENERATE_WGL_EXT_swap_control__

BOOL (GLApi *wglSwapIntervalEXT_ptr)(int interval) = 0;
int (GLApi *wglGetSwapIntervalEXT_ptr)(void) = 0;

#endif // __GENERATE_WGL_EXT_swap_control__

int CGL4Driver::n_GetSwapControlEXTFuncPointers()
{
	int n_failed_functions = 2;

#ifdef __GENERATE_WGL_EXT_swap_control__

	n_failed_functions = 0;

	if(!(wglSwapIntervalEXT_ptr = (BOOL(GLApi*)(int))wglGetProcAddress("wglSwapIntervalEXT"))) ++ n_failed_functions;
	if(!(wglGetSwapIntervalEXT_ptr = (int(GLApi*)(void))wglGetProcAddress("wglGetSwapIntervalEXT"))) ++ n_failed_functions;

#endif // __GENERATE_WGL_EXT_swap_control__

	return n_failed_functions;
}

#ifdef __GENERATE_WGL_ARB_pixel_format__

BOOL (GLApi *wglGetPixelFormatAttribivARB_ptr)(HDC hdc,
                               int iPixelFormat,
                               int iLayerPlane,
                               UINT nAttributes,
                               int *piAttributes,
                               int *piValues) = 0;
BOOL (GLApi *wglGetPixelFormatAttribfvARB_ptr)(HDC hdc,
                               int iPixelFormat,
                               int iLayerPlane,
                               UINT nAttributes,
                               int *piAttributes,
                               FLOAT *pfValues) = 0;
BOOL (GLApi *wglChoosePixelFormatARB_ptr)(HDC hdc,
                          const int *piAttribIList,
                          const FLOAT *pfAttribFList,
                          UINT nMaxFormats,
                          int *piFormats,
                          UINT *nNumFormats) = 0;

#endif // __GENERATE_WGL_ARB_pixel_format__

int CGL4Driver::n_GetPixelFormatARBFuncPointers()
{
	int n_failed_functions = 3;

#ifdef __GENERATE_WGL_ARB_pixel_format__

	n_failed_functions = 0;

	if(!(wglGetPixelFormatAttribivARB_ptr = (BOOL(GLApi*)(HDC, int, int, UINT, int*, int*))wglGetProcAddress("wglGetPixelFormatAttribivARB"))) ++ n_failed_functions;
	if(!(wglGetPixelFormatAttribfvARB_ptr = (BOOL(GLApi*)(HDC, int, int, UINT, int*, FLOAT*))wglGetProcAddress("wglGetPixelFormatAttribfvARB"))) ++ n_failed_functions;
	if(!(wglChoosePixelFormatARB_ptr = (BOOL(GLApi*)(HDC, const int*, const FLOAT*, UINT, int*, UINT*))wglGetProcAddress("wglChoosePixelFormatARB"))) ++ n_failed_functions;

#endif // __GENERATE_WGL_ARB_pixel_format__

	return n_failed_functions;
}

#ifdef __GENERATE_GLX_SGI_swap_control__

int (GLApi *glXSwapIntervalSGI_ptr)(int interval) = 0;

#endif // __GENERATE_GLX_SGI_swap_control__

int CGL4Driver::n_GetSwapIntervalSGIFuncPointers()
{
	int n_failed_functions = 1;

#ifdef __GENERATE_GLX_SGI_swap_control__

	n_failed_functions = 0;

	if(!(glXSwapIntervalSGI_ptr = (BOOL(GLApi*)(int))glxGetProcAddressARB("glXSwapIntervalSGI_ptr"))) ++ n_failed_functions;

#endif // __GENERATE_GLX_SGI_swap_control__

	return n_failed_functions;
}

CGL4Driver::CGL4Driver()
	:m_b_status(false)
{
}

CGL4Driver::~CGL4Driver()
{
    if(m_b_status)
        Shutdown();
}

bool CGL4Driver::Init(HWND h_wnd, bool b_forward_compatible,
	int n_opengl_major, int n_opengl_minor, int n_width, int n_height, int n_bpp,
	int n_depth_bpp, int n_stencil_bpp, bool b_fullscreen, bool b_enable_vsync,
	bool b_disable_vsync, int n_multisample_sample_num)
{
	if(m_b_status)
		Shutdown();

    if(b_fullscreen) {
		DEVMODE t_device_mode;
        memset(&t_device_mode, 0, sizeof(t_device_mode));
        t_device_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
        t_device_mode.dmSize = sizeof(DEVMODE);
        t_device_mode.dmPelsWidth = n_width;
        t_device_mode.dmPelsHeight = n_height;
        t_device_mode.dmBitsPerPel = n_bpp;
        // sets device mode for fullscreen mode

        if(ChangeDisplaySettings(&t_device_mode, 4) != DISP_CHANGE_SUCCESSFUL) {
            if(MessageBoxA(NULL, "Unable to set fullscreen mode.\n"
               "Use windowed mode instead?", "Fullscreen", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
                m_b_fullscreen = 0;
            else
                return false;
        }
        // tries to change the mode, allows fallback to windowed

        ShowCursor(false);
    }
	m_b_fullscreen = b_fullscreen;
	// set fullscreen mode

	HGLRC h_gl_rc;
	if(n_multisample_sample_num > 0) {
		// use WGL_ARB_pixel_format

		if(!wglChoosePixelFormatARB) {
			HWND h_dummy = CreateWindow("EDIT", "pfmt",
				WS_POPUP, 0, 0, 64, 16, NULL, NULL, NULL, NULL);
			HDC h_dummy_dc;
			if(!h_dummy || !(h_dummy_dc = GetDC(h_dummy))) {
				MessageBoxA(NULL, "Failed to create the dummy window.",
					"OpenGL driver", MB_OK | MB_ICONERROR);
				if(h_dummy)
					DestroyWindow(h_dummy);
				return false;
			}
			// create a dummy window

			PIXELFORMATDESCRIPTOR t_format_1;
			int n_pixel_format;
			HGLRC h_gl_rc;
			if(!DescribePixelFormat(h_dummy_dc, 1, sizeof(PIXELFORMATDESCRIPTOR), &t_format_1) ||
			   !(n_pixel_format = ChoosePixelFormat(h_dummy_dc, &t_format_1)) ||
			   !SetPixelFormat(h_dummy_dc, n_pixel_format, &t_format_1) ||
			   !(h_gl_rc = wglCreateContext(h_dummy_dc)) || !wglMakeCurrent(h_dummy_dc, h_gl_rc)) {
				MessageBoxA(NULL, "Failed to initialize the dummy GL context.",
					"OpenGL driver", MB_OK | MB_ICONERROR);
				ReleaseDC(h_dummy, h_dummy_dc);
				DestroyWindow(h_dummy);
				return false;
			}
			// init OpenGL

			n_GetPixelFormatARBFuncPointers();
			// get wglChoosePixelFormatARB

			wglMakeCurrent(NULL, NULL);
			wglDeleteContext(h_gl_rc);
			ReleaseDC(h_dummy, h_dummy_dc);
			DestroyWindow(h_dummy);
			// shutdown OpenGL (ignore any errors here)
		}
		// create a dummy invisible OpenGL window to get the extension

		if(wglChoosePixelFormatARB) {
			int p_pfmt_iattrib_list[] = {
				WGL_DRAW_TO_WINDOW_ARB, 1,
				WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
				WGL_SUPPORT_OPENGL_ARB, 1,
				WGL_DOUBLE_BUFFER_ARB, 1,
				WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB,
				WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
				WGL_COLOR_BITS_ARB, n_bpp,
				WGL_DEPTH_BITS_ARB, n_depth_bpp,
				WGL_ACCUM_BITS_ARB, 0, // ...
				WGL_STENCIL_BITS_ARB, n_stencil_bpp,

				WGL_SAMPLE_BUFFERS_ARB, 1,
				WGL_SAMPLES_ARB, n_multisample_sample_num,
				// enable multisampling

				0, 0 // terminator
			};
			float p_pfmt_fattrib_list[] = {
				0, 0 // terminator
			};
			// specify the attributes

			if(!(m_h_dc = GetDC(m_h_wnd = h_wnd))) {
				MessageBoxA(NULL, "Unable to get device context.",
					"OpenGL driver", MB_OK | MB_ICONERROR);
				return false;
			}
			// get DC

			int n_pixel_format_id;
			unsigned int n_format_num;
			if(!wglChoosePixelFormatARB(m_h_dc, p_pfmt_iattrib_list, p_pfmt_fattrib_list,
			   1, (int*)&n_pixel_format_id, &n_format_num) || !n_format_num) {
				MessageBoxA(NULL, "Unable to find a suitable pixelformat.",
					"OpenGL driver", MB_OK | MB_ICONERROR);
				return false;
			}
			m_n_pixel_format_id = n_pixel_format_id;
			// find pixel format

			if(!DescribePixelFormat(m_h_dc, m_n_pixel_format_id,
			   sizeof(PIXELFORMATDESCRIPTOR), &m_t_pixel_format)) {
				MessageBoxA(NULL, "Unable to describe the pixelformat.",
					"OpenGL driver", MB_OK | MB_ICONERROR);
				return false;
			}
			if(!SetPixelFormat(m_h_dc, m_n_pixel_format_id, &m_t_pixel_format)) {
				MessageBoxA(NULL, "Unable to set the pixelformat.",
					"OpenGL driver", MB_OK | MB_ICONERROR);
				return false;
			}
			if(!(h_gl_rc = wglCreateContext(m_h_dc))) {
				MessageBoxA(NULL, "Unable to create a GL rendering context.",
					"OpenGL driver", MB_OK | MB_ICONERROR);
				return false;
			}
			if(!wglMakeCurrent(m_h_dc, h_gl_rc)) {
				MessageBoxA(NULL, "Unable to activate the GL rendering context.",
					"OpenGL driver", MB_OK | MB_ICONERROR);
				return false;
			}
			// create the context
		} else {
			MessageBoxA(NULL, "Error: WGL_ARB_pixel_format not supported.",
				"OpenGL driver", MB_OK | MB_ICONERROR);
			return false;
		}
	} else {
		// use winapi (no extended formats)

		memset(&m_t_pixel_format, 0, sizeof(PIXELFORMATDESCRIPTOR));
		m_t_pixel_format.nSize = sizeof(PIXELFORMATDESCRIPTOR);
		m_t_pixel_format.nVersion = 1;
		m_t_pixel_format.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
			PFD_DOUBLEBUFFER | PFD_SWAP_EXCHANGE;
		m_t_pixel_format.dwLayerMask = PFD_MAIN_PLANE;
		m_t_pixel_format.iPixelType = PFD_TYPE_RGBA;
		m_t_pixel_format.cColorBits = n_bpp;
		m_t_pixel_format.cDepthBits = n_depth_bpp;
		m_t_pixel_format.cAccumBits = 0;
		m_t_pixel_format.cStencilBits = n_stencil_bpp;
		// sets pixel format descriptor

		if(!(m_h_dc = GetDC(m_h_wnd = h_wnd))) {
			MessageBoxA(NULL, "Unable to get device context.",
				"OpenGL driver", MB_OK | MB_ICONERROR);
			return false;
		}
		if(!(m_n_pixel_format_id = ChoosePixelFormat(m_h_dc, &m_t_pixel_format))) {
			MessageBoxA(NULL, "Unable to find a suitable pixelformat.",
				"OpenGL driver", MB_OK | MB_ICONERROR);
			return false;
		}
		if(!SetPixelFormat(m_h_dc, m_n_pixel_format_id, &m_t_pixel_format)) {
			MessageBoxA(NULL, "Unable to set the pixelformat.",
				"OpenGL driver", MB_OK | MB_ICONERROR);
			return false;
		}

		if(!(h_gl_rc = wglCreateContext(m_h_dc))) {
			MessageBoxA(NULL, "Unable to create a GL rendering context.",
				"OpenGL driver", MB_OK | MB_ICONERROR);
			return false;
		}
		if(!wglMakeCurrent(m_h_dc, h_gl_rc)) {
			MessageBoxA(NULL, "Unable to activate the GL rendering context.",
				"OpenGL driver", MB_OK | MB_ICONERROR);
			return false;
		}
		// create and activate the context
	}
	// create the dummy OpenGL context (having the coorect pixel format)

	if(b_forward_compatible) {
		if(!wglCreateContextAttribsARB && n_GetCreateContextARBFuncPointers()) {
			MessageBoxA(NULL, "OpenGL 3.0 not supported by window system\n"
				"(WGL_ARB_create_context not present).", "OpenGL driver", MB_OK | MB_ICONERROR);
			return false;
		}
		// needs wglCreateContextAttribsARB extension

		if(n_opengl_major || n_opengl_minor) {
			const int p_params[] = {
				WGL_CONTEXT_LAYER_PLANE_ARB, 0, // main plane
				WGL_CONTEXT_MAJOR_VERSION_ARB, n_opengl_major,
				WGL_CONTEXT_MINOR_VERSION_ARB, n_opengl_minor,
				WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, // want forward compatible context
				//WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, // want core profile; this is set by default and we do not set it here as nvidia drivers have some problems with that
				0
			};
			if(!(m_h_glrc = wglCreateContextAttribsARB(m_h_dc, 0, p_params))) {
				char p_s_error[64]; // the message is 46 chars long, + some for digits if large numbers got there
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
				sprintf_s(p_s_error, sizeof(p_s_error), "Unable to create "
					"OpenGL %d.%d rendering context.", n_opengl_major, n_opengl_minor);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
				sprintf(p_s_error, "Unable to create OpenGL %d.%d rendering context.",
					n_opengl_major, n_opengl_minor);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
				MessageBoxA(NULL, p_s_error, "OpenGL driver", MB_OK | MB_ICONERROR);
				return false;
			}
		} else {
			// if major and minor are both null, try to get the highest version possible

			int n_major_max, n_minor_max;
			glGetIntegerv(GL_MAJOR_VERSION, &n_major_max);
			glGetIntegerv(GL_MINOR_VERSION, &n_minor_max);
			if(glGetError() == GL_NO_ERROR && n_major_max >= 3) {
				const int p_params[] = {
					WGL_CONTEXT_LAYER_PLANE_ARB, 0, // main plane
					WGL_CONTEXT_MAJOR_VERSION_ARB, n_major_max,
					WGL_CONTEXT_MINOR_VERSION_ARB, n_minor_max,
					WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, // want forward compatible context
					//WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, // want core profile; this is set by default and we do not set it here as nvidia drivers have some problems with that
					0
				};
				m_h_glrc = wglCreateContextAttribsARB(m_h_dc, 0, p_params);
				// if the OpenGL version is available to us from start, use that
			} else {
				for(int n_major = 10; n_major >= 3; -- n_major) {
					for(int n_minor = 100; n_minor >= 0; -- n_minor) {
						const int p_params[] = {
							WGL_CONTEXT_LAYER_PLANE_ARB, 0, // main plane
							WGL_CONTEXT_MAJOR_VERSION_ARB, n_major,
							WGL_CONTEXT_MINOR_VERSION_ARB, n_minor,
							WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, // want forward compatible context
							//WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, // want core profile; this is set by default and we do not set it here as nvidia drivers have some problems with that
							0
						};
						if(m_h_glrc = wglCreateContextAttribsARB(m_h_dc, 0, p_params)) {
							n_major = 1; // to break form the outer loop
							break;
						}
					}
				}
				// attempts for the highest version supported
			}

			if(!m_h_glrc) {
				MessageBoxA(NULL, "Unable to create OpenGL 3.0+ rendering context.", "OpenGL driver", MB_OK | MB_ICONERROR);
				return false;
			}
		}
		if(!wglMakeCurrent(m_h_dc, m_h_glrc)) {
			MessageBoxA(NULL, "Unable to activate the GL rendering context.", "OpenGL driver", MB_OK | MB_ICONERROR);
			return false;
		}
		// creates forward compatible OpenGL context

		/*int n_profile_flags;
		glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &n_profile_flags);
		if(glGetError() != GL_NO_ERROR || !(n_profile_flags & WGL_CONTEXT_CORE_PROFILE_BIT_ARB)) {
			MessageBoxA(NULL, "Warning: Created OpenGL profile is not a core profile.",
				"OpenGL driver", MB_OK | MB_ICONEXCLAMATION);
		}
		int n_context_flags;
		glGetIntegerv(GL_CONTEXT_FLAGS, &n_context_flags);
		if(glGetError() != GL_NO_ERROR || !(n_context_flags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)) {
			MessageBoxA(NULL, "Warning: Created OpenGL profile is not a forward-compatible profile.",
				"OpenGL driver", MB_OK | MB_ICONEXCLAMATION);
		}*/
		// debug

		wglDeleteContext(h_gl_rc);
		// deletes the dummy context
	} else
		m_h_glrc = h_gl_rc; // otherwise just use the dummy context

	if((b_enable_vsync || b_disable_vsync) &&
	   (wglSwapIntervalEXT || !n_GetSwapControlEXTFuncPointers())) {
		_ASSERTE(!b_enable_vsync || !b_disable_vsync);
		if(b_enable_vsync)
			wglSwapIntervalEXT(1);
		else if(b_disable_vsync)
			wglSwapIntervalEXT(0);
	}
	// enable / disable VSync if required

    //glViewport(0, 0, n_width, n_height);
    // don't set viewport (default values are inferred from a window
	// dimensions when a GL context is first attached to it)

	/*if(n_multisample_sample_num > 0 &&
	   CGL4ExtensionHandler::b_Supported_Extension("GL_NV_multisample_filter_hint")) {
		enum {
			MULTISAMPLE_FILTER_HINT_NV = 0x8534
		};
		glHint(MULTISAMPLE_FILTER_HINT_NV, GL_FASTEST);
	}*/
	// no hinting!

    m_n_width = n_width;
    m_n_height = n_height;
    m_b_status = true;
	// remember framebuffer status (it may change, however)

    return true;
}

bool CGL4Driver::Shutdown()
{
	if(!m_b_status)
		return true;

    bool b_result = true;

    m_b_status = false;

    if(m_b_fullscreen) {
        ChangeDisplaySettings(NULL, 0);
        ShowCursor(true);
    }
	// returns from fullscreen mode

    if(m_h_glrc) {
        if(!wglMakeCurrent(NULL, NULL)) {
            MessageBoxA(NULL, "Release of DC and RC failed.", "OpenGL driver", MB_OK | MB_ICONERROR);
            b_result = false;
        }
        if(!wglDeleteContext(m_h_glrc)) {
            MessageBoxA(NULL, "Release rendering context failed.", "OpenGL driver", MB_OK | MB_ICONERROR);
            m_h_glrc = NULL;
            b_result = false;
        }
    }

    if(m_h_dc && !ReleaseDC(m_h_wnd, m_h_dc)) {
		MessageBoxA(NULL, "Release device context failed.", "OpenGL driver", MB_OK | MB_ICONERROR);
        m_h_dc = NULL;
        b_result = false;
    }

    return b_result;
}

bool CGL4Driver::b_Status() const
{
	return m_b_status;
}

bool CGL4Driver::MakeCurrent()
{
    if(!wglMakeCurrent(m_h_dc, m_h_glrc))
        return false;
	return true;
}

void CGL4Driver::ResetViewport() const
{
    glViewport(0, 0, m_n_width, m_n_height);
}

void CGL4Driver::SwapBuffers() const
{
    ::SwapBuffers(m_h_dc);
}

/*
 *								=== ~CGL4Driver ===
 */
