//-------------------------------------------------------------------------
//
// File:		OpenGLBufferC.h
// Desc:		OpenGL off-screen graphics rendering implementation.
// Author:		memon <memon@inside.org>
//
//-------------------------------------------------------------------------
//	Copyright (c) 2000 Moppi Productions. All Rights Reserved.
//  This file is part of Moppi Demopaja SDK. For conditions of 
//  distribution and use, see the accompanying license.txt file.
//  http://moppi.inside.org/demopaja/
//-------------------------------------------------------------------------


#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include "wglext.h"
#include "glext.h"
#include "PajaTypes.h"
#include "DeviceInterfaceI.h"
#include "GraphicsBufferI.h"
#include "OpenGLBufferC.h"
#include "ImportableImageI.h"

//#include "logger\logger.h"

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


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
bool
CHECK_GL_ERROR( const char* szName )
{
	GLenum	eError = glGetError();
	if( eError ) {
		OutputDebugString( szName );
		OutputDebugString( " " );
		OutputDebugString( (const char*)gluErrorString( eError ) );
		OutputDebugString( "\n" );
//		TRACE_LOG( "%s %s", szName, (const char*)gluErrorString( eError ) );
		return true;
	}
	return false;
}

inline
uint32
lowest_bit_mask( uint32 v )
{
	return (v & -v);
}

static
uint32
ceil_power2( uint32 ui32Num )
{
	uint32	i = lowest_bit_mask( ui32Num );
	while( i < ui32Num )
		i <<= 1;
	return i;
}


static bool g_bPBufferExtInit = false;

// pbuffer function prototypes
//static PFNWGLMAKECONTEXTCURRENTARBPROC		wglMakeContextCurrentARB = NULL;
static PFNWGLCHOOSEPIXELFORMATARBPROC		wglChoosePixelFormatARB = NULL;
static PFNWGLCREATEPBUFFERARBPROC			wglCreatePbufferARB = NULL;
static PFNWGLDESTROYPBUFFERARBPROC			wglDestroyPbufferARB = NULL;
static PFNWGLGETPBUFFERDCARBPROC			wglGetPbufferDCARB = NULL;
static PFNWGLRELEASEPBUFFERDCARBPROC		wglReleasePbufferDCARB = NULL;
static PFNWGLQUERYPBUFFERARBPROC			wglQueryPbufferARB = NULL;
static PFNWGLGETPIXELFORMATATTRIBIVARBPROC	wglGetPixelFormatAttribivARB = NULL;

static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL;

static bool g_bPBufferBindTexInit = false;
static PFNWGLBINDTEXIMAGEARBPROC			wglBindTexImageARB = NULL;
static PFNWGLRELEASETEXIMAGEARBPROC			wglReleaseTexImageARB = NULL;
static PFNWGLSETPBUFFERATTRIBARBPROC		wglSetPbufferAttribARB = NULL;

static
bool
init_extensions()
{
	if( g_bPBufferExtInit )
		return true;

	HDC	hDC = wglGetCurrentDC();

	// initialize extension entry points
//	wglMakeContextCurrentARB = (PFNWGLMAKECONTEXTCURRENTARBPROC)wglGetProcAddress( "wglMakeContextCurrentARB" );
	wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress( "wglChoosePixelFormatARB" );
	wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress( "wglCreatePbufferARB" );
	wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress( "wglDestroyPbufferARB" );
	wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress( "wglGetPbufferDCARB" );
	wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress( "wglReleasePbufferDCARB" );
	wglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC)wglGetProcAddress( "wglQueryPbufferARB" );
	wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress( "wglGetPixelFormatAttribivARB" );

	wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress( "wglGetExtensionsStringARB" );

	// for faster rendering...
	wglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress( "wglBindTexImageARB" );
	wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress( "wglReleaseTexImageARB" );
	wglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC)wglGetProcAddress( "wglSetPbufferAttribARB" );


	if( wglGetExtensionsStringARB ) {
		const char *buf = wglGetExtensionsStringARB( hDC );
//		TRACE_LOG( "Extensions ARB: %s\n", buf );
	}
	else {
//		TRACE_LOG( "No wglGetExtensionsStringARB\n" );
	}

/*	if( wglMakeContextCurrentARB == NULL ) {
		TRACE_LOG( "NO wglMakeContextCurrentARB!\n" );
		return false;
	}*/
	if( wglChoosePixelFormatARB == NULL ) {
//		TRACE_LOG( "NO wglChoosePixelFormatARB!\n" );
		return false;
	}
	if( wglCreatePbufferARB == NULL ) {
//		TRACE_LOG( "NO wglCreatePbufferARB!\n" );
		return false;
	}
	if( wglDestroyPbufferARB == NULL ) {
//		TRACE_LOG( "NO wglDestroyPbufferARB!\n" );
		return false;
	}
	if( wglGetPbufferDCARB == NULL ) {
//		TRACE_LOG( "NO wglGetPbufferDCARB!\n" );
		return false;
	}
	if( wglReleasePbufferDCARB == NULL ) {
//		TRACE_LOG( "NO wglReleasePbufferDCARB!\n" );
		return false;
	}
	if( wglQueryPbufferARB == NULL ) {
//		TRACE_LOG( "NO wglQueryPbufferARB!\n" );
		return false;
	}
	if( wglGetPixelFormatAttribivARB == NULL ) {
//		TRACE_LOG( "NO wglGetPixelFormatAttribivARB!\n" );
		return false;
	}

	if( wglBindTexImageARB && wglReleaseTexImageARB && wglSetPbufferAttribARB ) {
		TRACE( "Bind tex image OK\n" );
		g_bPBufferBindTexInit = true;
	}


	g_bPBufferExtInit = true;

	return true;
}




OpenGLBufferC::OpenGLBufferC() :
	m_hPBuffer( 0 ),
	m_hPBufferDC( 0 ),
	m_hPBufferRC( 0 ),
	m_ui32PBufferTexID( 0 ),
	m_pParentDev( 0 ),
	m_ui32InitFlags( GRAPHICSBUFFER_INIT_OFFSCREEN ),
	m_bBindToRenderTexture( false ),
	m_bRectangle( false )
{
	m_pViewport = OpenGLViewportC::create_new();
	m_ui32State = DEVICE_STATE_LOST;
}

OpenGLBufferC::OpenGLBufferC( GraphicsDeviceI* pDevice ) :
	m_hPBuffer( 0 ),
	m_hPBufferDC( 0 ),
	m_hPBufferRC( 0 ),
	m_ui32PBufferTexID( 0 ),
	m_ui32InitFlags( GRAPHICSBUFFER_INIT_OFFSCREEN ),
	m_pParentDev( (OpenGLDeviceC*)pDevice )
{
	m_pViewport = OpenGLViewportC::create_new();
	m_ui32State = DEVICE_STATE_LOST;
}

OpenGLBufferC::~OpenGLBufferC()
{
	destroy();
	if( m_pViewport )
		m_pViewport->release();
}


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

OpenGLBufferC*
OpenGLBufferC::create_new( GraphicsDeviceI* pDevice )
{
	return new OpenGLBufferC( pDevice );
}

ClassIdC
OpenGLBufferC::get_class_id() const
{
	return CLASS_OPENGL_BUFFER;
}

const char*
OpenGLBufferC::get_class_name()
{
	return "OpenGLBuffer";
}


DeviceInterfaceI*
OpenGLBufferC::query_interface( const SuperClassIdC& rSuperClassId )
{
	if( rSuperClassId == GRAPHICSDEVICE_VIEWPORT_INTERFACE ) {
		return m_pViewport;
	}
	return 0;
}


void
OpenGLBufferC::set_graphicsdevice( GraphicsDeviceI* pDevice )
{
	m_pParentDev = (OpenGLDeviceC*)pDevice;
}


void
OpenGLBufferC::destroy()
{
	// unset old context if it's currently in use
	HDC		hOldDC = wglGetCurrentDC();
	HGLRC	hOldRC = wglGetCurrentContext();
	if( hOldDC == m_hPBufferDC && hOldRC == m_hPBufferRC )
		wglMakeCurrent( NULL, NULL );

	if( m_hPBufferRC )
		wglDeleteContext( m_hPBufferRC );
	m_hPBufferRC = 0;

	if( m_hPBuffer ) {
		wglReleasePbufferDCARB( m_hPBuffer, m_hPBufferDC );
		wglDestroyPbufferARB( m_hPBuffer );
	}
	m_hPBuffer = 0;
	m_hPBufferDC = 0;

	if( m_ui32PBufferTexID )
		glDeleteTextures( 1, &m_ui32PBufferTexID );
	m_ui32PBufferTexID = 0;

	m_ui32State = DEVICE_STATE_LOST;
}



#define MAX_PFORMATS 256
#define MAX_ATTRIBS  32

bool
OpenGLBufferC::init( uint32 ui32Flags, uint32 ui32Width, uint32 ui32Height )
{
	m_ui32State = DEVICE_STATE_LOST;

	// if extensions cannot be initialsed, bail out.
	if( !init_extensions() ) {
		TRACE( "init extensions failed.\n" );
		return false;
	}

	// destroy current buffer
	destroy();

	// activate parent, so that we have active context while creatign the new buffer.
	m_pParentDev->activate();

	// Check if the new size is rectangle
	uint32	ui32WidthPOT = ceil_power2( ui32Width );
	uint32	ui32HeightPOT = ceil_power2( ui32Height );

	if( ui32Width == ui32WidthPOT && ui32Height == ui32HeightPOT )
		m_bRectangle = false;
	else
		m_bRectangle = true;

	
	// Query for a suitable pixel format based on the specified mode.
	int32		iAttributes[2 * MAX_ATTRIBS];
	float32 	fAttributes[2 * MAX_ATTRIBS];
	int32		nFAttribs = 0;
	int32		nIAttribs = 0;

  // Attribute arrays must be "0" terminated - for simplicity, first
  // just zero-out the array entire, then fill from left to right.
  memset( iAttributes, 0, sizeof(int)*2*MAX_ATTRIBS);
  memset( fAttributes, 0, sizeof(float)*2*MAX_ATTRIBS);
  // Since we are trying to create a pbuffer, the pixel format we
  // request (and subsequently use) must be "p-buffer capable".
  iAttributes[nIAttribs  ] = WGL_DRAW_TO_PBUFFER_ARB;
  iAttributes[++nIAttribs] = GL_TRUE;
  // we are asking for a pbuffer that is meant to be bound
  // as an RGBA texture - therefore we need a color plane
	if( !m_bRectangle && ui32Flags == GRAPHICSBUFFER_INIT_TEXTURE ) {
		iAttributes[++nIAttribs] = WGL_BIND_TO_TEXTURE_RGBA_ARB;
		iAttributes[++nIAttribs] = GL_TRUE;
	}

	iAttributes[++nIAttribs] = WGL_DEPTH_BITS_ARB;
	iAttributes[++nIAttribs] = 1;
	
	iAttributes[++nIAttribs] = WGL_STENCIL_BITS_ARB;
	iAttributes[++nIAttribs] = 1;
	
	iAttributes[++nIAttribs] = WGL_SUPPORT_OPENGL_ARB;
	iAttributes[++nIAttribs] = GL_TRUE;


	int format;
	int pformat[MAX_PFORMATS];
	unsigned int nformats;
	if( !wglChoosePixelFormatARB( m_pParentDev->get_hdc(), iAttributes, fAttributes, MAX_PFORMATS, pformat, &nformats ) ) {
		TRACE( "pbuffer creation error:  Couldn't find a suitable pixel format.\n" );
		return false;
	}
	format = pformat[0];


	// Create the p-buffer.

  // Set up the pbuffer attributes
  memset(iAttributes,0,sizeof(int)*2*MAX_ATTRIBS);
  nIAttribs = 0;
	if( !m_bRectangle && ui32Flags == GRAPHICSBUFFER_INIT_TEXTURE ) {
		// the render texture format is RGBA
		iAttributes[nIAttribs] = WGL_TEXTURE_FORMAT_ARB;
		iAttributes[++nIAttribs] = WGL_TEXTURE_RGBA_ARB;
		// the render texture target is GL_TEXTURE_2D
		iAttributes[++nIAttribs] = WGL_TEXTURE_TARGET_ARB;
		iAttributes[++nIAttribs] = WGL_TEXTURE_2D_ARB;
	}

	m_hPBuffer = wglCreatePbufferARB( m_pParentDev->get_hdc(), format, ui32Width, ui32Height, iAttributes );
	if ( !m_hPBuffer ) {
		DWORD err = GetLastError();
		TRACE( "pbuffer creation error:  wglCreatePbufferARB() failed (%d)\n", err );

		CHECK_GL_ERROR( "pbuffer creation.\n" );

		return false;
	}
	
	// Get the device context.
	m_hPBufferDC = wglGetPbufferDCARB( m_hPBuffer );
	if ( !m_hPBufferDC )
	{
		TRACE( "pbuffer creation error:  wglGetPbufferDCARB() failed\n" );
		return false;
	}
	
	// Create a gl context for the p-buffer.
	m_hPBufferRC = wglCreateContext( m_hPBufferDC );
	if ( !m_hPBufferRC ) {
		TRACE( "pbuffer creation error:  wglCreateContext() failed\n" );
		return false;
	}
	
	if( !wglShareLists( m_pParentDev->get_glrc(), m_hPBufferRC ) ) {
		TRACE( "pbuffer: wglShareLists() failed\n" );
		return false;
	}
	
	int32	w, h;

	// Determine the actual width and height we were able to create.
	wglQueryPbufferARB( m_hPBuffer, WGL_PBUFFER_WIDTH_ARB, &w );
	wglQueryPbufferARB( m_hPBuffer, WGL_PBUFFER_HEIGHT_ARB, &h );
	
	TRACE( "Created a %d x %d pbuffer\n", w, h );

	if( w && h ) {

		m_pViewport->set_dimension( 0, 0, w, h );

		if( ui32Flags == GRAPHICSBUFFER_INIT_TEXTURE ) {
	
			HDC		hOldDC = wglGetCurrentDC();
			HGLRC	hOldRC = wglGetCurrentContext();

			// reset old dependancies
			glBindTexture( GL_TEXTURE_2D, 0 );
			glBindTexture( GL_TEXTURE_1D, 0 );

			// set current device context
			wglMakeCurrent( m_hPBufferDC, m_hPBufferRC );

			if( m_ui32PBufferTexID )
				glDeleteTextures( 1, &m_ui32PBufferTexID );
		
			glGenTextures( 1, &m_ui32PBufferTexID );
	//			CHECK_GL_ERROR( "OpenGLBufferC::init() [gen tex]" );

			glBindTexture( GL_TEXTURE_2D, m_ui32PBufferTexID );
	//			CHECK_GL_ERROR( "OpenGLBufferC::init() [bind]" );

			glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

			// If not using render to texture extension, create the texture.
			if( m_bRectangle )
			{
				// create texture
				glTexImage2D( GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, m_pViewport->get_width(), m_pViewport->get_height(), 0, GL_RGB, GL_FLOAT, 0 );
			}
			else
			{
				if( !g_bPBufferBindTexInit )
				{
					// create texture
					glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, m_pViewport->get_width(), m_pViewport->get_height(), 0, GL_RGB, GL_FLOAT, 0 );
				}
			}

			wglMakeCurrent( hOldDC, hOldRC );
		}
	}
	
	CHECK_GL_ERROR( "OpenGLBufferC::init() [done]" );

	m_ui32InitFlags = ui32Flags;

	m_ui32State = DEVICE_STATE_OK;

	// Set texcoord bounds.
	m_rTexBounds[0] = Vector2C( 0, 0 );
	m_rTexBounds[1] = Vector2C( 1, 1 );

	return true;
}

uint32
OpenGLBufferC::get_flags()
{
	return m_ui32InitFlags;
}

void
OpenGLBufferC::begin_draw()
{
	// empty
}

void
OpenGLBufferC::end_draw()
{
	// empty
}

void
OpenGLBufferC::flush()
{
	if( !m_hPBuffer )
		return;

	glFlush();

	// make pbuffer into texture

	if( m_ui32InitFlags == GRAPHICSBUFFER_INIT_TEXTURE ) {

		if( g_bPBufferBindTexInit )
		{
			// Do nothing.
		}
		else {
			if( m_ui32PBufferTexID ) {
				// copy texture
				glBindTexture( GL_TEXTURE_2D, m_ui32PBufferTexID );
				if( CHECK_GL_ERROR( "OpenGLBufferC::flush() [bind]" ) ) {
	//				TRACE_LOG( "- texture ID: 0x%08x\n", m_ui32PBufferTexID );
				}

				glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_pViewport->get_width(), m_pViewport->get_height() );
				if( CHECK_GL_ERROR( "OpenGLBufferC::flush() [copy]" ) ) {
	//				TRACE_LOG( " - width: %d height: %d\n", m_pViewport->get_width(), m_pViewport->get_height() );
				}

				glBindTexture( GL_TEXTURE_2D, 0 );
			}
		}
	}
}

BBox2C&
OpenGLBufferC::get_tex_coord_bounds()
{
	return m_rTexBounds;
}

void
OpenGLBufferC::bind_texture( PajaSystem::DeviceInterfaceI* pInterface, PajaTypes::uint32 ui32Stage, uint32 ui32Properties )
{
	if( pInterface->get_class_id() != CLASS_OPENGL_DEVICEDRIVER )
		return;

	if( m_ui32PBufferTexID ) {
		CHECK_GL_ERROR( "OpenGLBufferC::bind_texture [has tex ID]" );

		glBindTexture( GL_TEXTURE_2D, m_ui32PBufferTexID );

		if( CHECK_GL_ERROR( "OpenGLBufferC::bind_texture [bind]" ) ) {
//			TRACE_LOG( "- texture ID: 0x%08x\n", m_ui32PBufferTexID );
		}

		glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

		if( ui32Properties & Import::IMAGE_CLAMP ) {
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
		}
		else {
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
		}

		if( g_bPBufferBindTexInit )
		{
			if( !m_bBindToRenderTexture )
			{
				// bind the pbuffer to the render texture object
				if( wglBindTexImageARB( m_hPBuffer, WGL_FRONT_LEFT_ARB ) == FALSE )
				{
					CHECK_GL_ERROR( "OpenGLBufferC::flush() bind render to texture" );
				}
				m_bBindToRenderTexture = true;
			}
		}

	}
	else {
//		TRACE_LOG( "Trying to bind P-Buffer texture with NULL texture ID\n" );
	}
}


void
OpenGLBufferC::read_pixels( uint32 ui32Flags, void* pData )
{
	if( !m_hPBuffer )
		return;

	// save old read buffer
	GLint	iOldBuffer;
	glGetIntegerv( GL_READ_BUFFER, &iOldBuffer );

	glReadBuffer( GL_FRONT_LEFT );


	glPixelStorei( GL_PACK_SWAP_BYTES, false );
	glPixelStorei( GL_PACK_LSB_FIRST, false );
	glPixelStorei( GL_PACK_ROW_LENGTH, 0 );
	glPixelStorei( GL_PACK_SKIP_ROWS, 0 );
	glPixelStorei( GL_PACK_SKIP_PIXELS, 0 );
	glPixelStorei( GL_PACK_ALIGNMENT, 1 );


	if( ui32Flags == GRAPHICSBUFFER_GET_RGB ) {
		glReadPixels( 0, 0, m_pViewport->get_width(), m_pViewport->get_height(), GL_RGB, GL_UNSIGNED_BYTE, pData );
	}
	else if( ui32Flags == GRAPHICSBUFFER_GET_RGBA ) {
		glReadPixels( 0, 0, m_pViewport->get_width(), m_pViewport->get_height(), GL_RGBA, GL_UNSIGNED_BYTE, pData );
	}
	else if( ui32Flags == GRAPHICSBUFFER_GET_ALPHA ) {
		glReadPixels( 0, 0, m_pViewport->get_width(), m_pViewport->get_height(), GL_ALPHA, GL_UNSIGNED_BYTE, pData );
	}
	else if( ui32Flags == GRAPHICSBUFFER_GET_DEPTH ) {
		glReadPixels( 0, 0, m_pViewport->get_width(), m_pViewport->get_height(), GL_DEPTH_COMPONENT, GL_FLOAT, pData );
	}
	else if( ui32Flags == GRAPHICSBUFFER_GET_STENCIL ) {
		glReadPixels( 0, 0, m_pViewport->get_width(), m_pViewport->get_height(), GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, pData );
	}

	glReadBuffer( iOldBuffer );
}

void
OpenGLBufferC::activate()
{
	if( !m_hPBuffer )
		return;

	// reset old dependancies
	glBindTexture( GL_TEXTURE_2D, 0 );
	glBindTexture( GL_TEXTURE_1D, 0 );

	// release the pbuffer from the render texture object
	if( g_bPBufferBindTexInit )
	{
		if( wglReleaseTexImageARB( m_hPBuffer, WGL_FRONT_LEFT_ARB ) == FALSE )
		{
			CHECK_GL_ERROR( "wglReleaseTexImageARB" );
		}
		m_bBindToRenderTexture = false;
	}

	// set current device context
	wglMakeCurrent( m_hPBufferDC, m_hPBufferRC );

	// Handle device lost
	int32	i32Lost = 0;
	wglQueryPbufferARB( m_hPBuffer, WGL_PBUFFER_LOST_ARB, &i32Lost );
	if( i32Lost ) {
		destroy();
		init( m_ui32InitFlags, m_pViewport->get_width(), m_pViewport->get_height() );
	}

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

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