//-----------------------------------------------------------------------------
//
//  $Logfile:: /Source/gl_draw.c                                              $
// $Revision:: 3                                                              $
//   $Author:: Burgermac                                                      $
//     $Date:: 2/5/02 7:49 PM                                                 $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// DESCRIPTION:
//

#include "gl_local.h"

image_t *Draw_Chars;

#define CHAREPSILON (1.0f/512.0f)

#define MAX_PICIMAGES 64
#define MAX_PICIMAGE_LENGTH ( 64 - ( sizeof( image_t * ) ) )

typedef struct {
	char name[ MAX_PICIMAGE_LENGTH ];
	image_t *image;
} picimage_t;

static picimage_t picimages[ MAX_PICIMAGES ];
static int numpicimages = 0;
static int picimagesptr = 0;

/*
===============
GL_Draw_InitLocal
===============
*/
void GL_Draw_InitLocal (void)
{
	// load console characters (don't bilerp characters)
	numpicimages = 0;
	picimagesptr = 0;

	Draw_Chars = GL_FindImage (r_conchars->string, it_pic);
	if (!Draw_Chars) {
		ri.Sys_Error (ERR_FATAL,"GL_Draw_InitLocal: Could not load %s",r_conchars->string);
	}
	GL_BindImage( Draw_Chars );
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}


/*
=============
DoDraw_Fill3D
Fills a box of pixels with a single color
=============
*/
static void DoDraw_Fill3D (vec3_t org, float width, float height, vec3_t u, vec3_t v, float r, float g, float b, float a)
{
	vec3_t origin,svup,svright,point;

	qglDisable ( GL_TEXTURE_2D );

	if (a < 1.0f)
	{
		qglDisable( GL_ALPHA_TEST );
		qglBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
		qglEnable( GL_BLEND );
	}

	qglColor4f ( r,g,b,a );

	origin[0] = org[0];
	origin[1] = org[1];
	origin[2] = org[2];

	VectorCopy( v,svup );
	VectorCopy( u,svright );
	qglBegin ( GL_QUADS );

	// lower left
	VectorCopy ( origin,point );
	qglVertex3fv ( point );

	// upper left
	VectorMA ( origin, height, svup, point );
	qglVertex3fv ( point );

	// upper right
	VectorMA ( origin, height, svup, point );
	VectorMA ( point, width, svright, point );
	qglVertex3fv ( point );

	// lower right
	VectorMA ( origin, width, svright, point );
	qglVertex3fv ( point );

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

	if (a < 1.0f)
	{
		qglEnable( GL_ALPHA_TEST );
		qglDisable( GL_BLEND );
	}
}

void Draw_Fill3D (float x1, float y1, float width, float height, float r, float g, float b, float a)
{
	vec3_t origin;
	vec3_t org1;
	float mat[3][3];
	
	origin[0] = x1 * consoleInfo.surface_width;
	origin[1] = y1 * consoleInfo.surface_height;
	origin[2] = 0;
	
	mat[0][0] = consoleInfo.u[0]; mat[0][1] = consoleInfo.u[1]; mat[0][2] = consoleInfo.u[2];
	mat[1][0] = consoleInfo.v[0]; mat[1][1] = consoleInfo.v[1]; mat[1][2] = consoleInfo.v[2];
	mat[2][0] = consoleInfo.n[0]; mat[2][1] = consoleInfo.n[1]; mat[2][2] = consoleInfo.n[2];
	
	MatrixTransformVector(origin,mat,org1);
	
	DoDraw_Fill3D(org1,
		width * consoleInfo.surface_width,
		height * consoleInfo.surface_height,
		consoleInfo.u,consoleInfo.v,
		r,g,b,a*consoleInfo.alpha);
}

static void DoDraw_AltFill3D (vec3_t org, float width, float height, vec3_t u, vec3_t v, float r, float g, float b, float a)
{
	vec3_t origin,svup,svright,point;

	qglDisable ( GL_TEXTURE_2D );

	if (a < 1.0f)
	{
		qglDisable( GL_ALPHA_TEST );
		qglBlendFunc ( GL_DST_COLOR, GL_ZERO );
		qglEnable( GL_BLEND );
	}

	qglColor4f ( r,g,b,a );

	origin[0] = org[0];
	origin[1] = org[1];
	origin[2] = org[2];

	VectorCopy( v,svup );
	VectorCopy( u,svright );
	qglBegin ( GL_QUADS );

	// lower left
	VectorCopy( origin,point );
	qglVertex3fv ( point );

	// upper left
	VectorMA ( origin, height, svup, point );
	qglVertex3fv ( point );

	// upper right
	VectorMA ( origin, height, svup, point );
	VectorMA ( point, width, svright, point );
	qglVertex3fv ( point );

	// lower right
	VectorMA ( origin, width, svright, point );
	qglVertex3fv ( point );

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

	if (a < 1.0f)
	{
		qglEnable( GL_ALPHA_TEST );
		qglDisable( GL_BLEND );
	}
}

void Draw_AltFill3D (float x1, float y1, float width, float height, float r, float g, float b, float a)
{
	vec3_t origin;
	vec3_t org1;
	float mat[3][3];

	origin[0] = x1 * consoleInfo.surface_width;
	origin[1] = y1 * consoleInfo.surface_height;
	origin[2] = 0;

	mat[0][0] = consoleInfo.u[0]; mat[0][1] = consoleInfo.u[1]; mat[0][2] = consoleInfo.u[2];
	mat[1][0] = consoleInfo.v[0]; mat[1][1] = consoleInfo.v[1]; mat[1][2] = consoleInfo.v[2];
	mat[2][0] = consoleInfo.n[0]; mat[2][1] = consoleInfo.n[1]; mat[2][2] = consoleInfo.n[2];

	MatrixTransformVector( origin,mat,org1 );

	DoDraw_AltFill3D( org1,
						width * consoleInfo.surface_width,
						height * consoleInfo.surface_height,
						consoleInfo.u,consoleInfo.v,
						r,g,b,a*consoleInfo.alpha );
}

static qboolean bInString;

void Flush_Char3D (float r, float g, float b, float a)
{
	if (!bInString || (rb_vertex == 0) || (rb_index == 0))
	{
		return;
	}

	qglColor4f( r,g,b,a );

	GL_TexEnv( GL_MODULATE );

	if (a < 1.0f) {
		qglDisable( GL_ALPHA_TEST );
		qglBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
		qglEnable( GL_BLEND );
	}

	GL_BindImage( Draw_Chars );

	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

	R_RenderMeshGeneric (false);

	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

	if (a < 1.0f) {
		qglEnable( GL_ALPHA_TEST );
		qglDisable( GL_BLEND );
	}

	qglColor4f( 1,1,1,1 );
	GL_TexEnv( GL_REPLACE );

	rb_vertex = rb_index = 0;
	bInString = false;
}

static void DoDraw_Char3D(vec3_t coord,vec3_t u, vec3_t v,int num,float font_width, float font_height,float r, float g, float b, float a)
{
	/* FS: Now using vertex arrays instead of constantly changing the state for every char drawn! */
	int row, col;
	float frow, fcol, size;
	vec3_t svup, svright;
	vec3_t origin,point;

	num &= 255;

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

	origin[0] = coord[0];
	origin[1] = coord[1];
	origin[2] = coord[2];

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

	frow = (float)row*0.0625f;
	fcol = (float)col*0.0625f;
	size = 0.0625f;

	VectorCopy( v,svup );
	VectorCopy( u,svright );

	if(!bInString)
		rb_vertex = rb_index = 0;

	if (R_CheckArrayOverflow(4, 6))
		Flush_Char3D(r,g,b,a);

	indexArray[rb_index++] = rb_vertex+0;
	indexArray[rb_index++] = rb_vertex+1;
	indexArray[rb_index++] = rb_vertex+2;
	indexArray[rb_index++] = rb_vertex+0;
	indexArray[rb_index++] = rb_vertex+2;
	indexArray[rb_index++] = rb_vertex+3;

	VA_SetElem2(texCoordArray[0][rb_vertex], fcol+CHAREPSILON, frow + size-CHAREPSILON);
	VA_SetElem3v(vertexArray[rb_vertex], origin);
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);
	rb_vertex++;

	VA_SetElem2(texCoordArray[0][rb_vertex], fcol+CHAREPSILON, frow+CHAREPSILON);
	VectorMA ( origin, font_height, svup, point );
	VA_SetElem3v(vertexArray[rb_vertex], point);
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);
	rb_vertex++;

	VA_SetElem2(texCoordArray[0][rb_vertex], fcol + size-CHAREPSILON, frow+CHAREPSILON);
	VectorMA ( origin, font_height, svup, point );
	VectorMA ( point, font_width, svright, point );
	VA_SetElem3v(vertexArray[rb_vertex], point);
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);
	rb_vertex++;

	VA_SetElem2(texCoordArray[0][rb_vertex], fcol + size-CHAREPSILON, frow + size-CHAREPSILON);
	VectorMA ( origin, font_width, svright, point );
	VA_SetElem3v(vertexArray[rb_vertex], point);
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);
	rb_vertex++;

	bInString = true;
}

void Draw_Char3D (float x, float y, int c, int rows, int cols, float r, float g, float b, float a)
{
	vec3_t origin,org1;
	float mat[3][3];
	float font_width  = consoleInfo.surface_width / (float)cols;
	float font_height = consoleInfo.surface_height / (float)rows;

	origin[0] = x * consoleInfo.surface_width;
	origin[1] = y * consoleInfo.surface_height;
	origin[2] = 0;

	mat[0][0] = consoleInfo.u[0]; mat[0][1] = consoleInfo.u[1]; mat[0][2] = consoleInfo.u[2];
	mat[1][0] = consoleInfo.v[0]; mat[1][1] = consoleInfo.v[1]; mat[1][2] = consoleInfo.v[2];
	mat[2][0] = consoleInfo.n[0]; mat[2][1] = consoleInfo.n[1]; mat[2][2] = consoleInfo.n[2];

	MatrixTransformVector( origin,mat,org1 );
	DoDraw_Char3D ( org1,consoleInfo.u,consoleInfo.v,c,font_width,font_height,r,g,b,a*consoleInfo.alpha );
}

static void DoDraw_TilePic3D (vec3_t coord, vec3_t u, vec3_t v, int width, int height, const char *pic, float r, float g, float b, float a)
{
	vec3_t svup, svright;	// in worldspace
	vec3_t origin,point;
	image_t *gl;

	origin[0] = coord[0];
	origin[1] = coord[1];
	origin[2] = coord[2];

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

	if (scrap_dirty)
		Scrap_Upload ();

	qglColor4f( r,g,b,a );

	GL_BindImage( gl );

	if (a < 1.0f)
	{
		qglDisable ( GL_ALPHA_TEST );
		qglBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
		qglEnable( GL_BLEND );
	}

	VectorCopy( v,svup );
	VectorCopy( u,svright );

	qglBegin ( GL_QUADS );

	// lower left
	VectorCopy ( origin, point );
	qglTexCoord2f ( point[0]/gl->width, -point[1]/gl->height );
	qglVertex3fv ( point );

	// upper left
	VectorMA ( origin, height, svup, point );
	qglTexCoord2f ( point[0]/gl->width, -point[1]/gl->height );
	qglVertex3fv ( point );

	// upper right
	VectorMA ( origin, height, svup, point );
	VectorMA ( point, width, svright, point );
	qglTexCoord2f ( point[0]/gl->width, -point[1]/gl->height );
	qglVertex3fv ( point );

	// lower right
	VectorMA ( origin, width, svright, point );
	qglTexCoord2f ( point[0]/gl->width, -point[1]/gl->height );
	qglVertex3fv ( point );

	qglEnd ();

	if (a < 1.0f)
	{
		qglDisable( GL_BLEND );
		qglEnable( GL_ALPHA_TEST );
	}
}

void Draw_TilePic3D (float x, float y, float width, float height, const char *picn, float r, float g, float b, float a)
{
	vec3_t origin,org1;
	float mat[3][3];

	origin[0] = x * consoleInfo.surface_width;
	origin[1] = y * consoleInfo.surface_height;
	origin[2] = 0;

	mat[0][0] = consoleInfo.u[0]; mat[0][1] = consoleInfo.u[1]; mat[0][2] = consoleInfo.u[2];
	mat[1][0] = consoleInfo.v[0]; mat[1][1] = consoleInfo.v[1]; mat[1][2] = consoleInfo.v[2];
	mat[2][0] = consoleInfo.n[0]; mat[2][1] = consoleInfo.n[1]; mat[2][2] = consoleInfo.n[2];

	MatrixTransformVector( origin,mat,org1 );

	DoDraw_TilePic3D( org1,
	                  consoleInfo.u,
	                  consoleInfo.v,
	                  (int)(width * consoleInfo.surface_width),
	                  (int)(height * consoleInfo.surface_height),
	                  picn,
	                  r,g,b,a*consoleInfo.alpha );
}

static void DoDraw_Pic3D (vec3_t coord, vec3_t u, vec3_t v, const char *pic, float scalex, float scaley, float r, float g, float b, float a)
{
	vec3_t svup, svright;	// in worldspace
	vec3_t origin,point;
	float width,height;
	image_t *gl;
	float xepsilon;
	float yepsilon;

	origin[0] = coord[0];
	origin[1] = coord[1];
	origin[2] = coord[2];
	gl = Draw_FindPic ( pic );
	if (!gl) {
		ri.Con_Printf ( PRINT_DEVELOPER, "Can't find pic: %s\n", pic );
		return;
	}

	if (scrap_dirty) {
		Scrap_Upload ();
	}
	qglColor4f( r,g,b,a );

	GL_BindImage( gl );

	if (a < 1.0f) {
		qglDisable( GL_ALPHA_TEST );
		qglBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
		qglEnable( GL_BLEND );
	}

	width  = (float)gl->width;
	height = (float)gl->height;
	xepsilon = 0.5f/width;
	yepsilon = 0.5f/height;
	width  = width*scalex;
	height = height*scaley;

	VectorCopy( v,svup );
	VectorCopy( u,svright );

	qglBegin ( GL_QUADS );

	// lower left
	qglTexCoord2f ( gl->sl+xepsilon, gl->th-yepsilon );
	VectorCopy ( origin,point );
	qglVertex3fv ( point );

	// upper left
	qglTexCoord2f ( gl->sl+xepsilon, gl->tl+yepsilon );
	VectorMA ( origin, height, svup, point );
	qglVertex3fv ( point );

	// upper right
	qglTexCoord2f ( gl->sh-xepsilon, gl->tl+yepsilon );
	VectorMA ( origin, height, svup, point );
	VectorMA ( point, width, svright, point );
	qglVertex3fv ( point );

	// lower right
	qglTexCoord2f ( gl->sh-xepsilon, gl->th-yepsilon );
	VectorMA ( origin, width, svright, point );
	qglVertex3fv ( point );
	qglEnd ();

	if (a < 1.0f) {
		qglDisable( GL_BLEND );
		qglEnable( GL_ALPHA_TEST );
	}

	qglColor4f( 1,1,1,1 );
}

void Draw_Pic3D (float x, float y, const char *picn, float scalex, float scaley, float r, float g, float b, float a)
{
	vec3_t origin,org1;
	float mat[3][3];

	origin[0] = x * consoleInfo.surface_width;
	origin[1] = y * consoleInfo.surface_height;
	origin[2] = 0;

	mat[0][0] = consoleInfo.u[0];
	mat[0][1] = consoleInfo.u[1];
	mat[0][2] = consoleInfo.u[2];
	mat[1][0] = consoleInfo.v[0];
	mat[1][1] = consoleInfo.v[1];
	mat[1][2] = consoleInfo.v[2];
	mat[2][0] = consoleInfo.n[0];
	mat[2][1] = consoleInfo.n[1];
	mat[2][2] = consoleInfo.n[2];
	MatrixTransformVector( origin,mat,org1 );
	DoDraw_Pic3D( org1,
					consoleInfo.u,
					consoleInfo.v,
					picn,
					consoleInfo.surface_width*scalex,
					consoleInfo.surface_height*scaley,
					r,g,b,a*consoleInfo.alpha );
}

static void DoDraw_StretchPic3D (vec3_t coord, vec3_t u, vec3_t v, int width, int height, const char *pic, float r, float g, float b, float a)
{
	vec3_t svup, svright;	// in worldspace
	vec3_t origin,point;
	image_t *gl;

	origin[0] = coord[0];
	origin[1] = coord[1];
	origin[2] = coord[2];

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

	if (scrap_dirty)
		Scrap_Upload ();

	qglColor4f( r,g,b,a );

	GL_BindImage( gl );

	if (a < 1.0f)
	{
		qglDisable ( GL_ALPHA_TEST );
		qglBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
		qglEnable( GL_BLEND );
	}

	VectorCopy( v,svup );
	VectorCopy( u,svright );

	qglBegin ( GL_QUADS );

	// lower left
	qglTexCoord2f ( gl->sl, gl->th );
	VectorCopy ( origin, point );
	qglVertex3fv ( point );

	// upper left
	qglTexCoord2f ( gl->sl, gl->tl );
	VectorMA ( origin, height, svup, point );
	qglVertex3fv ( point );

	// upper right
	qglTexCoord2f ( gl->sh, gl->tl );
	VectorMA ( origin, height, svup, point );
	VectorMA ( point, width, svright, point );
	qglVertex3fv ( point );

	// lower right
	qglTexCoord2f ( gl->sh, gl->th );
	VectorMA ( origin, width, svright, point );
	qglVertex3fv ( point );

	qglEnd ();

	if (a < 1.0f)
	{
		qglDisable( GL_BLEND );
		qglEnable( GL_ALPHA_TEST );
	}
}

void Draw_StretchPic3D (float x, float y, float width, float height, const char *picn, float r, float g, float b, float a)
{
	vec3_t origin,org1;
	float mat[3][3];

	origin[0] = x * consoleInfo.surface_width;
	origin[1] = y * consoleInfo.surface_height;
	origin[2] = 0;

	mat[0][0] = consoleInfo.u[0]; mat[0][1] = consoleInfo.u[1]; mat[0][2] = consoleInfo.u[2];
	mat[1][0] = consoleInfo.v[0]; mat[1][1] = consoleInfo.v[1]; mat[1][2] = consoleInfo.v[2];
	mat[2][0] = consoleInfo.n[0]; mat[2][1] = consoleInfo.n[1]; mat[2][2] = consoleInfo.n[2];

	MatrixTransformVector( origin,mat,org1 );

	DoDraw_StretchPic3D( org1,
	                     consoleInfo.u,
	                     consoleInfo.v,
	                     (int)(width * consoleInfo.surface_width),
	                     (int)(height * consoleInfo.surface_height),
	                     picn,
	                     r,g,b,a*consoleInfo.alpha );
}

/*
================
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 = (float)row*0.0625f;
	fcol = (float)col*0.0625f;
	
	size = 0.0625f;
	
	GL_BindImage( Draw_Chars );
	
	y = vid.height - y;
	
	qglBegin (GL_QUADS);
	qglTexCoord2f (fcol+CHAREPSILON, frow+CHAREPSILON);
	qglVertex2f (x, y);
	qglTexCoord2f (fcol+CHAREPSILON, frow+size-CHAREPSILON);
	qglVertex2f (x, y-8);
	qglTexCoord2f (fcol+size-CHAREPSILON, frow+size-CHAREPSILON);
	qglVertex2f (x+8, y-8);
	qglTexCoord2f (fcol+size-CHAREPSILON, frow+CHAREPSILON);
	qglVertex2f (x+8, y);
	qglEnd ();
}

/*
==============
PicImage
==============
*/
static void AddPicImage( const char * name, image_t * image )
{
	if ( strlen( name ) > MAX_PICIMAGE_LENGTH )
	{
		ri.Con_Printf (PRINT_DEVELOPER, "AddPicImage: image name too long %s\n", name ) ;
		return;
	}

	strcpy( picimages[ picimagesptr ].name, name );
	picimages[ picimagesptr ].image = image;
	picimagesptr++;
	if ( picimagesptr >= MAX_PICIMAGES )
		picimagesptr = 0;
	if ( numpicimages < MAX_PICIMAGES )
		numpicimages++;
}

static image_t * FindPicImage( const char * name )
{
	int i;

	for( i = 0; i < numpicimages; i++ )
	{
		if ( !Q_stricmp( name, picimages[ i ].name ) )
		{
			return picimages[ i ].image;
		}
	}
	return NULL;
}

static image_t *PicImage ( const char * name )
{
	image_t *image;

	image = FindPicImage( name );
	if ( image )
	{
		return image;
	}

	image = GL_FindImage( name, it_pic );
	AddPicImage( name, image );

	return image;
}

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

	if (name[0] != '/' && name[0] != '\\')
	{
		Com_sprintf (fullname, sizeof(fullname), "pics/%s", name);
		COM_DefaultExtension( fullname, ".tga" );
		gl = PicImage (fullname);
	}
	else
		gl = PicImage (name+1);

	if (gl)
	{
		if (!gl->bilinear)
		{
			GL_BindImage(gl);
			qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			gl->bilinear = true;
		}
	}

	return gl;
}

/*
=============
Draw_GetPicSize
=============
*/
void Draw_GetPicSize (int *w, int *h, const 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_StretchPic (int x, int y, int w, int h, const char *pic)
{
	image_t *gl;
	float xepsilon;
	float yepsilon;
	
	gl = Draw_FindPic (pic);
	if (!gl) {
		ri.Con_Printf (PRINT_DEVELOPER, "Can't find pic: %s\n", pic);
		return;
	}
	
	if (scrap_dirty) {
		Scrap_Upload ();
	}
#ifndef macintosh
	if (gl_config.renderer & (GL_RENDERER_MCD|GL_RENDERER_RENDITION) && !gl->has_alpha)
		qglDisable (GL_ALPHA_TEST);
#endif

	xepsilon = 0.5f/gl->width;
	yepsilon = 0.5f/gl->height;
	GL_BindImage( gl );

	y = vid.height - y;
	qglBegin (GL_QUADS);
	// lower left
	qglTexCoord2f (gl->sl+xepsilon, gl->tl+yepsilon);
	qglVertex2f (x, y);
	
	// upper left
	qglTexCoord2f (gl->sl+xepsilon, gl->th-yepsilon);
	qglVertex2f (x, y-h);
	
	// upper right
	qglTexCoord2f (gl->sh-xepsilon, gl->th-yepsilon);
	qglVertex2f (x+w, y-h);
	
	// lower right
	qglTexCoord2f (gl->sh-xepsilon, gl->tl+yepsilon);
	qglVertex2f (x+w, y);
	qglEnd ();

#ifndef macintosh
	if (gl_config.renderer & (GL_RENDERER_MCD|GL_RENDERER_RENDITION) && !gl->has_alpha)
		qglEnable (GL_ALPHA_TEST);
#endif
}


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

	gl = Draw_FindPic (pic);
	if (!gl) {
		ri.Con_Printf (PRINT_DEVELOPER, "Can't find pic: %s\n", pic);
		return;
	}
	if (scrap_dirty)
		Scrap_Upload ();

#ifndef macintosh
	if (gl_config.renderer & (GL_RENDERER_MCD|GL_RENDERER_RENDITION) && !gl->has_alpha)
		qglDisable (GL_ALPHA_TEST);
#endif
	
	GL_BindImage( gl );
	
	y = vid.height - y;
	qglBegin (GL_QUADS);
	qglTexCoord2f (gl->sl, gl->tl);
	qglVertex2f (x, y);
	qglTexCoord2f (gl->sl, gl->th);
	qglVertex2f (x, y-gl->height);
	qglTexCoord2f (gl->sh, gl->th);
	qglVertex2f (x+gl->width, y-gl->height);
	qglTexCoord2f (gl->sh, gl->tl);
	qglVertex2f (x+gl->width, y);
	qglEnd ();

#ifndef macintosh
	if (gl_config.renderer & (GL_RENDERER_MCD|GL_RENDERER_RENDITION) && !gl->has_alpha)
		qglEnable (GL_ALPHA_TEST);
#endif
}

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

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

	image = Draw_FindPic (pic);
	if (!image)
	{
		ri.Con_Printf (PRINT_DEVELOPER, "Can't find pic: %s\n", pic);
		return;
	}

#ifndef macintosh
	if (gl_config.renderer & (GL_RENDERER_MCD|GL_RENDERER_RENDITION) && !image->has_alpha)
		qglDisable (GL_ALPHA_TEST);
#endif

	GL_BindImage( image );

	y = vid.height - y;

	qglBegin (GL_QUADS);
	qglTexCoord2f (x/64.0f, y/64.0f);
	qglVertex2f (x, y);
	qglTexCoord2f ( (x+w)/64.0f, y/64.0f);
	qglVertex2f (x+w, y);
	qglTexCoord2f ( (x+w)/64.0f, (y+h)/64.0f);
	qglVertex2f (x+w, y-h);
	qglTexCoord2f ( x/64.0f, (y+h)/64.0f );
	qglVertex2f (x, y-h);
	qglEnd ();

#ifndef macintosh
	if (gl_config.renderer & (GL_RENDERER_MCD|GL_RENDERER_RENDITION) && !image->has_alpha)
		qglEnable (GL_ALPHA_TEST);
#endif
}


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

Fills a box of pixels with a single color
=============
*/
void Draw_Fill (int x, int y, int w, int h, float r, float g, float b)
{
	qglDisable (GL_TEXTURE_2D);

	qglColor3f ( r, g, b );

	y = vid.height - y;
	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);
}

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

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

================
*/
void Draw_FadeScreen (float r, float g, float b, float a)
{
	qglEnable (GL_BLEND);
	qglDisable (GL_TEXTURE_2D);
	if (a < 1.0f) {
		qglDisable(GL_ALPHA_TEST);
		qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	}
	qglColor4f (r, g, b, a);

	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);

	if (a < 1.0f)
	{
		qglEnable(GL_ALPHA_TEST);
	}
}


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

/* Since the mac cannot have 256K local storage, I have to allocate */
/* a temp buffer and dispose of it when the cinematic is done */

#ifdef macintosh
#include <MacMemory.h>
static unsigned *image32;		/* Pointer to the memory */
#endif

void Draw_BeginCinematic( void )
{
	qglClearColor( 0, 0, 0, 1 );
	qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	GLimp_EndFrame();
	qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	GLimp_EndFrame();
	qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	GLimp_EndFrame();
}

void Draw_EndCinematic( void )
{
#ifdef macintosh
	if (image32) {				/* Was a buffer allocated? */
		DisposePtr((char *)image32);	/* Call MACOS to get rid of it */
		image32 = 0;
	}
#endif
}

void Draw_CinematicFrame(int x, int y, int width, int height, int cols, int rows, int pitch, unsigned short * data )
{
	int i, j, trows;
	int	frac, fracstep;
	float hscale, t;
	int row;
	qboolean drawpixels = false;
	unsigned *dest;
	unsigned short * src;
	unsigned short pixel;
	int r,g,b;
	
#ifdef macintosh
	if (!image32) {
		image32 = (unsigned *)NewPtr(sizeof(unsigned)*256*256);		/* Get the buffer */
		if (!image32) {				/* Memory failure? */
			return;
		}
	}
#else
	unsigned image32[256*256];		/* Use on the stack for other machines */
#endif

	if ( drawpixels ) {
		qglPixelZoom( vid.width / cols, vid.height / rows );
		qglDrawPixels( cols, rows, GL_RGB, GL_UNSIGNED_SHORT, data );
		qglPixelZoom( 1, 1 );
		return;
	}
	
	if (rows<=256) {
		hscale = 1;
		trows = rows;
	} else {
		hscale = rows/256.0f;
		trows = 256;
	}
	t = rows*hscale / 256;

	//
	// source data is in unsigned short format
	//
	fracstep = (cols*0x10000) / 256;
	for (i=0 ; i<trows ; i++) {
		row = (int)(i*hscale);
		if (row > rows)
			break;
		src = ( unsigned short * )data + ((pitch*row)>>1);
		dest = &image32[i<<8];
		frac = fracstep >> 1;
		for (j=0 ; j<256 ; j++) {
			pixel = src[frac>>16];
			// r = ( pixel >> 11 ) << 3;
			// g = (( pixel >> 5 ) & 63 ) << 10;
			// b = ( pixel & 0x1f ) << 19;
			r = ( pixel & 0x7C00 ) << 17;
			g = ( pixel & 0x03E0 ) << 14;
			b = ( pixel & 0x1F ) << 11;
			dest[j] = (unsigned int)( r + g + b );
			frac += fracstep;
		}
	}
	GL_Bind (0);

	qglTexImage2D (GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, image32);

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

#ifndef macintosh
	if (gl_config.renderer & (GL_RENDERER_MCD|GL_RENDERER_RENDITION))
		qglDisable (GL_ALPHA_TEST);
#endif

	qglBegin (GL_QUADS);
	qglTexCoord2f (0, t);
	qglVertex2f (x, y);
	qglTexCoord2f (1, t);
	qglVertex2f (x+width, y);
	qglTexCoord2f (1, 0);
	qglVertex2f (x+width, y+height);
	qglTexCoord2f (0, 0);
	qglVertex2f (x, y+height);
	qglEnd ();

#ifndef macintosh
	if (gl_config.renderer & (GL_RENDERER_MCD|GL_RENDERER_RENDITION))
		qglEnable (GL_ALPHA_TEST);
#endif
	// GLimp_EndFrame();
}
