/*
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_font.c this is where our font engine is located
//

/*
NOTE:
fonts are simple bitmaps, with characters drawn on them. To add/create a font,
make a font image (as seen on the sample font), also make sure not to use any
colors. Also add the alpha channel as shown. 

To add your font to the quake engine, find id1/scripts/fonts.txt. What you will find 
there is something like
1
{
	file gfx/fonts/font_default
}
2
{
	file gfx/fonts/font_ingame
}

to add your font, make a structure like the above and add the path to your font file
(without extension!). Save the file.

Now you can use colored msg'es and different fonts, to do this, start with
"&frgbx". This looks kind of cryptic, but it's actually very simple, &f is so
that the font engine will identify our wish, rgb are the r(ed), g(reen), b(lue)
values and x is the font number you specified in the fonts.txt file.

For example, a red message with your own font will be: "&f9003".
To reset the colors back to normal, use "&r".

note that 0 is the default quake font, but can be overwritten by using 0 as the font name
*/

#include "quakedef.h"

float		scr_centertime_start;	// for slow victory printing
float		scr_centertime_off;

int			char_texture;
int			font_texture[9]; // allow up to 10 font textures
int			scr_center_lines;
int			scr_erase_lines;
int			scr_erase_center;
int			font_initialised = true;

cvar_t		scr_centertime	= {"scr_centertime",	"2"};
cvar_t		scr_printspeed	= {"scr_printspeed",	"8"};

qboolean	scr_drawdialog;

char		scr_centerstring[1024];
char		*scr_notifystring;


typedef struct 
{
	int		spacing;
	int		scale;
	int		num;
} font_t;


font_t	fonts[10];


/*
================
Font_Init

This is the main font function, where all fonts/chars are loaded...
================
*/
void Font_Init(void)
{
	byte		*draw_chars;// 8*8 graphic characters
	FILE		*f;
	char		*ch, *file;
	int			i, texture_num, instructure;
	char		*tmp;
	int			spacing = 8, scale = 8; 

	ch			= malloc(1024);
	tmp			= malloc(1024); // 2?
	file		= malloc(1024);
	
	Cvar_RegisterVariable (&scr_centertime);
	Cvar_RegisterVariable (&scr_printspeed);

	//
	// load default font
	//
	draw_chars = W_GetLumpName ("conchars");
	for (i=0 ; i<256*64 ; i++)
		if (draw_chars[i] == 0)
			draw_chars[i] = 255;

	font_texture[0] = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true, 1); // default conchars as font 0	

	//
	// check to see if the default font is loaded (we cannot live without default font)
	//
	if (!font_texture[0])
	{
		// crash if the default font isn't found
		Sys_Error("could not load default quake font");
	}

	return;

	//
	// open font script
	//
	COM_FOpenFile("scripts/fonts.txt",&f);

	if (!f || feof(f)) 
	{
		Con_Printf(" &f9000 *Failed to load Font script &r\n");
		font_initialised = false; // disable font engine, and revert all fonts back to the default font
	}

	instructure = 0;

	// 
	// read values from font script
	//
	if (font_initialised) // check if file exists
	{
		Con_Printf(" *Loaded Font script\n"); // print a msg to the console	
		while (!feof(f)) // loop trough this until we find an eof (end of file)
		{
			fscanf(f,"%s",ch);
			if (instructure) // decide if where are in the script
			{	
				if (!_stricmp(ch,"file"))
				{
					fscanf(f,"%s",file);				
					font_texture[texture_num] = loadtextureimage (file, false, true);
				}
				else if (!_stricmp(ch,"scale"))
				{
					fscanf(f, "%i", &scale);
					fonts[texture_num].scale = scale;
				}
				else if (!_stricmp(ch,"spacing"))
				{
					fscanf(f, "%i", &spacing);
					fonts[texture_num].spacing = spacing;
				//	Con_Printf("Filename: %s at number: %i\n height is: %f, width is %f, num is %i\n", file, texture_num, fonts[texture_num].height, fonts[texture_num].width, num);
				}
				else if (!_stricmp(ch,"}"))
				{
					instructure = 0;
				}
			}	
			else 
			{
				if (_stricmp(ch,"{"))
				{
					strcpy(tmp,ch);
					texture_num = (int)(*tmp - '0'); // nasty conversion
				}
				else
				{
					instructure = 1;
				}
			}
			
		}	
		fclose(f); // close file
	}
}

void Font_Set(int font)
{
	int i;

	//
	// Check if our font engine is initialised, if not, use default quake font
	//
	if (!font_initialised)
	{	
		char_texture = font_texture[0]; // select default font
		return;
	}

	//
	// set the fonts from our script...
	//
	for (i=0 ; i<9 ; i++) // loop trough font_texture array
	{
		if (font == i)
		{
			char_texture = font_texture[i];
		}
	}
}


/*
================
Draw_Character

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_Character (int x, int y, int num)
{
	int				row, col;
	int		        font = 0;
	float			frow, fcol;
	float			font_height = 8, font_width = 8;

	//
	// Set our current font
	//



	Font_Set           (font);



	//
	// Don't print spaces
	//
	if (num == 32)
		return;	

	//
	// Return if we go offscreen
	//
	if (y <= -8)
		return;

	//
	// 255 chars in one charset
	//
	num &= 255;

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

	//
	// Check to see if our params are set for this font..
	//
	if (!font == 0) // FIXME: do this right
	{
		font_height = 8 * fonts[font].scale;
		font_width = 8 * fonts[font].scale;

	}

	//
	// Split up in 8X8 pictures
	//
	frow = row*0.0625;
	fcol = col*0.0625;


	//
	// Draw the characters
	//
	glBindTexture (GL_TEXTURE_2D, char_texture);
	glBegin (GL_QUADS);
	glTexCoord2f (fcol, frow);
	glVertex2f (x, y);
	glTexCoord2f (fcol + 0.0625, frow);
	glVertex2f (x+font_height, y);
	glTexCoord2f (fcol + 0.0625, frow + 0.0625);
	glVertex2f (x+font_height, y+font_width);
	glTexCoord2f (fcol, frow + 0.0625);
	glVertex2f (x, y+font_width);
	glEnd ();
}


/*
================
Draw_String
================
*/
void Draw_String (int x, int y, char *str)
{
	float	r, g, b;
	int		inc = 8; // distance between characters
	int		font = 0;

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	while (*str)
	{
		if (*str == '&')
		{
			++str; 

			if (!*str)
			{
				return;
			}

			switch(*str)
			{
			case 'f':
				{
					++str;
					if(!*str)
					{
						return;
					}

					r = (float)(*str - '0') * 0.11111111;

					++str;
					if(!*str)
					{
						return;
					}

					g = (float)(*str - '0') * 0.11111111;

					++str;
					if(!*str)
					{
						return;
					}

					b = (float)(*str - '0') * 0.11111111;

					++str;
					if(!*str)
					{
						return;
					}
					font = (int)(*str - '0');

					++str;
					if(!*str)
					{
						return;
					}

					++str;
					if(!*str)
					{
						return;
					}

					glColor3f(r,g,b);

					break;
				}
			case 'r':
				{
					glColor3f(1,1,1);
					font = 0;

					++str;
					if(!*str)
					{
						return;
					}
					++str;
					if(!*str)
					{
						return;
					}
				}

			default:
				{
					--str;
				}
			}
		}

		Draw_Character (x, y, *str);

		if (!font == 0)
		{
			inc = fonts[font].spacing;
		}

		++str;

		x += inc;

		if(x > (signed)vid.width - 16)
		{
			y	+= inc;
		}
	}
	glColor3f(1,1,1);

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}

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

CENTER PRINTING

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


/*
==============
CPrintf

prints a font to centered to the screen, is removed after it is stopped being called
==============
*/
void CPrintf(char *str)
{
	int	x,y,l,j;
	int		font = 0;

	y = vid.height*0.35;

	do	
	{
	// scan the width of the line
		for (l=0 ; l<40 ; l++)
		{
			if (str[l] == '\n' || !str[l])
				break;
		}

		x = (vid.width - l*20)/2;
		
		for (j=0 ; j<l ; j++, x+=20)
		{
			Draw_Character (x, y, str[j]);
		}
			
		y += 30;

		while (*str && *str != '\n')
			str++;

		if (!*str)
			break;
		str++;		// skip the \n
	} while (1);	
}
/*
==============
SCR_CenterPrint

Called for important messages that should stay in the center of the screen
for a few moments
==============
*/
void SCR_CenterPrint (char *str)
{
	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
	scr_centertime_off = scr_centertime.value;
	scr_centertime_start = cl.time;

	if(print_center_to_console.value)
		Con_Printf("%s\n", str);

// count the number of lines for centering
	scr_center_lines = 1;
	while (*str)
	{
		if (*str == '\n')
			scr_center_lines++;
		str++;
	}
}


void SCR_DrawCenterString (void)
{
	char	*start;
	int		l;
	int		j;
	int		x, y;
	int		remaining;
	float	fade;

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

// the finale prints the characters one at a time
	if (cl.intermission)
		remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
	else
		remaining = 9999;

	scr_erase_center = 0;
	start = scr_centerstring;

	if (scr_center_lines <= 4)
		y = vid.height*0.35;
	else
		y = 48;

	do	
	{
	// scan the width of the line
		for (l=0 ; l<40 ; l++)
			if (start[l] == '\n' || !start[l])
				break;
		x = (vid.width - l*8)/2;
		for (j=0 ; j<l ; j++, x+=8)
		{
			if (!cl.intermission && centerfade.value)
			{
				if (cl.time - scr_centertime_start < 1)
					fade =  (cl.time - scr_centertime_start);
				else	
					fade = -(cl.time - scr_centertime_start) + 2;
			
				glColor4f(1,1,1,fade);
			}
			else
				fade = 1;

			Draw_Character (x, y, start[j]);	
			
			if (!remaining--)
			{
				glColor4f(1,1,1,1);
				return;
			}
		}

		y += 8;

		while (*start && *start != '\n')
			start++;

		if (!*start)
			break;
		start++;		// skip the \n
	} while (1);

	glColor4f(1,1,1,1);	
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}

void SCR_CheckDrawCenterString (void)
{
	scr_copytop = 1;
	if (scr_center_lines > scr_erase_lines)
		scr_erase_lines = scr_center_lines;

	scr_centertime_off -= host_frametime;
	
	if (scr_centertime_off <= 0 && !cl.intermission)
		return;
	if (key_dest != key_game)
		return;

	SCR_DrawCenterString ();
}

void SCR_DrawNotifyString (void)
{
	char	*start;
	int		l;
	int		j;
	int		x, y;

	start = scr_notifystring;

	y = vid.height*0.35;

	do	
	{
	// scan the width of the line
		for (l=0 ; l<40 ; l++)
			if (start[l] == '\n' || !start[l])
				break;
		x = (vid.width - l*8)/2;
		for (j=0 ; j<l ; j++, x+=8)
			Draw_Character (x, y, start[j]);	
			
		y += 8;

		while (*start && *start != '\n')
			start++;

		if (!*start)
			break;
		start++;		// skip the \n
	} while (1);
}

/*
==================
SCR_ModalMessage

Displays a text string in the center of the screen and waits for a Y or N
keypress.  
==================
*/
int SCR_ModalMessage (char *text)
{
	if (cls.state == ca_dedicated)
		return true;

	scr_notifystring = text;
 
// draw a fresh screen
	scr_fullupdate = 0;
	scr_drawdialog = true;
	SCR_UpdateScreen ();
	scr_drawdialog = false;
	
	S_ClearBuffer ();		// so dma doesn't loop current sound

	do
	{
		key_count = -1;		// wait for a key down and up
		Sys_SendKeyEvents ();
	} while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);

	scr_fullupdate = 0;
	SCR_UpdateScreen ();

	return key_lastpress == 'y';
}
