/*
Copyright (C) 1997-2001 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.

*/

// r_draw.c

#include "r_local.h"

image_t		*draw_chars;


// vertex arrays
float	tex_array[MAX_ARRAY][2];
float	vert_array[MAX_ARRAY][3];
float	col_array[MAX_ARRAY][4];


extern	qboolean	scrap_dirty;
void Scrap_Upload (void);

#define DEFAULT_FONT_SIZE 8.0f

void RefreshFont (void)
{
	con_font->modified = false;

	draw_chars = GL_FindImage (va("fonts/%s.pcx", con_font->string), it_pic);
	if (!draw_chars) // fall back on default font
		draw_chars = GL_FindImage ("fonts/default.pcx", it_pic);
	if (!draw_chars) // fall back on old Q2 conchars
		draw_chars = GL_FindImage ("pics/conchars.pcx", it_pic);
	if (!draw_chars) // Knightmare- prevent crash caused by missing font
		VID_Error (ERR_FATAL, "RefreshFont: couldn't load pics/conchars");

	GL_Bind( draw_chars->texnum );
}


/*
===============
R_DrawInitLocal
===============
*/
void R_DrawInitLocal (void)
{
	// load console characters (don't bilerp characters)
	//draw_chars = GL_FindImage ("pics/conchars.pcx", it_pic);
	//GL_Bind( draw_chars->texnum );

	image_t	*R_DrawFindPic (char *name);

	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	// load console characters (don't bilerp characters)
	RefreshFont();
}


/*
================
R_CharMapScale
================
*/
float R_CharMapScale (void)
{
	return (draw_chars->width/128.0); //current width / original width
}


/*
================
R_DrawCharacter
================
*/
void R_DrawCharacter (float x, float y, float frow, float fcol, float size, float scale,
					int red, int green, int blue, int alpha, qboolean italic)
{
	float italicAdd = 0;

	if (italic)
		italicAdd = scale*0.25;

	qglColor4ub( (byte)red, (byte)green, (byte)blue, (byte)alpha);

	qglTexCoord2f (fcol, frow);
	qglVertex2f (x+italicAdd, y);

	qglTexCoord2f (fcol + size, frow);
	qglVertex2f (x+scale+italicAdd, y);

	qglTexCoord2f (fcol + size, frow + size);
	qglVertex2f (x+scale-italicAdd, y+scale);

	qglTexCoord2f (fcol, frow + size);
	qglVertex2f (x-italicAdd, y+scale);
}


/*
================
R_DrawScaledChar
================
*/
void R_DrawScaledChar (float x, float y, int num, float scale, 
	 int red, int green, int blue, int alpha, qboolean italic)
{
	int				row, col;
	float			frow, fcol, size, cscale;

	num &= 255;


	if (alpha >= 255)
		alpha = 255;
	else if (alpha <= 1)
		alpha = 1;

	if ( (num&127) == 32 )
		return;		// space

	if (y <= -8)
		return;			// totally off screen

	row = num>>4;
	col = num&15;

	frow = row*0.0625;
	fcol = col*0.0625;
	size = 0.0625;
	cscale = scale * DEFAULT_FONT_SIZE;

	{
		GLSTATE_DISABLE_ALPHATEST
		GL_TexEnv( GL_MODULATE );
		GLSTATE_ENABLE_BLEND
		qglDepthMask   (false);
	}

	GL_Bind(draw_chars->texnum);


	qglBegin (GL_QUADS);
	{
		R_DrawCharacter(x, y, frow, fcol, size, cscale,
						red, green, blue, alpha, italic);
	}
	qglEnd ();

	{
		qglDepthMask (true);
		GL_TexEnv( GL_REPLACE );
		GLSTATE_DISABLE_BLEND
		qglColor4f   (1,1,1,1);
		GLSTATE_ENABLE_ALPHATEST
	}
}

/*
================
R_DrawChar

Draws one 8*8 graphics character with 0 being transparent.
It can be clipped to the top of the screen to allow the console to be
smoothly scrolled off.
================
*/
// Knightmare- added alpha for Psychospaz's fading centerprints
void R_DrawChar (int x, int y, int num, int alpha)
{
	int				row, col;
	float			frow, fcol, size, scale;

	num &= 255;
	
	if (alpha >= 255)
		alpha = 255;
	else if (alpha <= 1)
		alpha = 1;

	if ( (num&127) == 32 )
		return;		// space

	if (y <= -8)
		return;			// totally off screen

	row = num>>4;
	col = num&15;

	frow = row*0.0625;
	fcol = col*0.0625;
	size = 0.0625;
	scale = DEFAULT_FONT_SIZE;

	// Knightmare- added Psychospaz's alpha for chars
	{
		qglDisable (GL_ALPHA_TEST);
		GL_TexEnv( GL_MODULATE );
		qglColor4ub( 255, 255, 255, (byte)alpha);
		qglEnable( GL_BLEND );
		qglDepthMask   (false);
	}

	GL_Bind (draw_chars->texnum);

	qglBegin (GL_QUADS);
	{
		R_DrawCharacter(x, y, frow, fcol, size, scale,
						255, 255, 255, alpha, false);
		/*qglTexCoord2f (fcol, frow);
		qglVertex2f (x, y);
		qglTexCoord2f (fcol + size, frow);
		qglVertex2f (x+scale, y);
		qglTexCoord2f (fcol + size, frow + size);
		qglVertex2f (x+scale, y+scale);
		qglTexCoord2f (fcol, frow + size);
		qglVertex2f (x, y+scale);*/
	}
	qglEnd ();

	{
		qglDepthMask (true);
		GL_TexEnv( GL_REPLACE );
		qglDisable ( GL_BLEND );
		qglColor4f   (1,1,1,1);

		qglEnable (GL_ALPHA_TEST);
	}
}

/*
=============
R_DrawFindPic
=============
*/
image_t	*R_DrawFindPic (char *name)
{
	image_t *gl;
	char	fullname[MAX_QPATH];

	if (name[0] != '/' && name[0] != '\\')
	{
		Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
		gl = GL_FindImage (fullname, it_pic);
	}
	else
		gl = GL_FindImage (name+1, it_pic);
	// jitfix
	//if (!gl) // jit -- remove "can't find pic" spam
	//	return r_notexture;
	//else 
	// end jitfix
		return gl;
}

/*
=============
R_DrawGetPicSize
=============
*/
void R_DrawGetPicSize (int *w, int *h, char *pic)
{
	image_t *gl;

	gl = R_DrawFindPic (pic);
	if (!gl)
	{
		*w = *h = -1;
		return;
	}
	*w = gl->width;
	*h = gl->height;
}

/*
=============
R_DrawStretchPic
=============
*/
void R_DrawStretchPic (int x, int y, int w, int h, char *pic, float alpha)
{
	image_t *gl;

	gl = R_DrawFindPic (pic);
	if (!gl)
	{
		VID_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}

	if (scrap_dirty)
		Scrap_Upload ();

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
		qglDisable (GL_ALPHA_TEST);

	//Knightare- Psychospaz's transparent console support
	if (gl->has_alpha || alpha<1)
	{
		qglDisable (GL_ALPHA_TEST);
		GL_Bind(gl->texnum);
		GL_TexEnv(GL_MODULATE);
		qglColor4f(1,1,1,alpha);	
		qglEnable(GL_BLEND);
		qglDepthMask(false);
	}
	else //end Knightmare
		GL_Bind (gl->texnum);

	qglBegin (GL_QUADS);
	qglTexCoord2f (gl->sl, gl->tl);
	qglVertex2f (x, y);
	qglTexCoord2f (gl->sh, gl->tl);
	qglVertex2f (x+w, y);
	qglTexCoord2f (gl->sh, gl->th);
	qglVertex2f (x+w, y+h);
	qglTexCoord2f (gl->sl, gl->th);
	qglVertex2f (x, y+h);
	qglEnd ();

	//Knightare- Psychospaz's transparent console support
	if (gl->has_alpha || alpha < 1)
	{
		qglDepthMask (true);
		GL_TexEnv(GL_REPLACE);
		qglDisable(GL_BLEND);
		qglColor4f(1,1,1,1);

		qglEnable(GL_ALPHA_TEST);
	}
	//end Knightmare

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
		qglEnable (GL_ALPHA_TEST);
}

//Knightmare- this is Psychospaz's code for drawing stretched crosshairs
/*
=============
R_DrawScaledPic
=============
*/
void R_DrawScaledPic (int x, int y, float scale, float alpha, char *pic, qboolean fixcoords, qboolean repscale)
{
	float xoff, yoff;
	float scale_x, scale_y;
	image_t *gl;

	gl = R_DrawFindPic (pic);
	if (!gl)
	{
		VID_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}
	if (scrap_dirty)
		Scrap_Upload ();

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
		qglDisable (GL_ALPHA_TEST);

	//add alpha support
	{
		qglDisable (GL_ALPHA_TEST);

		qglBindTexture (GL_TEXTURE_2D, gl->texnum);

		GL_TexEnv( GL_MODULATE );
		qglColor4f(1,1,1, alpha);	//need <1 for trans to work
		qglEnable( GL_BLEND );
		qglDepthMask   (false);
	}

	scale_x = scale_y = scale;
	// NOTE: replace this with shaders as soon as they are supported
	if (repscale) {
		scale_x *= gl->replace_scale_w; // scale down if replacing a pcx image
		scale_y *= gl->replace_scale_h; // scale down if replacing a pcx image
	}

	if (fixcoords) // Knightmare- whether to adjust coordinates for scaling
	{
		xoff = (gl->width*scale_x-gl->width)/2;
		yoff = (gl->height*scale_y-gl->height)/2;

		GL_Bind (gl->texnum);
		qglBegin (GL_QUADS);
		qglTexCoord2f (gl->sl, gl->tl);
		qglVertex2f (x-xoff, y-yoff);
		qglTexCoord2f (gl->sh, gl->tl);
		qglVertex2f (x+gl->width+xoff, y-yoff);
		qglTexCoord2f (gl->sh, gl->th);
		qglVertex2f (x+gl->width+xoff, y+gl->height+yoff);
		qglTexCoord2f (gl->sl, gl->th);
		qglVertex2f (x-xoff, y+gl->height+yoff);
		qglEnd ();
	}
	else
	{
		xoff = gl->width*scale_x-gl->width;
		yoff = gl->height*scale_y-gl->height;

		GL_Bind (gl->texnum);
		qglBegin (GL_QUADS);
		qglTexCoord2f (gl->sl, gl->tl);
		qglVertex2f (x, y);
		qglTexCoord2f (gl->sh, gl->tl);
		qglVertex2f (x+gl->width+xoff, y);
		qglTexCoord2f (gl->sh, gl->th);
		qglVertex2f (x+gl->width+xoff, y+gl->height+yoff);
		qglTexCoord2f (gl->sl, gl->th);
		qglVertex2f (x, y+gl->height+yoff);
		qglEnd ();
	}

	//add alpha support
	{
		qglDepthMask (true);
		GL_TexEnv( GL_REPLACE );
		qglDisable ( GL_BLEND );
		qglColor4f   (1,1,1,1);

		qglEnable (GL_ALPHA_TEST);
	}

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !gl->has_alpha)
		qglEnable (GL_ALPHA_TEST);
}

/*
=============
R_DrawPic
=============
*/
void R_DrawPic (int x, int y, char *pic)
{
	image_t *gl;

	gl = R_DrawFindPic (pic);
	if (!gl)
	{
		VID_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}
	if (scrap_dirty)
		Scrap_Upload ();

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
		qglDisable (GL_ALPHA_TEST);

	GL_Bind (gl->texnum);
	qglBegin (GL_QUADS);
	qglTexCoord2f (gl->sl, gl->tl);
	qglVertex2f (x, y);
	qglTexCoord2f (gl->sh, gl->tl);
	qglVertex2f (x+gl->width, y);
	qglTexCoord2f (gl->sh, gl->th);
	qglVertex2f (x+gl->width, y+gl->height);
	qglTexCoord2f (gl->sl, gl->th);
	qglVertex2f (x, y+gl->height);
	qglEnd ();

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !gl->has_alpha)
		qglEnable (GL_ALPHA_TEST);
}

/*
=============
R_DrawTileClear

This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
void R_DrawTileClear (int x, int y, int w, int h, char *pic)
{
	image_t	*image;

	image = R_DrawFindPic (pic);
	if (!image)
	{
		VID_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !image->has_alpha)
		qglDisable (GL_ALPHA_TEST);

	GL_Bind (image->texnum);
	qglBegin (GL_QUADS);
	qglTexCoord2f (x/64.0, y/64.0);
	qglVertex2f (x, y);
	qglTexCoord2f ( (x+w)/64.0, y/64.0);
	qglVertex2f (x+w, y);
	qglTexCoord2f ( (x+w)/64.0, (y+h)/64.0);
	qglVertex2f (x+w, y+h);
	qglTexCoord2f ( x/64.0, (y+h)/64.0 );
	qglVertex2f (x, y+h);
	qglEnd ();

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !image->has_alpha)
		qglEnable (GL_ALPHA_TEST);
}


/*
=============
R_DrawFill

Fills a box of pixels with a single color
=============
*/
void R_DrawFill (int x, int y, int w, int h, int c)
{
	union
	{
		unsigned	c;
		byte		v[4];
	} color;

	if ( (unsigned)c > 255)
		VID_Error (ERR_FATAL, "Draw_Fill: bad color");

	qglDisable (GL_TEXTURE_2D);

	color.c = d_8to24table[c];
	qglColor3f (color.v[0]/255.0,
		color.v[1]/255.0,
		color.v[2]/255.0);

	qglBegin (GL_QUADS);

	qglVertex2f (x,y);
	qglVertex2f (x+w, y);
	qglVertex2f (x+w, y+h);
	qglVertex2f (x, y+h);

	qglEnd ();
	qglColor3f (1,1,1);
	qglEnable (GL_TEXTURE_2D);
}

// Knightmare added
/*
======================
R_DrawFill2

Fills a box of pixels with a
24-bit color w/ alpha
===========================
*/
void R_DrawFill2 (int x, int y, int w, int h, int red, int green, int blue, int alpha)
{
	red = min(red, 255);
	green = min(green, 255);
	blue = min(blue, 255);

	if (alpha >= 255)
		alpha = 255;
	else if (alpha <= 1)
		alpha = 1;

	qglDisable (GL_TEXTURE_2D);
	GLSTATE_DISABLE_ALPHATEST
	GL_TexEnv( GL_MODULATE );
	GLSTATE_ENABLE_BLEND
	qglDepthMask   (false);

	qglColor4ub ((byte)red, (byte)green, (byte)blue, (byte)alpha);
	
	qglBegin (GL_QUADS);

	qglVertex2f (x,y);
	qglVertex2f (x+w, y);
	qglVertex2f (x+w, y+h);
	qglVertex2f (x, y+h);

	qglEnd ();

	qglDepthMask (true);
	GL_TexEnv( GL_REPLACE );
	GLSTATE_DISABLE_BLEND
	qglColor4f   (1,1,1,1);
	GLSTATE_ENABLE_ALPHATEST
	qglEnable (GL_TEXTURE_2D);
}

//=============================================================================

/*
================
R_DrawFadeScreen

================
*/
void R_DrawFadeScreen (void)
{
	qglEnable (GL_BLEND);
	qglDisable (GL_TEXTURE_2D);
	qglColor4f (0, 0, 0, 0.8);
	qglBegin (GL_QUADS);

	qglVertex2f (0,0);
	qglVertex2f (vid.width, 0);
	qglVertex2f (vid.width, vid.height);
	qglVertex2f (0, vid.height);

	qglEnd ();
	qglColor4f (1,1,1,1);
	qglEnable (GL_TEXTURE_2D);
	qglDisable (GL_BLEND);
}


//====================================================================


/*
=============
R_DrawStretchRaw

Cinematic streaming
=============
*/
#ifdef ROQ_SUPPORT

void R_DrawStretchRaw (int x, int y, int w, int h, const byte *raw, int rawWidth, int rawHeight) //qboolean noDraw)
{
	int		width = 1, height = 1;

	// Make sure everything is flushed if needed
	//if (!noDraw)
	//	RB_RenderMesh();

	// Check the dimensions
	while (width < rawWidth)
		width <<= 1;
	while (height < rawHeight)
		height <<= 1;

	if (rawWidth != width || rawHeight != height)
		VID_Error(ERR_DROP, "Draw_StretchRaw2: size is not a power of two (%i x %i)", rawWidth, rawHeight);

	if (rawWidth > gl_config.max_texsize || rawHeight > gl_config.max_texsize)
		VID_Error(ERR_DROP, "Draw_StretchRaw2: size exceeds hardware limits (%i > %i or %i > %i)", rawWidth, gl_config.max_texsize, rawHeight, gl_config.max_texsize);

	// Update the texture as appropriate
	GL_Bind(r_rawtexture->texnum);
	
	if (rawWidth == r_rawtexture->upload_width && rawHeight == r_rawtexture->upload_height)
		qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rawWidth, rawHeight, GL_RGBA, GL_UNSIGNED_BYTE, raw);
	else
	{
		r_rawtexture->upload_width = rawWidth;
		r_rawtexture->upload_height = rawHeight;
		qglTexImage2D(GL_TEXTURE_2D, 0, gl_tex_solid_format, rawWidth, rawHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, raw);
	}

	//if (noDraw)
	//	return;

	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	// Draw it
	qglColor4ub(255, 255, 255, 255);

	qglBegin(GL_QUADS);
	qglTexCoord2f(0, 0);
	qglVertex2f(x, y);
	qglTexCoord2f(1, 0);
	qglVertex2f(x+w, y);
	qglTexCoord2f(1, 1);
	qglVertex2f(x+w, y+h);
	qglTexCoord2f(0, 1);
	qglVertex2f(x, y+h);
	qglEnd();
}

#else // old 8-bit, 256x256 version

extern unsigned	r_rawpalette[256];

void R_DrawStretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data)
{
	unsigned	image32[256*256];
	unsigned char image8[256*256];
	int			i, j, trows;
	byte		*source;
	int			frac, fracstep;
	float		hscale;
	int			row;
	float		t;

	// Knightmare- Nicolas' fix for stray pixels at bottom and top
	memset(image32, 0, sizeof(image32));

	GL_Bind (0);

	if (rows<=256)
	{
		hscale = 1;
		trows = rows;
	}
	else
	{
		hscale = rows/256.0;
		trows = 256;
	}
	t = rows*hscale / 256;

	if ( !qglColorTableEXT )
	{
		unsigned *dest;

		for (i=0 ; i<trows ; i++)
		{
			row = (int)(i*hscale);
			if (row > rows)
				break;
			source = data + cols*row;
			dest = &image32[i*256];
			fracstep = cols*0x10000/256;
			frac = fracstep >> 1;
			for (j=0 ; j<256 ; j++)
			{
				dest[j] = r_rawpalette[source[frac>>16]];
				frac += fracstep;
			}
		}

		qglTexImage2D (GL_TEXTURE_2D, 0, gl_tex_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, image32);
	}
	else
	{
		unsigned char *dest;

		for (i=0 ; i<trows ; i++)
		{
			row = (int)(i*hscale);
			if (row > rows)
				break;
			source = data + cols*row;
			dest = &image8[i*256];
			fracstep = cols*0x10000/256;
			frac = fracstep >> 1;
			for (j=0 ; j<256 ; j++)
			{
				dest[j] = source[frac>>16];
				frac += fracstep;
			}
		}

		qglTexImage2D( GL_TEXTURE_2D, 
			           0, 
					   GL_COLOR_INDEX8_EXT, 
					   256, 256, 
					   0, 
					   GL_COLOR_INDEX, 
					   GL_UNSIGNED_BYTE, 
					   image8 );
	}
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) 
		qglDisable (GL_ALPHA_TEST);

	qglBegin (GL_QUADS);
	qglTexCoord2f (0, 0);
	qglVertex2f (x, y);
	qglTexCoord2f (1, 0);
	qglVertex2f (x+w, y);
	qglTexCoord2f (1, t);
	qglVertex2f (x+w, y+h);
	qglTexCoord2f (0, t);
	qglVertex2f (x, y+h);
	qglEnd ();

	if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) 
		qglEnable (GL_ALPHA_TEST);
}
#endif // ROQ_SUPPORT
