DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T d

⟦315c10f6f⟧ TextFile

    Length: 21285 (0x5325)
    Types: TextFile
    Names: »dmdslave.c«

Derivation

└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
    └─⟦this⟧ »./DVIware/laser-setters/umd-dvi/dev/dmdslave.c« 

TextFile

/*
 * Typesetter/Terminal Emulator for the DMD 5620
 *
 *	Lou Salkind
 *	New York University
 *	Thu Apr  2 01:21:09 EST 1987
 *
 * This program was inspired by the DMD proof program
 * and the Impress typesetting language.  It is used by
 * the TeX DVIDMD driver.
 */

#include <jerq.h>
#include "layer.h"
#include "font.h"
#include "dmdcodes.h"

#define	MAXFAMILY	128	/* number of different fonts */
#define	MAXFONTNAME	16	/* maximum font string */
#define	PAGECHAR	8192	/* buffered characters to save */
#define	MAXPAGE		127

#define	SCROLLSIZE	20	/* scrolling border */
#define	PAGEPIXELS	1010	/* XXX - length of page (should be an argument) */
#define	NEWLINESIZE	16
#define CURSOR '\01'	/* cursor char in font */
#define	LINEBUFSIZE 100

#define MOVED 256

#ifdef	PAGECHAR
/* treatment of input characters */
#define	CHAR_DISCARD	0
#define	CHAR_STORE	1
#define	CHAR_FETCH	2

int savechars;
char savebuf[PAGECHAR];
char *saveptr;
#endif

#define	RoundUp(a, b)	(((a) + (b) - 1) & ~((b) - 1))

#ifdef	MPX
#undef	cursinhibit
#undef	cursallow
#define	cursinhibit()	{}
#define	cursallow()	{}
#endif

static Texture16 prompt = {
	0x0000, 0x0000, 0x0000, 0x322E, 0x4B69, 0x4369, 0x42A9, 0x42A9,
	0x42A9, 0x4229, 0x4229, 0x4229, 0x322E, 0x0000, 0x0000, 0x0000
};

Point fudge = {5, 3};	/* DAG - offsets from corners */

int dotypeset;	/* 1==typesetter, 0==terminal */
int cursvis;	/* is cursor visible */
Point org;	/* current origin */
Point typeorg;	/* current typesetter origin */
Point curpt;	/* current typesetter point relative to origin */
Point curpos;	/* current ascii terminal position */

struct line {
	char buf[LINEBUFSIZE];
	char *bufp;
};

struct line line;

struct glyph {
	Bitmap	g_bitmap;
	short	g_pxwidth;
	short	g_xoffset;
	short	g_yoffset;
};

struct fontinfo {
	char	f_name[MAXFONTNAME];
	struct glyph	f_glyph[128];
};

struct fontinfo *ftbl[MAXFAMILY];
struct fontinfo *curfont;
Point inpoint();


main()
{
	register int c;

	resetmode(DMD_TERM);
#ifdef	MPX
	P->state |= RESHAPED;	/* set window parameters */
#else
	Drect = inset(Drect, 2);
#endif	/* MPX */
	windowupdate();
	for(;;) {
		c = inchar();
		if (dotypeset)
			typeset(c);
		else {
			if(cursvis)
				term(CURSOR, 0);	/* undraw cursor */
			term(c, 1);
			while (own()&RCV)
				term(inchar(), 1);
			term(CURSOR, 0);	/* draw at new spot */
			cursvis = 1;
		}
	}
}

/* terminal emulation */
term(c, advance)
	register int c;
{
	register struct line *linep = &line;
	register Point *pp = &curpos;
	register Fontchar *fp;
	Rectangle r;
	Point p;

	if (c & 0x80) {
		if (c == DMD_TYPESET) {
			resetmode(DMD_TYPESET);
			send(DMD_ACK);
			return;
		}
		c &= 0x7F;
	}
	switch(c) {
	default:
		fp = defont.info+c;
		if (fp->width+pp->x >= Drect.corner.x)
			newline(linep, pp);
		p = *pp;
		r.origin.x = fp->x;
		r.corner.x = (fp+1)->x;
		if (advance) {
			r.origin.y = 0;
			r.corner.y = defont.height;
			bitblt(defont.bits, r, &display, p, F_STORE);
			pp->x += fp->width;
			if (linep->bufp < linep->buf+LINEBUFSIZE)
				*linep->bufp++ = c;
		} else {
			r.origin.y = fp->top;
			r.corner.y = fp->bottom;
			p.y += fp->top;
			bitblt(defont.bits, r, &display, p, F_XOR);
		}
		break;
	case '\n':
		newline(linep, pp);
		break;
	case '\7':
		ringbell();	/* DAG -- should work? */
	case 0:
		break;
	case '\r':
		pp->x=Drect.origin.x+fudge.x;	/* DAG -- changed 5 to fudge.x */
		linep->bufp = linep->buf;
		break;
	case '\013':	/* ^K: reverse linefeed */
		if(pp->y>Drect.origin.y+fudge.y+defont.height)
			pp->y-=NEWLINESIZE;
		break;
	case '\b':
		backspace(linep, pp);
		break;
	case '\014':
		formfeed(linep, pp);
		break;
	case '\t':
		pp->x=nexttab(pp->x);
		if(pp->x>=Drect.corner.x)
			newline(linep, pp);
		if(linep->bufp<linep->buf+LINEBUFSIZE)
			*linep->bufp++=c;
		break;
	}
}

/*int eightspaces=8*dispatch[' '].c_wid;*/
int eightspaces=72;

nexttab(x)
{
	register int xx = x-Drect.origin.x-fudge.x;

	return(xx-(xx%eightspaces)+eightspaces+Drect.origin.x+fudge.x);
}

backspace(linep, pp)
	register struct line *linep;
	register Point *pp;
{
	register char *p;
	register int x = Drect.origin.x+fudge.x;

	if (linep->bufp>linep->buf) {
		for (p=linep->buf; p<linep->bufp-1; p++)
			if (*p=='\t')
				x = nexttab(x);
			else
				x += defont.info[*p].width;
		pp->x = x;
		--linep->bufp;
		if (*p!='\t')
			term(*p, 0);
	}
}

newline(linep, pp)
	struct line *linep;
	register Point *pp;
{
	register cursoff=0;

	if (pp->y+2*NEWLINESIZE > Drect.corner.y-fudge.y+1) {
		/* weirdness is because the tail of the arrow may be anywhere */
		if (rectXrect(Rect(mouse.xy.x-16, mouse.xy.y-16, mouse.xy.x+16,
				mouse.xy.y+16), Drect)){
			cursinhibit();
			cursoff++;
		}
		lscroll();
		if(cursoff)
			cursallow();
	} else
		pp->y += NEWLINESIZE;
	pp->x = Drect.origin.x+fudge.x;
	linep->bufp = linep->buf;
}

lscroll()
{
	Rectangle r;

	r = Drect;
	r.origin.y += NEWLINESIZE;
	bitblt(&display, r, &display, Pt(r.origin.x, r.origin.y-NEWLINESIZE), F_STORE);
	stipple(Rpt(Pt(Drect.origin.x, Drect.corner.y-NEWLINESIZE), Drect.corner));
}

formfeed(linep, pp)
	struct line *linep;
	Point *pp;
{
	cursinhibit();
	stipple(Drect);
	cursallow();
	*pp=add(Drect.origin, fudge);
	linep->bufp=linep->buf;
}

stipple(r)
	Rectangle r;
{
	cursinhibit();
	rectf(&display, r, F_CLR);
	cursallow();
}

/* routines to handle command input */

inchar()
{
	register int c;

#ifdef	PAGECHAR
	if (savechars == CHAR_FETCH)
		return(*saveptr++ & 0377);
#endif
#ifdef	MPX
	wait(RCV);
	if (P->state&(RESHAPED|MOVED))
		windowupdate();
	c = rcvchar();
#else
	for ( ; ; ) {
		wait(RCV|KBD);
		if (own() & RCV) {
			c = rcvchar();
			break;
		}
		if (!dotypeset)
			send(kbdchar());
	}
#endif	MPX
#ifdef	PAGECHAR
	if (savechars == CHAR_STORE) {
		if (saveptr < &savebuf[PAGECHAR])
			*saveptr++ = c;
		else
			savechars = CHAR_DISCARD;
	}
#endif
	return(c&0377);
}

insignchar()
{
	register int c;

	c = inchar();
	if (c > 127)
		c -= 256;
	return(c);
}

inshort()
{
	register short i;

	i = inchar() << 8;
	i |= inchar();
	return(i);
}

Point
inpoint()
{
	Point p;

	p.x = inshort() + typeorg.x;
	p.y = inshort() + typeorg.y;
	return(p);
}

send(c)
{
	char cc = c;

	sendnchars(1, &cc);
}

/* typesetter emulation */
typeset(c)
	register int c;
{
	register struct glyph *g;
	register Bitmap *b;
	Point pprime;
	int old;

	if (c <= 127) {
		if (curfont == 0)
			return;
		g = &curfont->f_glyph[c];
		b = &g->g_bitmap; 
		if (b->base == 0) {
			curpt.x += g->g_pxwidth;
			return;
		}
		pprime = add(curpt, typeorg);
		pprime.x -= g->g_xoffset;
		pprime.y -= g->g_yoffset;
		bitblt(b, b->rect, &display, pprime, F_OR);
		curpt.x += g->g_pxwidth;
		return;
	}

	switch (c) {
	case DMD_EXIT:
		bye();
		break;
	case DMD_TERM:
#ifdef	PAGECHAR
		savechars = CHAR_DISCARD;
#endif
		resetmode(DMD_TERM);
		break;
	case DMD_CLEAR:
		stipple(Drect);
		curpos = add(org, fudge);
		break;
	case DMD_TYPESET:
		send(DMD_ACK);
		break;
	case DMD_ASCII:
#ifdef	PAGECHAR
		if (savechars == CHAR_STORE)
			saveptr--;
		old = savechars;
		savechars = CHAR_DISCARD;
#endif
		while (c = inchar())
			term(c, 1);
#ifdef	PAGECHAR
		savechars = old;
#endif
		break;
	case DMD_RULE: {
		short w, h;
		Rectangle r;

		w = inshort();
		h = inshort();
		pprime = add(curpt, typeorg);
		pprime.y++;
		r.origin = pprime;
		r.origin.y = pprime.y - h;
		r.corner = pprime;
		r.corner.x = pprime.x + w;
		rectf(&display, r, F_STORE);
		break;
	}
	case DMD_FORW:
		curpt.x++;
		break;
	case DMD_BACK:
		curpt.x--;
		break;
	case DMD_HABS:
		curpt.x = inshort();
		break;
	case DMD_HREL:
		curpt.x += insignchar();
		break;
	case DMD_VABS:
		curpt.y = inshort();
		break;
	case DMD_VREL:
		curpt.y += insignchar();
		break;
	case DMD_PAGE:
#ifdef	PAGECHAR
		saveptr = savebuf;
		savechars = CHAR_STORE;
#endif
		stipple(Drect);
		curpos = add(org, fudge);
		curpt.x = curpt.y = 0;
		break;
	case DMD_ENDPAGE:
		pagecmd();
		break;
	case DMD_SETFONT: {
		int i;

		i = inchar();
		if (i < MAXFAMILY)
			curfont = ftbl[i];
		break;
	}
	case DMD_MKFONT:
	case DMD_SGLYPH:
	case DMD_BGLYPH:
#ifdef	PAGECHAR
		if (savechars == CHAR_STORE)
			saveptr--;
		old = savechars;
		savechars = CHAR_DISCARD;
#endif
		if (c == DMD_MKFONT)
			ldfont();
		else
			ldglyph(c);
#ifdef	PAGECHAR
		savechars = old;
#endif
		break;
	case DMD_SEGMENT:
	case DMD_SPLINE:
		define_path(c);
		break;
	case DMD_CIRCLE:
		define_circle();
		break;
	case DMD_ELLIPSE:
		define_ellipse();
		break;
	case DMD_DRAWPATH:
		draw_path();
		break;
	case DMD_FILLPATH:
		fill_path();
		break;
	case DMD_PENSIZE:
		set_pen();
		break;
	default:
		break;
	}
}

/* request an index number for a new font */
ldfont()
{
	register struct fontinfo *f;
	register int i, j;
	register int x = -1;
	char name[MAXFONTNAME];
	register char *p;
	char loaded[16];

	p = name;
	while (*p++ = inchar())
		if (p >= &name[MAXFONTNAME]) {
			while (inchar())
				continue;
			break;
		}
	for (i = 0; i < sizeof(loaded); i++)
		loaded[i] = 0;
	/* look for the font... */
	for (i = 0; i < MAXFAMILY; i++) {
		f = ftbl[i];
		if (f && strncmp(f->f_name, name, sizeof(f->f_name)) == 0) {
			for (j = 0; j < 128; j++) {
				if (f->f_glyph[j].g_bitmap.base)
					loaded[j>>3] |= 1 << (~j & 07);
			}
			send(i);
			sendnchars(sizeof(loaded), loaded);
			return;
		}
		if (x == -1 && f == 0)
			x = i;
	}
	if (x == -1) {
		send(-1);
		return;
	}
	f = (struct fontinfo *)alloc(sizeof (struct fontinfo));
	if (f == 0) {
		send(-1);
		return;
	}
	ftbl[x] = f;
	strncpy(f->f_name, name, sizeof(f->f_name));
	send(x);
	sendnchars(sizeof(loaded), loaded);
}

/* download a particular character in a font */
ldglyph(c)
	int c;
{
	register struct glyph *g;
	register int i, j;
	register char *p;
	short chr, fam, w;
	int words;
	int o;
	short xs, ys;
	int endb;
	static struct glyph gdummy;

	w = inshort();
	fam = (w >> 7) & 0177;
	chr = w & 0177;
	if (ftbl[fam])
		g = &(ftbl[fam]->f_glyph[chr]);
	else {
		ftbl[fam] = (struct fontinfo *)alloc(sizeof (struct fontinfo));
		g = ftbl[fam] ? &(ftbl[fam]->f_glyph[chr]) : &gdummy;
	}

	if (c == DMD_SGLYPH) {
		g->g_pxwidth = insignchar();
		xs = inchar();
		g->g_xoffset = insignchar();
		ys = inchar();
		g->g_yoffset = insignchar();
	} else {
		g->g_pxwidth = inshort();
		xs = inshort();
		g->g_xoffset = inshort();
		ys = inshort();
		g->g_yoffset = inshort();
	}
	words = RoundUp(xs, WORDSIZE) >> WORDSHIFT;
	o = RoundUp(xs, 8) >> 3;
	endb = words * sizeof(Word);
	if (g->g_bitmap.base)
		free(g->g_bitmap.base);
	if (g == &gdummy || (p = alloc(ys * endb)) == 0) {
		/* skip raster bytes */
		j = o * ys;
		for (i = 0; i < j; i++)
			inchar();
	} else {
		/* read raster here */
		g->g_bitmap.base = (Word *)p;
		g->g_bitmap.width = words;
		g->g_bitmap.rect.origin.x = 0;
		g->g_bitmap.rect.origin.y = 0;
		g->g_bitmap.rect.corner.x = xs;
		g->g_bitmap.rect.corner.y = ys;
		g->g_bitmap._null = 0;
		p = (char *)g->g_bitmap.base;
		for (j = 0; j < ys; j++) {
			for (i = 0; i < o; i++)
				*p++ = inchar();
			for ( ; i < endb; i++)
				*p++ = 0;
		}
	}
}

/* mouse and keyboard input routines at end of page */

static char *b3m[] = {
	"redraw",
	"next",
	"prev",
	"quit",
	"exit",
	NULL
};

static Menu menu = { b3m };

Texture16 ok = {
	 0x1C44, 0x2248, 0x2250, 0x2270,
	 0x2248, 0x1C44, 0x0000, 0x0380,
	 0x0440, 0x0440, 0x0080, 0x0100,
	 0x0100, 0x0100, 0x0000, 0x0100,
};

minkbd()
{
	Texture16 *t;
	register int i;
	int oscroll = 0;
	register int inscroll = 0;
	Point selpt;

	while (i = wait(KBD|MOUSE|RCV)) {
		if (i&KBD)
			return(kbdchar());
		else if (i&RCV)
			return(rcvchar());
		selpt = mouse.xy;
		i = selpt.x - Drect.origin.x;
		inscroll = 0;
		if (i >= 0 && i < SCROLLSIZE)
			inscroll += 1;
		i = Drect.corner.y - selpt.y;
		if (i >= 0 && i < SCROLLSIZE)
			inscroll += 2;
		if (inscroll != oscroll) {
			cursswitch(inscroll ? &C_crosshair : &prompt);
			oscroll = inscroll;
		}
		switch (inscroll) {
		case 0:
			if (!bttn3())
				break;
			switch (i = menuhit(&menu, 3)) {
			case -1:
				break;
			case 4:
				t = cursswitch(&ok);
				while (!bttn123()) sleep(1);
				i = bttn3();
				while (bttn123()) sleep(1);
				(void)cursswitch(t);
				if (i)
					return('x');
				break;
			default:
				return("rnpq"[i]);
			}
			break;
		case 1:
			if (!bttn13())
				break;
			if (bttn1())
				typeorg.y -= selpt.y - Drect.origin.y;
			else
				typeorg.y += selpt.y - Drect.origin.y;
			/* primitive scroll for now */
			while (bttn123());
			return('s');
		case 2:
			if (!bttn13())
				break;
			if (bttn1())
				typeorg.x -= selpt.x - Drect.origin.x;
			else
				typeorg.x += selpt.x - Drect.origin.x;
			/* primitive scroll for now */
			while (bttn123());
			return('s');
		case 3:
			if (bttn1())
				return('n');
			else if (bttn2())
				return('r');
			else if (bttn3())
				return('p');
			break;
		}
		sleep(1);
	}
	/*NOT REACHED*/
}

pagecmd()
{
	register int i;
	register Texture16 *t;
	int cmd;
	Point p1, p2;
	int redraw;
#ifdef	PAGECHAR
	int pagesaved;
	char buf[40];

	pagesaved = savechars != CHAR_DISCARD;
#endif
	t = cursswitch(&prompt);
pgstart:
	redraw = 0;
	/*
	 * draw outlines of scroll bars.  We will draw
	 * the whole lines when we can't write in the
	 * scroll area, but for now, do it this way.
	 */
	p1 = Drect.origin;
	p1.x += SCROLLSIZE;
	p2.x = p1.x;
	p2.y = p1.y + SCROLLSIZE;
	segment(&display, p1, p2, F_STORE);
	p1.y = Drect.corner.y - 2*SCROLLSIZE;
	p2.y = Drect.corner.y;
	segment(&display, p1, p2, F_STORE);
	p1.y = Drect.corner.y - SCROLLSIZE;
	p2.y = p1.y;
	p1.x = Drect.origin.x;
	p2.x = p1.x + 2*SCROLLSIZE;
	segment(&display, p1, p2, F_STORE);
	p1.x = Drect.corner.x - SCROLLSIZE;
	p2.x = Drect.corner.x;
	segment(&display, p1, p2, F_STORE);
#ifdef	PAGECHAR
	savechars = CHAR_DISCARD;
#ifdef	DEBUG
	sprintf(buf, "%d", saveptr-savebuf);
	p1 = org;
	p1.x += 20;
	p1.y += 20;
	string(&defont, buf, &display, p1, F_XOR);
#endif
#endif
	switch (cmd = minkbd()) {
	case 0177:
	case 04:
	case 'q':
		send(DMD_EXIT);
		resetmode(DMD_TERM);
		t = 0;
		break;
	case 'x':
		send(DMD_EXIT);
		bye();
		break;
	case 'r':
	case '\f':
		typeorg = org;
		/* fall into... */
	case 's':
		redraw = 1;
		break;
	case 'n':
	case ' ':
		typeorg.y -= Drect.corner.y - Drect.origin.y;
		if (org.y - typeorg.y < PAGEPIXELS) {
			redraw = 1;
			break;
		}
		/* fall into... */
	case '+':
	case '\r':
	case '\n':
		typeorg = org;
		send(DMD_PAGE);
		send(1);
		break;
	case 'p':
		typeorg.y += Drect.corner.y - Drect.origin.y;
		if (org.y >= typeorg.y) {
			redraw = 1;
			break;
		}
		/* fall into... */
	case '-':
		typeorg = org;
		send(DMD_PAGE);
		send(-1);
		break;
	default:
	/*	ringbell(); */
		goto pgstart;
	}
	if (redraw) {
#ifdef	PAGECHAR
		if (pagesaved) {
#ifdef	MPX
			if (P->state&(RESHAPED|MOVED))
				windowupdate();
#endif
			typeset(DMD_PAGE);
			saveptr = savebuf;
			savechars = CHAR_FETCH;
			while ((i = inchar()) != DMD_ENDPAGE)
				typeset(i);
			(void)cursswitch(&prompt);
			goto pgstart;
		}
#endif
		send(DMD_PAGE);
		send(0);
	}
	(void)cursswitch(t);
}

inkbd()
{
	wait(RCV|KBD);
	return((own()&KBD)? kbdchar():rcvchar());
}

bye()
{
	register int i;

	for (i = 0; i < MAXFAMILY; i++) {
		if (ftbl[i])
			freefont(ftbl[i]);
	}
	exit();
}

freefont(f)
	struct fontinfo *f;
{
	struct glyph *g;

	for (g = f->f_glyph; g < &f->f_glyph[128]; g++)
		if (g->g_bitmap.base)
			free((char *)g->g_bitmap.base);
	free((char *)f);
}

#ifdef	notdef
edit(s)
	char *s;
{
	char buf[40];
	Point p;
	int c;
	register i;

	strcpy(buf, s);
	p = mouse.xy;
	disp(buf, p);
	for(i = strlen(buf); (c = inkbd()) != '\r';)
	{
		disp(buf, p);
		p = mouse.xy;
		switch(c)
		{
		case '\b':
			if((buf[i] != ' ') && (i > 0))
				buf[--i] = 0;
			break;
		case '@':
			while(buf[i] != ' ') i--;
			buf[++i] = 0;
			break;
		default:
			buf[i++] = c;
			buf[i] = 0;
			break;
		}
		disp(buf, p);
	}
	disp(buf, p);
	strcpy(s, buf);
}

disp(s, p)
	char *s;
	Point p;
{
	string(&defont, "\001", &display,
		string(&defont, s, &display, p, F_XOR), F_XOR);
}
#endif

resetmode(c)
	int c;
{
	if (c == DMD_TERM) {
		cursvis = dotypeset = 0;
#ifdef	MPX
		request(SEND|RCV);
#else
		request(SEND|RCV|KBD);
#endif
		curpos.x = org.x + fudge.x;
		curpos.y = Drect.corner.y - fudge.y - defont.height;
	} else {
		dotypeset = 1;
		request(SEND|RCV|KBD|MOUSE);
		typeorg = org;
	}
}

windowupdate()
{
#ifdef	MPX
	if (P->state&RESHAPED) {
#endif
		org = Drect.origin;
		typeorg = org;
		curpos = add(org, fudge);
		line.bufp = line.buf;
		if (cursvis) {
			term(CURSOR, 0);	/* flip state */
			cursvis = 0;
		}
#ifdef	MPX
	} else {
		curpos = add(sub(curpos, org), Drect.origin);
		typeorg = add(sub(typeorg, org), Drect.origin);
		org = Drect.origin;
	}
	P->state &= ~(MOVED|RESHAPED);
#endif
	artdeco();
}

static Texture16 vstripe = {
	0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0,
	0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0,
	0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0,
	0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0
};

static Texture16 hstripe = {
	0xffff, 0xffff, 0xffff, 0xffff,
	0x0000, 0x0000, 0x0000, 0x0000,
	0xffff, 0xffff, 0xffff, 0xffff,
	0x0000, 0x0000, 0x0000, 0x0000,
};

artdeco()
{
	texture16(&display, Rect(display.rect.origin.x, display.rect.origin.y,
		display.rect.corner.x, Drect.origin.y), &vstripe, F_XOR);
	texture16(&display, Rect(display.rect.origin.x, Drect.origin.y,
		Drect.origin.x, Drect.corner.y), &hstripe, F_XOR);
	texture16(&display, Rect(Drect.corner.x, Drect.origin.y,
		display.rect.corner.x, Drect.corner.y), &hstripe, F_XOR);
	texture16(&display, Rect(display.rect.origin.x, Drect.corner.y,
		display.rect.corner.x, display.rect.corner.y), &vstripe, F_XOR);
}

/* graphics support; for now there are some unimplemented operations */

#define	MAXPOINTS	60

#define	PATH_NONE	-1
#define	PATH_SEGMENT	0
#define	PATH_SPLINE	1
#define	PATH_CIRCLE	2
#define	PATH_ELLIPSE	3

int path_type = PATH_NONE;
int pen_size = 1;

struct {
	Point c_center;
	Point c_start; 
	Point c_finish; 
} path_circle;

struct {
	Point e_center;
	Point e_start;
	Point e_finish;
	short e_xradius;
	short e_yradius;
} path_ellipse;

Point path_pts[MAXPOINTS+2];
int path_len;

define_path(c)
{
	register int i, n;
	register Point *pp;

	path_type = (c==DMD_SEGMENT) ? PATH_SEGMENT : PATH_SPLINE;
	n = inshort();
	path_len = n;
	if (path_len > MAXPOINTS) {
		path_len = MAXPOINTS;
		for (i = path_len; i < n; i++)
			(void)inpoint();
	}
	pp = &path_pts[1];
	for (i = 0; i < path_len; i++)
		*pp++ = inpoint();
}

define_circle()
{
	path_circle.c_center = inpoint();
	path_circle.c_start = inpoint();
	path_circle.c_finish = inpoint();
	path_type = PATH_CIRCLE;
}

define_ellipse()
{
	path_ellipse.e_center = inpoint();
	path_ellipse.e_start = inpoint();
	path_ellipse.e_finish = inpoint();
	path_ellipse.e_xradius = inshort();
	path_ellipse.e_yradius = inshort();
	path_type = PATH_ELLIPSE;
}

draw_path()
{
	int rop;

	rop = inchar();		/* ignore for now */
	switch (path_type) {
	case PATH_SEGMENT:
		draw_segment(F_OR);
		break;
	case PATH_SPLINE:
		draw_spline(F_OR);
		break;
	case PATH_CIRCLE:
		draw_circle(F_OR);
		break;
	case PATH_ELLIPSE:
		draw_ellipse(F_OR);
		break;
	}
}

fill_path()
{
	int rop;

	rop = inchar();		/* ignore for now */
}

set_pen()
{
	int i = inchar();

	if (i < 1)
		i = 1;
	pen_size = i;
}

/* draw a spline path */
draw_spline(f)
	int f;
{
	register Point *pp = path_pts;
	register long w, t1, t2, t3, scale=1000; 
	register int i, j, steps=10; 
	int n = path_len + 1;
	Point p, q;

	pp[0] = pp[1];
	pp[n] = pp[n-1];
	p = pp[0];
	for (i = 0; i < n-1; i++) {
		for (j = 0; j < steps; j++) {
			w = scale * j / steps;
			t1 = w * w / (2 * scale);
			w = w - scale/2;
			t2 = 3*scale/4 - w * w / scale;
			w = w - scale/2;
			t3 = w * w / (2*scale);
			q.x = (t1*pp[i+2].x + t2*pp[i+1].x + 
				t3*pp[i].x + scale/2) / scale;
			q.y = (t1*pp[i+2].y + t2*pp[i+1].y + 
				t3*pp[i].y + scale/2) / scale;
			line_btw(p, q, f);
			p = q;
		}
	}
}

/* draw a segment path */
draw_segment(f)
	int f;
{
	register Point *pp;
	register int i;

	pp = &path_pts[1];
	if (path_len == 1) {
		if (pen_size > 1)
			disc(&display, pp[0], pen_size, f);
		else
			point(&display, pp[0], f);
	} else {
		for (i = 1; i < path_len; i++) {
			line_btw(pp[0], pp[1], f);
			pp++;
		}
	}
}

draw_circle(f)
	int f;
{
	/* ignore pen size for now */

	if (path_circle.c_center.x == path_circle.c_finish.x &&
	    path_circle.c_center.y == path_circle.c_finish.y) {
		circle(&display, path_circle.c_center, path_circle.c_start.x, f);
	} else {
		arc(&display, path_circle.c_center, path_circle.c_start,
		    path_circle.c_finish, f);
	}
}

draw_ellipse(f)
	int f;
{
	/* ignore pen size for now */

	if (path_ellipse.e_center.x == path_ellipse.e_finish.x &&
	    path_ellipse.e_center.y == path_ellipse.e_finish.y) {
		ellipse(&display, path_ellipse.e_center, path_ellipse.e_xradius,
		    path_ellipse.e_yradius, f);
	} else {
		elarc(&display, path_ellipse.e_center, path_ellipse.e_xradius,
		    path_ellipse.e_yradius, path_ellipse.e_start,
		    path_ellipse.e_finish, f);
	}
}

/* Draw a line on the screen.  */
line_btw(p0, p1, rop)
	Point p0, p1;
{
	register int i;
	register int incx;

	if (abs(p1.y-p0.y) > abs(p1.x-p0.x)) {
		incx = 1;
		p0.x -= pen_size/2;
		p1.x -= pen_size/2;
	} else {
		incx = 0;
		p0.y -= pen_size/2;
		p1.y -= pen_size/2;
	}
	for (i = 0; i < pen_size; i++) {
		segment(&display, p0, p1, rop);
		if (incx) {
			p0.x++; p1.x++;
		} else {
			p0.y++; p1.y++;
		}
	}
}