#
/*
   device dependent core graphics driver for genisco
   A Christopher Hall fecit

ASSUMPTION: SCREEN COORDINATES LINE IN RANGE [0,1]

notes:  have 2 fonts, really: going across and going down

*/
#define CLEAR   0       /* complete */
#define INITIAL 1       /* complete */
#define SETVSBL 2       /* na */
#define SETHILIT 3      /* na */
#define SETDTCT 4       /* na */
#define DELETE  5       /* na */
#define ROTATE  6       /* na */
#define SCALE   7       /* na */
#define TRANSLATE 8     /* na */
#define OPENSEG 9       /* na */
#define TERMINATE 10    /* complete */
#define CLOSEG  11      /* na */
#define NDCSP2  12      /* complete */
#define GETCP   13      /* complete */
#define SETPID  14      /* na */
#define SETCOL  15      /* complete */
#define SETWIDTH 16     /* na */
#define SETSTYL 17
#define SETINT  18      /* na */
#define MOVE    19      /* complete */
#define LINE    20      /* complete */
#define TEXT    21      /* check on width of a character for computation of cp */

#define MARK    23      /* complete */
#define SETFONT 24      /* complete */
#define SETSIZE 25      /* don't agree on algorithm, maybe specs are incorrect */
#define SETANGLE 26     /* complete */



gensco1(ddstruct)
struct {
	int opcode;
	int logical;
	char *string;
	int int1;
	float float1;
	float float2;
	float float3;
} *ddstruct;
{
char onechr[3];
register int i,j;
register int i1,i2,i3;
int i4,i5,i6;
double f1,f2;
static int x,y;
static int zoom,direct,angle;   /* parameters for text */
static int color1[16]   0,15, 0, 0,15,15, 0,15,0,8,0,0,8,8,0,8;
static int color2[16]   0, 0,15, 0,15, 0,15,15,0,0,8,0,8,0,8,8;
static int color3[16]   0, 0, 0,15, 0,15,15,15,0,0,0,8,0,8,8,8;
static int topcol;


	switch(ddstruct->opcode) {

	case INITIAL:
		gopen();
		gucolor(1);
		zoom = direct = angle = 0;
		gscolor( 0, 0, 0, 0);
		gscolor(15, 0, 0, 1);
		gscolor( 0,15, 0, 2);
		gscolor( 0, 0,15, 3);
		gscolor(15,15, 0, 4);
		gscolor(15, 0,15, 5);
		gscolor( 0,15,15, 6);
		gscolor(15,15,15, 7);
		gscolor( 0, 0, 0, 8);
		gscolor( 8, 0, 0, 9);
		gscolor( 0, 8, 0,10);
		gscolor( 0, 0, 8,11);
		gscolor( 8, 8, 0,12);
		gscolor( 8, 0, 8,13);
		gscolor( 0, 8, 8,14);
		gscolor( 8, 8, 8,15);
	case TERMINATE:
	case CLEAR:
		gclear();
		x = y = 0;
		break;
	case SETCOL:
		f1 = .5 + 15. * ddstruct->float1;
		i1 = f1;
		f1 = .5 + 15. * ddstruct->float2;
		i2 = f1;
		f1 = .5 + 15. * ddstruct->float3;
		i3 = f1;
/*
	convert user's color to one which is in the VLT
*/
		if (i1<=4) i4 = 0;
			else if (i1<=10) i4 = 8;
				else i4 = 15;
		if (i2<=4) i5 = 0;
			else if (i2<=10) i5 = 8;
				else i5 = 15;
		if (i3<=4) i6 = 0;
			else if (i3<=10) i6 = 8;
				else i6 = 15;
/*
   now i4:6 can be mixed 0's and 15's or 0's and 8's, but not 8's and 15's.
   In the last case, convert the 8's to 15's if i1+i2+i3 >= 25;
   else convert the 15's to 8's
*/
		if (((i4==15) | (i5==15) | (i6==15)) &
			((i4==8) | (i5==8) | (i6==8))) {

			if ((i1 + i2 + i3) >= 25) {
				if (i4==8) i4 = 15;
				if (i5==8) i5 = 15;
				if (i6==8) i6 = 15;
			}
			else {
				if (i4==15) i4 = 8;
				if (i5==15) i5 = 8;
				if (i6==15) i6 = 8;
			}
		}
/*
   now find this color in the lookup table
   note, by the way, that black will be found in slot 8, not slot 0
   thus, slot 0 is not used, except to erase the screen
*/
		j = -1;
		for (i=1; i<=15; i++)
			if ((color1[i] == i4) && (color2[i] == i5)
				&& (color3[i] == i6)) j = i;

		if (j >= 0) {
			gucolor(j);
			break;
		}
/*
	If color not found, horrendous error; use white
*/
		gucolor(7);
		break;
	case SETSTYL:
		printf("SETSTYL not implemented yet\n");
		break;
/*
for text:
   normal-size characters are 5x7 in a 7x12 box
   sizes are limited to 1,2,3,...,16 * normal size
   angle is 0, 90, 180, 270
   font defines direct = 0,1
*/
	case SETFONT:
		direct = ddstruct->int1;
		goto setgt;
	case SETANGLE:
		angle = (45.5 + 360. * ddstruct->float1 / 6.28) / 90.;
		if (angle != 0) angle = 4 - angle;
		goto setgt;
	case SETSIZE:
		f1 = 511. * ddstruct->float1 / 7.;
		f2 = 511. * ddstruct->float2 / 5.;
		zoom = ((f1 < f2) ? f1 : f2) - .999999;
		if (zoom<0) zoom = 0;
setgt:          gtparm(zoom,direct,angle,0);
		break;
	case MARK:
		i1 = x - 3;
		i2 = 511 - (y + 5);
		gtparm(0,0,0,0);
		onechr[0] = ddstruct->string;
		onechr[1] = '\0';
		onechr[2] = '\0';
		gtext(i1,i2,onechr);
		goto setgt;
	case TEXT:
		i1 = x - (zoom + 1);
		i2 = (511 - y) - (7 + (zoom * 8));
		gtext(i1,i2,ddstruct->string);
		if(ddstruct->logical)
		   {
		   x =+ length(ddstruct->string) * 7 * (zoom + 1);
		   }
		break;
	case GETCP:
		ddstruct->float1 = x / 511.;
		ddstruct->float2 = y / 511.;
		break;
	case MOVE:
		i1 = x = 511. * ddstruct->float1 + .5;
		i2 = 511. - (y = 511. * ddstruct->float2 + .5);
		/* ADJUST Y COORDINATE TO ACCOUNT FOR FLIPPING OF SCREEN */
		gmove(i1,i2);
	case NDCSP2:
		break;
	case LINE:
		i1 = x = 511. * ddstruct->float1 + .5;
		i2 = 511 - (y = 511. * ddstruct->float2 + .5);
		/* ADJUST Y COORDINATE TO ACCOUNT FOR FLIPPING OF SCREEN */
		glinea(i1,i2);
		break;
	default:
		break;
	}
}
/*
	graphics subroutines. load with your favorite graphics program
	A Christopher Hall fecit

The following routines are defined:

INITIALIZERS:
	gopen()         hook up the genisco device
	gclear()        clear the screen

BASIC DRAWING ROUTINES:
	gmove(x,y)      move to (x,y)
	gpoint(x,y)     light the point at (x,y)
	glinea(x,y)     line from prrameters
	askfor(string)          collect text string from terminal

VIDEO LOOKUP TABLE MANIPULATORS:
	gscolor(red,gre,blu,slot)  set VLT slot to given intensities
	gucolor(slot)           write memory planes given by slot

ROUTINES FOR USING MEMORY PLANES INDEPENDENTLY:
	[gucolor(15) should be called before these are used]
	gselect(planes)         write only the given planes *
	gsplanes(red,green,blue,plane)  set up given color in plane
	gshowp(plane)           display the given plane
	ghidep(plane)           suppress the given plane

* for the above, plane is in the range 1-4. But for gselect, planes
  is in 0-15, where each plane is represented by a single bit. So
  planes == 5 means write on planes 1 and 3; planes == 8 => write on 4.

HARDWARE EXPLOITERS:
	gscroll(x,y)    set screen origin to (x,y)
	gzoom(zoom)     zoom by a factor of 2 ** zoom
	gfill(planes)   set fill mode on given planes


THE FOLLOWING DEFINES THE COMMANDS KNOWN BY THE GENISCO OPERATING SYSTEM
*/
/*#define CLEAR  8        /* 0 args */
/*#define MOVE   1        /* 2 args */
/*#define POINT  2        /* 2 args */
/*#define LINEA  3        /* 2 args */
/*#define LINER  4        /* 2 args */
/*#define TEXT   14       /* 2 args */
/*#define UCOLOR 5        /* 1 args */
/*#define SCOLOR 9        /* 4 args */
/*#define SOLID  7        /* 4 args */
/*#define FILL   10       /* 1 arg  */
/*#define SCROLL 11       /* 2 args */
/*#define ZOOM   12       /* 1 arg  */
/*#define SELECT 6        /* 1 arg  */

#define CLEAR  0        /* 0 args */
#define MOVE   1        /* 2 args */
#define POINT  2        /* 2 args */
#define LINEA  3        /* 2 args */
#define LINER  4        /* 2 args */
#define TEXT   5        /* 2 args */
#define UCOLOR 6        /* 1 args */
#define SCOLOR 7        /* 4 args */
#define SOLID  8        /* 4 args */
#define FILL   9        /* 1 arg  */
#define SCROLL 10       /* 2 args */
#define ZOOM   11       /* 1 arg  */
#define SELECT 12       /* 1 arg  */

int pointc[3];          /* output vector */
int fd;                 /* genisco file device */
int ucolor 0;
int zoom   0;
int direct 0;
int angle  0;
int back   0;
int plared[5];          /* colors saved in VLT */
int plagre[5];
int plablu[5];
int onplanes;           /* flags for planes on: 1 & 3 on => == 5 (= 0101) */
int placol[15];         /* plane which this VLT slot belongs to */
/*
	subroutines to do things with the genisco

	like clear the screen
*/
gclear() {
	pointc[0] = CLEAR;      /* clear screen */
	write (fd,pointc,6);
}
/*
	select memory planes given by planes
*/
gselect(planes) {
	pointc[0] = SELECT;
	pointc[1] = planes;
	write (fd,pointc,6);
}
/*
	set up color in VLT slots - for when memory planes are
	used to hold independent images.

	If plane==4, loads slots 8-15 with given color;
	If plane==3, loads slots 4-7
	If plane==2, loads slots 2-3
	If plane==1, just loads slot 1.

	Thus, plane 8 dominates 4 dominates 2 dominates 1
	ie, if images overlap, the one that will appear will be on the
	higher-numbered plane
*/
gsplanes(red,green,blue,plane) {
register int i,j,k;

	if ((plane < 1) | (plane > 4)) {
		printf("plane number too high\n");
		return;
	}
	k = (1 << (plane-1));
	j = (k << 1) - 1;
	pointc[0] = SCOLOR;
	pointc[1] = (blue << 8) | (green << 4) | red;

	for (i=k; i<=j; i++) {
		pointc[2] = i;
		write (fd,pointc,6);
		placol[i] = k;
	}
	plared[plane] = red;
	plagre[plane] = green;
	plablu[plane] = blue;
	onplanes =| k;
}
/*
	show the given plane
*/
gshowp(plane) {
		onplanes =| 1 << (plane-1);
		gvltp();
}
/*
	suppress the given plane
*/
ghidep(plane) {
		onplanes =& ~(1 << (plane-1));
		gvltp();
}
/*
	function used by gshowp & ghidep to mess with VLT
	Not intended to be called by outsiders
*/
gvltp() {
register int i,c,d;

	for (i=1; i<=15; i++) {
		c = i & onplanes;       /* find highest turned-on plane */
		if (c >= 8) d = 4;      /* and load its color into this */
		    else if (c >= 4) d = 3;     /* slot */
			else if (c >= 2) d = 2;
			    else if (c == 1) d = 1;
				else d = 0;
		if (placol[i] != d) {
			gscolor(plared[d],plagre[d],plablu[d],i);
			placol[i] = d;
}       }       }
/*
	set up color in VLT slot
*/
gscolor(red,green,blue,slot) {
	pointc[0] = SCOLOR;
	pointc[1] = (blue << 8) | (green << 4) | red;
	pointc[2] = slot;
	write (fd,pointc,6);
}
/*
	set to draw using given VLT slot
*/
gucolor(slot) {
	ucolor = slot;
	pointc[0] = UCOLOR;
	pointc[1] = slot;
	write (fd,pointc,6);
}
/*
	scroll so that point (x,y) is at origin (ULHC)
*/
gscroll(x,y) {
	pointc[0] = SCROLL;
	pointc[1] = x;
	pointc[2] = y;
	write (fd,pointc,6);
}
/*
	zoom by a factor of 2**zoom
(MIGHT BE NICE TO ZOOM AROUND A GIVEN POINT)
*/
gzoom(zoom) {
	pointc[0] = ZOOM;
	pointc[1] = zoom << 10;
	write (fd,pointc,6);
}
/*
	set fill mode on planes given by set. set == 0 => clear fill mode
	set == -1 => fill on all planes
*/
gfill(set) {
	pointc[0] = FILL;
	pointc[1] = set;
	write (fd,pointc,6);
}
/*
	draw a line from (x1,y1) to (x2,y2)
*/
gline(x1,y1,x2,y2) {
	pointc[0] = MOVE;
	pointc[1] = x1;
	pointc[2] = y1;
	write (fd,pointc,6);
	pointc[0] = LINEA;
	pointc[1] = x2;
	pointc[2] = y2;
	write (fd,pointc,6);
}
/*
	draw a line from present position to (x,y)
*/
glinea(x,y) {
	pointc[0] = LINEA;
	pointc[1] = x;
	pointc[2] = y;
	write (fd,pointc,6);
}
/*
	draw a line from present position over dx by dy units
*/
gliner(dx,dy) {
	pointc[0] = LINER;
	pointc[1] = dx;
	pointc[2] = dy;
	write (fd,pointc,6);
}
/*
	move to (x,y)
*/
gmove(x,y) {
	pointc[0] = MOVE;
	pointc[1] = x;
	pointc[2] = y;
	write (fd,pointc,6);
}
/*
	light point at (x,y)
*/
gpoint(x,y) {
	pointc[0] = POINT;
	pointc[1] = x;
	pointc[2] = y;
	write (fd,pointc,6);
}
/*
   subroutine to draw a solid box. Uses current color, like it should.
   However, for drawing gray pictures which consist of a lot of little
   boxes of different shades, it is faster to include the slot to be
   used with the solid call. In that case, call solid1. The current
   color remains unchanged after solid1; it's just a one-shot deal.
*/
gsolid(x1,y1,x2,y2) {
	gsolid1(x1,y1,x2,y2,-1);        /* -1 means use current color */
}
/*
   subroutine to draw a solid box, using given VLT slot
*/
gsolid1(x1,y1,x2,y2,slot) {
register int i;

	if (x1 > x2) {i=x1; x1=x2; x2=i;}
	if (y1 > y2) {i=y1; y1=y2; y2=i;}
	pointc[0] = SOLID;
	pointc[1] = x1;
	pointc[2] = y1;
	write (fd,pointc,6);
	pointc[0] = x2;
	pointc[1] = y2;
	pointc[2] = slot;
	write (fd,pointc,6);
}
/*
	draw a box, given opposite corner coords
*/
gbox(x1,y1,x2,y2) {
	gline(x1,y1,x1,y2);
	glinea(x2,y2);
	glinea(x2,y1);
	glinea(x1,y1);
}
/*
	draw a circle, given coords of center and radius
*/
gcircle(x,y,rad) {
	register int i,j,k;
	double angle, sin(), cos(), inc;

	inc = 8. / rad;

	gmove(x+rad,y);
	for (angle=0.0; angle<=6.3; angle =+ inc) {
		i = x + rad*cos(angle);
		j = y + rad*sin(angle);
		glinea(i,j);
	}
	glinea(x+rad,y);
}
/*
	set text parameters
*/
gtparm(b,c,d,e) {
	zoom = 15 & b;
	direct = 1 & c;
	angle = 3 & d;
	back = e;
}
/*
	display text
*/
gtext(x,y,s)
    char *s; {
register int i;

	pointc[0] = TEXT;
	i = (((angle << 1) | direct ) << 5) | zoom;
	if (back) i = i | 020;
	pointc[1] = i;
	pointc[2] = back;       /* background color */
	write (fd,pointc,6);

	pointc[0] = ucolor;     /* foreground color */
	pointc[1] = x;          /* x-position */
	pointc[2] = y;          /* y-position */
	write (fd,pointc,6);

	i = -1;                    /* send characters until null found */
	while (i) {
		if ((pointc[0] = *s++) == 0)
			pointc[1] = pointc[2] = i = 0;
		else if ((pointc[1] = *s++) == 0)
			pointc[2] = i = 0;
		else if((pointc[2] = *s++) == 0) i = 0;
		write (fd,pointc,6);
	}
}
/*
   open genisco device
*/
gopen() {
	if ((fd = open("/dev/gn",1)) < 0)
	{       printf ("Can't open the genisco\n");
		exit(1);
}       }
