/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.

This file is part of GtkRadiant.

GtkRadiant 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.

GtkRadiant 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 GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "q3data.h"

byte			*byteimage, *lbmpalette;
int				byteimagewidth, byteimageheight;


char		mip_prefix[1024];		// directory to dump the textures in

qboolean	colormap_issued;
byte		colormap_palette[768];

/*
==============
Cmd_Grab

$grab filename x y width height
==============
*/
void Cmd_Grab (void)
{
	int             xl,yl,w,h,y;
	byte			*cropped;
	char			savename[1024];
	char			dest[1024];

	GetToken (qfalse);

	if (token[0] == '/' || token[0] == '\\')
		sprintf (savename, "%s%s.pcx", writedir, token+1);
	else
		sprintf (savename, "%spics/%s.pcx", writedir, token);

	if (g_release)
	{
		if (token[0] == '/' || token[0] == '\\')
			sprintf (dest, "%s.pcx", token+1);
		else
			sprintf (dest, "pics/%s.pcx", token);

		ReleaseFile (dest);
		return;
	}

	GetToken (qfalse);
	xl = atoi (token);
	GetToken (qfalse);
	yl = atoi (token);
	GetToken (qfalse);
	w = atoi (token);
	GetToken (qfalse);
	h = atoi (token);

	if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
		Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);

	// crop it to the proper size
	cropped = malloc (w*h);
	for (y=0 ; y<h ; y++)
	{
		memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
	}

	// save off the new image
	printf ("saving %s\n", savename);
	CreatePath (savename);
	WritePCXfile (savename, cropped, w,	h, lbmpalette);

	free (cropped);
}

/*
==============
Cmd_Raw

$grab filename x y width height
==============
*/
void Cmd_Raw (void)
{
	int             xl,yl,w,h,y;
	byte			*cropped;
	char			savename[1024];
	char			dest[1024];

	GetToken (qfalse);

	sprintf (savename, "%s%s.lmp", writedir, token);

	if (g_release)
	{
		sprintf (dest, "%s.lmp", token);
		ReleaseFile (dest);
		return;
	}

	GetToken (qfalse);
	xl = atoi (token);
	GetToken (qfalse);
	yl = atoi (token);
	GetToken (qfalse);
	w = atoi (token);
	GetToken (qfalse);
	h = atoi (token);

	if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
		Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);

	// crop it to the proper size
	cropped = malloc (w*h);
	for (y=0 ; y<h ; y++)
	{
		memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
	}

	// save off the new image
	printf ("saving %s\n", savename);
	CreatePath (savename);

	SaveFile (savename, cropped, w*h);

	free (cropped);
}

/*
=============================================================================

COLORMAP GRABBING

=============================================================================
*/

/*
===============
BestColor
===============
*/
byte BestColor (int r, int g, int b, int start, int stop)
{
	int	i;
	int	dr, dg, db;
	int	bestdistortion, distortion;
	int	bestcolor;
	byte	*pal;

//
// let any color go to 0 as a last resort
//
	bestdistortion = 256*256*4;
	bestcolor = 0;

	pal = colormap_palette + start*3;
	for (i=start ; i<= stop ; i++)
	{
		dr = r - (int)pal[0];
		dg = g - (int)pal[1];
		db = b - (int)pal[2];
		pal += 3;
		distortion = dr*dr + dg*dg + db*db;
		if (distortion < bestdistortion)
		{
			if (!distortion)
				return i;		// perfect match

			bestdistortion = distortion;
			bestcolor = i;
		}
	}

	return bestcolor;
}


/*
==============
Cmd_Colormap

$colormap filename

  the brightes colormap is first in the table (FIXME: reverse this now?)

  64 rows of 256 : lightmaps
  256 rows of 256 : translucency table
==============
*/
void Cmd_Colormap (void)
{
	int		levels, brights;
	int		l, c;
	float	frac, red, green, blue;
	float	range;
	byte	*cropped, *lump_p;
	char	savename[1024];
	char	dest[1024];

	colormap_issued = qtrue;
	if (!g_release)
		memcpy (colormap_palette, lbmpalette, 768);

	if (!TokenAvailable ())
	{	// just setting colormap_issued
		return;
	}

	GetToken (qfalse);
	sprintf (savename, "%spics/%s.pcx", writedir, token);

	if (g_release)
	{
		sprintf (dest, "pics/%s.pcx", token);
		ReleaseFile (dest);
		return;
	}

	range = 2;
	levels = 64;
	brights = 1;	// ignore 255 (transparent)

	cropped = malloc((levels+256)*256);
	lump_p = cropped;

// shaded levels
	for (l=0;l<levels;l++)
	{
		frac = range - range*(float)l/(levels-1);
		for (c=0 ; c<256-brights ; c++)
		{
			red = lbmpalette[c*3];
			green = lbmpalette[c*3+1];
			blue = lbmpalette[c*3+2];

			red = (int)(red*frac+0.5);
			green = (int)(green*frac+0.5);
			blue = (int)(blue*frac+0.5);
			
//
// note: 254 instead of 255 because 255 is the transparent color, and we
// don't want anything remapping to that
// don't use color 0, because NT can't remap that (or 255)
//
			*lump_p++ = BestColor(red,green,blue, 1, 254);
		}

		// fullbrights allways stay the same
		for ( ; c<256 ; c++)
			*lump_p++ = c;
	}
	
// 66% transparancy table
	for (l=0;l<255;l++)
	{
		for (c=0 ; c<255 ; c++)
		{
			red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66;
			green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66;
			blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66;

			*lump_p++ = BestColor(red,green,blue, 1, 254);
		}
		*lump_p++ = 255;
	}
	for (c=0 ; c<256 ; c++)
		*lump_p++ = 255;
	
	// save off the new image
	printf ("saving %s\n", savename);
	CreatePath (savename);
	WritePCXfile (savename, cropped, 256, levels+256, lbmpalette);

	free (cropped);
}

/*
=============================================================================

MIPTEX GRABBING

=============================================================================
*/

byte	pixdata[256];

int		d_red, d_green, d_blue;

byte	palmap[32][32][32];
qboolean	palmap_built;

/*
=============
FindColor
=============
*/
int FindColor (int r, int g, int b)
{
	int		bestcolor;

	if (r > 255)
		r = 255;
	if (r < 0)
		r = 0;
	if (g > 255)
		g = 255;
	if (g < 0)
		g = 0;
	if (b > 255)
		b = 255;
	if (b < 0)
		b = 0;
#ifndef TABLECOLORS
	bestcolor = BestColor (r, g, b, 0, 254);
#else
	bestcolor = palmap[r>>3][g>>3][b>>3];
#endif

	return bestcolor;
}


void BuildPalmap (void)
{
#ifdef TABLECOLORS
	int		r, g, b;
	int		bestcolor;

	if (palmap_built)
		return;
	palmap_built = qtrue;

	for (r=4 ; r<256 ; r+=8)
	{
		for (g=4 ; g<256 ; g+=8)
		{
			for (b=4 ; b<256 ; b+=8)
			{
				bestcolor = BestColor (r, g, b, 1, 254);
				palmap[r>>3][g>>3][b>>3] = bestcolor;
			}
		}
	}
#endif

	if (!colormap_issued)
		Error ("You must issue a $colormap command first");

}

/*
=============
AveragePixels
=============
*/
byte AveragePixels (int count)
{
	int		r,g,b;
	int		i;
	int		vis;
	int		pix;
	int		bestcolor;
	byte	*pal;
	int		fullbright;
	
	vis = 0;
	r = g = b = 0;
	fullbright = 0;
	for (i=0 ; i<count ; i++)
	{
		pix = pixdata[i];
		
		r += lbmpalette[pix*3];
		g += lbmpalette[pix*3+1];
		b += lbmpalette[pix*3+2];
		vis++;
	}
		
	r /= vis;
	g /= vis;
	b /= vis;

	// error diffusion
	r += d_red;
	g += d_green;
	b += d_blue;
	
//
// find the best color
//
	bestcolor = FindColor (r, g, b);

	// error diffusion
	pal = colormap_palette + bestcolor*3;
	d_red = r - (int)pal[0];
	d_green = g - (int)pal[1];
	d_blue = b - (int)pal[2];

	return bestcolor;
}



/*
=============================================================================

ENVIRONMENT MAP GRABBING

Creates six pcx files from tga files without any palette edge seams
also copies the tga files for GL rendering.
=============================================================================
*/

// 3dstudio environment map suffixes
char	*suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"};

/*
=================
Cmd_Environment
=================
*/
void Cmd_Environment (void)
{
	char	name[1024];
	int		i, x, y;
	byte	image[256*256];
	byte	*tga;

	GetToken (qfalse);

	if (g_release)
	{
		for (i=0 ; i<6 ; i++)
		{
			sprintf (name, "env/%s%s.pcx", token, suf[i]);
			ReleaseFile (name);
			sprintf (name, "env/%s%s.tga", token, suf[i]);
			ReleaseFile (name);
		}
		return;
	}
	// get the palette
	BuildPalmap ();

	sprintf (name, "%senv/", gamedir);
	CreatePath (name);

	// convert the images
	for (i=0 ; i<6 ; i++)
	{
		sprintf (name, "%senv/%s%s.tga", gamedir, token, suf[i]);
		printf ("loading %s...\n", name);
		LoadTGA (name, &tga, NULL, NULL);

		for (y=0 ; y<256 ; y++)
		{
			for (x=0 ; x<256 ; x++)
			{
				image[y*256+x] = FindColor (tga[(y*256+x)*4+0],tga[(y*256+x)*4+1],tga[(y*256+x)*4+2]);
			}
		}
		free (tga);
		sprintf (name, "%senv/%s%s.pcx", writedir, token, suf[i]);
		if (FileTime (name) != -1)
			printf ("%s already exists, not overwriting.\n", name);
		else
			WritePCXfile (name, image, 256, 256, colormap_palette);
	}
}

