/************************************************************************/
/**                                                                    **/
/**    Starfox Cad Tools - (c) 1994 Dylan Cuthbert (Argonaut Software) **/
/**                                                                    **/
/************************************************************************/

#define _FONTS_

#include "sfc.h"

#include "fonts.h"
#include "japan.h"

char *cgxfile,*scrfile;

FRPath cgxpath=
	{
	"*.cgx"
	};

FRPath scrpath=
	{
	"*.scr"
	};

FRPath savefontpath=
	{
	"*.bin"
	};

int xsize,ysize,charysize;

char fontfileroot[MAXFILE];

struct FontHeader fh;

struct CharData chardata[256];

unsigned char mapping[256];

FontDef chars[] =
	{
	"A",'A',
	"B",'B',
	"C",'C',
	"D",'D',
	"E",'E',
	"F",'F',
	"G",'G',
	"H",'H',
	"I",'I',
	"J",'J',
	"K",'K',
	"L",'L',
	"M",'M',
	"N",'N',
	"O",'O',
	"P",'P',
	"Q",'Q',
	"R",'R',
	"S",'S',
	"T",'T',
	"U",'U',
	"V",'V',
	"W",'W',
	"X",'X',
	"Y",'Y',
	"Z",'Z',
	"a",'a',
	"b",'b',
	"c",'c',
	"d",'d',
	"e",'e',
	"f",'f',
	"g",'g',
	"h",'h',
	"i",'i',
	"j",'j',
	"k",'k',
	"l",'l',
	"m",'m',
	"n",'n',
	"o",'o',
	"p",'p',
	"q",'q',
	"r",'r',
	"s",'s',
	"t",'t',
	"u",'u',
	"v",'v',
	"w",'w',
	"x",'x',
	"y",'y',
	"z",'z',

	"0",'0',
	"1",'1',
	"2",'2',
	"3",'3',
	"4",'4',
	"5",'5',
	"6",'6',
	"7",'7',
	"8",'8',
	"9",'9',

	"!",'!',
	"@",'@',
	"#",'#',
	"$",'$',
	"%",'%',
	"^",'^',
	"&",'&',
	"*",'*',
	"(",'(',
	")",')',
	"-",'_',
	"=",'=',
	"_",'_',
	"+",'+',

	"[",']',
	"]",']',
	"\\",'\\',
	"{",'{',
	"}",'}',
	"|",'|',

	",",',',
	".",'.',
	"/",'/',
	";",';',
	"'",'\'',
	"<",'<',
	">",'>',
	"?",'?',
	":",'\"',
	"~",'~',

	"Special 1",J_SPECIAL1,
	"Special 2",J_SPECIAL2,
	"Special 3",J_SPECIAL3,
	"Special 4",J_SPECIAL4,
	"Special 5",J_SPECIAL5,
	"Special 6",J_SPECIAL6,
	"Special 7",J_SPECIAL7,
	"Special 8",J_SPECIAL8,
	"Special 9",J_SPECIAL9,
	"Special 10",J_SPECIAL10,
	"Special 11",J_SPECIAL11,

// -- Japanese punctuation

	"Daku-ten",J_PLING,
	"Han-daku-ten",J_CIRCLE,
	"Ku-ten",J_FULLSTOP,
	"Tou-ten",J_COMMA,
	"Katakana ten", K_DOT,

// -- Japanese hiragana

	"Japanese A",J_A,
	"Japanese I",J_I,
	"Japanese U",J_U,
	"Japanese E",J_E,
	"Japanese O",J_O,
	"Japanese a",J_a,
	"Japanese i",J_i,
	"Japanese u",J_u,
	"Japanese e",J_e,
	"Japanese o",J_o,
	"Japanese KA",J_KA,
	"Japanese KI",J_KI,
	"Japanese KU",J_KU,
	"Japanese KE",J_KE,
	"Japanese KO",J_KO,
	"Japanese SA",J_SA,
	"Japanese SHI",J_SHI,
	"Japanese SU",J_SU,
	"Japanese SE",J_SE,
	"Japanese SO",J_SO,
	"Japanese TA",J_TA,
	"Japanese CHI",J_CHI,
	"Japanese TSU",J_TSU,
	"Japanese TE",J_TE,
	"Japanese TO",J_TO,
	"Japanese NA",J_NA,
	"Japanese NI",J_NI,
	"Japanese NU",J_NU,
	"Japanese NE",J_NE,
	"Japanese NO",J_NO,
	"Japanese HA",J_HA,
	"Japanese HI",J_HI,
	"Japanese HU",J_HU,
	"Japanese HE",J_HE,
	"Japanese HO",J_HO,
	"Japanese MA",J_MA,
	"Japanese MI",J_MI,
	"Japanese MU",J_MU,
	"Japanese ME",J_ME,
	"Japanese MO",J_MO,
	"Japanese YA",J_YA,
	"Japanese YU",J_YU,
	"Japanese YO",J_YO,
	"Japanese RA",J_RA,
	"Japanese RI",J_RI,
	"Japanese RU",J_RU,
	"Japanese RE",J_RE,
	"Japanese RO",J_RO,
	"Japanese WA",J_WA,
	"Japanese WO",J_WO,
	"Japanese N",J_N,
	"Japanese tsu",J_tsu,
	"Japanese ya",J_ya,
	"Japanese yu",J_yu,
	"Japanese yo",J_yo,

// -- Japanese katakana

	"Katakana A",K_A,
	"Katakana I",K_I,
	"Katakana U",K_U,
	"Katakana E",K_E,
	"Katakana O",K_O,
	"Katakana a",K_a,
	"Katakana i",K_i,
	"Katakana u",K_u,
	"Katakana e",K_e,
	"Katakana o",K_o,
	"Katakana KA",K_KA,
	"Katakana KI",K_KI,
	"Katakana KU",K_KU,
	"Katakana KE",K_KE,
	"Katakana KO",K_KO,
	"Katakana SA",K_SA,
	"Katakana SHI",K_SHI,
	"Katakana SU",K_SU,
	"Katakana SE",K_SE,
	"Katakana SO",K_SO,
	"Katakana TA",K_TA,
	"Katakana CHI",K_CHI,
	"Katakana TSU",K_TSU,
	"Katakana TE",K_TE,
	"Katakana TO",K_TO,
	"Katakana NA",K_NA,
	"Katakana NI",K_NI,
	"Katakana NU",K_NU,
	"Katakana NE",K_NE,
	"Katakana NO",K_NO,
	"Katakana HA",K_HA,
	"Katakana HI",K_HI,
	"Katakana HU",K_HU,
	"Katakana HE",K_HE,
	"Katakana HO",K_HO,
	"Katakana MA",K_MA,
	"Katakana MI",K_MI,
	"Katakana MU",K_MU,
	"Katakana ME",K_ME,
	"Katakana MO",K_MO,
	"Katakana YA",K_YA,
	"Katakana YU",K_YU,
	"Katakana YO",K_YO,
	"Katakana RA",K_RA,
	"Katakana RI",K_RI,
	"Katakana RU",K_RU,
	"Katakana RE",K_RE,
	"Katakana RO",K_RO,
	"Katakana WA",K_WA,
	"Katakana WO",K_WO,
	"Katakana N",K_N,
	"Katakana tsu",K_tsu,
	"Katakana ya",K_ya,
	"Katakana yu",K_yu,
	"Katakana yo",K_yo,

	NULL,0
	};


#define CHARSPERLINE (256/xsize)
#define CharX(c) (((unsigned int)(c)%CHARSPERLINE)*xsize)
#define CharY(c) (((unsigned int)(c)/CHARSPERLINE)*ysize)
#define GridCharX(x) ((x)/xsize)
#define GridCharY(y) ((y)/ysize)
#define WhichChar(x,y) (((y)<256)?(((x)/xsize<CHARSPERLINE && (x)>=0)?((x)/xsize+((y)/ysize*(256/xsize))):-1):-1)


int oldx=-1,oldy=-1;


//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
void DrawCursor(int x,int y)
	{
	oldx = x; oldy = y;

	if (x == -1 || y == -1) return;
	tw->FGcolor(GrXOR|RED);
	tw->filledbox(x*xsize,y*ysize,x*xsize+xsize-1,y*ysize+ysize-1);
	}


//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
// decodes 64 bytes from a character
void getcharbytes(unsigned char *out,unsigned char *in)
	{
	register short n,y,x,d;

	for (y=0;y<8;y++)
		{
		for (x=0; x<8; x++)
			{
			out[7-x] = ((in[0]&(1<<x))>>x);
			out[7-x] |= ((in[1]&(1<<x))>>x)*2;
			out[7-x] |= ((in[16]&(1<<x))>>x)*4;
			out[7-x] |= ((in[17]&(1<<x))>>x)*8;

			}

		in  += 2;
		out += 8;
		}
	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
void DrawGrid(int xsize,int ysize)
	{
	int x,y;

	if (xsize<16 || ysize<16) return;

	DrawCursor(oldx,oldy);
	DrawCursor(-1,-1);

	tw->FGcolor(BLUE|GrXOR);
	for (x=0;x<256;x+=xsize)
		{
		tw->line(x,0,x,255);
		}

	for (y=0;y<256;y+=ysize)
		{
		tw->line(0,y,255,y);
		}
	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
// Work out the width of a character

int CharWidth(int x,int y)
	{
	int i,j;
	unsigned char n;
	int maxwidth=0;

	for (j=y;j<y+ysize;j++)
		{
		for (i=0;i<xsize;i++)
			{
			if (tw->pixel(x+i,j) && maxwidth<i) maxwidth = i;
			}
		}
	return maxwidth+1;
	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
// Work out the width of the entire font (when compacted)

int FontWidth()
	{
	int i,j;
	unsigned char n;
	int width;

	for (n=0,width=0;n<numselected;n++)
		{
		width += CharWidth(CharX(selected[n]),CharY(selected[n]));
		}

	return (width+7)/8;
	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
// Get the memory required for the compacted image of the font

unsigned char *AllocFont(int width, int height)
	{
	return (unsigned char *)calloc(width*height,1);
	}


//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
// Plot pixel into compacted font format

void FontPutPixel(struct FontHeader *fh,unsigned char *p,int x,int y)
	{

	if (x>=fh->width*8 || y>=fh->height || x<0 || y<0)
		{
		printf("Error - data clipped\n");
		return;
		}

	*(p+((unsigned int)fh->width)*y+x/8)  |= 1<<(7-(x&7));

	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
// Copy character from screen into compacted font format

int CopyChar(struct FontHeader *fh,unsigned char *p,int sel,int start)
	{
	int x = CharX(selected[sel]);
	int y = CharY(selected[sel]);
	int i,j;

	chardata[sel].startwidth = ((start<<startshift)&startmask) | ((CharWidth(x,y)<<widthshift)&widthmask);

	for (j = 0; j<fh->height; j++)
		{
		for (i=0;i<((chardata[sel].startwidth&widthmask)>>widthshift);i++)
			{
			if (tw->pixel(x+i,y+j))
				FontPutPixel(fh,p,i+start,j);
			}
		}

	return ((chardata[sel].startwidth) & widthmask) >> widthshift;
	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
unsigned char *CompactFont(struct FontHeader *fh)
	{
	int n,x;
	unsigned char *p;

	p = AllocFont(fh->width = FontWidth(),fh->height = charysize);
	fh->firstentry = 255;
	fh->lastentry = 0;
	fh->spacing = xsize/8;

	for (n=0,x=0;n<numselected;n++)
		{
		x += CopyChar(fh,p,n,x);
		if (mapping[n] < fh->firstentry) fh->firstentry = mapping[n];
		if (mapping[n] > fh->lastentry) fh->lastentry = mapping[n];
		}

	fh->offset = fh->lastentry-fh->firstentry+1 + numselected*2 + sizeof(struct FontHeader);
	return p;
	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
// Save the font out

void SaveFont()
	{
	char *savefile;
	char temp[MAXFILE+MAXEXT];
	FILE *fp;
	int n,lw=256/xsize;
	unsigned short sk;
	int val=1;
	unsigned char *buffer;

	DrawGrid(xsize,ysize);

	strcpy(temp,fontfileroot);
	strcpy(temp+strlen(fontfileroot),".bin");

	if ((savefile = getfilename("Binary Save File",&savefontpath, temp, FR_SETPATH)))
		{
		if (fp = fopen(savefile,"wb"))
			{

// Compact the font

			buffer = CompactFont(&fh);

// Write out the font header

			fwrite(&fh,sizeof(struct FontHeader),1,fp);

// Write out the ascii mapping table

			for (n=fh.firstentry;n<=fh.lastentry;n++)
				{
				int m;

				for (m=0;m<numselected;m++)
					{
					if (mapping[m] == n)
						{
						fputc(m,fp);
						break;
						}
					}
				if (m>=numselected) fputc(-1,fp);
				}

// Write out the character information

			for (n=0;n<numselected;n++)
				{
				fwrite(&chardata[n],sizeof(struct CharData),1,fp);
				}

// And Finally write the compressed font data out

			fwrite(buffer,fh.height,fh.width,fp);

			free(buffer);
			fclose(fp);
			}
		else Wait_ok(GrScreenX()/2,GrScreenY()/2,"Unable to open %s.\n",savefile);
		}

	DrawGrid(xsize,ysize);
	}
//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴

void SetGrid()
	{
	Window *sg;
	int exitplease = 0;
	char *list;
	int n;
	char *sizes[] =
		{
		"4",
		"5",
		"6",
		"7",
		"8",
		"12",
		"16",
		"20",
		"24",
		"32",
		"48",
		NULL
		};

	DrawGrid(xsize,ysize);

	sl_init(&list);
	for (n=0;sizes[n];n++) sl_add(&list,sizes[n]);
	sl_end(&list);

	sg = new Window((GrScreenX()*4)/16,(GrScreenY()*3)/8,(GrScreenX()*12)/16,(GrScreenY()*5)/8+16,RED,"Set Grid",W_BACKINGSTORE|W_MOTIFBORDER);

	sg->setfont(nicefont);
	sg->FGcolor(BLACK);
	new Gadget(sg,2,2+tw->textheight(),64,100,list,6,G_LIST|G_BOXHIGHLIGHT|G_TOGGLE,0);
	new Gadget(sg,96,2+tw->textheight(),96+62,100,list,8,G_LIST|G_BOXHIGHLIGHT|G_TOGGLE,0);
	new Gadget(sg,192,2+tw->textheight(),192+62,100,list,10,G_LIST|G_BOXHIGHLIGHT|G_TOGGLE,0);
	new Gadget(sg,sg->MaxX()-GADGETSIZEX(sg,"OK")-2,sg->MaxY()-GADGETSIZEY(sg),0,0,"OK",0,G_TEXTHIGHLIGHT|G_BOXTEXT,13);

	sg->Highlight(6);

	sg->textxy(2,2);
	*sg << "X Size\n";
	sg->textxy(96,2);
	*sg << "Y Size\n";
	sg->textxy(192,2);
	*sg << "Char Y Size\n";

	sg->Direct();

	while (!exitplease)
		{
		Update_Mouse();
		if (sg->mouse())
			{
			if (sg->input.gflags&(GF_SELECTED))
				{
				switch(sg->input.gadget)
					{
					case 0:
						exitplease=1;
						break;

					default:
						break;
					}
				}
			}
		}

	if (sg->GetSelectedItem(6)) xsize = strtol(sg->GetSelectedItem(6),NULL,0);
	if (sg->GetSelectedItem(8)) ysize = strtol(sg->GetSelectedItem(8),NULL,0);
	if (sg->GetSelectedItem(10)) charysize = strtol(sg->GetSelectedItem(10),NULL,0);

	delete sg;
	sl_free(&list);

	DrawGrid(xsize,ysize);
	}



//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴

void SetChar(int sel)
	{
	Window *sg;
	int exitplease = 0;
	char *list;
	int n;
	static int oldtopitem=-1;
	int lastitem=-1;

	sl_init(&list);
	for (n=0;chars[n].letter;n++)
		{
		sl_add(&list,chars[n].letter);
		if (chars[n].code == mapping[sel]) lastitem = n;
		}
	sl_end(&list);

	sg = new Window((GrScreenX()*6)/16,(GrScreenY()*1)/8,(GrScreenX()*10)/16,(GrScreenY()*7)/8+16,RED,"Set Grid",W_BACKINGSTORE|W_MOTIFBORDER);

	sg->setfont(nicefont);
	sg->FGcolor(BLACK);
	new Gadget(sg,sg->MaxX()-GADGETSIZEX(sg,"OK")-2,sg->MaxY()-GADGETSIZEY(sg),0,0,"OK",0,G_TEXTHIGHLIGHT|G_BOXTEXT,13);
	new Gadget(sg,2,2+tw->textheight(),128,sg->MaxY()-GADGETSIZEY(sg),list,6,G_LIST|G_TOGGLE,0);

	sg->Highlight(6);

	if (lastitem != -1) sg->SetSelectedItem(6,lastitem);
	else if (oldtopitem != -1) sg->SetSelectedItem(6,oldtopitem);

	sg->textxy(2,2);
	*sg << "Character Mapping\n";

	sg->Direct();

	while (!exitplease)
		{
		Update_Mouse();
		if (sg->mouse()) if (sg->input.gflags&(GF_SELECTED))
			if (sg->input.gadget==6 || sg->input.gadget==0) break;
		}

	if (sg->GetSelectedItem(6))
		{
		mapping[sel] = chars[sg->GetSelectedItemNum(6)].code;
		oldtopitem = sg->GetSelectedItemNum(6);
		}
	else mapping[sel] = 0;

	delete sg;
	sl_free(&list);

	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴

void ShowCGX(unsigned char *cgx, unsigned short *scr)
	{
	register short cx,cy,x,y;
	unsigned char buffer[64];
	

	for (cy=0;cy<32;cy++)
		{
		for (cx=0;cx<32;cx++)
			{
			getcharbytes(buffer,cgx+ (scr[cx+cy*32] & 0x3ff)*32 );
			for (y=0;y<8;y++)
				{
				for (x=0;x<8;x++)
					{
					tw->FGcolor(buffer[x+y*8]);
					tw->plot(cx*8+x,cy*8+y);
					}
				}
			}
		}

	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
void DoFonts()
	{
	int newx=oldx,newy=oldy;

	if (!scrfile || !cgxfile) return;

	if (tw->mouse())
		{
		if (tw->input.flags&M_MOTION)
			{
			newx = GridCharX(tw->input.x); newy = GridCharY(tw->input.y);
			}
		if (tw->input.flags&M_KEYPRESS)
			{
			switch(tw->input.key)
				{
				case KB_UP:
					if (newy>0) newy--;
					break;
				case KB_LEFT:
					if (newx>0) newx--;
					break;
				case KB_DOWN:
					if (newy<256/ysize-1) newy++;
					break;
				case KB_RIGHT:
					if (newx<CHARSPERLINE-1) newx++;
					break;
				default:
					break;
				}
			if (newx!=oldx || newy!=oldy)
				{
				if (newx==-1) newx=0;
				if (newy==-1) newy=0;
				}
			}

		if (WhichChar(newx*xsize,newy*ysize) == -1)
			{
			newx = -1; newy = -1;
			}

// Check if cursor needs redrawing

		if (oldx != newx || oldy != newy)
			{
			DrawCursor(oldx,oldy);
			DrawCursor(newx,newy);
			}

// Check for gadgets that have been selected

		if ((tw->input.gflags&GF_SELECTED))
			{
			switch(tw->input.gadget)
				{
// Save
				case 1:
					SaveFont();
					break;
// Load
				case 2:
					CloseMode(MODE_TEXT);
					OpenMode(MODE_TEXT);
					return;
// Compression on/off
				case 3:
					break;
// Set grid
				case 4:
					SetGrid();
					break;

				default:
					break;
				}
			}
// Now check if the mouse button was pushed

		if ((((tw->input.flags&M_KEYPRESS) && (tw->input.key==' '||tw->input.key==13)) || ((tw->input.flags&M_BUTTON_DOWN) && (tw->input.buttons&M_LEFT))) && oldx != -1 && oldy != -1)
			{
			int n;

			if ((n = WhichChar(oldx*xsize,oldy*ysize)) != -1)
				{
				if (FindSelected(n)==-1) AddSelected(n);
				SetChar(FindSelected(n));
				if (mapping[FindSelected(n)]==0) DelSelected(n);
				}
			}

		}
	}
//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
void OpenFonts()
	{
	cgxfile = NULL; scrfile = NULL;

	tw = new Window(64,64,64+255,64+320,BLACK,"Font Conversion",W_BACKINGSTORE|W_MOTIFBORDER);

	tw->Direct();

	if (!(cgxfile = getfilename("CGX File",&cgxpath, "", FR_SETPATH))) return;
	fnsplit(cgxfile,NULL,NULL,fontfileroot,NULL);
	cgxfile = LoadFile(cgxfile);
	if (!(scrfile = getfilename("SCR File",&scrpath, "", FR_SETPATH))) return;
	scrfile = LoadFile(scrfile);

// Save and load gadgets
	tw->setfont(nicefont);
	*tw << WT_BLACK;			
	new Gadget(tw,0,tw->MaxY()-(GADGETSIZEY(tw)*2),0,0,"SAVE",1,G_TEXTHIGHLIGHT|G_BOXHIGHLIGHT|G_BOXTEXT,KB_ALTS);
	new Gadget(tw,0,tw->MaxY()-(GADGETSIZEY(tw)*1),0,0,"LOAD",2,G_TEXTHIGHLIGHT|G_BOXHIGHLIGHT|G_BOXTEXT,KB_ALTL);
	new Gadget(tw,96,tw->MaxY()-(GADGETSIZEY(tw)*2),0,0,"COMPRESS",3,G_TEXTHIGHLIGHT|G_BOXHIGHLIGHT|G_BOXTEXT|G_TOGGLE,KB_ALTC);
	new Gadget(tw,96,tw->MaxY()-(GADGETSIZEY(tw)*1),0,0,"SET GRID",4,G_TEXTHIGHLIGHT|G_BOXHIGHLIGHT|G_BOXTEXT,KB_ALTG);


	ShowCGX((unsigned char *)cgxfile,(unsigned short *)scrfile);
	DrawGrid(xsize = 24,ysize = 32);

	oldx = -1; oldy = -1;
	}

//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
void CloseFonts()
	{
	delete tw;
	if (cgxfile) FreeFile(cgxfile);
	if (scrfile) FreeFile(scrfile);
	}

