#include <math.h>
#include "GlCompat.h"
#include "main.h"
#include <alleggl.h>
#include <allegro.h>
#include <map>

using namespace std;

struct bmpHashStruct {
	bool operator()(GLuint b1, GLuint b2) {
		return (int)b1 < (int)b2;
	}
};

map<GLuint, GLuint, bmpHashStruct> texture;


/// Fills the map for correlating bitmaps to texture indices
// The datafile must be loaded for this to work!
void install_textures() {
	if(!data) return;
		
	texture.clear();
	
	int i;
	for(i=0; data[i].type != DAT_END; i++) {
		// exclude all but bitmaps
		if(data[i].type != DAT_ID('B','M','P',' ')) continue;
		GLuint idx = allegro_gl_make_masked_texture((BITMAP*)data[i].dat);
		texture[(GLuint)data[i].dat] = idx;	// Make the bitmap pointer valid
		texture[i] = idx;			// Make the datafile index valid

		glBindTexture(GL_TEXTURE_2D, idx);
		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);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	}
}


/// Note that this disregards the dest bitmap.  It is provided to make
// an easy drop-in interface to the old draw_sprite function.
// If your source is not the screen, you should not use this function.
void gl_draw_sprite(BITMAP *dest, BITMAP *src, int x, int y) {
	glEnable(GL_TEXTURE_2D);
	
	glBindTexture(GL_TEXTURE_2D, texture[(GLuint)src]);
	glBegin(GL_QUADS);
		glTexCoord2f(0.0, 1.0); glVertex2i(x, y);
		glTexCoord2f(1.0, 1.0); glVertex2i(x+src->w, y);
		glTexCoord2f(1.0, 0.0); glVertex2i(x+src->w, y+src->h);
		glTexCoord2f(0.0, 0.0); glVertex2i(x, y+src->h);
	glEnd();
}


void gl_draw_sprite_ex(int tex_idx, int x, int y) {
	BITMAP *src = (BITMAP*)data[tex_idx].dat;
	glEnable(GL_TEXTURE_2D);
	
	glBindTexture(GL_TEXTURE_2D, texture[tex_idx]);
	glBegin(GL_QUADS);
		glTexCoord2f(0.0, 1.0); glVertex2f(x, y);
		glTexCoord2f(1.0, 1.0); glVertex2f(x+src->w, y);
		glTexCoord2f(1.0, 0.0); glVertex2f(x+src->w, y+src->h);
		glTexCoord2f(0.0, 0.0); glVertex2f(x, y+src->h);
	glEnd();
}

void gl_draw_sprite_v_flip(BITMAP *dest, BITMAP *src, int x, int y) {
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture[(GLuint)src]);
	
	glBegin(GL_QUADS);
		glTexCoord2i(0, 0); glVertex2i(x, y);
		glTexCoord2i(1, 0); glVertex2i(x+src->w, y);
		glTexCoord2i(1, 1); glVertex2i(x+src->w, y+src->h);
		glTexCoord2i(0, 1); glVertex2i(x, y+src->h);
	glEnd();
}


void gl_draw_sprite_h_flip(BITMAP *dest, BITMAP *src, int x, int y) {
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture[(GLuint)src]);
	glBegin(GL_QUADS);
		glTexCoord2i(1, 1); glVertex2i(x, y);
		glTexCoord2i(0, 1); glVertex2i(x+src->w, y);
		glTexCoord2i(0, 0); glVertex2i(x+src->w, y+src->h);
		glTexCoord2i(1, 0); glVertex2i(x, y+src->h);
	glEnd();
}


void gl_draw_sprite_h_flip_ex(int tex_idx, int x, int y) {
	BITMAP *src = (BITMAP*)data[tex_idx].dat;
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture[tex_idx]);
	glBegin(GL_QUADS);
		glTexCoord2i(1, 1); glVertex2i(x, y);
		glTexCoord2i(0, 1); glVertex2i(x+src->w, y);
		glTexCoord2i(0, 0); glVertex2i(x+src->w, y+src->h);
		glTexCoord2i(1, 0); glVertex2i(x, y+src->h);
	glEnd();
}




void gl_setcolor(int col) { glColor3ub(getr(col), getg(col), getb(col)); }

void gl_polygon(BITMAP *dest, int numPts, int *data, int col) {
	numPts *= 2;
	glDisable(GL_TEXTURE_2D);
	glBegin(GL_POLYGON);
		int i;
		gl_setcolor(col);
		for(i=0; i<numPts; i+=2) glVertex2i(data[i], data[i+1]);
	glEnd();
}



void gl_rectfill(BITMAP *dest, int x1, int y1, int x2, int y2, int col) {
	glDisable(GL_TEXTURE_2D);
	glBegin(GL_QUADS);
		gl_setcolor(col);
		glVertex2i(x1, y1);
		glVertex2i(x1, y2);
		glVertex2i(x2, y2);
		glVertex2i(x2, y1);
	glEnd();
}


void gl_rect(BITMAP *dest, int x1, int y1, int x2, int y2, int col) {
	glDisable(GL_TEXTURE_2D);
	glBegin(GL_LINE_LOOP);
		gl_setcolor(col);
		glVertex2i(x1, y1);
		glVertex2i(x1, y2);
		glVertex2i(x2, y2);
		glVertex2i(x2, y1);
	glEnd();
}


void gl_pivot_sprite(BITMAP *dest, BITMAP *src, int x, int y, int cx, int cy, fixed angleFix) {
	float angleD = fixtof(angleFix) / 256.0 * 360;
	float angleR = angleD / 180 * M_PI;
	float cosar = cos(angleR);
	float sinar = sin(angleR);
	glPushMatrix();
	glTranslatef(x - cx*cosar, y - cy*sinar, 0);
	glRotatef(angleD, 0, 0, 1);
	gl_draw_sprite(dest, src, -cx + src->w/2, -cy);
	glPopMatrix();
}


void gl_pivot_sprite_ex(int tex_idx, int x, int y, int cx, int cy, float angleRad) {
	BITMAP *src = (BITMAP*)data[tex_idx].dat;
	float angleDeg = angleRad * 180 / M_PI;
	
	glPushMatrix();
	glTranslatef(x - cx*cos(angleRad), y - cy*sin(angleRad), 0);
	glRotatef(angleDeg, 0, 0, 1);
	gl_draw_sprite_ex(tex_idx, -cx + src->w/2, -cy);
	glPopMatrix();
}



// this function does not work properly!
void gl_pivot_sprite_v_flip(BITMAP *dest, BITMAP *src, int x, int y, int cx, int cy, fixed angleFix) {
	float angleD = fixtof(angleFix) / 256.0 * 360;
	float angleR = angleD / 180 * M_PI;
	float cosar = cos(angleR);
	float sinar = sin(angleR);
	cx = src->w-cx;
	cy = src->h-cy;
	glPushMatrix();
	glTranslatef(x - cx*cosar, y - cy*sinar, 0);
	glRotatef(angleD, 0, 0, 1);
	gl_draw_sprite_v_flip(dest, src, -cx + src->w/2, -cy);
	glPopMatrix();
}


void gl_pivot_sprite_h_flip(BITMAP *dest, BITMAP *src, int x, int y, int cx, int cy, fixed angleFix) {
	float angleD = fixtof(angleFix) / 256.0 * 360;
	float angleR = angleD / 180 * M_PI;
	float cosar = cos(angleR);
	float sinar = sin(angleR);
	glPushMatrix();
	glTranslatef(x - cx*cosar, y - cy*sinar, 0);
	glRotatef(angleD, 0, 0, 1);
	gl_draw_sprite_h_flip(dest, src, -cx + src->w/2, -cy);
	glPopMatrix();
}


void gl_pivot_sprite_h_flip_ex(int tex_idx, int x, int y, int cx, int cy, float angleRad) {
	BITMAP *src = (BITMAP*)data[tex_idx].dat;
	float angleDeg = angleRad * 180 / M_PI;
	
	glPushMatrix();
	glTranslatef(x - cx*cos(angleRad), y - cy*sin(angleRad), 0);
	glRotatef(angleDeg, 0, 0, 1);
	gl_draw_sprite_h_flip_ex(tex_idx, -cx + src->w/2, -cy);
	glPopMatrix();
}



