#ifdef LINUX
#include <stdio.h>

#else

#include <ultra64.h>
#include <stdarg.h>
#include "font.h"

#endif

#include "stdio.h"

#ifndef LINUX

#ifdef 0
void	printm(fb,drawbuffer,m)
FB	*fb;
int	drawbuffer;
Mtx	*m;
{
	Mtx_i	*Mi;	/* Matrix int portion */
	Mtx_f	*Mf;	/* Matrix frac portion */

	/* pointer abuse */
	Mi = (Mtx_i *)&(m->m[0][0]);
	Mf = (Mtx_f *)&(m->m[2][0]);

	printf(fb,drawbuffer,"x0 %wd y0 %wd z0 %wd w0 %wd\n",Mi->x0,Mi->y0,Mi->z0,Mi->w0);
	printf(fb,drawbuffer,"x1 %wd y1 %wd z1 %wd w1 %wd\n",Mi->x1,Mi->y1,Mi->z1,Mi->w1);
	printf(fb,drawbuffer,"x2 %wd y2 %wd z2 %wd w2 %wd\n",Mi->x2,Mi->y2,Mi->z2,Mi->w2);
	printf(fb,drawbuffer,"xt %wd yt %wd zt %wd w  %wd\n",Mi->xt,Mi->yt,Mi->zt,Mi->w);

	printf(fb,drawbuffer,"x0 %wu y0 %wu z0 %wu w0 %wu\n",Mf->x0,Mf->y0,Mf->z0,Mf->w0);
	printf(fb,drawbuffer,"x1 %wu y1 %wu z1 %wu w1 %wu\n",Mf->x1,Mf->y1,Mf->z1,Mf->w1);
	printf(fb,drawbuffer,"x2 %wu y2 %wu z2 %wu w2 %wu\n",Mf->x2,Mf->y2,Mf->z2,Mf->w2);
	printf(fb,drawbuffer,"xt %wu yt %wu zt %wu w  %wu\n",Mf->xt,Mf->yt,Mf->zt,Mf->w);
}
#endif

void	blit(fb,x,y,wd,ht,src,dst)
FB	*fb;
u16	x,y,wd,ht;
u16	*src,*dst;
{
	int	tx,ty;

	for (ty=0; ty<ht; ty++)
		for (tx=0; tx<wd; tx++)
			dst[(ty+y)*fb->screen_wd+(tx+x)] = src[ty*wd+tx];
}

#endif

void	printf(FB *fb, int currfb, char *fmt, ...)
{
	va_list	ap;
	char	*instr,*outstr;
	char	printme[64];
	int		done=0,nbytes=0,bsigned,digits,fmtdone=0;
	char	*pstr;
	Arg	arg;

	va_start(ap, fmt);

	printme[63]='\0';

	instr = fmt;
	outstr = printme;

	while (!done) {
		if ( *instr == '%' ) {
			instr++;
			nbytes = 4;
			bsigned = 1;
			fmtdone=0;

			while ( !fmtdone ) {
				switch ( *instr ) {
					case 'l' :
						nbytes = 4;
						break;
					case 'w' :
						nbytes = 2;
						break;
					case 'b' :
						nbytes = 1;
						break;

					case 'c' :
						arg.ui = va_arg(ap,unsigned int);
						if (arg.ui == '\n') {
							*outstr++ = '\\';
							*outstr++ = 'n';
						}
						else
						if (arg.ui == '\0') {
							*outstr++ = '\\';
							*outstr++ = '0';
						}
						else
							*outstr++ = arg.ui;
						fmtdone=1;
						break;
					case 'd' :
						if ( nbytes == 4 ) arg.i = va_arg(ap,int);
						if ( nbytes == 2 ) arg.i = (int)va_arg(ap,int);
						cvt(10,&outstr,arg,nbytes,bsigned=1,0); 
						fmtdone=1;
						break;
					case 'u' :
						if ( nbytes == 4 ) arg.ui = va_arg(ap, unsigned int);
						if ( nbytes == 2 ) arg.ui = (unsigned int)va_arg(ap,unsigned int);
						cvt(10,&outstr,arg,nbytes,bsigned=0,0); 
						fmtdone=1;
						break;
					case 'x' :
						if ( nbytes == 1 )
							arg.ui = (unsigned int)va_arg(ap, unsigned char);
						if ( nbytes == 2 )
							arg.ui = (unsigned int)va_arg(ap, unsigned short);
						if ( nbytes == 4 )
							arg.ui = (unsigned int)va_arg(ap, unsigned int);
						cvt(16,&outstr,arg,nbytes,bsigned=0,0);
						fmtdone=1;
						break;
					case 'f' :
						/* *********** NOTE *********** */
						/* for some reason gcc passes floats as double */
						/* *********** NOTE *********** */
						nbytes=8;
						arg.f = va_arg(ap, double);
						cvt(10,&outstr,arg,nbytes,bsigned,8); 
						fmtdone=1;
						break;
					case 's' :
						pstr = va_arg(ap, char *);
						while ( *pstr != '\0' )
							*outstr++ = *pstr++;
						fmtdone=1;
						break;
					default : 
						fmtdone=1;
						break ;
				} /* switch */
				instr++;
			} /* !fmtdone */
		}
		else {
			if ( *instr == '\0' ) {
				*outstr++ = *instr++;
				done = 1;
			}
			else
				*outstr++ = *instr++;
		}
	}
	va_end(ap);

	*outstr++ = '\0';	/* might save our butts */
	rasterize(fb,currfb,printme);
}

void	cvt(base,ostr,arg,nbytes,bsign,digits)
int		base;
char	**ostr;
Arg		arg;
int		nbytes;
int		bsign;
int		digits;
{
	char	chars[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',};
	char	outsign,outtmpint[64],outtmpfrac[64];
	int	cvtint,cvtfrac,outint,outfrac,i,firstchar;
	char	*tmpstr;

	outsign = ' ';

	tmpstr = *ostr;

	 /* int */
	if ( digits == 0 ) {
		/* fractional portion=0 */
		outfrac = 0;
		if ( nbytes == 1 ) {
			if ( base==10 ) outint = 3;
			if ( base==16 ) outint = 2;

			if ( bsign ) {
				cvtint = arg.c;
				if ( cvtint < 0 ) {
					outsign = '-';
					cvtint = -cvtint;
				}
			}
			else
				cvtint = arg.uc;
		}

		if ( nbytes == 2 ) {
			if ( base==10 ) outint = 5;
			if ( base==16 ) outint = 4;

			if ( bsign ) {
				cvtint = arg.s;
				if ( cvtint < 0 ) {
					outsign = '-';
					cvtint = -cvtint;
				}
			}
			else
				cvtint = arg.us;
		}

		if ( nbytes == 4 ) {
			if ( base==10 ) outint = 10;
			if ( base==16 ) outint = 8;

			if ( bsign ) {
				cvtint = arg.i;
				if ( cvtint < 0 ) {
					outsign = '-';
					cvtint = -cvtint;
				}
			}
			else
				cvtint = arg.ui;
		}

	}
	/* else float */
	else
	{
		outfrac = 0;
		outint = 0;
		if ( base != 10 ) return;

		if ( nbytes == 1 ) {
			cvtint = 0;	/* integer portion */
			outint = 1;
			outfrac = 3;

			if ( bsign ) {
				cvtfrac = arg.c;
				if ( cvtfrac < 0 ) {
					outsign = '-';
					cvtfrac = -cvtfrac;
				}
			}
			else
				cvtfrac = arg.uc;
		}

		if ( nbytes == 2 ) {	/* s15.16 */
			outfrac = 5;
			outint = 5;
			cvtint = (arg.i >> 16) & 0xFF;
			if ( cvtint < 0 ) {
				outsign = '-';
				cvtint = -cvtint;
			}

			cvtfrac = arg.ui & 0xFF;
		}

		if ( nbytes == 8 ) {	/* single float=gcc passes doubles */
			outint = 10;
			outfrac = 4;
			if ( arg.f < 0 ) {
				outsign = '-';
				cvtint = (int)-arg.f;
				cvtfrac = (int) ( ( -(arg.f) - (double)cvtint ) * 10000.0 );
			}
			else {
				cvtint = (int)arg.f;
				cvtfrac = (int)( (arg.f - (double)cvtint) * 10000.0 );
			}
		}
	}

	/* 1 char at start for period */
	for (i=outfrac; i>0; i--) {
		if ( base == 10 ) {
			outtmpfrac[i] = chars[cvtfrac % base];
			cvtfrac /= base;
		}
		if ( base == 16 ) {
			outtmpfrac[i] = chars[cvtfrac & 0xF];
			cvtfrac = cvtfrac >> 4;
		}
	}
	outtmpfrac[i] = '.';

	/* 1 char at start for sign */
	for (i=outint; i>0; i--) {
		if ( base == 10 ) {
			outtmpint[i] = chars[cvtint % base];
			cvtint /= base;
		}
		if ( base == 16 ) {
			outtmpint[i] = chars[cvtint & 0xF];
			cvtint = cvtint >> 4;
		}
	}

	/* supress zeros */
	if ( base != 16 ) {
		for (i=1; i<outint; i++) {
			if ( outtmpint[i] != '0' )	break;
		}
		firstchar = i-1;
		/* save sign */
		if ( outsign == '-' )
			outtmpint[firstchar] = outsign;
		else
			firstchar++;
	}
	else
		firstchar = 1;


	for (i=firstchar; i<(outint+1); i++)
		*tmpstr++ = outtmpint[i];

	for (i=0; i<outfrac; i++)
		*tmpstr++ = outtmpfrac[i];

	*ostr = tmpstr;
}

#ifdef LINUX
void	rasterize(fb,string)
u16	*fb;	/* framebuffer */
char	*string;
{
	puts(string);
}

#else

void	rasterize(fb,currfb,string)
FB	*fb;
int	currfb;
char	*string;
{
	int	i,offset,x,y;
	u16	*mem,*tfb,col;

	x = fb->x * FONT_W;		/* on a font/byte boundary */
	y = fb->y * FONT_H;	/* on a font/byte boundary */
	col = fb->color;

	if ( currfb )
		tfb = fb->fb1;
	else
		tfb = fb->fb0;

	while (*string != '\0')
	{
		if ( *string == '\n' ) {
			y += FONT_H;
			x = fb->startx * FONT_W;
			string++;
			continue;
		}

		if (x >= fb->screen_wd) {
			y += FONT_H;
			x = fb->startx * FONT_W;
		}
		if (y >= fb->screen_ht) {
			y -= FONT_H;
		}

		offset = *string * FONT_H;
		for (i=0; i<FONT_H; i++,offset++)
		{
			mem = &(tfb[(y+i) * fb->screen_wd + x]);

			if (font[offset]&(1<<7))	*mem ^= col;
			*mem |= 1; mem++;
			if (font[offset]&(1<<6))	*mem ^= col;
			*mem |= 1; mem++;
			if (font[offset]&(1<<5))	*mem ^= col;
			*mem |= 1; mem++;
			if (font[offset]&(1<<4))	*mem ^= col;
			*mem |= 1; mem++;
			if (font[offset]&(1<<3))	*mem ^= col;
			*mem |= 1; mem++;
			if (font[offset]&(1<<2))	*mem ^= col;
			*mem |= 1; mem++;
			if (font[offset]&(1<<1))	*mem ^= col;
			*mem |= 1; mem++;
			if (font[offset]&(1<<0))	*mem ^= col;
			*mem |= 1; mem++;
		}
		x+=FONT_W;
		string++;
	}
	fb->x = x / FONT_W;
	fb->y = y / FONT_H;
}
#endif
