/*
 *	Graphics support for T3X programs.
 *	Portable routines.
 *	Copyright (C) 1997 Nils M. Holm.
 *	(Taken from the SGFX library and slightly modified).
 *	See the file LICENSE for conditions of use.
 */

#ifdef GRAPHICS_EXT

#ifdef plan9
#include <u.h>
#include <libc.h>
#include <stdio.h>
#else
#include <stdlib.h>
#ifdef __TURBOC__
 #ifndef LIB
  #define open	_open
  #define read	_read
  #define close	_close
 #endif
#endif

#endif

#include "gfx.h"


#define POOLSIZE	1536

uchar	**Vfont;
char	Pool[POOLSIZE];
int	Pt = 0;
int	Gfx_open = 0;
int	Vfx, Vfy;


#ifdef msdos
str_len(s) char *s; {
	int	k = 0;

	while (s[k]) k++;
	return k;
}

str_cpy(a, b) char *a, *b; {
	int	k = 0;

	while (b[k]) {
		a[k] = b[k++];
	}
	a[k] = 0;
}

str_cat(a, b) char *a, *b; {
	int	k = str_len(a), m = 0;

	while (b[m]) {
		a[k++] = b[m++];
	}
	a[k] = 0;
}
#else
#define str_cat	strcat
#define str_cpy	strcpy
#define str_len	strlen
#endif


void *allocate(size)
unsigned	size;
{
	void	*a;

	if (size + Pt >= POOLSIZE) return(NULL);
	a = &Pool[Pt];
	Pt += size;
	return(a);
}


uchar **g_loadvf(file, statusp)
char	*file;
int	*statusp;
{
	int	infd;
	uchar	buf[4], ch;
	int	n, i, k;

	if ((Vfont = (uchar **) allocate(sizeof(uchar *) * 128)) == NULL) {
		*statusp = GFX_NOMEM;
		return(NULL);
	}

	if ((infd = open(file, 0)) < 0) {
		*statusp = GFX_NOFILE;
		Pt = 0;
		return(NULL);
	}

	if (	read(infd, buf, 4) != 4 ||
		memcmp(buf, GFX_MAGIC, 4)
	) {
		close(infd);
		Pt = 0;
		*statusp = GFX_BADFILE;
		return(NULL);
	}

	for (i=0; i<32; i++) Vfont[i] = NULL;

	if ((Vfont[0] = (uchar *) allocate(3)) == NULL) {
		close(infd);
		Pt = 0;
		*statusp = GFX_NOMEM;
		return(NULL);
	}

	Vfont[0][0] = 0;
	read(infd, &ch, 1); Vfont[0][1] = Vfx = ch;
	k = read(infd, &ch, 1); Vfont[0][2] = Vfy = ch;

	while (k > 0 && i < 128) {
		read(infd, &ch, 1); n = ch;
		if ((Vfont[i] = (uchar *) allocate(n+1)) == NULL) {
			close(infd);
			Pt = 0;
			*statusp = GFX_NOMEM;
			return(NULL);
		}
		Vfont[i][0] = n;
		k = n? read(infd, &Vfont[i][1], n): 1;
		i++;
	}

	close(infd);

	if (i<128) {
		Pt = 0;
		*statusp = GFX_BADFILE;
		return(NULL);
	}

	*statusp = GFX_OK;
	return(Vfont);
}


extern	Fx, Fy;
void g_fontsize(scale, fxy)
int	scale;
short	fxy[];
{
	fxy[0] = GFX_FSX * scale;
	fxy[1] = GFX_FSY * scale;
}


int g_copyfont(area, buffer)
ushort	*area;
uchar	*buffer;
{
	int	i, j, bt = 0;

	for (i=0; i<128; i++) {
		if (area && buffer) {
			area[i] = bt;
			if (!Vfont[i]) {
				buffer[bt] = 0;
				j = 0;
			}
			else {
				for (j=0; j<=Vfont[i][0]; j++)
					buffer[bt+j] = Vfont[i][j];
			}
		}
		bt += (j+1);
	}
	return bt;
}


/*****
void g_unloadvf(vfont)
uchar	**vfont;
{
	Pt = 0;
}
*****/


void g_putv(x, y, scale, mode, v)
int	x, y, scale, mode;
uchar	*v;
{
	int	dx, dy, nx, ny, i;
	int	cx, cy;

	cx = GFX_FSX / Vfx * scale;
	cy = GFX_FSY / Vfy * scale;
	for (i=1; i<=v[0]; i++) {
		switch((v[i] & 0x70) >> 4) {
			case 0: dx =  0; dy = -1; break;
			case 1: dx =  1; dy = -1; break;
			case 2: dx =  1; dy =  0; break;
			case 3: dx =  1; dy =  1; break;
			case 4: dx =  0; dy =  1; break;
			case 5: dx = -1; dy =  1; break;
			case 6: dx = -1; dy =  0; break;
			case 7: dx = -1; dy = -1; break;
		}
		nx = x + (dx * (v[i] & 15) * cx);
		ny = y + (dy * (v[i] & 15) * cy);
		if (v[i] & 0x80) g_line(x, y, nx, ny, mode);
		x = nx;
		y = ny;
	}
}


void g_putc(x, y, scale, mode, c)
int	x, y, scale, mode, c;
{
	if (!Vfont[c]) return;
	g_putv(x, y, scale, mode, Vfont[c]);
}


void g_puts(x, y, scale, mode, s)
int	x, y, scale, mode;
uchar	*s;
{
	int	cx = GFX_FSX * scale;

	while (*s) {
		g_putv(x, y, scale, mode, Vfont[*s++]);
		x += cx;
	}
}


void g_error(char *s);
void g_error(s)
char	*s;
{
	if (Gfx_open) g_end();
	write(2, "TXX: ", 5);
	write(2, s, str_len(s));
	write(2, "\n", 1);
#ifdef plan9
	exits(s);
#else
	_exit(2);
#endif
}


void g_init(void);
void g_init() {
	int	p;
	char	fp[256];

	Gfx_open = 0;
	if (_g_init()) g_error("Could not initialize graphics device");
	Gfx_open = 1;
	e_init();
	if (g_loadvf(GFX_SYSFONT, &p) == NULL) {
		str_cpy(fp, FNTPATH);
		str_cat(fp, "/");
		str_cat(fp, GFX_SYSFONT);
		if (g_loadvf(fp, &p) == NULL) {
			g_error(p == GFX_NOMEM? "Not enough memory":
				p == GFX_NOFILE? "Cannot open font file":
				p == GFX_BADFILE? "Invalid font file":
				"Unknown error in g_init()");
		}
	}
}


#endif	/* GRAPHICS_EXT */
