#include "texture.h"
#include "macros.h"

Texture::Texture () {

  glGenTextures(1, &texture);

  wrap_s = GL_REPEAT;
  wrap_t = GL_REPEAT;
  min_filter = GL_LINEAR;
  mag_filter = GL_LINEAR;
  border_color[0] = 0.0; border_color[1] = 0.0;
  border_color[2] = 0.0; border_color[3] = 0.0;
  priority = 1.0;
  env_mode =  GL_MODULATE;
  env_color[0] = 0.0; env_color[1] = 0.0;
  env_color[2] = 0.0; env_color[3] = 0.0;

  transferred = false;
  altered = true;
}

void Texture::WrapS (GLint n) {
  wrap_s = n; altered = true;
}
void Texture::WrapT (GLint n) {
  wrap_t = n; altered = true;
}
void Texture::MinFilter (GLint n) {
  min_filter = n; altered = true;
}
void Texture::MagFilter (GLint n) {
  mag_filter = n; altered = true;
}
void Texture::Priority (GLfloat f) {
  priority = f; altered = true;
}
void Texture::BorderColor4fv (GLfloat *v) {
  border_color[0] = *v; border_color[1] = *(v+1);
  border_color[2] = *(v+2); border_color[3] = *(v+3);
  altered = true;
}
void Texture::EnvMode (GLenum e) {
  env_mode = e; altered = true;
}
void Texture::EnvColor4f (GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
  env_color[0] = r; env_color[1] = g;
  env_color[2] = b; env_color[3] = a;
  altered = true;
}
void Texture::EnvColor4fv (GLfloat *v) {
  env_color[0] = *v; env_color[1] = *(v+1);
  env_color[2] = *(v+2); env_color[3] = *(v+3);
  altered = true;
}
GLint Texture::WrapS () {
  return wrap_s;
}
GLint Texture::WrapT () {
  return wrap_t;
}
GLint Texture::MinFilter () {
  return min_filter;
}
GLint Texture::MagFilter () {
  return mag_filter;
}
GLfloat Texture::Priority () {
  return priority;
}
const GLfloat* Texture::BorderColor4fv () {
  return border_color;
}
GLenum Texture::EnvMode () {
  return env_mode;
}
const GLfloat* Texture::EnvColor4fv () {
  return env_color;
}

void TextureGL::GL ()
{
  glBindTexture(GL_TEXTURE_2D, texture);
  if(altered) {
    altered = false;
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, priority);
  }
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env_color);
}

void TextureGL::TexImage2D (GLenum target, GLint level, GLint internalformat,
                            GLsizei width, GLsizei height, GLint border,
                            GLenum format, GLenum type, void *data)
{
  GLint old;
  glGetIntegerv(GL_TEXTURE_BINDING_2D, &old);
  glBindTexture(GL_TEXTURE_2D, texture);
  glTexImage2D(GL_TEXTURE_2D, level, internalformat,
               width, height, border,
               format, type, data);
  glBindTexture(GL_TEXTURE_2D, old);
}

void TextureFile::GL ()
{
  if(Name()==0) {    
    glBindTexture(GL_TEXTURE_2D, 0);
    return;
  }
  if(texture==0)
    glGenTextures(1, &texture);

  glBindTexture(GL_TEXTURE_2D, texture);

  if(altered) {
    altered = false;
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, priority);
  }
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env_color);

  if(!transferred) {
    Image img;
    img.Load(Name()());

    switch(img.format())
    {
      case OGL_IMAGE_RGB888:
        img.FlipVertical();
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1,
                     img.width(), img.height(), 0,
                     GL_RGB, GL_UNSIGNED_BYTE, img.data());
  
        cout << "texture transferred" << endl;
        break;

      case OGL_IMAGE_RGBA8888:
        img.FlipVertical();
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1,
                     img.width(), img.height(), 0,
                     GL_RGBA, GL_UNSIGNED_BYTE, img.data());
  
        cout << "texture transferred" << endl;
        break;

      default:
        cout << "Bad image type " << img.format() << endl;
        break;
    }

    transferred = true;
  }
}

Texture::~Texture () {
  if(texture==0)
    return;
  glDeleteTextures(1, &texture);
}
