#include "texture.h"											// Header File Containing Our Texture Structure ( NEW )
#include "tgaloader.cpp"

extern FILE *debug;

typedef struct {
	float x, y, z;
	float u, v;
	int iu, iv;
	int c;
} V3D_f;

struct color {
	GLubyte r;
	GLubyte g;
	GLubyte b;
	GLubyte a;

	bool operator ==(color &c) {
		if(c.r == r && c.g == g && c.b == b && c.a == a) return true;
		return false;
	}

	bool operator !=(color &c) {
		if(c.r != r || c.g != g || c.b != b || c.a != a) return false;
		return true;
	}
};

color green, black, white, magenta, gray, yellow, nullcolor;

int getr32(int c) {
	return c / 1000000;
}

int getg32(int c) {
	return (c / 1000) % 1000;
}

int getb32(int c) {
	return c % 1000;
}

int getr(int c) {
	return c / 1000000;
}

int getg(int c) {
	return (c / 1000) % 1000;
}

int getb(int c) {
	return c % 1000;
}

color getpixel(ABITMAP *bmp, int x, int y) {
	color rv;
	int start;

	start = (bmp->h - y - 1) * bmp->w * bmp->bypp + x * bmp->bypp;

	rv.r = bmp->imageData[start];
	rv.g = bmp->imageData[start+1];
	rv.b = bmp->imageData[start+2];
	if(bmp->bypp == 4)
		rv.a = bmp->imageData[start+3];
	else
		rv.a = 255;
	//rv = bmp->imageData[start] * 1000000 + bmp->imageData[start + 1] * 1000 + bmp->imageData[start + 2];
	return rv;
}

float getpixelalpha(ABITMAP *bmp, int x, int y) {
	if(bmp->type == GL_RGB) return 1.0;

	int rv;
	int start;

	start = (bmp->h - y - 1) * bmp->w * bmp->bypp + x * bmp->bypp;

	rv = bmp->imageData[start + 3];
	return rv;
}

void putpixel(ABITMAP *bmp, int x, int y, color c) {
	GLubyte *start = &(bmp->imageData[(bmp->h - y - 1) * bmp->w * bmp->bypp + x * bmp->bypp]);

	*start = c.r;
	start++;
	*start = c.g;
	start++;
	*start = c.b;
	if(bmp->bypp == 4) {
		start++;
		*start = c.a;
	}
}

//GLubyte r, GLubyte g, GLubyte b) {
int makecol(int r, int g, int b) {
	return r * 1000000 + g * 1000 + b;
}

color makecol(int r, int g, int b, int a) {
	color c;
	c.r = r;
	c.g = g;
	c.b = b;
	c.a = a;
	return c;
}

color makecol16(int r, int g, int b) {
	color c;
	c.r = r;
	c.g = g;
	c.b = b;
	c.a = 255;
	return c;
}

void createtexture(ABITMAP *tex);

//bool LoadTGA(Texture * texture, char * filename)
ABITMAP *load_bitmap(char *fn) {
	ABITMAP *r;
	r = new ABITMAP;
	LoadTGA(r, fn);
	createtexture(r);
	return r;
}

ABITMAP *load_bitmap_notex(char *fn) {
	ABITMAP *r;
	r = new ABITMAP;
	LoadTGA(r, fn);
	return r;
}

ABITMAP *create_bitmap_ex(int bpp, int w, int h) {
	ABITMAP *r;
	r = new ABITMAP;

	r->width = w;
	r->height = h;
	r->bpp = bpp;
	
	r->imageData = (GLubyte *)malloc(w * h * bpp);
	r->datasize = w * h * bpp;

	if(bpp == 24) {
		r->type	= GL_RGB;
	}
	else {
		r->type	= GL_RGBA;
	}

	r->w = w;
	r->h = h;
	r->bypp = bpp / 8;

	return r;
}

ABITMAP *create_bitmap(int w, int h) {
	return create_bitmap_ex(24, w, h);
}

void destroy_bitmap(ABITMAP *bmp) {
	//if(bmp->imageData) free(bmp->imageData);
}

void clear(ABITMAP *bmp) {
	memset(bmp->imageData, 0, bmp->datasize);
}

void clear_to_color(ABITMAP *bmp, color c) {
	clear(bmp);
}

void drawsomething() {
	ABITMAP *bmp;

	bmp = load_bitmap("graphics\\building.tga");

	//fprintf(debug, "char: %i, glubyte: %i\n", sizeof(char), sizeof(GLubyte));
	fprintf(debug, "(%i,%i):%f\n", 5, 5, getpixelalpha(bmp, 5, 5));

	/*
	fprintf(debug, "magenta: %i\n", makecol(255, 255, 0));
	fprintf(debug, "black: %i\n", makecol(0, 0, 0));
	fprintf(debug, "pixel at 0,0: %i\n", getpixel(bmp,0,0));
	fprintf(debug, "\n\n%ix%ix%i\n\n", bmp->w, bmp->h, bmp->bypp);
	for(int x = 0; x < bmp->w; x++) {
		for(int y = 0; y < bmp->h; y++) {
			fprintf(debug, "pixel at %i,%i: %i\n", x, y, getpixel(bmp,x,y));
		}
	}

	fprintf(debug, "\n\nImage Data:\n\n");
	for(int i = 0; i < bmp->h * bmp->w * bmp->bypp; i++) {
		fprintf(debug, "%i,", bmp->imageData[i]);
	}
	*/
}

void blit(ABITMAP *src, ABITMAP *dst, int src_xstart, int src_ystart, int dst_xstart, int dst_ystart, int src_width, int src_height, int blend, int alpha) {
	int i,j,k;
	unsigned char *s, *d;										// Source & Destination

	// Clamp Alpha If Value Is Out Of Range
    if( alpha > 255 ) alpha = 255;
    if( alpha < 0 ) alpha = 0;

	// Check For Incorrect Blend Flag Values
    if( blend < 0 ) blend = 0;
    if( blend > 1 ) blend = 1;

    d = dst->imageData + (dst_ystart * dst->width * dst->bypp);    // Start Row - dst (Row * Width In Pixels * Bytes Per Pixel)
    s = src->imageData + (src_ystart * src->width * src->bypp);    // Start Row - src (Row * Width In Pixels * Bytes Per Pixel)

    for (i = 0 ; i < src_height && i + dst_ystart < dst->h && i + src_ystart < src->h ; i++ )							// Height Loop
    {
        s = s + (src_xstart * src->bypp);						// Move Through Src Data By Bytes Per Pixel
        d = d + (dst_xstart * dst->bypp);						// Move Through Dst Data By Bytes Per Pixel
        for (j = 0 ; j < src_width; j++ ) {					// Width Loop
            for( k = 0; k < src->bypp; k++, d++, s++) {			// "n" Bytes At A Time
				if(j + dst_xstart < dst->w && j + src_xstart < src->w && i + src_ystart >= 0 && i + dst_ystart >= 0 && j + src_xstart >= 0 && j + dst_ystart >= 0) {
					if (blend)										// If Blending Is On
						*d = ( (*s * alpha) + (*d * (255-alpha)) ) >> 8; // Multiply Src Data*alpha Add Dst Data*(255-alpha)
					else											// Keep in 0-255 Range With >> 8
						*d = *s;									// No Blending Just Do A Straight Copy
				}
            }
        }
        s = s + (src->width - (src_width + src_xstart))*src->bypp;	// Add End Of Row */
        d = d + (dst->width - (src_width + dst_xstart))*dst->bypp;	// Add End Of Row */
    }
}

void debrisblit(ABITMAP *src, ABITMAP *dst, int src_xstart, int src_ystart, int dst_xstart, int dst_ystart, int src_width, int src_height) {
	int i,j,k;
	unsigned char *s, *d, alpha;										// Source & Destination
	bool overwrite;

    d = dst->imageData + (dst_ystart * dst->width * dst->bypp);    // Start Row - dst (Row * Width In Pixels * Bytes Per Pixel)
    s = src->imageData + (src_ystart * src->width * src->bypp);    // Start Row - src (Row * Width In Pixels * Bytes Per Pixel)

    for (i = 0 ; i < src_height && i + dst_ystart < dst->h && i + src_ystart < src->h; i++ )							// Height Loop
    {
        s = s + (src_xstart * src->bypp);						// Move Through Src Data By Bytes Per Pixel
        d = d + (dst_xstart * dst->bypp);						// Move Through Dst Data By Bytes Per Pixel
        for (j = 0 ; j < src_width; j++ ) {						// Width Loop
			if(*s == 255 && *(s + 1) == 0 && *(s + 2) == 255) {
				alpha = 1;
				overwrite = true;
			}
			else if(src->bpp == 32) {
				alpha = *(s + 3);
				overwrite = false;
			}
            for( k = 0; k < 3; k++, d++, s++) {			// "n" Bytes At A Time
				if(alpha != 0 && j + dst_xstart < dst->w && j + src_xstart < src->w && i + src_ystart >= 0 && i + dst_ystart >= 0 && j + src_xstart >= 0 && j + dst_ystart >= 0)
					if(overwrite)
						*d = 0;
					else if(alpha != 255)
						*d = ((*s * alpha) + (*d * (255-alpha))) >> 8;
					else						
						*d = *s;
			}
			if(overwrite)
				*d = 0;
			s++;
			d++;
        }
        s = s + (src->width - (src_width + src_xstart))*src->bypp;	// Add End Of Row */
        d = d + (dst->width - (src_width + dst_xstart))*dst->bypp;	// Add End Of Row */
    }
}

void blitopaque(ABITMAP *src, ABITMAP *dst, int src_xstart, int src_ystart, int dst_xstart, int dst_ystart, int src_width, int src_height) {
	int i,j,k;
	unsigned char *s, *d;										// Source & Destination

    d = dst->imageData + (dst_ystart * dst->width * dst->bypp);    // Start Row - dst (Row * Width In Pixels * Bytes Per Pixel)
    s = src->imageData + (src_ystart * src->width * src->bypp);    // Start Row - src (Row * Width In Pixels * Bytes Per Pixel)

    for (i = 0 ; i < src_height && i + dst_ystart < dst->h && i + src_ystart < src->h; i++ )							// Height Loop
    {
        s = s + (src_xstart * src->bypp);						// Move Through Src Data By Bytes Per Pixel
        d = d + (dst_xstart * dst->bypp);						// Move Through Dst Data By Bytes Per Pixel
        for (j = 0 ; j < src_width; j++ ) {						// Width Loop
            for( k = 0; k < src->bypp; k++, d++, s++) {			// "n" Bytes At A Time
				if(j + dst_xstart < dst->w && j + src_xstart < src->w && i + src_ystart >= 0 && i + dst_ystart >= 0 && j + src_xstart >= 0 && j + dst_ystart >= 0)
					*d = *s;
			}
        }
        s = s + (src->width - (src_width + src_xstart))*src->bypp;	// Add End Of Row */
        d = d + (dst->width - (src_width + dst_xstart))*dst->bypp;	// Add End Of Row */
    }
}

void blit1(ABITMAP *src, ABITMAP *dst, int src_xstart, int src_ystart, int dst_xstart, int dst_ystart, int src_width, int src_height) {
	int i,j,k;
	unsigned char *s, *d, alpha;										// Source & Destination

    d = dst->imageData + (dst_ystart * dst->width * dst->bypp);    // Start Row - dst (Row * Width In Pixels * Bytes Per Pixel)
    s = src->imageData + (src_ystart * src->width * src->bypp);    // Start Row - src (Row * Width In Pixels * Bytes Per Pixel)

    for (i = 0 ; i < src_height && i + dst_ystart < dst->h && i + src_ystart < src->h; i++ )							// Height Loop
    {
        s = s + (src_xstart * src->bypp);						// Move Through Src Data By Bytes Per Pixel
        d = d + (dst_xstart * dst->bypp);						// Move Through Dst Data By Bytes Per Pixel
        for (j = 0 ; j < src_width; j++ ) {						// Width Loop
			if(j + dst_xstart < dst->w && j + src_xstart < src->w && i + src_ystart >= 0 && i + dst_ystart >= 0 && j + src_xstart >= 0 && j + dst_xstart >= 0) {
				if(src->bpp == 32)
					alpha = *(s + 3);
				else if(*s == 255 && *(s + 1) == 0 && *(s + 2) == 255)
					alpha = 0;
				else
					alpha = 255;
			}
            for( k = 0; k < src->bypp; k++, d++, s++) {			// "n" Bytes At A Time
				if(alpha != 0 && j + dst_xstart < dst->w && j + src_xstart < src->w && i + src_ystart >= 0 && i + dst_ystart >= 0 && j + src_xstart >= 0 && j + dst_xstart >= 0) {
					if(alpha != 255)
						*d = ((*s * alpha) + (*d * (255-alpha))) >> 8;
					else						
						*d = *s;
				}
			}
			/*
			if(src->bypp == 4) {
				s++;
				d++;
			}
			*/
        }
        s = s + (src->width - (src_width + src_xstart))*src->bypp;	// Add End Of Row */
        d = d + (dst->width - (src_width + dst_xstart))*dst->bypp;	// Add End Of Row */
    }
}

void blit2(ABITMAP *src, ABITMAP *dst, int src_xstart, int src_ystart, int dst_xstart, int dst_ystart, int src_width, int src_height) {
	int i,j,k;
	unsigned char *s, *d, alpha;									// Source & Destination

    d = dst->imageData + (dst_ystart * dst->width * dst->bypp);    // Start Row - dst (Row * Width In Pixels * Bytes Per Pixel)
    s = src->imageData + (src_ystart * src->width * src->bypp);    // Start Row - src (Row * Width In Pixels * Bytes Per Pixel)

    for (i = 0 ; i < src_height && i + dst_ystart < dst->h && i + src_ystart < src->h; i++ )							// Height Loop
    {
        s = s + (src_xstart * src->bypp);						// Move Through Src Data By Bytes Per Pixel
        d = d + (dst_xstart * dst->bypp);						// Move Through Dst Data By Bytes Per Pixel
        for (j = 0 ; j < src_width; j++ ) {						// Width Loop
			if(src->bpp == 32)
				alpha = *(s + 3);
			else if(*s == 255 && *(s + 1) == 0 && *(s + 2) == 255)
				alpha = 0;
			else
				alpha = 255;
            for( k = 0; k < dst->bypp && k < src->bypp; k++, d++, s++) {			// "n" Bytes At A Time
				if(alpha != 0 && j + dst_xstart < dst->w && j + src_xstart < src->w && i + src_ystart >= 0 && i + dst_ystart >= 0 && j + src_xstart >= 0 && j + dst_ystart >= 0)
					if(alpha != 255)
						*d = ((*s * alpha) + (*d * (255-alpha))) >> 8;
					else						
						*d = *s;

			}
			if(src->bypp > dst->bypp) s++;
			else d++;
        }
        s = s + (src->width - (src_width + src_xstart))*src->bypp;	// Add End Of Row */
        d = d + (dst->width - (src_width + dst_xstart))*dst->bypp;	// Add End Of Row */
    }
}

void blitalpha(ABITMAP *src, ABITMAP *srca, ABITMAP *dst, int src_xstart, int src_ystart, int dst_xstart, int dst_ystart, int src_width, int src_height) {
	int i,j,k;
	unsigned char *s, *sa, *d;										// Source & Destination
	unsigned char alpha;

    d = dst->imageData + (dst_ystart * dst->width * dst->bypp);    // Start Row - dst (Row * Width In Pixels * Bytes Per Pixel)
    s = src->imageData + (src_ystart * src->width * src->bypp);    // Start Row - src (Row * Width In Pixels * Bytes Per Pixel)
    sa = srca->imageData + (src_ystart * srca->width * srca->bypp);    // Start Row - src (Row * Width In Pixels * Bytes Per Pixel)

    for (i = 0 ; i < src_height && i + dst_ystart < dst->h && i + src_ystart < src->h; i++ )							// Height Loop
    {
        s = s + (src_xstart * src->bypp);						// Move Through Src Data By Bytes Per Pixel
        sa = sa + (src_xstart * srca->bypp);						// Move Through Src Data By Bytes Per Pixel
        d = d + (dst_xstart * dst->bypp);						// Move Through Dst Data By Bytes Per Pixel
        for (j = 0 ; j < src_width; j++ ) {						// Width Loop
			alpha = *(s + 3);
            for( k = 0; k < src->bypp; k++, d++, s++, sa++) {			// "n" Bytes At A Time
				if(j + dst_xstart < dst->w && j + src_xstart < src->w && i + src_ystart >= 0 && i + dst_ystart >= 0 && j + src_xstart >= 0 && j + dst_ystart >= 0)
					if(k == 3)
						*d = *sa;
					else
						*d = ((*s * alpha) + (*d * (255-alpha))) >> 8;
						//*d = *s;								// No Blending Just Do A Straight Copy
           }
        }
        s = s + (src->width - (src_width + src_xstart))*src->bypp;	// Add End Of Row */
        sa = sa + (src->width - (src_width + src_xstart))*srca->bypp;	// Add End Of Row */
        d = d + (dst->width - (src_width + dst_xstart))*dst->bypp;	// Add End Of Row */
    }
}

void blit(ABITMAP *src, ABITMAP *dst, int src_xstart, int src_ystart, int dst_xstart, int dst_ystart, int src_width, int src_height) {
	if(src->bypp == dst->bypp)
		blit1(src, dst, src_xstart, src_ystart, dst_xstart, dst_ystart, src_width, src_height);
	else
		blit2(src, dst, src_xstart, src_ystart, dst_xstart, dst_ystart, src_width, src_height);
}

void masked_blit(ABITMAP *src, ABITMAP *dst, int src_xstart, int src_ystart, int dst_xstart, int dst_ystart, int src_width, int src_height) {
	int i,j,k;
	unsigned char *s, *d;										// Source & Destination

    d = dst->imageData + (dst_ystart * dst->width * dst->bypp);    // Start Row - dst (Row * Width In Pixels * Bytes Per Pixel)
    s = src->imageData + (src_ystart * src->width * src->bypp);    // Start Row - src (Row * Width In Pixels * Bytes Per Pixel)

    for (i = 0 ; i < src_height && i + dst_ystart < dst->h && i + src_ystart < src->h; i++ ) {
        s = s + (src_xstart * src->bypp);						// Move Through Src Data By Bytes Per Pixel
        d = d + (dst_xstart * dst->bypp);						// Move Through Dst Data By Bytes Per Pixel
        for (j = 0 ; j < src_width; j++ ) {					// Width Loop
			if(!(*s == 255 && *(s + 1) == 0 && *(s + 2) == 255)) {
				for( k = 0; k < src->bypp; k++, d++, s++) {			// "n" Bytes At A Time
					if(j + dst_xstart < dst->w && j + src_xstart < src->w && i + src_ystart >= 0 && i + dst_ystart >= 0 && j + src_xstart >= 0 && j + dst_ystart >= 0)
						*d = *s;									// No Blending Just Do A Straight Copy
				}
			}
			else {
				d += src->bypp;
				s += src->bypp;
			}
        }
        s = s + (src->width - (src_width + src_xstart))*src->bypp;	// Add End Of Row */
        d = d + (dst->width - (src_width + dst_xstart))*dst->bypp;	// Add End Of Row */
    }
}

void draw_sprite(ABITMAP *buf, ABITMAP *spr, int x, int y) {
	blit(spr, buf, 0, 0, x, y, spr->w, spr->h);
}

void draw_sprite_h_flip(ABITMAP *bmp, ABITMAP *sprite, int x, int y) {
	blit(sprite, bmp, 0, 0, x, y, sprite->w, sprite->h);
}

void draw_trans_sprite(ABITMAP *buf, ABITMAP *spr, int x, int y) {
	blit(spr, buf, 0, 0, x, y, spr->w, spr->h);
}

void rotate_sprite(ABITMAP *bmp, ABITMAP *sprite, int x, int y, float angle) {
	draw_sprite(bmp, sprite, x, y);
}

void pivot_sprite(ABITMAP *bmp, ABITMAP *sprite, int x, int y, int cx, int cy, float angle) {
}

void line(ABITMAP *bmp, int x1, int y1, int x2, int y2, color color) {
}

void do_line(ABITMAP *bmp, int x1, int y1, int x2, int y2, int d, void (*proc)()) {
}

void triangle3d_f(ABITMAP *bmp, ABITMAP *tex, V3D_f *v1, V3D_f *v2, V3D_f *v3) {
}

void polygon(ABITMAP *bmp, int vertices, int *points, color color) {
}

void circle(ABITMAP *bmp, int x, int y, int radius, int color) {
}

void circlefill(ABITMAP *bmp, int x, int y, int radius, int color) {
}

void vsync() {
}

//*AUDIO*

struct SAMPLE {
};

struct MIDI {
};

int play_sample(const SAMPLE *spl, int vol, int pan, int freq, int loop) {
	return 1;
}

int allocate_voice(const SAMPLE *spl) {
	return 0;
}

void voice_set_priority(int voice, int priority) {
}

void voice_start(int voice) {
}

void release_voice(int voice) {
}

void voice_set_frequency(int voice, int frequency) {
}

void deallocate_voice(int voice) {
}

SAMPLE *voice_check(int voice) {
	return 0;
}

void voice_set_pan(int voice, int pan) {
}

void voice_set_volume(int voice, int volume) {
}

void voice_set_position(int voice, int position) {
}

int voice_get_position(int voice) {
	return 10000000;
}

void voice_set_playmode(int voice, int playmode) {
}

void voice_stop(int voice) {
}

void voice_ramp_volume(int voice, int time, int endvol) {
}

SAMPLE *load_sample(const char *filename) {
	return 0;
}

MIDI *load_midi(const char *filename) {
	return 0;
}

//*MISC*

int mouse_x;
int mouse_y;
int mouse_z;
int mouse_b;

void position_mouse(int x, int y) {
}
