[net.micro] Tektronix emulator for Zenith Z100

kfl@hoxna.UUCP (Kenton Lee) (09/16/84)

xxx
I wrote this program so I could run S from my home computer.  It
works with the CI C86 compiler under MS-DOS 1.25.  Non-Z100 users
will have to modify the 4 short Z100 specific routines at the end.
The program requires some simple line drawing routines.  You IBM PC
folks can use the routines provided with the CI C86 compiler and
scrap my Z100 stuff.  All rights reserved.
--------------------------------------------------------------------
/* 
 *	tek.c	Kenton Lee (hoxna!kfl)	September 15, 1984.
 *
 *	All rights reserved.
 *	Converts Tektronix 4010 escape sequences (stored in file)
 *	to Heath/Zenith Z100 graphics.
 *	Based on Byte article, "Mainframe Graphics on a Microcomputer",
 *	by Mahlon Kelley, October, 1983, p. 439-442.
 *	Works with CI C86 compiler under MS-DOS 1.25.
 *
 *	This program uses CGRAPH graphics subroutine library:
 *		cgraph.h stores external pen position (x,y).
 *		lineto(x,y) draws line from pen position to (x,y).
 *		moveto(x,y) updates pen position without drawing.
 *		setpoint() specifies the user provided pixel subroutine.
 *		drawchar(c) draws on char and moves pen to next char position.
 *	This subroutine library is advertised for about $50 in various 
 *	magazines.  Since only the simple stuff is used here, you can
 *	fudge your own routines.
 */

help()
{
	puts("Tektronix 4010 emulator for Heath/Zenith Z100");
	puts("This program allows you to display Tektronix 4010 vectors");
	puts("on a Zenith Z100.  Collect the 4010 vectors into a Z100");
	puts("disk file (by downloading, or whatever), then run this");
	puts("program on the file.");
	puts("usage:  tek filename");
}

#include "cgraph.h"
#include <stdio.h>
/* allowed values of "pen" mode */
#define PEN_DOWN	'A'
#define PEN_UP		'B'
#define TEXT		'T'
/* dimensions (in pixels) of Zenith Z100 screen */
#define Z100X		640
#define Z100Y		225
/* dimensions (in pixels) of Tek 4010 screen */
#define TEKX		1024
#define TEKY		780
/* external variables: pen mode and old character */
int mode = TEXT, oldc = 0;

main(argc, argv)
int argc;
char *argv[];
{
	FILE *fopen();
	int mypoint();				/* pixel liter for cgraph */
	if (argc != 2) {			/* require "tek file" invoc. */
		help();
		exit();
	}
	setpoint(mypoint);			/* set cgraph pixel liter */
	cls();					/* clear screen */
	venable();				/* enable video RAM access */
	runtek(fopen(argv[1], "r"));		/* read file */
	vdisable();				/* disable video */
}

runtek(fp)	/* parse Tek 4010 commands and data in the file */
FILE *fp;
{
	int c;					/* current char. */
	while ((c = getc(fp)) != EOF) {
		if (c < 32)
			control(c);		/* control char */
		else if (mode == TEXT)
			text(c);		/* text, put char */
		else
			graph(c);		/* graphics, draw line */
		oldc = c;			/* save old char, external */
	}
}

control(c)	/* Tek 4010 control character */
int c;
{
	switch(c) {
		case 12:	/* clear text and graphics */
			if (oldc == 27) cls();
			break;
		case 26:	/* erase text but not graphics */
			/* not implemented, sorry */
			break;
		case 29:	/* switch to graphics mode, lift pen */
			mode = PEN_UP;
			break;
		case 31:	/* switch to text mode */
			mode = TEXT;
			break;
		default:	/* all other control commands are ignored */
			break;
	}
}

/*
 *	Text mode.  Write character c at the current pen position and
 *	move pen to beginning of next character position.
 */
text(c)
int c;
{
	drawchar(c);
}

/*
 * Process Tektronix vectors.  These vectors are 4 bytes long, but not all
 * four bytes are sent for each point.  Only the changed bytes are sent.
 * The 4 bytes are called hix, lowx, hiy, lowy.  These are converted to
 * cartesian coordinates (with the range x<1024, y<780) as follows:
 * x = (hix-32)*32+lowx-64; y = (hiy-32)*32+lowy-96.
 * To determine which of the 4 bytes is received:
 *	64 <= c <= 95 is lowx
 *	96 <= c <= 127 is lowy
 *	32 <= c <= 63 immediately preceded by lowy is hix
 *	32 <= c <= 63 otherwise is hiy
 * Pen is updated whenever lowx is received.
 */
graph(c)
int c;
{
	static int lowx, hix, lowy, hiy;	/* TEK vector */
	if (c > 95) {				/* c is lowy */
		lowy = c;
	} else if (c > 63) {			/* c is lowx, draw line */
		lowx = c;
		pen(lowx, hix, lowy, hiy);
	} else if (oldc > 95) {			/* hix/hiy test */
		hix = c;
	} else {
		hiy = c;
	}
}

/*
 *	Calculate new pen position.  If pen is down, draw line beteen
 *	new and old positions, else update position and put pen down.
 */
pen(lowx, hix, lowy, hiy)
int lowx, hix, lowy, hiy;		/* TEK vector */
{
	int x, y;			/* coordinates of current point */
	x = Z100X./TEKX. * ((hix-32) * 32 + (lowx-64));
	y = Z100Y./TEKY. * ((hiy-32) * 32 + (lowy-96));
	if (mode == PEN_DOWN) {
		lineto(x, y);
	} else {
		moveto(x, y);
		mode = PEN_DOWN;
	}
}

venable()	/* enable writing to Z100 video ram */
{
	outportb(0xd8, (inportb(0xd8) & 0x7f));
}

vdisable()	/* disable writing to Z100 video ram */
{
	outportb(0xd8, (inportb(0xd8) | 0x80));
}

#define BLUE  0xc000
#define RED   0xd000
#define GREEN 0xe000
/*
 *	Lights one pixel on the specified Z100 color plane.
 *	(0,0) is lower left corner.
 */
mypoint(x, y)
int x, y;
{
	unsigned offset, mask;
	y = 224 - y;
	offset = (x >> 3) | (y%9) << 7 | (y/9) << 11;
	mask = 0x80 >> (x % 8);
	pokeb(offset, GREEN, (peek(offset, GREEN) | mask));
}

cls()	/* clear Z100 screen */
{
	puts("\033E");
}

-- 
Kenton Lee, Bell Labs - WB
wb3g!kfl or hoxna!kfl