[comp.sources.atari.st] v01i033: vdit -- VDI interface with GDOS font support

koreth@ssyx.ucsc.edu (Steven Grimm) (05/20/88)

Submitted-by: egisin@watmath.waterloo.edu (Eric Gisin)
Posting-number: Volume 1, Issue 33
Archive-name: vdit

This is a partial PD VDI interface with support for loading GDOS fonts.
See the file "readme" at the beginning of the shell archive.
A set of PD GDOS fonts has been posted to comp.binaries.atari.st.

[I don't know which C compiler was used to develop this program, but the
 code looks fairly non-compiler-specific. -sg]

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by watmath!egisin on Tue May 17 11:30:45 EDT 1988
# Contents:  readme gfont.h loadfont.c vdi.c vdi.h vdit.c
 
echo x - readme
sed 's/^@//' > "readme" <<'@//E*O*F readme//'
This package contains a partial public domain VDI interface.
It includes a working interface to the undocumented
VDI "load_fonts" and "unload_fonts" functions,
which allow you to use other fixed and proportional fonts with GEM's VDI.
See vdit.c for documentation and an example.
Most of vdi.h/vdi.c is untested, except for the functions
used by vdit.c and by my VT200 emulator.
If you make any fixes or enhancements to the VDI I'd like to see them.
I have also posted a public domain fixed width font family
suitable for use with terminal emulators to comp.binaries.atari.st.

vdi.h:		structure and macro definitions for VDI
vdi.c:		interface functions for VDI
gfont.h:	definition of a GDOS font
loadfont.c:	load GDOS fonts from disk
vdit.c:		a simple program to load fonts and display them

	Eric Gisin, egisin@math.UWaterloo.CA
@//E*O*F readme//
chmod u=rw,g=r,o=r readme
 
echo x - gfont.h
sed 's/^@//' > "gfont.h" <<'@//E*O*F gfont.h//'
/*
 * Internal representation of GDOS font. Author unknown.
 */

typedef struct {
	short	font_id;	/* Font face identifier, 1 -> system font */
	short	size;		/* Font size in points */
	char	name[32];	/* Font name */
	short	first_ade;	/* Lowest ADE value in the face */
	short	last_ade;	/* Highest ADE value in the face */
	short	top;		/* Distance of top line relative to baseline */
	short	ascent;		/* Distance of ascent line relative to baseline */
	short	half;		/* Distance of half line relative to baseline */
	short	descent;	/* Distance of decent line relative to baseline */
	short	bottom;		/* Distance of bottom line relative to baseline */
				/* All distances are measured in absolute values */
				/* rather than as offsets. They are always +ve */
	short	max_char_width;	/* Width of the widest character in font */
	short	max_cell_width;	/* Width of the widest cell character cell in face */
	short	loffset;	/* Left Offset see Vdi appendix G */
	short	roffset;	/* Right offset   "      "     " */
	short	thicken;	/* Number of pixels by which to thicken characters */
	short	ul_size;	/* Width in pixels of the underline */
	short	lighten;	/* The mask used to lighten characters */
	short	skew;		/* The mask used to determine when to perform */
			/* additional rotation on the character to perform skewing */
	short	flags;		/* Flags */
				/*  $01 default system font */
				/*   02 horiz offset table should be used */
				/*   04 byte-swap flag (thanks to Motorla idiots) */
				/*   08 mono spaced font */
	short *	hoff_base;	/* Offset to horizontal offset table */
	short *	coff_base;	/* Offset to character offset table */
		/* font bitmap is byte[width][height], width must be even */
	short *	form_base;	/* Offset to font data */
	short	form_width;	/* Form width (#of bytes/scanline in font data) */
	short	form_height;	/* Form height (#of scanlines in font data) */
	char *	next_font;	/* Pointer to next font in face */
} GFont;

@//E*O*F gfont.h//
chmod u=rw,g=r,o=r gfont.h
 
echo x - loadfont.c
sed 's/^@//' > "loadfont.c" <<'@//E*O*F loadfont.c//'
/*
 * Load GDOS font, Eric Gisin.
 * loads a font from file name.FED. Tries in ., then $FONTDIR, then A:\FONT.
 * does not have enough error checking.
 */

#define	NULL	0L
#include <gfont.h>

#define	open(file, mode)	gemdos(0x3D, file,mode)
#define close(fd)		gemdos(0x3E, fd)
#define	read(fd, buf, size)	gemdos(0x3F, fd,(long)size,buf)

#define	Swapw(v)	(v) = ((v)<<8) | ((v)>>8)&0x00FF
#define	Swapl(v)	(v) = ((v)>>24)&0x000000FF | ((v)>>8)&0x0000FF00

char * font_dir = NULL;
extern char * malloc();
extern char * getenv();

/*
 * load GDOS font, return pointer to font.
 */
GFont *
load_font(name)
	char *	name;
{
	int fd, i, n, size;
	char temp [64], * p = temp;
	char * q, * tcwd;
	int swapf;
	register GFont*	fp;

	if (font_dir == NULL)
		font_dir = getenv("FONTDIR");
	if (font_dir == NULL)
		font_dir = "A:\\font";

	fp = malloc(sizeof(GFont));
	if (fp == NULL) return NULL;

	/* set up font file's path name */
	for (q = font_dir; *q; )
		*p++ = *q++;
	*p++ = '\\';
	tcwd = p;
	for (q = name; *q; )
		*p++ = *q++;
	for (q = ".fed"; *q; )
		*p++ = *q++;
	*p = '\0';

	/* open font file */
	fd = open(tcwd, 0);		/* try name.fed */
	if (fd < 0)
		fd = open(temp, 0);
	if (fd < 0)
		return (0);

	/* read header */
	size = sizeof(GFont);
	read(fd, fp, size);		/* should (char *)fp */

	swapf = !(fp->flags&0x0004);
	if (swapf) {
		/* swap header words and longs */
		Swapw(fp->font_id);		Swapw(fp->size);
		Swapw(fp->first_ade);		Swapw(fp->last_ade);
		Swapw(fp->top);			Swapw(fp->ascent);
		Swapw(fp->half);		Swapw(fp->descent);
		Swapw(fp->bottom);
		Swapw(fp->max_char_width);	Swapw(fp->max_cell_width);
		Swapw(fp->loffset);		Swapw(fp->roffset);
		Swapw(fp->thicken);		Swapw(fp->ul_size);
		/* Swapw(fp->flags); */		Swapl(fp->hoff_base);
		Swapl(fp->coff_base);		Swapl(fp->form_base);
		Swapw(fp->form_width);		Swapw(fp->form_height);
	}

	/* read offset table */
	n = fp->last_ade + 1 - fp->first_ade + 1;
	size = n * sizeof(short);
	fp->coff_base = malloc(size);
	if (fp->coff_base == NULL) return NULL;
#if 0
	for (i = 0; i < fp->first_ade; i++)
		fp->coff_base[i] = 0;
#endif
	read(fd, fp->coff_base, size);
	if (swapf)		/* swap offset array words */
		for (i = 0; i < n; i++)
			Swapw(fp->coff_base[i]);

	/* read bitmap */
	size = fp->form_width*fp->form_height;
	fp->form_base = malloc(size);
	if (fp->form_base == NULL) return NULL;
	read(fd, fp->form_base, size);

	close(fd);
	return fp;
}

/* load a set of fonts, linking them for vst_load_font */
GFont *
load_fonts(fontv)
	char **fontv;
{
	int errors = 0;			/* should return */
	GFont * fhead = NULL;
	GFont * f, ** fpp = &fhead;

	/* load fonts, create linked list fhead */
	while (*fontv != NULL) {
		*fpp = f = load_font(*fontv++);
		if (f != NULL)
			fpp = &f->next_font;
		else
			errors++;
	}
	return fhead;
}


@//E*O*F loadfont.c//
chmod u=rw,g=r,o=r loadfont.c
 
echo x - vdi.c
sed 's/^@//' > "vdi.c" <<'@//E*O*F vdi.c//'
/*
 * PD mini VDI interface, Eric Gisin
 */

#include <osbind.h>
#include <vdi.h>
#include <gfont.h>

#define	NULL	0L

static	short ct [12];		/* VDI/AES control block */
static	short ii [140];
static	short pi [16];
static	short io [47];
static	short po [16];
struct Params v_ps = {ct, ii, pi, io, po, NULL};
struct Params v_pt = {ct, ii, pi, io, po, NULL}; /* modifiable version of v_ps */

/* VDI operations with no parameters */
vdi_none(h, op)
	short h, op;
{
	vdi_setup(op, h, 0, 0);
	vdi(&v_ps);
}

/* VDI operations with one integer parameter */
vdi_int1(h, op, i)
	short h, op;
	short i;
{
	ii[0] = i;
	vdi_setup(op, h, 1, 0);
	vdi(&v_ps);
	return io[0];
}

/* VDI operations with one point parameter */
vdi_pnt1(h, op, x, y)
	short h, op;
	short x, y;
{
	pi[0] = x, pi[1] = y;
	vdi_setup(op, h, 0, 1);
	vdi(&v_ps);
}

vdi_pnt4v(h, op, fn, pnt)
	short h;
	short op, fn;
	short *pnt;
{
	register int i;

	for (i = 0; i < 4; i++)
		pi[i] = pnt[i];
	vdi_setup(op, h, 0, 2);
	ct[5] = fn;
	vdi(&v_ps);
}

/* open virtual work */
v_opnvwk(in, hp, out) /* todo: vdi_open */
	short in[];
	short *hp;
	short out[];
{
	v_pt.ii = in;
	v_pt.io = out;
	v_pt.pi = pi;
	v_pt.po = out+34;
	vdi_setup(100, *hp, 11, 0);
	vdi(&v_pt);
	*hp = ct[6];
}

vdi_cpyfm(h, op, mode, sdr, src, dst)
	short h, op;
	short mode;
	short *sdr;			/* source/dest rectangles */
	Form *src, *dst;		/* source/dest forms */
{
	register int i;

	*((Form**)&ct[7]) = src;
	*((Form**)&ct[9]) = dst;
	ii[0] = mode;
	for (i = 0; i < 8; i++)
		pi[i] = sdr[i];
/***
	*((Rect*)&pi[0]) = sdr[0];
	*((Rect*)&pi[4]) = sdr[1];
***/
	vdi_setup(op, h, 1, 4); vdi(&v_ps);
}

vst_alignment(h, x, y, xp, yp) 
	short h;
	short x, y;
	short *xp, *yp;
{
	ii[0] = x, ii[1] = y;
	vdi_setup(39, h, 2, 0);
	vdi(&v_ps);
	*xp = io[0], *yp = io[1];
}

v_gtext(h, x, y, s)
	short h;
	short x, y;
	unsigned char *s;
{
	register int i;

	for (i = 0; *s != 0 && i < 140; i++)
		ii[i] = *s++;
	pi[0] = x; pi[1] = y;
	vdi_setup(8, h, i, 1);
	vdi(&v_ps);
}

vqt_attributes(h, at)
	short *at;	/*struct vdi_tattr *at;*/
{
	v_pt.io = at; v_pt.po = at+6;
	vdi_setup(38, h, 0, 0);
	vdi(&v_pt);
}

static char *vdi_scratch = NULL;	/* VDI/LineA scratch buffer */

#if 0
/* load GDOS fonts using user's vx_load_fonts */
vst_load_fonts(h, select)
	short h, select;
{
	GFont * fp;
	extern char * malloc();
	extern GFont * vx_load_fonts();	/* user routine to load fonts */

	if (vdi_scratch == NULL)
		vdi_scratch = malloc(1024);	/* scratch buffer */
	*((char **)&ct[7]) = vdi_scratch;
	ct[9] = 256;			/* offset of enlargment buffer */
	*((char **)&ct[10]) = fp = vx_load_fonts(select); /* GDOS font list */
	if (fp == 0)
		return 0;
	vdi_setup(119, h, 0, 0);
	vdi(&v_ps);
	return io[0];			/* number of fonts loaded */
}

vst_unload_fonts(h)
{
	extern void vx_unload_fonts();

	vdi_setup(120, h, 0, 0);
	vdi(&v_ps);
	vx_unload_fonts();
}
#endif

/* load GDOS fonts using fp */
/* make sure your ct array is large enough if you port this */
vstx_load_fonts(h, fp)
	short h;
	GFont *fp;
{
	extern char * malloc();

	if (vdi_scratch == NULL)
		vdi_scratch = malloc(1024);	/* scratch buffer */
	*((char **)&ct[7]) = vdi_scratch;
	ct[9] = 256;			/* offset of enlargment buffer */
	*((char **)&ct[10]) = fp;
	if (fp == NULL)
		return 0;
	vdi_setup(119, h, 0, 0);
	vdi(&v_ps);
	return io[0];			/* number of fonts loaded */
}

vstx_unload_fonts(h)
{
	vdi_setup(120, h, 0, 0);
	vdi(&v_ps);
}

#if 0
/*
 * This code invokes VDI ESC 102 code (page 440 in the July '86
 * Abacus ST Internals BIOS listing).  I decompiled some library
 * routines to see how to make it work.  It may not work on new ROMS.
 * Martin Minow, Arlington MA 02174.  This routine is in the public domain.
 */
vt_set_font(fp)
	register GFont * fp;
{
	(*(GFont**)&ii[0]) = fp;	/* Put font info in intin[0] */
	vdi_setup(5, 0, 2, 0);
	ct[5] = 102;
	vdi(&v_ps);
}
#endif

@//E*O*F vdi.c//
chmod u=rw,g=r,o=r vdi.c
 
echo x - vdi.h
sed 's/^@//' > "vdi.h" <<'@//E*O*F vdi.h//'
/*
 * PD mini VDI interface, Eric Gisin
 */

/* Memory Form descriptor */
typedef struct {
	short *	base;
	short	width;
	short	height;
	short	wwidth;
	short	standard;
	short	planes;
	short	resv1, resv2, resv3;
} Form;

/* Rectangle descriptor */
typedef struct {
	short	x1, y1;		/* upper left */
	short	x2, y2;		/* lower right */
} Rect;

/* VDI/AES parameter block */
struct Params {
	short  *ct;			/* control */
	short  *ii;			/* ints in */
	short  *pi;			/* points in */
	short  *io;			/* ints out */
	short  *po;			/* points out */
	short  *xx;
};

#define	vdi(params)		bdos(115, params)
#define	vdi_setup(f, h, ii, pi) {ct[0] = f; ct[6] = h; ct[1] = pi; ct[3] = ii; }

#define	v_clsvwk(h)		vdi_none(h, 101)
#define	v_clrwk(h)		vdi_none(h, 3)
#define	vro_cpyfm(h, m, r, s, d) vdi_cpyfm(h, 109, m, r, s, d)
#define	vrt_cpyfm(h, m, r, s, d) vdi_cpyfm(h, 121, m, r, s, d)
#define	vsf_color(h, c)		vdi_int1(h, 25, c)
#define	vsf_perimeter(h, f)	vdi_int1(h, 104, f)
#define	vsf_interior(h, s)	vdi_int1(h, 23, s)
#define	vsf_style(h, s)		vdi_int1(h, 24, s)
#define	vst_color(h, c)		vdi_int1(h, 22, c)
#define	vst_effects(h, e)	vdi_int1(h, 106, e)
#define	vst_point(h, s)		vdi_int1(h, 107, s)
#define	vst_rotation(h, a)	vdi_int1(h, 13, a)
#define	vst_font(h, f)		vdi_int1(h, 21, f)
#define	vswr_mode(h, m)		vdi_int1(h, 32, m)
#define	vst_height(h, ht)	vdi_pnt1(h, 12, 0, ht)
#define	v_bar(h, p)		vdi_pnt4v(h, 11, 1, p)
#define	v_rbox(h, p)		vdi_pnt4v(h, 11, 8, p)
#define	v_rfbox(h, p)		vdi_pnt4v(h, 11, 9, p)
#define	v_recfl(h, p)		vdi_pnt4v(h, 114, 0, p)

@//E*O*F vdi.h//
chmod u=rw,g=r,o=r vdi.h
 
echo x - vdit.c
sed 's/^@//' > "vdit.c" <<'@//E*O*F vdit.c//'
/*
 * Sample program to load fonts, display them. Eric Gisin.
 * try: vdit -f91 fixed8 fixed9 fixed10 fixed11 fixed12
 *
 *	void vstx_load_fonts(short vdi_handle, GFont *fonts);
 *	void vstx_unload_fonts(short vdi_handle);
 *
 * These two undocumented VDI functions are used to add fonts
 * to a virtual screen. Unlike the VDI function vst_load_fonts,
 * which requires GDOS, it does not load the fonts from disk.
 * Instead you load them explicitly with load_fonts (or load_font),
 * and pass the linked list of fonts to vstx_load_fonts as "fonts".
 * To change the fonts in a virtual screen, unload then load again.
 *
 * The fonts must have valid font_id and size information.
 * The font_id is used by vst_font to select a font family.
 */

#include <vdi.h>
#include <gfont.h>

#define	NULL	0L

extern	GFont *load_fonts();

main(argc, argv)
	char ** argv;
{
	register int i;
	int font = 1, size = 10;
	short h = 1;
	short in [11];
	short out [57];

	/* parse options */
	for (i = 1; i < argc; i ++) {
		register char * arg = argv[i];
		if (arg[0]=='-') {
		    if (arg[1]=='f')
			font = atoi(&arg[2]);
		    if (arg[1]=='p')
			size = atoi(&arg[2]);
		} else
			break;
	}
		
	/* set up opnvwk parameters */
	in[0] = 1;			/* device is screen */
	in[1] = in[2] = 1;		/* line type/color */
	in[3] = in[4] = 1;		/* marker type/color */
	in[5] = in[6] = 1;		/* text font/color */
	in[7] = in[8] = in[9] = 1;	/* fill type/style/color */
	in[10] = 2;			/* raster coordinates */

	v_opnvwk(in, &h, out);
	vstx_load_fonts(h, load_fonts(&argv[i]));
	v_clrwk(h);
	i = vst_font(h, font);
	for (i = 6; i < 25; i += (i<14) ? 1 : 2) {
		vst_point(h, i);
		v_gtext(h, 0, i*16, "A test of load_fonts ?! {123<@>}");
	}
	vstx_unload_fonts(h);
	v_clsvwk(h);
	return 0;
}

@//E*O*F vdit.c//
chmod u=rw,g=r,o=r vdit.c
 
exit 0