/*
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.

*/

// draw.c

#include "gl_local.h"

image_t		*draw_chars;

extern	qboolean	scrap_dirty;
void Scrap_Upload (void);


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



/*
===============
Draw_InitLocal
===============
*/
void Draw_InitLocal (void)
{
	// load console characters (don't bilerp characters)
	draw_chars = GL_FindImage ("pics/conchars.pcx", it_pic);
	GL_Bind( draw_chars->texnum );
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

/*
================
Draw_Char

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.
================
*/
void Draw_Char (int x, int y, int num)
{
	int				row, col;
	float			frow, fcol, size;

	num &= 255;
	
	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;

	GL_Bind (draw_chars->texnum);

	VA_SetElem2(tex_array[0],fcol, frow);
	VA_SetElem2(vert_array[0],x, y);
	VA_SetElem2(tex_array[1],fcol + size, frow);
	VA_SetElem2(vert_array[1],x+8, y);
	VA_SetElem2(tex_array[2],fcol + size, frow + size);
	VA_SetElem2(vert_array[2],x+8, y+8);
	VA_SetElem2(tex_array[3],fcol, frow + size);
	VA_SetElem2(vert_array[3],x, y+8);
	qglDrawArrays (GL_QUADS, 0, 4);

}

void Draw_String (int x, int y, char *str)
{
	int				px,py,row, col,num,va=0;
	float			frow, fcol, size;
	char			*s = str;

	if (gl_state.currenttextures[gl_state.currenttmu] != draw_chars->texnum)
		GL_Bind (draw_chars->texnum);

	px=x; py=y;
	size = 0.0625;
	while (*s) {
		num=*s;
		num &= 255;
	
		if ( (num&127) == 32 ) {		// space
			s++; px+=8;
			continue;
		}

		if (y <= -8) {	// totally off screen
			s++; px+=8;
			continue;
		}

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

		frow = row*0.0625;
		fcol = col*0.0625;

		VA_SetElem2(tex_array[va],fcol, frow);
		VA_SetElem2(vert_array[va],px, y); va++;
		VA_SetElem2(tex_array[va],fcol + size, frow);
		VA_SetElem2(vert_array[va],px+8, y); va++;
		VA_SetElem2(tex_array[va],fcol + size, frow + size);
		VA_SetElem2(vert_array[va],px+8, y+8); va++;
		VA_SetElem2(tex_array[va],fcol, frow + size);
		VA_SetElem2(vert_array[va],px, y+8); va++;
		s++; px+=8;
	}
	qglDrawArrays (GL_QUADS, 0, va);
}

/*
=============
Draw_FindPic
=============
*/
image_t	*Draw_FindPic (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);

	if (gl)
		if (gl != r_notexture)
			strcpy(gl->bare_name,name);
	return gl;
}

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

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

/*
=============
Draw_StretchPic
=============
*/

void Draw_StretchPic2 (int x, int y, int w, int h, image_t *gl)
{
	rscript_t *rs;
	float	txm,tym, alpha,s,t;
	rs_stage_t *stage;

	if (!gl)
	{
		ri.Con_Printf (PRINT_ALL, "NULL pic in Draw_StretchPic\n");
		return;
	}

	if (scrap_dirty)
		Scrap_Upload ();

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) {
		GLSTATE_DISABLE_ALPHATEST
	}

	rs=RS_FindScript(gl->bare_name);

	VA_SetElem2(vert_array[0],x, y);
	VA_SetElem2(vert_array[1],x+w, y);
	VA_SetElem2(vert_array[2],x+w, y+h);
	VA_SetElem2(vert_array[3],x, y+h);

	if (!rs) {
		GLSTATE_ENABLE_ALPHATEST
		GL_Bind (gl->texnum);
		VA_SetElem2(tex_array[0],gl->sl, gl->tl);
		VA_SetElem2(tex_array[1],gl->sh, gl->tl);
		VA_SetElem2(tex_array[2],gl->sh, gl->th);
		VA_SetElem2(tex_array[3],gl->sl, gl->th);
		qglDrawArrays (GL_QUADS, 0, 4);
	} else {
		RS_ReadyScript(rs);
		stage=rs->stage;
		while (stage) {
			if (stage->anim_count)
				GL_Bind(RS_Animate(stage));
			else
				GL_Bind (stage->texture->texnum);
			if (stage->scroll.speedX) {
				switch(stage->scroll.typeX) {
					case 0:	// static
						txm=rs_realtime*stage->scroll.speedX;
						break;
					case 1:	// sine
						txm=sin(rs_realtime*stage->scroll.speedX);
						break;
					case 2:	// cosine
						txm=cos(rs_realtime*stage->scroll.speedX);
						break;
				}
			} else
				txm=0;

			if (stage->scroll.speedY) {
				switch(stage->scroll.typeY) {
					case 0:	// static
						tym=rs_realtime*stage->scroll.speedY;
						break;
					case 1:	// sine
						tym=sin(rs_realtime*stage->scroll.speedY);
						break;
					case 2:	// cosine
						tym=cos(rs_realtime*stage->scroll.speedY);
						break;
				}
			} else
				tym=0;

			if (stage->blendfunc.blend) {
				qglBlendFunc(stage->blendfunc.source,stage->blendfunc.dest);
				GLSTATE_ENABLE_BLEND
			} else {
				GLSTATE_DISABLE_BLEND
			}

			if (stage->alphashift.min || stage->alphashift.speed) {
				if (!stage->alphashift.speed && stage->alphashift.min > 0) {
					alpha=stage->alphashift.min;
				} else if (stage->alphashift.speed) {
					alpha=sin(rs_realtime * stage->alphashift.speed);
					alpha=(alpha+1)*0.5f;
					if (alpha > stage->alphashift.max) alpha=stage->alphashift.max;
					if (alpha < stage->alphashift.min) alpha=stage->alphashift.min;
				}
			} else
				alpha=1.0f;
			qglColor4f(1,1,1,alpha);

			if (stage->envmap) {
				qglTexGenf(GL_S,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
				qglTexGenf(GL_T,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
				GLSTATE_ENABLE_TEXGEN
			}

			if (stage->alphamask) {
				GLSTATE_ENABLE_ALPHATEST
			} else {
				GLSTATE_DISABLE_ALPHATEST
			}

			s = gl->sl;
			t = gl->tl;
			RS_SetTexcoords2D (stage, &s, &t);
			VA_SetElem2(tex_array[0],s+txm, t+tym);
			s = gl->sh;
			t = gl->tl;
			RS_SetTexcoords2D (stage, &s, &t);
			VA_SetElem2(tex_array[1],s+txm, t+tym);
			s = gl->sh;
			t = gl->th;
			RS_SetTexcoords2D (stage, &s, &t);
			VA_SetElem2(tex_array[2],s+txm, t+tym);
			s = gl->sl;
			t = gl->th;
			RS_SetTexcoords2D (stage, &s, &t);
			VA_SetElem2(tex_array[3],s+txm, t+tym);

			if (qglLockArraysEXT != 0) qglLockArraysEXT(0,4);
			qglDrawArrays(GL_QUADS,0,4);
			if (qglUnlockArraysEXT != 0) qglUnlockArraysEXT();

			qglColor4f(1,1,1,1);
			qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			GLSTATE_DISABLE_TEXGEN

			stage=stage->next;
		}
		GLSTATE_ENABLE_ALPHATEST
		GLSTATE_DISABLE_BLEND
	}

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) {
		GLSTATE_ENABLE_ALPHATEST
	}
}


void Draw_StretchPic (int x, int y, int w, int h, char *pic)
{
	image_t *gl;

	gl = Draw_FindPic (pic);
	if (!gl)
	{
		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}
	Draw_StretchPic2(x,y,w,h,gl);
}

/*
=============
Draw_Pic
=============
*/

void Draw_Pic2 (int x, int y, image_t *gl)
{
	rscript_t *rs;
	float	txm,tym, alpha,s,t;
	rs_stage_t *stage;

	if (!gl)
	{
		ri.Con_Printf (PRINT_ALL, "NULL pic in Draw_Pic\n");
		return;
	}
	if (scrap_dirty)
		Scrap_Upload ();

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) {
		GLSTATE_DISABLE_ALPHATEST
	}

	rs=RS_FindScript(gl->name);

	VA_SetElem2(vert_array[0],x, y);
	VA_SetElem2(vert_array[1],x+gl->width, y);
	VA_SetElem2(vert_array[2],x+gl->width, y+gl->height);
	VA_SetElem2(vert_array[3],x, y+gl->height);

	if (!rs) {
		GLSTATE_ENABLE_ALPHATEST
		GL_Bind (gl->texnum);
		VA_SetElem2(tex_array[0],gl->sl, gl->tl);
		VA_SetElem2(tex_array[1],gl->sh, gl->tl);
		VA_SetElem2(tex_array[2],gl->sh, gl->th);
		VA_SetElem2(tex_array[3],gl->sl, gl->th);
		qglDrawArrays (GL_QUADS, 0, 4);
	} else {
		RS_ReadyScript(rs);
		stage=rs->stage;
		while (stage) {
			if (stage->anim_count)
				GL_Bind(RS_Animate(stage));
			else
				GL_Bind (stage->texture->texnum);

			if (stage->scroll.speedX) {
				switch(stage->scroll.typeX) {
					case 0:	// static
						txm=rs_realtime*stage->scroll.speedX;
						break;
					case 1:	// sine
						txm=sin(rs_realtime*stage->scroll.speedX);
						break;
					case 2:	// cosine
						txm=cos(rs_realtime*stage->scroll.speedX);
						break;
				}
			} else
				txm=0;

			if (stage->scroll.speedY) {
				switch(stage->scroll.typeY) {
					case 0:	// static
						tym=rs_realtime*stage->scroll.speedY;
						break;
					case 1:	// sine
						tym=sin(rs_realtime*stage->scroll.speedY);
						break;
					case 2:	// cosine
						tym=cos(rs_realtime*stage->scroll.speedY);
						break;
				}
			} else
				tym=0;

			if (stage->blendfunc.blend) {
				qglBlendFunc(stage->blendfunc.source,stage->blendfunc.dest);
				GLSTATE_ENABLE_BLEND
			} else {
				GLSTATE_DISABLE_BLEND
			}

			if (stage->alphamask) {
				GLSTATE_ENABLE_ALPHATEST
			} else {
				GLSTATE_DISABLE_ALPHATEST
			}

			if (stage->alphashift.min || stage->alphashift.speed) {
				if (!stage->alphashift.speed && stage->alphashift.min > 0) {
					alpha=stage->alphashift.min;
				} else if (stage->alphashift.speed) {
					alpha=sin(rs_realtime * stage->alphashift.speed);
					alpha=(alpha+1)*0.5f;
					if (alpha > stage->alphashift.max) alpha=stage->alphashift.max;
					if (alpha < stage->alphashift.min) alpha=stage->alphashift.min;
				}
			} else
				alpha=1.0f;
			qglColor4f(1,1,1,alpha);

			if (stage->envmap) {
				qglTexGenf(GL_S,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
				qglTexGenf(GL_T,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
				GLSTATE_ENABLE_TEXGEN
			}

			s = gl->sl;
			t = gl->tl;
			RS_SetTexcoords2D (stage, &s, &t);
			VA_SetElem2(tex_array[0],s+txm, t+tym);
			s = gl->sh;
			t = gl->tl;
			RS_SetTexcoords2D (stage, &s, &t);
			VA_SetElem2(tex_array[1],s+txm, t+tym);
			s = gl->sh;
			t = gl->th;
			RS_SetTexcoords2D (stage, &s, &t);
			VA_SetElem2(tex_array[2],s+txm, t+tym);
			s = gl->sl;
			t = gl->th;
			RS_SetTexcoords2D (stage, &s, &t);
			VA_SetElem2(tex_array[3],s+txm, t+tym);

			if (qglLockArraysEXT != 0) qglLockArraysEXT(0,4);
			qglDrawArrays(GL_QUADS,0,4);
			if (qglUnlockArraysEXT != 0) qglUnlockArraysEXT();

			qglColor4f(1,1,1,1);
			qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			GLSTATE_DISABLE_TEXGEN

			stage=stage->next;
		}
		GLSTATE_DISABLE_BLEND
		GLSTATE_ENABLE_ALPHATEST
	}

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !gl->has_alpha) {
		GLSTATE_ENABLE_ALPHATEST
	}
}

void Draw_Pic (int x, int y, char *pic)
{
	image_t *gl;

	gl = Draw_FindPic (pic);
	if (!gl)
	{
		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}
	Draw_Pic2(x,y,gl);
}

/*
=============
Draw_TileClear

This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
void Draw_TileClear2 (int x, int y, int w, int h, image_t *image)
{
	if (!image)
	{
		ri.Con_Printf (PRINT_ALL, "NULL pic in Draw_TileClear\n");
		return;
	}

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !image->has_alpha) {
		GLSTATE_DISABLE_ALPHATEST
	}

	GL_Bind (image->texnum);
	VA_SetElem2(tex_array[0],x*0.015625, y*0.015625);
	VA_SetElem2(vert_array[0],x, y);
	VA_SetElem2(tex_array[1],(x+w)*0.015625, y*0.015625);
	VA_SetElem2(vert_array[1],x+w, y);
	VA_SetElem2(tex_array[2],(x+w)*0.015625, (y+h)*0.015625);
	VA_SetElem2(vert_array[2],x+w, y+h);
	VA_SetElem2(tex_array[3],x*0.015625, (y+h)*0.015625);
	VA_SetElem2(vert_array[3],x, y+h);

	qglDrawArrays(GL_QUADS,0,4);

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !image->has_alpha) {
		GLSTATE_ENABLE_ALPHATEST
	}
}

void Draw_TileClear (int x, int y, int w, int h, char *pic)
{
	image_t	*image;

	image = Draw_FindPic (pic);
	if (!image)
	{
		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}
	Draw_TileClear2(x,y,w,h,image);
}


/*
=============
Draw_Fill

Fills a box of pixels with a single color
=============
*/
void Draw_Fill (int x, int y, int w, int h, int c)
{
	if ( (unsigned)c > 255)
		ri.Sys_Error (ERR_FATAL, "Draw_Fill: bad color");

	qglDisable (GL_TEXTURE_2D);
	qglColor3f(d_8to24tablef[c][0],d_8to24tablef[c][1],d_8to24tablef[c][2]);

	VA_SetElem2(vert_array[0],x,y);
	VA_SetElem2(vert_array[1],x+w, y);
	VA_SetElem2(vert_array[2],x+w, y+h);
	VA_SetElem2(vert_array[3],x, y+h);
	qglDrawArrays (GL_QUADS, 0, 4);

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

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

/*
================
Draw_FadeScreen

================
*/
void Draw_FadeScreen (void)
{
	GLSTATE_DISABLE_ALPHATEST
	GLSTATE_ENABLE_BLEND
	qglDisable (GL_TEXTURE_2D);
	qglColor4f (0, 0, 0, 0.5);

	VA_SetElem2(vert_array[0],0,0);
	VA_SetElem2(vert_array[1],vid.width, 0);
	VA_SetElem2(vert_array[2],vid.width, vid.height);
	VA_SetElem2(vert_array[3],0, vid.height);
	qglDrawArrays (GL_QUADS, 0, 4);

	qglColor4f (1,1,1,1);
	qglEnable (GL_TEXTURE_2D);
	GLSTATE_DISABLE_BLEND
	GLSTATE_ENABLE_ALPHATEST
}


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


/*
=============
Draw_StretchRaw
=============
*/
extern unsigned	r_rawpalette[256];

void Draw_StretchRaw (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;

	GL_Bind (0);

	if (rows<=256)
	{
		hscale = 1;
		trows = rows;
	}
	else
	{
		hscale = rows * 0.00390625; // /256.0;
		trows = 256;
	}
	t = rows*hscale * 0.00390625;// / 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 *0.00390625; // /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 *0.00390625; // /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 ) ) {
		GLSTATE_DISABLE_ALPHATEST
	}

	VA_SetElem2(tex_array[0],0, 0);
	VA_SetElem2(vert_array[0],x, y);
	VA_SetElem2(tex_array[1],1, 0);
	VA_SetElem2(vert_array[1],x+w, y);
	VA_SetElem2(tex_array[2],1, t);
	VA_SetElem2(vert_array[2],x+w, y+h);
	VA_SetElem2(tex_array[3],0, t);
	VA_SetElem2(vert_array[3],x, y+h);
	qglDrawArrays (GL_QUADS, 0, 4);

	if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  {
		GLSTATE_ENABLE_ALPHATEST
	}
}
