#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <stdio.h>
#include <string>

#include "res\resource.h"

#include "PajaTypes.h"
#include "ColorC.h"
#include "OpenGLDeviceC.h"

using namespace PajaTypes;
using namespace PajaSystem;
using namespace PluginClass;
using namespace Edit;
using namespace FileIO;


static
void
TRACE( const char* szFormat, ...  )
{
	char	szMsg[256];
	va_list	rList;
	va_start( rList, szFormat );
	_vsnprintf( szMsg, 255, szFormat, rList );
	va_end( rList );
	OutputDebugString( szMsg );
}



// static variables
HGLRC	OpenGLDeviceC::m_hMainGLRC = 0;
int32	OpenGLDeviceC::m_i32RefCount = 0;
int32	OpenGLDeviceC::m_i32InstCount = 0;
bool	OpenGLDeviceC::m_bClassCreated = false;



LRESULT CALLBACK
OpenGLDeviceC::stub_window_proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	OpenGLDeviceC*	pDevice = reinterpret_cast<OpenGLDeviceC*>(GetWindowLong( hWnd, GWL_USERDATA ));
	PAINTSTRUCT		rPS;

	// the usual window procedure...

	switch( uMsg ) {
	case WM_CREATE:
		{
			SetWindowLong( hWnd, GWL_USERDATA, (LONG)((LPCREATESTRUCT)lParam)->lpCreateParams );

			pDevice = reinterpret_cast<OpenGLDeviceC*>(((LPCREATESTRUCT)lParam)->lpCreateParams);

            pDevice->m_hDC = GetDC( hWnd );

			if( !set_pixelformat( pDevice->m_hDC ) ) {
				OutputDebugString( "set pixel format failed." );
				return -1;
			}
            if ( (pDevice->m_hGLRC = wglCreateContext( pDevice->m_hDC )) == 0 ) {
				OutputDebugString( "wglCreateContext failed." );
				return -1;
			}

			if( !m_hMainGLRC ) {
				if( (m_hMainGLRC = wglCreateContext( pDevice->m_hDC )) == 0 ) {
					OutputDebugString( "m_rMainGLRC wglCreateContext failed." );
					return -1;
				}
			}

			wglShareLists( m_hMainGLRC, pDevice->m_hGLRC );
			m_i32RefCount++;

			wglMakeCurrent( NULL, NULL );

            if( !wglMakeCurrent( pDevice->m_hDC, pDevice->m_hGLRC ) ) {
				OutputDebugString( "wglMakeCurrent failed" );
				return -1;
			}
		}
		OutputDebugString( "Device Create\n" );
		return 0;

	case WM_DESTROY:
		wglMakeCurrent( NULL, NULL );
		wglDeleteContext( pDevice->m_hGLRC );
		ReleaseDC( hWnd, pDevice->m_hDC );

		if( m_i32RefCount )
			m_i32RefCount--;

		if( m_i32RefCount == 0 && m_hMainGLRC ) {
			wglDeleteContext( m_hMainGLRC );
			m_hMainGLRC = 0;
		}

		pDevice->m_hWnd = 0;

		OutputDebugString( "Device Destroy\n" );
		return 0;

	case WM_ERASEBKGND:
		return -1;	// we clear out mess ourselfs.

	case WM_PAINT:
		BeginPaint( hWnd, &rPS );
		EndPaint( hWnd, &rPS );
		return 0;

	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
	case WM_KEYDOWN:
	case WM_KEYUP:
	case WM_SETCURSOR:
	case WM_MOUSEMOVE:
		if( pDevice->m_ui32CreateFlags == GRAPHICSDEVICE_CREATE_EDITOR_CHILD )
			return PostMessage( GetParent( hWnd ), uMsg, wParam, lParam );
		break;

	case WM_CHAR:
		if( wParam == 27 ) {
			if( pDevice->m_ui32CreateFlags != GRAPHICSDEVICE_CREATE_EDITOR_CHILD ) {
				PostMessage( hWnd, DP_END_PREVIEW, 0, 0);
				return 0;
			}
		}
		break;

	case WM_CLOSE:
		if( pDevice->m_ui32CreateFlags != GRAPHICSDEVICE_CREATE_EDITOR_CHILD ) {
			PostMessage( hWnd, DP_END_PREVIEW, 0, 0);
			return 0;
		}
		break;

	case WM_SIZE:
		if( pDevice->m_ui32CreateFlags != GRAPHICSDEVICE_CREATE_EDITOR_CHILD ) {
			RECT	rRect;
			GetClientRect( hWnd, &rRect );
			uint32	ui32Width = rRect.right; //LOWORD( lParam );
			uint32	ui32Height = rRect.bottom; //HIWORD( lParam );
			pDevice->set_size( 0, 0, ui32Width, ui32Height );
		}

	case DP_END_PREVIEW:
		// make sure out message wont overflow to the system.
		return 0;

	}


	return DefWindowProc( hWnd, uMsg, wParam, lParam );
}



OpenGLDeviceC::OpenGLDeviceC() :
	m_hWnd( 0 ),
	m_hDC( 0 ),
	m_hGLRC( 0 ),
	m_bResolutionChanged( false ),
	m_pFeedback( 0 ),
	m_pCurrentBuffer( 0 ),
	m_pTempGBuffer( 0 )
{
	m_pInterface = OpenGLViewportC::create_new();
	m_pGUIDrawInterface = OpenGLGUIDrawInterfaceC::create_new( this );
}

OpenGLDeviceC::~OpenGLDeviceC()
{
	if( m_pTempGBuffer )
		m_pTempGBuffer->release();
	if( m_hWnd )
		destroy();
	if( m_pInterface )
		m_pInterface->release();
	if( m_pGUIDrawInterface )
		m_pGUIDrawInterface->release();
}

OpenGLDeviceC*
OpenGLDeviceC::create_new()
{
	return new OpenGLDeviceC;
}

DataBlockI*
OpenGLDeviceC::create()
{
	return new OpenGLDeviceC;
}

ClassIdC
OpenGLDeviceC::get_class_id() const
{
	return CLASS_OPENGL_DEVICEDRIVER;
}

const char*
OpenGLDeviceC::get_class_name()
{
	return "OpenGL Device Driver";
}

uint32
OpenGLDeviceC::save( SaveC* pSave )
{
	return IO_OK;
}

uint32
OpenGLDeviceC::load( LoadC* pLoad )
{
	return IO_OK;
}

bool
OpenGLDeviceC::init( HINSTANCE hInstance, HWND hParent, int32 i32ID, uint32 ui32Flags,
					   uint32 ui32Width, uint32 ui32Height, uint32 ui32BPP,
					   DeviceFeedbackC* pFeedback )
{

	//
	// Register window class.
	//
	if( !m_bClassCreated ) {
		WNDCLASS	rWndClass;

		// Set window infos
		memset( &rWndClass, 0, sizeof( rWndClass ) );
		rWndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
		rWndClass.lpfnWndProc = &stub_window_proc;
		rWndClass.cbClsExtra = 0;
		rWndClass.cbWndExtra = 0;
		rWndClass.hInstance = hInstance;
		rWndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
		rWndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
		rWndClass.hbrBackground = NULL;
		rWndClass.lpszMenuName = NULL;
		rWndClass.lpszClassName = "DemopajaOpenGLDevice";

		// register window
		if( !RegisterClass( &rWndClass ) )
			return false;

		m_bClassCreated = true;

		OutputDebugString( "class ok\n" );
	}

	if( ui32Flags == GRAPHICSDEVICE_CREATE_EDITOR_CHILD ) {
		// Create child window
		m_hWnd = CreateWindowEx( WS_EX_TRANSPARENT, "DemopajaOpenGLDevice", (LPSTR)NULL,
								WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
								0, 0, 0, 0,
								hParent, (HMENU)(int)i32ID, hInstance, (LPVOID)this );
	}
	else if( ui32Flags == GRAPHICSDEVICE_CREATE_CHILD ) {
		// Create child window
		m_hWnd = CreateWindowEx( WS_EX_TRANSPARENT, "DemopajaOpenGLDevice", (LPSTR)NULL,
								WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
								0, 0, 0, 0,
								hParent, (HMENU)(int)i32ID, hInstance, (LPVOID)this );
	}
	else if( ui32Flags == GRAPHICSDEVICE_CREATE_WINDOWED ) {

		uint32	ui32Caption = GetSystemMetrics( SM_CYCAPTION );
		uint32	ui32BorderX = GetSystemMetrics( SM_CXBORDER );
		uint32	ui32BorderY = GetSystemMetrics( SM_CXBORDER );

		// Create popup window
		m_hWnd = CreateWindowEx( 0, "DemopajaOpenGLDevice", "Demopaja",
								WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
								0, 0, ui32Width + 2 * ui32BorderX, ui32Height + ui32Caption + ui32BorderY * 2,
								hParent, NULL, hInstance, (LPVOID)this );

		ShowWindow( m_hWnd, SW_SHOW );

//		m_pInterface->set_dimension( 0, 0, ui32Width, ui32Height );
		set_size( 0, 0, ui32Width, ui32Height );
	}
	else if( ui32Flags == GRAPHICSDEVICE_CREATE_FULLSCREEN ) {
		// Create fullscreen window

		m_hWnd = CreateWindowEx( WS_EX_TOPMOST, "DemopajaOpenGLDevice", "Demopaja",
								WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
								0, 0, ui32Width, ui32Height,
								hParent, NULL, hInstance, (LPVOID)this );

		if( ui32BPP == 0 ) {
			// Get desktop BPP
			HDC dc = GetDC( 0 ); // desktop dc
			ui32BPP = GetDeviceCaps( dc, BITSPIXEL );
			ReleaseDC( 0, dc );
		}

		DEVMODE	rMode;
		bool	bFoundMode = false;
		uint32	ui32ScreenWidth = ui32Width;
		uint32	ui32ScreenHeight = ui32Height;
		uint32	i = 1;

		memset( &rMode, 0, sizeof( DEVMODE ) );
		rMode.dmSize = sizeof( DEVMODE );

		// init cache
		EnumDisplaySettings( NULL, 0, &rMode );

		// loop all modes
		while( EnumDisplaySettings( NULL, i, &rMode ) != FALSE ) {
			if( rMode.dmBitsPerPel == ui32BPP && rMode.dmPelsWidth >= ui32Width && rMode.dmPelsHeight >= ui32Height ) {
				ui32ScreenWidth = rMode.dmPelsWidth;
				ui32ScreenHeight = rMode.dmPelsHeight;
				bFoundMode = true;
				break;
			}
			i++;
		}

		if( !bFoundMode ) {
			MessageBox( NULL, "Could not find proper display settigs for fullscreen display.", "Error!", MB_OK );
			SendMessage( m_hWnd, WM_DESTROY, 0, 0);
			return false;
		}

		// full screen
		DEVMODE dm;
		memset( &dm, 0, sizeof( dm ) );
		dm.dmSize = sizeof( dm );
		dm.dmPelsWidth = ui32ScreenWidth;
		dm.dmPelsHeight = ui32ScreenHeight;
		dm.dmBitsPerPel = ui32BPP;
		dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
		if( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL ) {
			MessageBox( NULL, "Cannot change to requested fullscreen display mode.", "Error!", MB_OK );
			SendMessage( m_hWnd, WM_DESTROY, 0, 0);
			return false;
		}

		ShowWindow( m_hWnd, SW_MAXIMIZE );
		SetFocus( m_hWnd );
		BringWindowToTop( m_hWnd );
		SetForegroundWindow( m_hWnd );
		UpdateWindow( m_hWnd );

		m_pInterface->set_dimension( 0, 0, ui32ScreenWidth, ui32ScreenHeight );
		set_size( 0, 0, ui32Width, ui32Height );

		m_bResolutionChanged = true;
	}

	m_i32InstCount++;

	m_ui32CreateFlags = ui32Flags;
	m_pFeedback = pFeedback;

	// Create temporary buffer
	m_pTempGBuffer = OpenGLBufferC::create_new( this );
	if( !m_pTempGBuffer )
		return false;

	if( !m_pTempGBuffer->init( GRAPHICSBUFFER_INIT_TEXTURE, 256, 128 ) )
		return false;

	return true;
}

DeviceInterfaceI*
OpenGLDeviceC::query_interface( const SuperClassIdC& rSuperClassId )
{
	if( rSuperClassId == GRAPHICSDEVICE_VIEWPORT_INTERFACE ) {
		if( m_pCurrentBuffer )
			return m_pCurrentBuffer->query_interface( GRAPHICSDEVICE_VIEWPORT_INTERFACE );
		return m_pInterface;
	}
	else if( rSuperClassId == GRAPHICSDEVICE_GUIDRAW_INTERFACE ) {
		return m_pGUIDrawInterface;
	}

	return 0;
}


void
OpenGLDeviceC::activate()
{
	// reset old dependancies
//	glBindTexture( GL_TEXTURE_2D, 0 );
//	glBindTexture( GL_TEXTURE_1D, 0 );

	// unset old context
	wglMakeCurrent( NULL, NULL );
	// set current device context
	wglMakeCurrent( m_hDC, m_hGLRC );

	// Set viewport correctly
	glViewport( 0, 0, m_pInterface->get_width(), m_pInterface->get_height() );

	// Reset matrices.
	m_pInterface->activate();
}


void
OpenGLDeviceC::destroy()
{
	if( m_bResolutionChanged ) {
		// restore display mode
		ChangeDisplaySettings( NULL, 0 );
		m_bResolutionChanged = false;
	}

	DestroyWindow( m_hWnd );
}

void
OpenGLDeviceC::flush()
{
	if( m_pCurrentBuffer )
		m_pCurrentBuffer->flush();
	else
		SwapBuffers( m_hDC );
}



extern HINSTANCE	g_hInstance;


// Mesage handler for about box.
LRESULT CALLBACK
ConfigDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	switch( message ) {
	case WM_INITDIALOG:
		{
			std::string	sVendor = (const char*)glGetString( GL_VENDOR );
			std::string	sRenderer = (const char*)glGetString( GL_RENDERER );
			std::string	sVersion = (const char*)glGetString( GL_VERSION );
			std::string	sExtensions = (const char*)glGetString( GL_EXTENSIONS );

			std::string	sMsg;

			sMsg = "VENDOR:\r\n";
			sMsg += sVendor;
			sMsg += "\r\n\r\nRENDERER:\r\n";
			sMsg += sRenderer;
			sMsg += "\r\n\r\nVERSION:\r\n";
			sMsg += sVersion;
			sMsg += "\r\n\r\nEXTENSIONS:\r\n";

			for( uint32 i = 0; i < sExtensions.size(); i++ ) {
				if( sExtensions[i] == ' ' )
					sMsg += "\r\n";
				else
					sMsg += sExtensions[i];
			}

			HWND	hEdit;
			hEdit = GetDlgItem( hDlg, IDC_EDIT );
			SetWindowText( hEdit, sMsg.c_str() );

			return TRUE;
		}

	case WM_COMMAND:
		if( LOWORD( wParam ) == IDOK || LOWORD( wParam ) == IDCANCEL ) {
			EndDialog( hDlg, LOWORD( wParam ) );
			return TRUE;
		}
	}
    return FALSE;
}



bool
OpenGLDeviceC::configure()
{
	return DialogBox( g_hInstance, (LPCTSTR)IDD_CONFIG, NULL, (DLGPROC)ConfigDlgProc ) == IDOK ? true : false;
}


bool
OpenGLDeviceC::set_pixelformat( HDC hDC )
{
	PIXELFORMATDESCRIPTOR pfd = {
		sizeof( PIXELFORMATDESCRIPTOR ),// size of this pfd
		1,                              // version number
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,	
		PFD_TYPE_RGBA,                  // RGBA type
		32,								// color depth
		8, 0, 8, 0, 8, 0,               // color bits ignored
		8,                              // no alpha buffer
		0,                              // shift bit ignored
		0,                              // no accumulation buffer
		0, 0, 0, 0,                     // accum bits ignored
		24,								// 16-bit z-buffer
		8,                              // no stencil buffer
		0,                              // no auxiliary buffer
		PFD_MAIN_PLANE,                 // main layer
		0,                              // reserved
		0, 0, 0                         // layer masks ignored
	};

	int	iPixelformat;

	if( !(iPixelformat = ChoosePixelFormat( hDC, &pfd )) )
		return false;

	if( !SetPixelFormat( hDC, iPixelformat, &pfd ) )
		return false;

	return true;
}


void
OpenGLDeviceC::set_size( int32 i32X, int32 i32Y, int32 i32Width, int32 i32Height )
{

	if( m_ui32CreateFlags == GRAPHICSDEVICE_CREATE_EDITOR_CHILD ) {
		//
		// On child just enalrge the viewport (no scaling).
		//
		MoveWindow( m_hWnd, i32X, i32Y, i32Width, i32Height, TRUE);

		Vector2C	rDelta( (float32)(i32Width - m_pInterface->get_width()) / 2.0f, (float32)(i32Height - m_pInterface->get_height()) / 2.0f );
		rDelta = m_pInterface->delta_client_to_layout( rDelta );

		BBox2C	rViewport = m_pInterface->get_viewport();

		rViewport[0] -= rDelta;
		rViewport[1] += rDelta;

		m_pInterface->set_viewport( rViewport );

		if( m_pTempGBuffer )
			m_pTempGBuffer->init( GRAPHICSBUFFER_INIT_TEXTURE, 256, 128 );
	}
	else
	{
		//
		// The windowed and fullscreen are maximized.
		//
		BBox2C	rLayout = m_pInterface->get_layout();

		float32	f32LayoutWidth = rLayout.width();
		float32	f32LayoutHeight = rLayout.height();

		float64	f64AspectX = (float64)i32Width / (float64)f32LayoutWidth;
		float64	f64AspectY = (float64)i32Height / (float64)f32LayoutHeight;

		if( f64AspectX < f64AspectY )
			f32LayoutHeight = f32LayoutWidth / (float32)i32Width * (float32)i32Height;
		else
			f32LayoutWidth = f32LayoutHeight / (float32)i32Height * (float32)i32Width;

		float32	f32LayoutPosX = (f32LayoutWidth * 0.5f) - (rLayout.width() * 0.5f);
		float32	f32LayoutPosY = (f32LayoutHeight * 0.5f) - (rLayout.height() * 0.5f);


		BBox2C	rViewport( Vector2C( -f32LayoutPosX, -f32LayoutPosY ),
						   Vector2C( -f32LayoutPosX + f32LayoutWidth, -f32LayoutPosY + f32LayoutHeight ) );

		m_pInterface->set_viewport( rViewport );

		if( m_pTempGBuffer )
			m_pTempGBuffer->init( GRAPHICSBUFFER_INIT_TEXTURE, 256, 128 );
	}

	glViewport( 0, 0, i32Width, i32Height );

	m_pInterface->set_dimension( i32X, i32Y, i32Width, i32Height );

}

HWND
OpenGLDeviceC::get_hwnd()
{
	return m_hWnd;
}


void
OpenGLDeviceC::clear_device( uint32 ui32Flags, const ColorC& rColor, float32 f32Depth, int32 i32Stencil )
{
	GLint	iClearBits = 0;

	if( ui32Flags & GRAPHICSDEVICE_COLORBUFFER ) {
		glClearColor( rColor[0], rColor[1], rColor[2], rColor[3] );
		iClearBits |= GL_COLOR_BUFFER_BIT;
	}

	if( ui32Flags & GRAPHICSDEVICE_DEPTHBUFFER ) {
		glClearDepth( f32Depth );
		iClearBits |= GL_DEPTH_BUFFER_BIT;
	}

	if( ui32Flags & GRAPHICSDEVICE_STENCILBUFFER ) {
		glClearStencil( i32Stencil );
		iClearBits |= GL_STENCIL_BUFFER_BIT;
	}

	// make sure we clear whole screen despite the scissor stuff
	GLint	iScissorTest;
	glGetIntegerv( GL_SCISSOR_TEST, &iScissorTest );
	glDisable( GL_SCISSOR_TEST );

	glClear( iClearBits );

	if( iScissorTest )
		glEnable( GL_SCISSOR_TEST );
}

void
OpenGLDeviceC::begin_effects()
{
	glDepthMask( GL_TRUE );

	glPushAttrib( GL_ALL_ATTRIB_BITS );

	glMatrixMode( GL_PROJECTION );
	glPushMatrix();

	glMatrixMode( GL_MODELVIEW );
	glPushMatrix();
}

void
OpenGLDeviceC::end_effects()
{
	glDepthMask( GL_FALSE );

	glPopAttrib();

	glMatrixMode( GL_PROJECTION );
	glPopMatrix();

	glMatrixMode( GL_MODELVIEW );
	glPopMatrix();
}

bool
OpenGLDeviceC::begin_draw()
{
	if( m_pCurrentBuffer )
		m_pCurrentBuffer->begin_draw();
	return true;
}

void
OpenGLDeviceC::end_draw()
{
	if( m_pCurrentBuffer )
		m_pCurrentBuffer->end_draw();
}

HDC
OpenGLDeviceC::get_hdc()
{
	return m_hDC;
}

HGLRC
OpenGLDeviceC::get_glrc()
{
	return m_hGLRC;
}


bool
OpenGLDeviceC::set_fullscreen( uint32 ui32Width, uint32 ui32Height, uint32 ui32BPP )
{
	if( ui32BPP == 0 ) {
		// Get desktop BPP
		HDC dc = GetDC( 0 ); // desktop dc
		ui32BPP = GetDeviceCaps( dc, BITSPIXEL );
		ReleaseDC( 0, dc );
	}

	DEVMODE	rMode;
	bool	bFoundMode = false;
	uint32	ui32ScreenWidth = ui32Width;
	uint32	ui32ScreenHeight = ui32Height;
	uint32	i = 1;

	memset( &rMode, 0, sizeof( DEVMODE ) );
	rMode.dmSize = sizeof( DEVMODE );

	// init cache
	EnumDisplaySettings( NULL, 0, &rMode );

	// loop all modes
	while( EnumDisplaySettings( NULL, i, &rMode ) != FALSE ) {
		if( rMode.dmBitsPerPel == ui32BPP && rMode.dmPelsWidth >= ui32Width && rMode.dmPelsHeight >= ui32Height ) {
			ui32ScreenWidth = rMode.dmPelsWidth;
			ui32ScreenHeight = rMode.dmPelsHeight;
			bFoundMode = true;
			break;
		}
		i++;
	}

	if( !bFoundMode ) {
		MessageBox( NULL, "Could not find proper display settigs for fullscreen display.", "Error!", MB_OK );
		return false;
	}

	// full screen
/*	DEVMODE dm;
	memset( &dm, 0, sizeof( dm ) );
	dm.dmSize = sizeof( dm );
	dm.dmPelsWidth = ui32ScreenWidth;
	dm.dmPelsHeight = ui32ScreenHeight;
	dm.dmBitsPerPel = ui32BPP;
	dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;*/
	LONG	lRes = ChangeDisplaySettings( &rMode, CDS_FULLSCREEN );
	if( lRes != DISP_CHANGE_SUCCESSFUL ) {
		MessageBox( NULL, "Cannot change to requested fullscreen display mode.", "Error!", MB_OK );
		return false;
	}
	m_bResolutionChanged = true;

	m_rSavedViewport = m_pInterface->get_viewport();

//	m_pInterface->set_dimension( 0, 0, ui32ScreenWidth, ui32ScreenHeight );

	m_ui32SavedCreateFlags = m_ui32CreateFlags;
	m_ui32CreateFlags = GRAPHICSDEVICE_CREATE_FULLSCREEN;

	// Save window state
	m_lSavedWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
	m_lSavedExWindowStyle = GetWindowLong( m_hWnd, GWL_EXSTYLE );
	m_hSavedParent = GetParent( m_hWnd );
	GetWindowRect( m_hWnd, &m_rSavedWindowRect );

	SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
	SetWindowLong( m_hWnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW );
	SetParent( m_hWnd, NULL );

	ShowWindow( m_hWnd, SW_SHOW );
	MoveWindow( m_hWnd, 0, 0, ui32ScreenWidth, ui32ScreenHeight, TRUE );
	SetFocus( m_hWnd );
	BringWindowToTop( m_hWnd );
	SetForegroundWindow( m_hWnd );
	UpdateWindow( m_hWnd );

	set_size( 0, 0, ui32ScreenWidth, ui32ScreenHeight );

	return true;
}


bool
OpenGLDeviceC::set_windowed()
{
	if( m_bResolutionChanged ) {
		// restore display mode
		ChangeDisplaySettings( NULL, 0 );
		m_bResolutionChanged = false;
	}

	// Restore window state
	m_ui32CreateFlags = m_ui32SavedCreateFlags;
	SetWindowLong( m_hWnd, GWL_STYLE, m_lSavedWindowStyle );
	SetWindowLong( m_hWnd, GWL_EXSTYLE, m_lSavedExWindowStyle );
	SetParent( m_hWnd, m_hSavedParent );

	RECT	rRect;
	GetClientRect( m_hSavedParent, &rRect );
	MoveWindow( m_hWnd, rRect.left, rRect.top, (rRect.right - rRect.left), (rRect.bottom - rRect.top), TRUE );
	m_pInterface->set_dimension( rRect.left, rRect.top, (rRect.right - rRect.left), (rRect.bottom - rRect.top) );
	m_pInterface->set_viewport( m_rSavedViewport );

	ShowWindow( m_hWnd, SW_SHOW );
	UpdateWindow( m_hWnd );

	set_size( rRect.left, rRect.top, (rRect.right - rRect.left), (rRect.bottom - rRect.top) );

	return true;
}

GraphicsBufferI*
OpenGLDeviceC::create_graphicsbuffer()
{
	return OpenGLBufferC::create_new( this );
}

void
OpenGLDeviceC::set_temp_graphicsbuffer_size( PajaTypes::uint32 ui32Width, PajaTypes::uint32 ui32Height )
{
}

GraphicsBufferI*
OpenGLDeviceC::get_temp_graphicsbuffer( PajaTypes::uint32 ui32Flags )
{
	return (GraphicsBufferI*)m_pTempGBuffer;
}

void
OpenGLDeviceC::free_temp_graphicsbuffer( GraphicsBufferI* )
{
}

GraphicsBufferI*
OpenGLDeviceC::set_render_target( GraphicsBufferI* pBuffer )
{
	if( pBuffer ) {
		OpenGLBufferC*	pPrevBuffer = m_pCurrentBuffer;
		m_pCurrentBuffer = (OpenGLBufferC*)pBuffer;
		m_pCurrentBuffer->activate();
		return pPrevBuffer;
	}

	// use this buffer
	m_pCurrentBuffer = 0;
	activate();

	return 0;
}

GraphicsBufferI*
OpenGLDeviceC::get_render_target()
{
	return m_pCurrentBuffer;
}
