#include "3dc.h"
#include "inline.h"
#include "module.h"

#include "gamedef.h"
#include "font.h"

#include "indexfnt.hpp"

#define UseLocalAssert 1
#include "ourasert.h"


/*  Roxbys font stuff. any comments will be useful!!!

	font control - Fonts description and sturctures game/plat/font.h
								 Platform dependent processing		game/plat/platsup.c or ddplat.cpp
*/								 



/* general ideas. Crap I know!!!

	written to maintain compatiblity with the current texture (bitmap) processing tools.
	all the information about spacing of the font is maintained witin the bitmap itself,
	using hotspots for the texture processing, that way we dont need extra tools to convert
	fonts. It also allows complete font positioning (except different letter combos changing)
	I have shifted most of the emphasis onto the artists to set up the font and to mark it how they
	see fit. All the fonts must contain hotspots for all the letters. In that way we can easily 
	expand fonts. The character offests at the mo are simply -32. We may have to set up jump tables 
	at some later date to get chars for different languages.	

	Nothing supports anti-aliasing at the moment. Be careful with colours!!!
	
	Most of the info is being passed as locals. Clumsy I know. I didnt want to take up more
	space than was nessecery
	

	HARD coded. Names of the fonts
							Number of fonts to load
							Number of characters in the font. you can leave letters blank.	The number of
							characters in the fonts can be changed for different languages
								
	AVP-Win95
		
		This loads all the fonts in the structure PFFONT AvpFonts[] that is passed 
		to while NUM_FONTS. The Imageheader->ImagePtr for the data is maintained 
		untill we have processd	the characters. I dont fancy manipulating the data
		in a LPDIRECTDRAWSURFACE. The character descriptors in the font contain
		nothing but a src RECT. the void* pointer in the PFFONT structure in this
		case is cast to LPDIRECTDRAWSURFACE.
		
	
	
	Not that the entire font is placed into a 
	file That is then processed. CLUT where to
	put the CLU????	Put it into the vid memory.
	use a void*
*/
   
/*
	Only have 8 bit support a tne moment. More to come!!!
	Screen modes. I recommend loading up different fonts for different screen modes. 
	Simply reference a different structure.
*/
   

#define CHAR_WIDTH(font_num, offset) ((AvpFonts[font_num].srcRect[offset].right - AvpFonts[font_num].srcRect[offset].left))
#define CHAR_HEIGHT(font_num, offset) ((AvpFonts[font_num].srcRect[offset].bottom - AvpFonts[font_num].srcRect[offset].top))
#define IS_CHAR_WHITE_SPACE(ch)	((ch == '\t' || ch == '\n' || ch == ' ' || (int)ch == 0x0))

   

static int ProcessFontEntry
(
	PFFONT* font,
	unsigned char* fontstartaddress,
	unsigned pitch,
	int*  countfromrow,
	int*  countfromcol,
	int 	charnum
);

static int ProcessLineLength
(
	char* start_ch, 		// start char of string
	AVP_FONTS fontnum,		// the font we are using
	int offset,				// the offset from the font
	int max_width,			// the width of the line
	char** end_ch, 			// filled with end address
	int* line_length
);

void LoadAllFonts()
{
	// these fonts end up being in memory all the time,
	// I will also supply a function which is delete
	// specific font.

	int fontnum = 0;
	
	while(fontnum < NUM_FONTS)
		{
			/* load the font in turn */
			LoadPFFont(fontnum);
			fontnum ++;
		}
}


void LoadPFFont(int fontnum)
{
	// these fonts end up being in memory all the time,
	// I will also supply a function which is delete
	// specific font.

	PFFONT *font = &AvpFonts[fontnum];
	unsigned nPitch;
	unsigned char * pSurface;

	LoadFont(font);

	/* get the hotspot color  first entry in */
	
	if(font->fttexBitDepth == 15)font->fttexBitDepth = 16;
	
	pSurface = FontLock(font,&nPitch);
	GLOBALASSERT(pSurface);
	
	font->hotSpotValue = *(unsigned *)pSurface & (font->fttexBitDepth<32 ? (1<<font->fttexBitDepth)-1 : 0xffffffffU);
	
	/* the hotspot value is the top-left pixel */
	{			
		int charnum = 0;
		int countfromrow = 1;
		int countfromcol = 0;

		/*
			find the hotspots and send everything to the
			processing function. This part of routine find the
			hotspots in numbers of pixels
		*/
		
		/*Top line of the texture is redundent we get the hotspot from this*/
		/*edge of the texture has only lines*/


	 	while(charnum < font->num_chars_in_font)
 		{
			ProcessFontEntry(font,pSurface,nPitch,&countfromrow,&countfromcol,charnum);
			charnum++;
		}

		#if 0
		// Taken out by DHM 26/11/97:
		fontnum++;
		#endif
		charnum = 0;
	}
	
	FontUnlock(font);

	#if SupportWindows95
	INDEXFNT_PFLoadHook
	(
		(FontIndex) fontnum,
			// FontIndex I_Font_New,
		font // PFFONT *pffont_New
	);
	#endif
}



static int ProcessFontEntry
(
	PFFONT* font,
	unsigned char* fontstartaddress,
	unsigned pitch,
	int*  countfromrow,
	int*  countfromcol,
	int 	charnum
)
{
	/* 
		okay set the starting point
	
		countfromrow marks the current depth of the processing row in the texture.
		countfromcol marks how far along the current coloum we have processed
	
	 * = HOTSPOT .. the first pixel is used as the hotspot
	
	**********************
	 *	 **		**		****  *		<---- startfromrow
		###
		#
		##	 # #	###
		#		 # #	#	#			##
		###	 ###	####		##
	 *	 *	 # *		****	*  Blank chars marked by two hotspots adjacent
	  		 ###			 ^^			 |at the top and the bottom
				*		*			 ||			 |
	 ^							 ||______|
	 |							 
	 |
	 startfromcol
	 	
	********************* Note that the spot in col 0 marks a new linw of chars
	 
   */	 
	 

	int curr_row = *countfromrow;
	int curr_col = *countfromcol;
	int y_offset = 0, x_offset = curr_col;
				 
				 
	GLOBALASSERT(font);
	GLOBALASSERT(fontstartaddress);
	GLOBALASSERT(charnum < font->num_chars_in_font);
	GLOBALASSERT(curr_row < font->fttexHeight);
	GLOBALASSERT(curr_col <= font->fttexWidth);

	/*remember that all the corrdinates are done by pixels
		find the x and y corrdinates of the left lower hotspot
		we process each line (row) from startfromrow to the end
		first find the next marker in startfromrow
	*/
	
	// only supported if bit depth is a whole number of bytes
	GLOBALASSERT(8==font->fttexBitDepth || 16==font->fttexBitDepth || 24==font->fttexBitDepth || 32==font->fttexBitDepth);

	while(1)
		{
		// this bit processes the chars, finds uvs, extents and fills in the sturcture*/
		// count along the row to find the next x position
		
		unsigned int colour_here;

		if(x_offset > font->fttexWidth - 1)
		{
			// reached the end of the line! reset x and then y

			x_offset = 0;
			curr_col = 0;
			
			curr_row += font->fontHeight;	// max line height
			*countfromrow = curr_row;

			GLOBALASSERT(curr_row < font->fttexHeight);
		}
			
		switch (font->fttexBitDepth)
		{
			default:
				GLOBALASSERT(0);
			case 8:
				colour_here = *(fontstartaddress + (curr_row*pitch + x_offset));
				break;
			case 16:
				colour_here = *(unsigned short *)(fontstartaddress + (curr_row*pitch + 2*x_offset));
				break;
			case 24:
			{
				unsigned char * pPixel = fontstartaddress + (curr_row*pitch + 3*x_offset);
				// assuming the right endianness
				colour_here = pPixel[0] | (unsigned)pPixel[1] << 8 | (unsigned)pPixel[2] << 16;
				break;
			}
			case 32:
				colour_here = *(unsigned *)(fontstartaddress + (curr_row*pitch + 4*x_offset));
				break;
				
		}
		
		if(colour_here == font->hotSpotValue)
		{
			int width = -1, height = -1;
			/* set up the uv corrds of the top left corner*/
			int u = x_offset + 1;	 
			int v = curr_row + 1;	 


			/* scan down to give height*/
			for(y_offset = (curr_row + 1); y_offset < font->fttexHeight; y_offset++)
			{
				switch (font->fttexBitDepth)
				{
					default:
						GLOBALASSERT(0);
					case 8:
						colour_here = *(fontstartaddress + (y_offset*pitch + x_offset));
						break;
					case 16:
						colour_here = *(unsigned short *)(fontstartaddress + (y_offset*pitch + 2*x_offset));
						break;
					case 24:
					{
						unsigned char * pPixel = fontstartaddress + (y_offset*pitch + 3*x_offset);
						// assuming the right endianness
						colour_here = pPixel[0] | (unsigned)pPixel[1] << 8 | (unsigned)pPixel[2] << 16;
						break;
					}
					case 32:
						colour_here = *(unsigned *)(fontstartaddress + (y_offset*pitch + 4*x_offset));
						break;
						
				}
				
				if(colour_here == font->hotSpotValue)
				{
					height = y_offset - curr_row - 1;	 // -1 because we exclude the top and bottom hotspots
					break;
				}		
			}

		 	/* scan along to get the width*/
			for(++x_offset; x_offset < font->fttexWidth; x_offset ++)
			{
				switch (font->fttexBitDepth)
				{
					default:
						GLOBALASSERT(0);
					case 8:
						colour_here = *(fontstartaddress + (curr_row*pitch + x_offset));
						break;
					case 16:
						colour_here = *(unsigned short *)(fontstartaddress + (curr_row*pitch + 2*x_offset));
						break;
					case 24:
					{
						unsigned char * pPixel = fontstartaddress + (curr_row*pitch + 3*x_offset);
						// assuming the right endianness
						colour_here = pPixel[0] | (unsigned)pPixel[1] << 8 | (unsigned)pPixel[2] << 16;
						break;
					}
					case 32:
						colour_here = *(unsigned *)(fontstartaddress + (curr_row*pitch + 4*x_offset));
						break;
						
				}
				
				if(colour_here == font->hotSpotValue)
				{
					width = x_offset - curr_col - 1; // exclude end hotspot
					break;
				}	
			}
				
			*countfromcol = x_offset + 1; /* ready for the next char*/

			/*fill in the data structure -  platform dependent*/
			FillCharacterSlot(u, v, width, height, charnum, font);	
			return 0;														
		}

		x_offset++;

	}	
	return 0;
}											


#if 0 // obsolete
static int Process8BitEntry(PFFONT* font,
													char*  fontstartaddress,
													int*  countfromrow,
													int*  countfromcol,
													int   charnum)
{
	/* 
		okay set the starting point
	
		countfromrow marks the current depth of the processing row in the texture.
		countfromcol marks how far along the current coloum we have processed
	
	 * = HOTSPOT .. the first pixel is used as the hotspot
	
	**********************
	 *	 **		**		****  *		<---- startfromrow
		###
		#
		##	 # #	###
		#		 # #	#	#			##
		###	 ###	####		##
	 *	 *	 # *		****	*  Blank chars marked by two hotspots adjacent
	  		 ###			 ^^			 |at the top and the bottom
				*		*			 ||			 |
	 ^							 ||______|
	 |							 
	 |
	 startfromcol
	 	
	********************* Note that the spot in col 0 marks a new linw of chars
	 
   */	 
	 

	int curr_row = *countfromrow;
	int curr_col = *countfromcol;
	int y_offset = 0, x_offset = curr_col;
				 
				 
	GLOBALASSERT(font);
	GLOBALASSERT(fontstartaddress);
	GLOBALASSERT(charnum < font->num_chars_in_font);
	GLOBALASSERT(curr_row < font->fttexHeight);
	GLOBALASSERT(curr_col <= font->fttexWidth);

	/*remember that all the corrdinates are done by pixels
		find the x and y corrdinates of the left lower hotspot
		we process each line (row) from startfromrow to the end
		first find the next marker in startfromrow
	*/

	while(1)
		{
		// this bit processes the chars, finds uvs, extents and fills in the sturcture*/
		// count along the row to find the next x position
		
		unsigned int colour_here;

		if(x_offset > font->fttexWidth - 1)
		{
			// reached the end of the line! reset x and then y

			x_offset = 0;
			curr_col = 0;
			
			curr_row += font->fontHeight;	// max line height
			*countfromrow = curr_row;

			GLOBALASSERT(curr_row < font->fttexHeight);
		}
			
		colour_here = (int)*(fontstartaddress + (curr_row*font->fttexWidth	+ x_offset));
	
		
		if(colour_here == font->hotSpotValue)
		{
			int width = -1, height = -1;
			/* set up the uv corrds of the top left corner*/
			int u = x_offset + 1;	 
			int v = curr_row + 1;	 


			/* scan down to give height*/
			for(y_offset = (curr_row + 1); y_offset < font->fttexHeight; y_offset++)
			{
				colour_here = (int)*(fontstartaddress + (y_offset*font->fttexWidth	+ x_offset));

				if(colour_here == font->hotSpotValue)
				{
					height = y_offset - curr_row - 1;	 // -1 because we exclude the top and bottom hotspots
					break;
				}		
			}

		 	/* scan along to get the width*/
			for(++x_offset; x_offset < font->fttexWidth; x_offset ++)
			{
				colour_here = (int)*(fontstartaddress + (curr_row*font->fttexWidth	+ x_offset));
			

				if(colour_here == font->hotSpotValue)
				{
					width = x_offset - curr_col - 1; // exclude end hotspot
					break;
				}	
			}
				
			*countfromcol = x_offset + 1; /* ready for the next char*/

			/*fill in the data structure -  platform dependent*/
			FillCharacterSlot(u, v, width, height, charnum, font);	
			return 0;														
		}

		x_offset++;

	}	a
}



									
static int Process16BitEntry(PFFONT *font,
													char* fontstartaddress,
													int*  countfromrow,
													int*  countfromcol,
													int charnum)
{
int curr_row = *countfromrow;
int curr_col = *countfromcol;
int y_offset = 0, x_offset = curr_col;
			 
			 
GLOBALASSERT(font);
GLOBALASSERT(fontstartaddress);
GLOBALASSERT(charnum < font->num_chars_in_font);
GLOBALASSERT(curr_row < font->fttexHeight);
GLOBALASSERT(curr_col <= font->fttexWidth);

/*remember that all the corrdinates are done by pixels
	find the x and y corrdinates of the left lower hotspot
	we process each line (row) from startfromrow to the end
	first find the next marker in startfromrow
*/

	while(1)
	{
		// this bit processes the chars, finds uvs, extents and fills in the sturcture*/
		// count along the row to find the next x position
		
		unsigned int colour_here;

		if(x_offset > font->fttexWidth - 1)
		{
			// reached the end of the line! reset x and then y

			x_offset = 0;
			curr_col = 0;
			
			curr_row += font->fontHeight;	// max line height
			*countfromrow = curr_row;

			GLOBALASSERT(curr_row < font->fttexHeight);
		}

		{
			unsigned int colour_high  = 0x000000ff & (unsigned int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2);
			unsigned int colour_low = 0x000000ff & (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2  + 1);
 			colour_here = (colour_high <<  8) | colour_low;
		}
			
		if(colour_here == font->hotSpotValue)
		{
			int width = -1, height = -1;
			/* set up the uv corrds of the top left corner*/
			int u = x_offset + 1;	 
			int v = curr_row + 1;	 


			/* scan down to give height*/
			for(y_offset = (curr_row + 1); y_offset < font->fttexHeight; y_offset++)
			{
				{
					int colour_high  = 0x000000ff & (int)*(fontstartaddress + (y_offset*font->fttexWidth + x_offset)*2);
					int colour_low = 0x000000ff & (int)*(fontstartaddress + (y_offset*font->fttexWidth + x_offset)*2  + 1);
		 			colour_here = (colour_high <<  8) | colour_low;
				}
		 			 
				if(colour_here == font->hotSpotValue)
				{
					height = y_offset - curr_row - 1;	 // -1 because we exclude the top and bottom hotspots
					break;
				}		
			}

		 	/* scan along to get the width*/
			for(++x_offset; x_offset < font->fttexWidth; x_offset ++)
			{
				{
					int colour_high  = 0x000000ff & (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2);
					int colour_low = 0x000000ff & (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2  + 1);
		 			colour_here = (colour_high <<  8) | colour_low;
				}
				
				if(colour_here == font->hotSpotValue)
				{
					width = x_offset - curr_col - 1; // exclude end hotspot
					break;
				}	
			}
				
			*countfromcol = x_offset + 1; /* ready for the next char*/

			/*fill in the data structure -  platform dependent*/
			FillCharacterSlot(u, v, width, height, charnum, font);	
			return 0;														
		}

		x_offset++;

	}	
	return 0;
}											

static int Process24BitEntry(PFFONT* font,
													char* fontstartaddress,
													int*  countfromrow,
													int*  countfromcol,
													int charnum)
{
	return 0;
}

#endif





void BLTWholeFont(int fontnum, int x , int y, int win_width)
{
	int i = 0;
	int plotto_x = x, plotto_y = y;

	while(i < AvpFonts[fontnum].num_chars_in_font)
		{
			int charwidth = AvpFonts[fontnum].srcRect[i].right - AvpFonts[fontnum].srcRect[i].left;
	
			if((charwidth + plotto_x - x) > win_width)
				{
					plotto_y += AvpFonts[fontnum].fontHeight;
					plotto_x= x;
				}

			BLTFontOffsetToHUD(&AvpFonts[fontnum], plotto_x, plotto_y, i);

			plotto_x += charwidth + 1;

			i++;
		}
	return;
}


void BLTString(FONT_DESC str_packet)
{
	PFFONT font = AvpFonts[str_packet.fontnum];
  
	unsigned char *strptr = str_packet.string;
	int offset = 0;
	int not_finished = Yes;
	int pos_x = str_packet.destx;
	int pos_y = str_packet.desty;
	int white_space_width = CHAR_WIDTH(str_packet.fontnum, 0);


	// set up the font processing varibles depending on the type of font

	switch(font.font_type)
		{
			case(I_FONT_NUMERIC):
				{	
					offset = 0x30;
   					break;
				}
			case(I_FONT_UC_NUMERIC):
				{	
					offset = 0x20;
   					break;
				}
			case(I_FONT_UCLC_NUMERIC):
				{
					offset = 0x20;
 					break;
				}
			default:
				GLOBALASSERT(2<1);
		}			
	
	while(not_finished)
	{
		int line_length;
		char *end_char;
	
	
		// find the line length and the end char in the line
	
		not_finished = ProcessLineLength
		(
			strptr, 		// start char of string
			str_packet.fontnum,		// the font we are using
			offset,				// the offset from the font
			str_packet.width,			// the width of the line
			&end_char, 			// filled with end address
			&line_length		// filled with line length
		);			
					  
					  
		// work out where to print the line			  	

		if(line_length)						
		{
			switch(str_packet.just)
			{	
	
				case FJ_LEFT_JUST:
				{
					pos_x = str_packet.destx;					
					break;
				}
				case FJ_CENTRED:
				{
					pos_x = str_packet.destx + ((str_packet.width - line_length) >> 1);
					break;
				}
				case FJ_RIGHT_JUST:
				{
					pos_x = str_packet.destx + (str_packet.width - line_length);
					break;
				}
				default:
				{	
					;
				}
			}
				
			// now print the line untill we reach the address of
			// the end char

			do
			{
				if(*strptr == ' ')
				{
					pos_x += white_space_width;
				}
				else if(*strptr == '\t')
				{
					pos_x += 4*white_space_width;
				}	
				else if(*strptr == '\n' || strptr == 0x0)
				{
					GLOBALASSERT(strptr == end_char);
				}
				else if((int)*strptr == 0xD) 
				{
					// carrige return 
					// do nothing - our next char should be '\n'
					
					GLOBALASSERT(*(strptr + 1) == '\n');
				}
				else
				{
					extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock;
					int end_pos = pos_x + CHAR_WIDTH(str_packet.fontnum, ((int)*strptr - offset));
					int bottom_pos = pos_y + CHAR_HEIGHT(str_packet.fontnum, ((int)*strptr - offset));

					if(end_pos > ScreenDescriptorBlock.SDB_Width || pos_x < 0)
					{			
						//dont draw		
						//not_finished = No;
					}					
					else if( bottom_pos > ScreenDescriptorBlock.SDB_Height || pos_y < 0)
					{
						not_finished = No;
					}
					else								
					{
						pos_x += BLTFontOffsetToHUD
						(
							&font, 
							pos_x, 
							pos_y, 
							(int)*strptr - offset
						);
						
						pos_x ++; // to make space between letters
					}
				}
			}		
			while(++strptr != (unsigned char *)end_char);

			pos_y += font.fontHeight - 2;
		}
		
		strptr++;
	}
}



/*
RWH - changes to font line processing
This function takes a pointer to a string a font and a width and
puts the length of the line into line_length AND puts the end char address into end_ch

It returns 0 when we have reached the end of a string

*/



int ProcessLineLength
(
	char* start_ch, 		// start char of string
	AVP_FONTS fontnum,		// the font we are using
	int offset,				// the offset from the font
	int max_width,			// the width of the line
	char** end_ch, 			// filled with end address
	int* line_length
)
{
	int continue_to_process_word = Yes;
	int white_space_width = CHAR_WIDTH(fontnum, 0);	
	char *word_ptr = start_ch;
		
	*line_length = 0;	

	if(start_ch == NULL)
	{		
		*end_ch = NULL;
		*line_length = 0;
		return 0;
	}	   		

	// first process any white space at the end of the
	// line out 
	
	while(*start_ch == ' ')
	{
		// make sure we havent run out
		// of chars to process
		if(*start_ch == 0x0)
		{
			*end_ch = NULL;
			*line_length = 0;
			return 0;		
		}	
		
		start_ch++;
	}	
	
	// Now we can start on the characters in the line	
	// note that we have to have two loops. The first
	// continues untill we break out of it. The second
	// adds up the length of each word and sees if the line
	// with the new word will overrun the max_width
	
	
	// the  word_ptr points to the current char - it is only incremented
	// when we can be sure that we can add the current letter to the word
	
	
	while(1)
	{
		int word_length = 0;

		continue_to_process_word = Yes;

		while(continue_to_process_word) 				
		{
			// is the next char white space ?
			// if so close the word
		
			if(IS_CHAR_WHITE_SPACE(*(word_ptr + 1)))
			{
				// hit white space - finish this current word but only
				// AFTER we have processed the current char
				continue_to_process_word = No;
			}	
			
			// need to process every white space seperately
 			if(*word_ptr == '\t')
 			{
 				// a one char word!
 				word_length = 4 * white_space_width;
				continue_to_process_word = No;
				word_ptr++;
 			}
 			else if(*word_ptr == 0x0)
 			{
				// reached end of file - need to return 0 
				
				*end_ch = word_ptr;				
				return 0;
 			}
 			else if(*word_ptr == '\n')
 			{
				*end_ch = word_ptr;				
				return 1;
 			}
 			else if(*word_ptr == ' ')
 			{
				if(word_length)
				{
					// tag on the white space onto the word length
					word_length += white_space_width;
				}
				// other wise keep on tiking on
				
 				word_ptr++;
 			}														
 			else
 			{
 				// yeah add a letter to the word length
				int char_off = (char)(*word_ptr - offset);
				word_length += CHAR_WIDTH(fontnum, char_off);
				word_length ++; //for space between lettes

				word_ptr++; //process next char
			}		
		}
		
		// okay we have the length of this word - check to see if
		// it overruns the end of the line - if it is too long,
		// break out of the line loop
		
		
		if((word_length + *line_length) >= max_width) 
		{
			*end_ch = start_ch;
			return 1;				
		}	
		else 	
		{
			*line_length += word_length;
			// set up the next word save the beginning of teh word in start_ch
			start_ch = word_ptr;
		}												
	}
}		