// ShadFont.c

#include "ult_64.h"

#include "memory.h"
#include "file.h"
#include "teamdata.h"
#include "shadfont.h"
//#include "Shellgfx.h"
extern	Gfx *               SetPalette              (Gfx *, UI);


typedef struct SHeader
{
	char
		Type[4],
		Game[4],
		Platform[4];
	s32
		Version;
	u8
		NumChars,
		DirType,
		Gap,
		Space;
	s8
		DropX,
		DropY,
		pad[2];
} SHeader;

typedef struct SChar
{
	s32
		Offset;
	s8
		Width,
		Height,
		Off,
		PadW;
} SChar;

typedef struct SInfo
{
	SChar
		Font,
		Shad;
	s8
		ShadowX,
		ShadowY;
	char
		Char,
		pad;
} SInfo;


static SHeader
	*Font = NULL;

static SInfo
	*Info = NULL;

static u32
	ColorR = 255,
	ColorG = 255,
	ColorB = 255;

static s32
	ClipW = 512,
	ClipH = 240;


int SF_R = 0xf0;	// currently used as "team rankings"
int SF_G = 0xb0;
int SF_B = 0x60;



static SInfo *FindChar( const char c )
{
	s32
		i;

	if (Font && Info)
	{

		if(c == ',')
		{	// test only
			i = 1;
		}
	
		for (i=0; i<Font->NumChars; i++)
		{
			if (c == Info[i].Char)
				return( &Info[i] );
		}
	}

	return( NULL );
}


void ShadFont_Clip( const s32 width, const s32 height )
{
	ClipW = width;
	ClipH = height;
}


void *ShadFont_Load( char *filename )
{
	FH
		fh;
	void
		*mem;
	s32
		size;

	fh = FileOpen( filename, "rb" );

	FileSeek( fh, 0, SEEK_END );
	size = FileTell( fh );

	mem = MemMalloc( size, MEM_ANY );

	FileSeek( fh, 0, SEEK_SET );
	FileRead( mem, size, 1, fh );

	FileClose( fh );

	return( mem );
}


void ShadFont_Free( void *font )
{
	if (font)
		MemFree( font );
}


void ShadFont_Set( void *font )
{
	Font = (SHeader *)font;

	Info = (SInfo *)&Font[1];
}


void ShadFont_Color( const u8 r, const u8 g, const u8 b )
{
	ColorR = r;
	ColorG = g;
	ColorB = b;
}


static Gfx *DrawChar( Gfx *gp, SChar *chr, s32 x, s32 y )
{
	s32
		w,
		h,
		u,
		v;

	w = chr->Width;
	h = chr->Height;

	if (x < ClipW && (x+w) > 0 &&
			y < ClipH && (y+h) > 0)			// Cull
	{
		gDPLoadTextureBlock( gp++,
												 (u32)Font + chr->Offset,
												 G_IM_FMT_IA, G_IM_SIZ_8b,
												 chr->PadW,
												 chr->Height,
												 0,
												 G_TX_CLAMP,
												 G_TX_CLAMP,
												 6, 5,
												 G_TX_NOLOD,
												 G_TX_NOLOD );

		if (x >= 0 && (x+w) <= ClipW &&
				y >= 0 && (y+h) <= ClipH)
		{
			gSPTextureRectangle( gp++,
								 x<<2,
								 y<<2,
								 (x + chr->Width)<<2,
								 (y + chr->Height)<<2,
								 0,
								 0<<5, 0<<5,
								 (1<<10), (1<<10) );
		}
		else			// Clip...
		{
			if (x < 0)
			{
				u = -x << 6;
				w += x;
				x = 0;
			}

			if ((x+w) > ClipW)
			{
				u = 0;
				w -= (x+w) - ClipW;
			}

			if (y < 0)
			{
				v = -y << 6;
				h += y;
				y = 0;
			}

			if ((y+h) > ClipH)
			{
				v = 0;
				h -= (y+h) - ClipH;
			}

			gSPTextureRectangle( gp++,
								 x<<2,
								 y<<2,
								 (x+w)<<2,
								 (y+h)<<2,
								 0,
								 u<<5, v<<5,
								 (1<<10), (1<<10) );
		}
	}

	return( gp );
}


static Gfx *DrawVertText( Gfx *gp, char *text, s32 xpos, s32 ypos )
{
	SInfo
		*info;
	s16
		*ptr;
	s32
		c,
		i,
		x,
		y;

	gDPSetRenderMode( gp++, G_RM_XLU_SURF, G_RM_XLU_SURF2 );
	gSPTexture( gp++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON );
	gDPSetTextureLUT( gp++, G_TT_NONE );
	gDPSetAlphaCompare( gp++, G_AC_NONE );


#define MY_COMBINE 0, 0, 0, 0,  0, 0, 0, TEXEL0
	gDPSetCombineMode( gp++, MY_COMBINE, MY_COMBINE );
#undef MY_COMBINE

	y = ypos;
	i = 0;
	while (text[i])
	{
		c = text[i];
		if (c == ' ')
			y -= Font->Space;
		else
		{
			info = FindChar( c );
			if (info)
			{
				y -= info->Shad.Height;

				gp = DrawChar( gp,
											 &info->Shad,
											 xpos + info->Shad.Off + info->ShadowX + Font->DropX,
											 y + info->ShadowY + Font->DropY );

				y += info->Shad.Height;
				y -= info->Font.Height;
				y -= Font->Gap;
			}
		}

		i++;
	}


	gDPPipeSync( gp++ );
#define MY_COMBINE 0, 0, 0, PRIMITIVE,  0, 0, 0, TEXEL0
	gDPSetCombineMode( gp++, MY_COMBINE, MY_COMBINE );
#undef MY_COMBINE

	y = ypos;
	i = 0;
	while (text[i])
	{
		c = text[i];
		if (c == ' ')
			y -= Font->Space;
		else
		{
			info = FindChar( c );
			if (info)
			{
				y -= info->Font.Height;

				gp = DrawChar( gp, &info->Font, xpos + info->Font.Off, y );

				y -= Font->Gap;
			}
		}

		i++;
	}


	gDPPipeSync( gp++ );

	return( gp );
}


#define COMMA_DROP	1	//2

static Gfx *DrawHorzText( Gfx *gp, char *text, s32 xpos, s32 ypos )
{
	SInfo
		*info;
	s16
		*ptr;
	s32
		c,
		i,
		x,
		y;

	gDPSetRenderMode( gp++, G_RM_XLU_SURF, G_RM_XLU_SURF2 );
	gSPTexture( gp++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON );
	gDPSetTextureLUT( gp++, G_TT_NONE );
	gDPSetAlphaCompare( gp++, G_AC_NONE );


#define MY_COMBINE 0, 0, 0, 0,  0, 0, 0, TEXEL0
	gDPSetCombineMode( gp++, MY_COMBINE, MY_COMBINE );
#undef MY_COMBINE

	x = xpos;
	i = 0;
	while (text[i])
	{
		c = text[i];
		if (c == ' ')
			x += Font->Space;
		else
		{
			info = FindChar( c );
			if(c == ',')
			{
				y = COMMA_DROP;
			}
			else
			{
				y = 0;
			}

			if (info)
			{
				gp = DrawChar( gp,	&info->Shad,
									x + info->ShadowX + Font->DropX,
									ypos + info->Shad.Off + info->ShadowY + Font->DropY + y );

				x += info->Font.Width;
				x += Font->Gap;
			}
		}

		i++;
	}


	gDPPipeSync( gp++ );
#define MY_COMBINE 0, 0, 0, PRIMITIVE,  0, 0, 0, TEXEL0
	gDPSetCombineMode( gp++, MY_COMBINE, MY_COMBINE );
#undef MY_COMBINE

	x = xpos;
	i = 0;
	while (text[i])
	{
		c = text[i];
		if (c == ' ')
			x += Font->Space;
		else
		{
			info = FindChar( c );
			if(c == ',')
			{
				y = COMMA_DROP;
			}
			else
			{
				y = 0;
			}
			
			if (info)
			{
				gp = DrawChar( gp, &info->Font, x, ypos + info->Font.Off + y );

				x += info->Font.Width;
				x += Font->Gap;
			}
		}

		i++;
	}


	gDPPipeSync( gp++ );

	return( gp );
}


Gfx *ShadFont_Draw( Gfx *gp, char *text, s32 x, s32 y )
{
	if (Font)
	{
		gDPPipeSync( gp++ );
		gDPSetPrimColor( gp++, 0, 0, ColorR, ColorG, ColorB, 0 );

		if (Font->DirType == 1)
			gp = DrawVertText( gp, text, x, y );
		else
			gp = DrawHorzText( gp, text, x, y );
		
//		gp = SetPalette(gp, NULL);
		gDPSetTextureLUT( gp++, G_TT_RGBA16);

	}

	return( gp );
}



int GetShadFontLength(char * text)	// Based on currently selected Shadow Font
{
int len = 0;
int i;
char c;
SInfo *info;

	if (Font)
	{
		i = 0;
		while (text[i])
		{
			c = text[i];
			if (c == ' ')
			{
				len += Font->Space;
			}
			else
			{
				info = FindChar( c );
				if (info)
				{
					len += info->Font.Width;
					len += Font->Gap;
				
				}
			}

			i++;
		}


	}
	return (len);
}


int GetShadFontHeight(void)	// of current ShadowFont
{
SInfo *info;

	info = FindChar('A');

	return(info->Font.Height);
}


int GetShadFontBlankWidth(void)	// of current ShadowFont
{
	if(Font)
	{
		return(Font->Space);
	}
	return(0);
}






Gfx *ShadFont_DrawLowY( Gfx *gp, char *text, s32 x, s32 y )	// Y is lower part
{
int len;
SInfo *info;

	len = GetShadFontLength(text);	// Based on currently selected Shadow Font
	info = FindChar('A');

	gp = ShadFont_Draw(gp,text, x, y- (info->Font.Height) );
	
	return(gp);
}


Gfx *ShadFont_DrawCentered( Gfx *gp, char *text, s32 x, s32 y )	// both X,Y centered
{
int len;
SInfo *info;

	len = GetShadFontLength(text);	// Based on currently selected Shadow Font
	info = FindChar('A');

	gp = ShadFont_Draw(gp,text, x-(len>>1), y- ((info->Font.Height)>>1) );
	
	return(gp);
}



Gfx *ShadFont_DrawCenteredX( Gfx *gp, char *text, s32 x, s32 y ) // X centered, Y top
{
int len;
SInfo *info;

	len = GetShadFontLength(text);	// Based on currently selected Shadow Font
	gp = ShadFont_Draw(gp,text, x-(len>>1), y );
	
	return(gp);
}


Gfx *ShadFont_DrawRightCenterY( Gfx *gp, char *text, s32 x, s32 y )
{
int len,h;

	len = GetShadFontLength(text);	// Based on currently selected Shadow Font
	h = GetShadFontHeight();
	gp = ShadFont_Draw(gp,text, x-len, y- (h>>1) );
	
	return(gp);

}


Gfx *ShadFont_DrawRight( Gfx *gp, char *text, s32 x, s32 y )
{
int len,h;

	len = GetShadFontLength(text);	// Based on currently selected Shadow Font
//	h = GetShadFontHeight();
	gp = ShadFont_Draw(gp,text, x-len, y );
	
	return(gp);

}




/***************
int cstwk = 15;	//10

void CondenseString(char *tmp,int pixelwidth)
{
int len;

	len = strlen(tmp);

	if(GetShadFontLength(tmp) > pixelwidth)
	{

		if(Font == SmallShadFont)
		{
			while(GetShadFontLength(tmp) > pixelwidth-16)
			{	// put in dots until name is short enough 
				tmp[--len] = 0; 
			}
			strcat(tmp, "...");
		
		}
		else
		{
			while(GetShadFontLength(tmp) > pixelwidth-cstwk)
			{	// put in dots until name is short enough 
				tmp[--len] = 0; 
			}
			strcat(tmp, ". . .");	// "..." is too close together
		}
	}
}

************/

void CondenseString(char *string,int pixelwidth)	// a shadfont font string
{
int len;
char tmp[64];
char ending[16];

	if(GetShadFontLength(string) > pixelwidth)
	{
		// put in dots at end of name until name is short enough 

		if(Font == TinyShadFont)
		{
			strcpy(ending, ". . .");	// "..." is too close together
		}
		else
		{
			strcpy(ending,"...");
		}
		
		len = strlen(string);

		do
		{

			string[--len] = 0; 
			strcpy(tmp,string);
			strcat(tmp,ending);

		} while(GetShadFontLength(tmp) > pixelwidth);

		strcpy(string,tmp);		// restore

	}
}


/***************************    End of file: ShadFont.c  ********************/
