// OGLrendrer.cpp: implementation of the OGLrendrer class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "OGLrendrer.h"

#include "Character.h"
#include "png.h"

extern Character *myChar;

OGLrendrer::OGLrendrer()
{
	DLCached = false;
}

OGLrendrer::~OGLrendrer()
{
	vector<GLuint>::iterator texIter = textures.begin();
	for(; texIter!=textures.end() ; texIter++)
	{
		glDeleteTextures(1, &*texIter);
	}
}

void 
OGLrendrer::initGL()
{
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_LINE_SMOOTH);
	glShadeModel(GL_SMOOTH);
	glClearColor(0.0, 0.0, 0.0, 0.0);
	//glClearDepth(0.1f);
	glClear(GL_COLOR_BUFFER_BIT);

	//glEnable(GL_FOG);
	glEnable(GL_BLEND);
	//glFogf(GL_FOG_MODE, GL_LINEAR);
	//glFogf(GL_FOG_START, -1);
	//glFogf(GL_FOG_END, -50);
	glMatrixMode(GL_PROJECTION);
	gluPerspective(90.0, 1.0, 0.1, 100.0);

	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
	//glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16);
	
}

void 
OGLrendrer::setCamera(Camera *cam)
{
	mainCam = cam;
}

void OGLrendrer::loadtexture(){

	void(__stdcall* glActiveTextureAR)(int);
	(glActiveTextureAR)=(void(__stdcall*)(int))getGlProcAddress("glActiveTextureARB");
	glActiveTextureAR(GL_TEXTURE0_ARB);


	GLuint texture;
	glEnable(GL_TEXTURE_2D);
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glGenTextures( 1, &texture );
	glBindTexture(GL_TEXTURE_2D, texture);
	textures.push_back(texture);

	void *buffer = NULL;

	loadTexture("TileTexts.raw", &buffer);

	gluBuild2DMipmaps( GL_TEXTURE_2D, 3, 512, 128, GL_RGB, GL_UNSIGNED_BYTE, buffer );
	
}

void OGLrendrer::loadtex2(){

	void(__stdcall* glActiveTextureAR)(int);
	(glActiveTextureAR)=(void(__stdcall*)(int))getGlProcAddress("glActiveTextureARB");
	glActiveTextureAR(GL_TEXTURE0_ARB);

	GLuint texture;
	glEnable(GL_TEXTURE_2D);
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glGenTextures(1, &texture );
	glBindTexture(GL_TEXTURE_2D, texture);
	textures.push_back(texture);

	void *buffer;
	loadTexture("Character.raw", &buffer);

	gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA8, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, buffer );	
}

void OGLrendrer::loadtex3(){

	void(__stdcall* glActiveTextureAR)(int);
	(glActiveTextureAR)=(void(__stdcall*)(int))getGlProcAddress("glActiveTextureARB");
	glActiveTextureAR(GL_TEXTURE0_ARB);

	GLuint texture;
	glEnable(GL_TEXTURE_2D);
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glGenTextures(1, &texture );
	glBindTexture(GL_TEXTURE_2D, texture);
	textures.push_back(texture);

	void *buffer;
	loadTexture("Bomb.raw", &buffer);
	
	gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA8, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
}

void OGLrendrer::loadlightmap(){

	void(* glActiveTextureAR)(int);
	(glActiveTextureAR)=(void(*)(int))getGlProcAddress("glActiveTextureARB");

	glActiveTextureAR(GL_TEXTURE1_ARB);
	glEnable(GL_TEXTURE_2D);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	//glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_EXT);

	GLuint texture;
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	textures.push_back(texture);

	void *buffer;
	loadTexture("colgrad.raw", &buffer);

	gluBuild2DMipmaps( GL_TEXTURE_2D, 3, 512,
		512, GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer );
	
}

void OGLrendrer::loadCrosshair(){

	void(__stdcall* glActiveTextureAR)(int);
	(glActiveTextureAR)=(void(__stdcall*)(int))getGlProcAddress("glActiveTextureARB");

	glActiveTextureAR(GL_TEXTURE0_ARB);
	glEnable(GL_TEXTURE_2D);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	//glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_EXT);

	GLuint texture;
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	textures.push_back(texture);

	void *buffer;
	loadTexture("Xhair.raw", &buffer);

	gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA8, 64,
		64, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
	
}


void OGLrendrer::resize(unsigned int x, unsigned int y)
{
	glViewport(0, 0, x, y);
}

void OGLrendrer::startFrame()
{
	//glRotatef(1.0, 0.5, 0.5, 0.25);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor4f(0.5, 0.5, 0.5, 1.0);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(90.0, 1.0, 0.1, 100.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	float charX, charY;
	myChar->getPosition(&charX, &charY);

	gluLookAt(charX, charY, 4.0, charX, charY, 1.0, 0.0, -1.0, 0.0);

	float dx, dy;
	//mainCam->getDir(&dx, &dy);
	//glRotatef(dy, 1, 0, 0);
	//glRotatef(dx, 0, 1, 0);

	float x, y, z;
	//mainCam->getCoords(&x, &y, &z);
	//glTranslatef(x, y, z);
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glBindTexture(GL_TEXTURE_2D, 1);
}

GLuint
OGLrendrer::getList()
{
	return glGenLists(1);
}

void OGLrendrer::startList(GLuint dlHand)
{
	glNewList(dlHand, GL_COMPILE);
}

void OGLrendrer::endList()
{
	glEndList();
}

void OGLrendrer::drawList(GLuint dlHand)
{
	glCallList(dlHand);
}

bool OGLrendrer::cached()
{
	return DLCached;
}

void OGLrendrer::invalidateCache()
{
	//glDeleteLists(levelList, 1);
	DLCached = false;
}

void OGLrendrer::paintCrosshair()
{
	void(__stdcall* glMultiTexCoord2dARB)(GLenum, double,double)=(void(__stdcall*)(GLenum,double,double))this->getGlProcAddress("glMultiTexCoord2dARB");
	
	glBindTexture(GL_TEXTURE_2D, 2);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, 1000, 1000, 0, 0, 1);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glBegin(GL_POLYGON);
		glMultiTexCoord2dARB(GL_TEXTURE0_ARB,0.0,0.0); glVertex2f(400, 400);
		glMultiTexCoord2dARB(GL_TEXTURE0_ARB,1.0,0.0); glVertex2f(600, 400);
		glMultiTexCoord2dARB(GL_TEXTURE0_ARB,1.0,1.0); glVertex2f(600, 600);
		glMultiTexCoord2dARB(GL_TEXTURE0_ARB,0.0,1.0); glVertex2f(400, 600);
	glEnd();
	glMatrixMode (GL_MODELVIEW);
	glDisable (GL_BLEND);
}

unsigned int OGLrendrer::loadPngTex(char *fileName)
{
	int width, height;
	png_byte color_type;
	png_byte bit_depth;
	png_byte color_channels;

	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	int number_of_passes;
	png_bytep * row_pointers;

	char header[8];    // 8 is the maximum size that can be checked

	/* open file and test for it being a png */
	FILE *fp = fopen(fileName, "rb");
	if (!fp)
		return 0;
	fread(header, 1, 8, fp);
	if (png_sig_cmp((png_bytep)header, 0, 8))
		return 0;

	/* initialize stuff */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	//if (!png_ptr)
	//        abort_("[read_png_file] png_create_read_struct failed");

	info_ptr = png_create_info_struct(png_ptr);
	//if (!info_ptr)
	//        abort_("[read_png_file] png_create_info_struct failed");

	if (setjmp(png_jmpbuf(png_ptr)))
		return 0;

	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, 8);

	png_read_info(png_ptr, info_ptr);

	width = png_get_image_width(png_ptr, info_ptr);
	height = png_get_image_height(png_ptr, info_ptr);
	color_type = png_get_color_type(png_ptr, info_ptr);
	bit_depth = png_get_bit_depth(png_ptr, info_ptr);
	color_channels = png_get_channels(png_ptr, info_ptr);

	number_of_passes = png_set_interlace_handling(png_ptr);
	png_read_update_info(png_ptr, info_ptr);

	/* read file */
	if (setjmp(png_jmpbuf(png_ptr)))
		return 0;

	row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
	for (unsigned int y=0; y<height; y++)
		row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));

	png_read_image(png_ptr, row_pointers);

	fclose(fp);

	void(__stdcall* glActiveTextureAR)(int);
	(glActiveTextureAR)=(void(__stdcall*)(int))getGlProcAddress("glActiveTextureARB");
	glActiveTextureAR(GL_TEXTURE0_ARB);

	GLuint texture = 0;
	glEnable(GL_TEXTURE_2D);
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glGenTextures(1, &texture );
	glBindTexture(GL_TEXTURE_2D, texture);
	textures.push_back(texture);

	char *buffer = NULL;
	int channels = 0;
	if(color_channels == PNG_COLOR_TYPE_RGB)
		channels = 3;
	else if(color_channels == PNG_COLOR_TYPE_RGBA)
		channels = 4;
	buffer = new char[width*height*channels];

	// Copy data to flat array.

	for(unsigned int y=0 ; y<height ; y++)
	{
		png_byte *row = row_pointers[y];
		for(unsigned int x=0 ; x<width ; x++)
		{
			png_byte *pix = &row[x*channels];
			char *dstPix = &buffer[((width*y)+x)*channels];
			for(unsigned int chan=0 ; chan!=channels ; chan++)
			{
				dstPix[chan] = pix[chan];
			}
		}
	}

	if(color_channels == PNG_COLOR_TYPE_RGB)
		gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGB8, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer );
	else if(color_channels == PNG_COLOR_TYPE_RGBA)
		gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA8, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
	return texture;
}

unsigned int 
OGLrendrer::loadRawTex(char *fileName, unsigned int width, unsigned int height, unsigned int channels)
{
	void(__stdcall* glActiveTextureAR)(int);
	(glActiveTextureAR)=(void(__stdcall*)(int))getGlProcAddress("glActiveTextureARB");
	glActiveTextureAR(GL_TEXTURE0_ARB);


	GLuint texture;
	glEnable(GL_TEXTURE_2D);
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glGenTextures( 1, &texture );
	glBindTexture(GL_TEXTURE_2D, texture);
	textures.push_back(texture);

	void *buffer = NULL;

	loadTexture(fileName, &buffer);

	if(channels == 3)
		gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGB8, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer );
	else if(channels == 4);
		gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA8, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
	return texture;
}