// Brain Party
// Copyright (C) 2010 Paul Hudson (http://www.tuxradar.com/brainparty)

// Brain Party is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#include "Texture.h"
#include "SDL_image.h"

Texture::Texture(SDL_Surface* surface) {	
	int po2width = Texture::NextPO2(surface->w);
	int po2height = Texture::NextPO2(surface->h);
	
	if (Width != po2width or Height != po2height) {
		SDL_Surface* tmpsurface = SDL_CreateRGBSurface(SDL_SWSURFACE, po2width, po2height, 32,
		#if SDL_BYTEORDER == SDL_LIL_ENDIAN
			0x000000FF, 
			0x0000FF00, 
			0x00FF0000, 
			0xFF000000
		#else
			0xFF000000,
			0x00FF0000, 
			0x0000FF00, 
			0x000000FF
		#endif		
		);
		
		SDL_SetAlpha(surface, 0, 0);	
		SDL_BlitSurface(surface, NULL, tmpsurface, NULL);
		InitWithSurface(tmpsurface, surface->w, surface->h);
		SDL_FreeSurface(tmpsurface);		
	} else {
		InitWithSurface(surface, surface->w, surface->h);
	}
}

Texture::Texture(const char* filename, float actualwidth, float actualheight) {
	string file = filename;
	file.insert(0, "Content/");
	file.append(".png");

	SDL_Surface *surface = IMG_Load(file.c_str());
	if ((surface->w & (surface->w - 1)) != 0) printf("warning: %s's width is not a power of 2\n", file.c_str());
	if ((surface->h & (surface->h - 1)) != 0) printf("warning: %s's height is not a power of 2\n", file.c_str());
	
	InitWithSurface(surface, actualwidth, actualheight);
	
	SDL_FreeSurface(surface);
}

void Texture::InitWithSurface(SDL_Surface* surface, float actualwidth, float actualheight) {		
	Width = surface->w;
	Height = surface->h;
	
	GLenum texture_format;
	int colors = surface->format->BytesPerPixel;

        if (colors == 4) {
                if (surface->format->Rmask == 0x000000ff) {
                        texture_format = GL_RGBA;
                } else {
                        texture_format = GL_BGRA;
		}
        } else if (colors == 3) {
                if (surface->format->Rmask == 0x000000ff) {
                        texture_format = GL_RGB;
                } else {
                        texture_format = GL_BGR;
		}
        } else {
		// this shouldn't ever happen
		cout << "Problem loading texture!" << endl;
	}

	glGenTextures(1, &this->Surface);
	
	glBindTexture(GL_TEXTURE_2D, Surface);
	
	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);
	
	glTexImage2D(GL_TEXTURE_2D, 0, colors, Width, Height, 0, texture_format, GL_UNSIGNED_BYTE, surface->pixels);
		
	WidthRatio = actualwidth / Width;
	HeightRatio = actualheight / Height;
	
	// now store the real width and height away to be used later.
	Width = actualwidth;
	Height = actualheight;
	HalfWidth = actualwidth / 2;
	HalfHeight = actualheight / 2;
	
	TexCoords[0] = 0.0;
	TexCoords[1] = HeightRatio;
	
	TexCoords[2] = WidthRatio;
	TexCoords[3] = HeightRatio;
	
	TexCoords[4] = 0.0;
	TexCoords[5] = 0.0;
	
	TexCoords[6] = WidthRatio;
	TexCoords[7] = 0.0;
	
	Vertices[0] = 0.0f;
	Vertices[1] = actualheight;
	Vertices[2] = 0.0f;
	
	Vertices[3] = actualwidth;
	Vertices[4] = actualheight;
	Vertices[5] = 0.0f;
	
	Vertices[6] = 0.0f;
	Vertices[7] = 0.0f;
	Vertices[8] = 0.0f;
	
	Vertices[9] = actualwidth;
	Vertices[10] = 0.0f;
	Vertices[11] = 0.0f;
}

Texture::~Texture() {
	glDeleteTextures(1, &this->Surface);
}

void Texture::Draw(float x, float y) {
	if (y + Height < 0) return;
	if (y > 480) return;
		
	glBindTexture(GL_TEXTURE_2D, Surface);
	
	glLoadIdentity();
	
	glTranslatef(x, y, 0.0f);
	
	glVertexPointer(3, GL_FLOAT, 0, Vertices);
	glTexCoordPointer(2, GL_FLOAT, 0, TexCoords);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

void Texture::Draw(float x, float y, Colour &col) {
	glBindTexture(GL_TEXTURE_2D, Surface);
	
	glLoadIdentity(); 
	
	glTranslatef(x, y, 0.0f);
	glColor4f(col.R, col.G, col.B, col.A);
	
	glVertexPointer(3, GL_FLOAT, 0, Vertices);
	glTexCoordPointer(2, GL_FLOAT, 0, TexCoords);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}

void Texture::Draw(float x, float y, float width, float height) {
	glBindTexture(GL_TEXTURE_2D, Surface);
	
	glLoadIdentity(); 
	glTranslatef(x, y, 0.0f);
	
	float temp_vertices[] = { 0.0f, height, 0.0f,
					width, height, 0.0f,
					0.0f, 0.0f, 0.0f,
					width, 0.0f, 0.0f
	};
	
	glVertexPointer(3, GL_FLOAT, 0, temp_vertices);
	glTexCoordPointer(2, GL_FLOAT, 0, TexCoords);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 	
}

void Texture::Draw(float x, float y, float rotation, float scale, Colour &col) {
	float texwidth = Width * scale;
	float texheight = Height * scale;
	
	float originx = texwidth / 2;
	float originy = texheight / 2;
	
	glBindTexture(GL_TEXTURE_2D, Surface);
	
	glLoadIdentity(); 
	
	glTranslatef(x, y, 0.0f);
	glRotatef(rotation, 0, 0, 1);
	glColor4f(col.R, col.G, col.B, col.A);

	float temp_vertices[] = {
		-originx, texheight - originy, 0.0f,
		texwidth - originx, texheight - originy, 0.0f,
		-originx, -originy, 0.0f,
		texwidth - originx, -originy, 0.0f
	};
	
	glVertexPointer(3, GL_FLOAT, 0, temp_vertices);
	glTexCoordPointer(2, GL_FLOAT, 0, TexCoords);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}

int Texture::NextPO2(int num) {
	int value = 1;

	while (value < num) {
		value <<= 1;
	}
	return value;
}