/*
**  wt -- a 3d game engine
**
**  Copyright (C) 1994 by Chris Laurel
**  email:  claurel@mr.net
**  snail mail:  Chris Laurel, 5700 W Lake St #208,  St. Louis Park, MN  55416
**
**  This program 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/* GIF87a code from Thomas Hamren (d0hampe@dtek.chalmers.se) */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "wt.h"
#include "wtmem.h"
#include "error.h"
#include "color.h"
#include "graphfile.h"
#include "framebuf.h"
#include "graphics.h"
#include "texture.h"


#define COLOR_LEVELS 6


static int ilog2(int x);
static void quantize_texture(Graphic_file *gfile, Texture *t);

static int tex_rgb_cube_size;
static long *tex_color_lookup = NULL;


Texture *new_texture(int width, int height)
{
     Texture *t;

     if (height <= 0 || width <= 0)
	  fatal_error("new_texture:  bad texture dimensions");

     t = wtmalloc(sizeof(Texture));
     t->texels = wtmalloc(height * width * sizeof(Pixel));

     t->width = width;
     t->height = height;
     t->log2height = ilog2(height);
     
     return t;
}


Texture *read_texture_file(char *filename)
{
     Graphic_file *gfile;
     Texture *t;


     gfile = read_graphic_file(filename);
     if (gfile == NULL)
	  fatal_error("Error reading texture %s.", filename);

     /* The height and width should be powers of two for efficient
     **   texture mapping.  Here, we enforce this.
     */
     if (ilog2(gfile->width) == -1 || ilog2(gfile->height) == -1)
	  fatal_error("Dimensions texture %s are not powers of two.", 
		      filename);
     
     t = new_texture(gfile->width, gfile->height);
     quantize_texture(gfile, t);

     free_graphic_file(gfile);

     return t;
}


/* Set texture translation parameters.  This is sort of kludgy--the rest
**   the world loading code does not need any information about the graphics
**   device.  But here, we need to convert the texture maps to a one byte
**   per pixel format using the color map of output device.
*/
void set_texture_trans(int rgb_cube_size, long *color_lookup)
{
     tex_rgb_cube_size = rgb_cube_size;
     tex_color_lookup = color_lookup;
}


/* Return the log base 2 of the argument, or -1 if the argument is not
**   an integer power of 2.
*/
static int ilog2(int x)
{
     int i;
     unsigned int n;

     if (x <= 0)
	  return -1;
     else
	  n = (unsigned int) x;
     
     for (i = 0; (n & 0x1) == 0; i++, n >>= 1);

     if (n == 1)
	  return i;
     else
	  return -1;
}


static void quantize_texture(Graphic_file *gfile, Texture *t)
{
     RGBcolor pixel;
     int x, y;
     int color_divisor = 256 / tex_rgb_cube_size;
     Pixel *dest_pixel = t->texels;


     for (x = gfile->width - 1; x >= 0; x--)
     for (y = gfile->height - 1; y >= 0; y--) {
	  int red, green, blue;

	  pixel = graphic_file_pixel(gfile, x, y);

	  red = MIN(pixel.red / color_divisor, tex_rgb_cube_size - 1);
	  green = MIN(pixel.green / color_divisor, tex_rgb_cube_size - 1);
	  blue = MIN(pixel.blue / color_divisor, tex_rgb_cube_size - 1);

#ifndef TRUECOLOR
	  *dest_pixel++ = tex_color_lookup[(red * tex_rgb_cube_size + green) *
					   tex_rgb_cube_size + blue];
#else
	  *dest_pixel++ = (red * tex_rgb_cube_size + green) *
 	                   tex_rgb_cube_size + blue;
#endif
     }
}
