/*
Copyright (C) 1996-1997 Id Software, Inc.

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// gl_rmisc.c

#include "quakedef.h"
#include "gl_local.h"

#include "rulesets.h"


void R_InitOtherTextures (void) {
	static const int flags = TEX_MIPMAP | TEX_ALPHA | TEX_COMPLAIN;

	underwatertexture = GL_LoadTextureImage ("textures/water_caustic", NULL, 0, 0,  flags );	
	detailtexture = GL_LoadTextureImage("textures/detail", NULL, 256, 256, flags);	
}

void R_InitTextures (void) {
	int x,y, m;
	byte *dest;

	// create a simple checkerboard texture for the default
	r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16 * 16 + 8 * 8+4 * 4 + 2 * 2, "notexture");
	
	strcpy(r_notexture_mip->name, "notexture");
	r_notexture_mip->width = r_notexture_mip->height = 16;
	r_notexture_mip->offsets[0] = sizeof(texture_t);
	r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16 * 16;
	r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8 * 8;
	r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4 * 4;
	
	for (m = 0; m < 4; m++) {
		dest = (byte *) r_notexture_mip + r_notexture_mip->offsets[m];
		for (y = 0; y < (16 >> m); y++) {
			for (x = 0; x < (16 >> m); x++) {
				if ((y < (8 >> m)) ^ (x < (8 >> m)))
					*dest++ = 0;
				else
					*dest++ = 0x0e;
			}
		}
	}	
}

char *Skin_FindName (player_info_t *sc) ;
//Translates a skin texture by the per-player color lookup
void R_TranslatePlayerSkin (int playernum) {
	byte translate[256], *inrow, *original;
	char s[512];
	int	top, bottom, i, j, scaled_width, scaled_height, inwidth, inheight, tinwidth, tinheight;
	unsigned translate32[256], pixels[512 * 256], *out, frac, fracstep;
	player_info_t *player;
	extern byte player_8bit_texels[320 * 200];
	extern cvar_t gl_scaleModelTextures;
	extern int gl_max_size_default;

	player = &cl.players[playernum];
	if (!player->name[0])
		return;

	Q_strncpyz(s, Skin_FindName(player), sizeof(s));
	COM_StripExtension(s, s);

	if (player->skin && Q_strcasecmp(s, player->skin->name))
		player->skin = NULL;

	if (player->_topcolor == player->topcolor && player->_bottomcolor == player->bottomcolor && player->skin)
		return;

	GL_DisableMultitexture();

	player->_topcolor = player->topcolor;
	player->_bottomcolor = player->bottomcolor;

	top = bound(0, player->topcolor, 13) * 16;
	bottom = bound(0, player->bottomcolor, 13) * 16;

	for (i = 0; i < 256; i++)
		translate[i] = i;

	for (i = 0; i < 16; i++) {
		if (top < 128)	// the artists made some backwards ranges.  sigh.
			translate[TOP_RANGE + i] = top + i;
		else
			translate[TOP_RANGE + i] = top + 15 - i;

		if (bottom < 128)
			translate[BOTTOM_RANGE + i] = bottom + i;
		else
			translate[BOTTOM_RANGE + i] = bottom + 15 - i;
	}

	// locate the original skin pixels
	// real model width
	tinwidth = 296;
	tinheight = 194;

	if (!player->skin)
		Skin_Find(player);
	if ((original = Skin_Cache(player->skin)) != NULL) {
		//skin data width
		inwidth = 320;
		inheight = 200;
	} else {
		original = player_8bit_texels;
		inwidth = 296;
		inheight = 194;
	}

	GL_Bind(playertextures + playernum);

	scaled_width = gl_scaleModelTextures.value ? min(gl_max_size.value, 512) : min(gl_max_size_default, 512);
	scaled_height = gl_scaleModelTextures.value ? min(gl_max_size.value, 256) : min(gl_max_size_default, 256);

	// allow users to crunch sizes down even more if they want
	scaled_width >>= (int) gl_playermip.value;
	scaled_height >>= (int) gl_playermip.value;
	if (scaled_width < 1)
		scaled_width = 1;
	if (scaled_height < 1)
		scaled_height = 1;

	for	(i = 0; i < 256; i++)
		translate32[i] = d_8to24table[translate[i]];

	out	= pixels;
	memset(pixels, 0, sizeof(pixels));
	fracstep = tinwidth * 0x10000 / scaled_width;
	for	(i = 0; i < scaled_height; i++, out += scaled_width) {
		inrow =	original + inwidth*(i * tinheight / scaled_height);
		frac = fracstep	>> 1;
		for	(j = 0; j < scaled_width; j += 4) {
			out[j] = translate32[inrow[frac >> 16]];
			frac += fracstep;
			out[j + 1] = translate32[inrow[frac >> 16]];
			frac += fracstep;
			out[j + 2] = translate32[inrow[frac >> 16]];
			frac += fracstep;
			out[j + 3] = translate32[inrow[frac >> 16]];
			frac += fracstep;
		}
	}

	glTexImage2D (GL_TEXTURE_2D, 0,	3, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	playerfbtextures[playernum] = 0;
	if (Img_HasFullbrights ((byte *) original, inwidth * inheight)) {
		playerfbtextures[playernum] = playertextures + playernum + MAX_CLIENTS;

		GL_Bind(playerfbtextures[playernum]);

		out = pixels;
		memset(pixels, 0, sizeof(pixels));
		fracstep = tinwidth * 0x10000 / scaled_width;

		// make all non-fullbright colors transparent
		for (i = 0; i < scaled_height; i++, out += scaled_width) {
			inrow = original + inwidth * (i * tinheight / scaled_height);
			frac = fracstep >> 1;
			for (j = 0; j < scaled_width; j += 4) {
				if (inrow[frac >> 16] < 224)
					out[j] = translate32[inrow[frac >> 16]] & 0x00FFFFFF; // transparent
				else
					out[j] = translate32[inrow[frac >> 16]]; // fullbright
				frac += fracstep;
				if (inrow[frac >> 16] < 224)
					out[j + 1] = translate32[inrow[frac >> 16]] & 0x00FFFFFF;
				else
					out[j + 1] = translate32[inrow[frac >> 16]];
				frac += fracstep;
				if (inrow[frac >> 16] < 224)
					out[j + 2] = translate32[inrow[frac >> 16]] & 0x00FFFFFF;
				else
					out[j + 2] = translate32[inrow[frac >> 16]];
				frac += fracstep;
				if (inrow[frac >> 16] < 224)
					out[j + 3] = translate32[inrow[frac >> 16]] & 0x00FFFFFF;
				else
					out[j + 3] = translate32[inrow[frac >> 16]];
				frac += fracstep;
			}
		}

		glTexImage2D (GL_TEXTURE_2D, 0, 4, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}
}


void R_PreMapLoad(char *name) {

	Cvar_ForceSet (&mapname, name);
	if (!dedicated)
		lightmode = gl_lightmode.value == 0 ? 0 : 2;
}

void R_NewMap (void) {
	int	i, waterline;

	for (i = 0; i < 256; i++)
		d_lightstylevalue[i] = 264;		// normal light value

	memset (&r_worldentity, 0, sizeof(r_worldentity));
	r_worldentity.model = cl.worldmodel;

	// clear out efrags in case the level hasn't been reloaded
	// FIXME: is this one short?
	for (i = 0; i < cl.worldmodel->numleafs; i++)
		cl.worldmodel->leafs[i].efrags = NULL;
		 	
	r_viewleaf = NULL;
	R_ClearParticles ();

	GL_BuildLightmaps ();

	// identify sky texture
	for (i = 0; i < cl.worldmodel->numtextures; i++) {
		if (!cl.worldmodel->textures[i])
			continue;
		for (waterline = 0; waterline < 2; waterline++) {
 			cl.worldmodel->textures[i]->texturechain[waterline] = NULL;
			cl.worldmodel->textures[i]->texturechain_tail[waterline] = &cl.worldmodel->textures[i]->texturechain[waterline];
		}
	}
}

void R_TimeRefresh_f (void) {
#ifndef USEFAKEGL
	int i;
	float start, stop, time;

	if (cls.state != ca_active)
		return;

	if (!Rulesets_AllowTimerefresh()) {
		Com_Printf("Timerefresh's disabled during match\n");
		return;
	}

	glDrawBuffer  (GL_FRONT);
	glFinish ();

	start = Sys_DoubleTime ();
	for (i = 0; i < 128; i++) {
		r_refdef.viewangles[1] = i * (360.0 / 128.0);
		R_RenderView ();
	}

	glFinish ();
	stop = Sys_DoubleTime ();
	time = stop-start;
	Com_Printf ("%f seconds (%f fps)\n", time, 128/time);

	glDrawBuffer  (GL_BACK);
	GL_EndRendering ();
#endif
}

void D_FlushCaches (void) {}
