#include "win32.h"
#include "gl_drv.h"


/* OpenGL contexts */
HDC hdc;
HGLRC hrc;

/* Misc */
void* fb = NULL;
uint32_t fb_tex = 0;
uint32_t fb_tex_fmt = GL_BGRA_EXT;
uint32_t fb_tex_target = GL_TEXTURE_2D;


int ogl_init_fb_tex( GLsizei width, GLsizei height, GLuint target, GLenum format )
{
	uint32_t* buf = NULL;

	/* Delete texture if it already exists in memory */
	if( fb_tex )
	{
		glDeleteTextures( 1, &fb_tex );
		fb_tex = 0;
	}

	glEnable( format );

	/* Create the frame buffer texture */
	glGenTextures( 1, &fb_tex );
	glBindTexture( target, fb_tex );

	/* Initialize texture data */
	/* TODO: Verify valid formats, i.e. no 24-bit, 8-bit, etc. */
	fb_tex_fmt = format;
	fb_tex_target = target;

	glTexImage2D( target, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, fb );

	/* Enable bilinear filtering */
	glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

	return 1;
}

void ogl_delete_fb_tex()
{
	/* Delete the frame buffer texture */
	if( fb_tex )
	{
		glDeleteTextures( 1, &fb_tex );
		fb_tex = 0;
	}
}

void ogl_enable2d()
{
	glMatrixMode( GL_PROJECTION );
	glPushMatrix();
	glLoadIdentity();

	glOrtho( 0, 640, 480, 0, -1, 1 );
	glMatrixMode( GL_MODELVIEW );
	glPushMatrix();
	glLoadIdentity();
 //  glTranslatef(0.375, 0.375, 0.);

	glPushAttrib( GL_DEPTH_BUFFER_BIT );
	glDisable( GL_DEPTH_TEST );
}

void ogl_disable2d()
{
   glPopAttrib();
   glMatrixMode( GL_PROJECTION );
   glPopMatrix();   
   glMatrixMode( GL_MODELVIEW );
   glPopMatrix();       
}

/* Initialize OpenGL */
int		enable_ogldrv( struct window_t* wnd )
{
	PIXELFORMATDESCRIPTOR pfd;
	int pixel_format = 0;

	if( !wnd )
		return 0;

	/* Initialize OpenGL */
	memset( &pfd, 0, sizeof(pfd) );
	pfd.nVersion = 1;
	pfd.cColorBits = 32;
	pfd.cDepthBits = 16;
	pfd.cStencilBits = 8;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.iLayerType = PFD_MAIN_PLANE;
	pfd.nSize = sizeof(pfd);

	hdc = GetDC( wnd->hwnd );
	if( !hdc )
		return 0;

	pixel_format = ChoosePixelFormat( hdc, &pfd );
	if( !pixel_format )
		return 0;

	if( !SetPixelFormat( hdc, pixel_format, &pfd ) )
		return 0;

	hrc = wglCreateContext(hdc);
	if( !hrc )
		return 0;

	if( !wglMakeCurrent( hdc, hrc ) )
		return 0;

	/* Set up viewport and projection matrix */
	glViewport( 0, 0, 640, 480 );
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	gluPerspective( 45.0f, 640/480, 0.1, 1000.0f );
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();

	/* Set up default render states */
	glEnable( GL_DEPTH_TEST );
	glDepthFunc( GL_LEQUAL );
	glClearDepth( 1.0f );

	glDisable( GL_CULL_FACE );
	glDisable( GL_LIGHTING );
	glDisable( GL_BLEND );
	glDisable( GL_DITHER );
	glDisable( GL_ALPHA_TEST );

	/* Allocate framebuffer pointer */
//	fb = malloc( 640*480*4 );
	fb = malloc( 4*1024*1024 );
	if(!fb)
		return 0;

//	memset( fb, 0, 640*480*4 );
	memset( fb, 0, 4*1024*1024 );

	/* Create framebuffer texture */
//	ogl_init_fb_tex( 640, 480, GL_TEXTURE_RECTANGLE_NV, GL_BGRA_EXT );

	return 1;
}

/* Uninitialize OpenGL */
void	disable_ogldrv()
{
//	ogl_delete_fb_tex();

	if(fb)
	{
		free(fb);
		fb = NULL;
	}

	if( hrc )
	{
		wglMakeCurrent( NULL, NULL );
		wglDeleteContext( hrc );
		hrc = NULL;
	}

	if( hdc )
	{
		ReleaseDC( GetActiveWindow(), hdc );
		hdc = NULL;
	}
}

/* Clear the colour buffer */
void	ogl_clear_colour_buffer()
{
	glClear( GL_COLOR_BUFFER_BIT );
}

void	ogl_clear_depth_buffer()
{
	glClear( GL_DEPTH_BUFFER_BIT );
}

void	ogl_clear_stencil_buffer()
{
	glClear( GL_STENCIL_BUFFER_BIT );
}

void	ogl_swap_buffers()
{
	SwapBuffers( hdc );
}

void	ogl_draw_to_fb32( int x, int y, uint32_t colour )
{
	unsigned char r = (colour>>16)&0xff;
	unsigned char g = (colour>> 8)&0xff;
	unsigned char b = (colour>> 0)&0xff;

	if(!fb) return;

	((unsigned int*)fb)[x+(y*640)] = (0xff<<24)|(b<<16)|(g<<8)|(r);
	//((uint32_t*)fb)[x+(y*640)] = colour;
}

uint32_t ogl_read_from_fb32( int x, int y )
{
	uint32_t colour = ((uint32_t*)fb)[x+(y*640)];
	unsigned char b = (colour>>16)&0xff;
	unsigned char g = (colour>> 8)&0xff;
	unsigned char r = (colour>> 0)&0xff;

	if(!fb) return 0;

	return (0xff<<24)|(b<<16)|(g<<8)|(r);
}

void	ogl_update_fb()
{
	if(!fb) return;
	
#if 1
	glDrawPixels( 640, 480, GL_BGRA_EXT, GL_UNSIGNED_BYTE, fb );
#else
	ogl_enable2d();
	glPushAttrib( GL_ALL_ATTRIB_BITS );
	glEnable( fb_tex_fmt );
//	glEnable( GL_BLEND );
//	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	glBindTexture( fb_tex_target, fb_tex );
	//	glTexSubImage2D( fb_tex_target, 0, 0, 0, 640, 480, fb_tex_fmt, GL_UNSIGNED_BYTE, fb );
	glTexImage2D( fb_tex_target, 0, fb_tex_fmt, 640, 480, 0, fb_tex_fmt, GL_UNSIGNED_BYTE, fb );
	glBegin( GL_QUADS );
		glColor3f( 1.0f, 1.0f, 1.0f );
		glTexCoord2f( 0.0f, 480.0f ); glVertex2f( 0, 0 );
		glTexCoord2f( 640.0f, 480.0f ); glVertex2f( 640, 0 );
		glTexCoord2f( 640.0f, 0.0f ); glVertex2f( 640, 480 );
		glTexCoord2f( 0.0f, 0.0f ); glVertex2f( 0, 480 );
	glEnd();
	glPopAttrib();
	ogl_disable2d();
#endif
}

void*	ogl_get_fb()
{
	return fb;
}