/* texture.c: RenderPark texture objects */

#include "texture.h"
#include "pools.h"
#include "error.h"

#ifdef NOPOOLS
#define NEWTEXTURE()	(TEXTURE *)Alloc(sizeof(TEXTURE))
#define DISPOSETEXTURE(ptr) Free((char *)ptr, sizeof(TEXTURE))
#else
static POOL *texturePool = (POOL *)NULL;
#define NEWTEXTURE()	(TEXTURE *)NewPoolCell(sizeof(TEXTURE), 0, "textures", &texturePool)
#define DISPOSETEXTURE(ptr) Dispose((char *)ptr, &texturePool)
#endif

TEXTURE* CreateTexture(int width, int height, int channels, unsigned char* data)
{
  TEXTURE *t = NEWTEXTURE();

  t->width = width;
  t->height = height;
  t->channels = channels;
  t->data = data;

  return t;
}

void DestroyTexture(TEXTURE* t)
{
  if (t) DISPOSETEXTURE(t);
}

void PrintTexture(FILE *out, TEXTURE *t)
{
  if (!t)
    fprintf(out, "(NULL TEXTURE)");
  else
    fprintf(out, "%dx%dx%d texture", t->width, t->height, t->channels);
}

#define RGBSETMONOCHROME(rgb, val) RGBSET(rgb, val, val, val)

COLOR EvalTextureColor(TEXTURE *texture, float u, float v)
{
  RGB rgb00, rgb10, rgb01, rgb11, rgb;
  COLOR col;
  unsigned char *pix00, *pix01, *pix10, *pix11;
  double u1 = u-floor(u), u0 = 1.-u1, v1 = v-floor(v), v0 = 1.-v1;
  int i = (u1 * (float)texture->width), i1= i+1;
  int j = (v1 * (float)(texture->height)), j1=j+1;
  if (i<0) i=0; if (i>=texture->width) i=texture->width-1;
  if (j<0) j=0; if (j>=texture->height) j=texture->height-1;
  if (i1 >= texture->width) i1 -= texture->width;
  if (j1 >= texture->height) j1 -= texture->height;

  COLORCLEAR(col);
  if (!texture->data)
    return col;

  pix00 = texture->data + (j  * texture->width + i ) * texture->channels;
  pix01 = texture->data + (j1 * texture->width + i ) * texture->channels;
  pix10 = texture->data + (j  * texture->width + i1) * texture->channels;
  pix11 = texture->data + (j1 * texture->width + i1) * texture->channels;

  switch (texture->channels) {
  case 1:
    RGBSETMONOCHROME(rgb00, (float)pix00[0] / 255.);
    RGBSETMONOCHROME(rgb10, (float)pix10[0] / 255.);
    RGBSETMONOCHROME(rgb01, (float)pix01[0] / 255.);
    RGBSETMONOCHROME(rgb11, (float)pix11[0] / 255.);
    break;
  case 3: case 4:
    {
      RGBSET(rgb00, (float)pix00[0]/255., (float)pix00[1]/255., (float)pix00[2]/255.);
      RGBSET(rgb10, (float)pix10[0]/255., (float)pix10[1]/255., (float)pix10[2]/255.);
      RGBSET(rgb01, (float)pix01[0]/255., (float)pix01[1]/255., (float)pix01[2]/255.);
      RGBSET(rgb11, (float)pix11[0]/255., (float)pix11[1]/255., (float)pix11[2]/255.);
    }
    break;
  default:
    break;
  }

  RGBSET(rgb, 
	 0.25 * ( u0 * v0 * rgb00.r + u1 * v0 * rgb10.r + u0 * v1 * rgb01.r + u1 * v1 * rgb11.r ), 
	 0.25 * ( u0 * v0 * rgb00.g + u1 * v0 * rgb10.g + u0 * v1 * rgb01.g + u1 * v1 * rgb11.g ), 
	 0.25 * ( u0 * v0 * rgb00.b + u1 * v0 * rgb10.b + u0 * v1 * rgb01.b + u1 * v1 * rgb11.b ));
  RGBToColor(rgb, &col);
  return col;
}
