/* $Id: tektest.c,v 1.2 2001/01/03 22:02:24 mlebrun Exp $

	Maurice LeBrun
	IFS, University of Texas
	Feb 15, 1995

	Test program for illustrating possible Tek GIN anomalies.  In
	particular, for problems with GIN reports encountered in VLT (Tek
	4107 emulator for the Amiga).  May not work right with other Tek
	emulators.

	To compile: "$CC foo.c -o foo", where $CC is an ANSI-C compiler.

	Usage:

	% foo [x0 [y0]]

	To reproduce problem:
	Run program, then turn on graphic crosshair with XY and position over
	the intersection of the drawn lines.  Experiment with different
	crosshair locations, entered via the command line.  Invariably,
	the reported position is systematically <= than the drawn one,
	sometimes by as much as 2 pixels.

	Note: this anomaly has important consequences when doing graphic
	input, because the reported world coordinates are then
	systematically off.
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

/* Static function prototypes */

void plD_init_vlt		(void);
void plD_line_tek		(short, short, short, short);
void plD_eop_tek		(void);
void plD_bop_tek		(void);
void plD_tidy_tek		(void);

static void	WaitForPage	(void);
static void	tek_text	(void);
static void	tek_graph	(void);
static void	encode_int	(char *c, int i);
static void	encode_vector	(char *c, int x, int y);
static void	tek_vector	(int x, int y);

/* Graphics control characters. */

#define RING_BELL	"\007"		/* ^G = 7 */
#define CLEAR_VIEW	"\033\f"	/* clear the view = ESC FF */

#define ALPHA_MODE	"\037"		/* Enter Alpha  mode:  US */
#define VECTOR_MODE	"\035"		/* Enter Vector mode:  GS */
#define GIN_MODE	"\033\032"	/* Enter GIN    mode:  ESC SUB */
#define BYPASS_MODE	"\033\030"	/* Enter Bypass mode:  ESC CAN */
#define XTERM_VTMODE	"\033\003"	/* End xterm-Tek mode: ESC ETX */
#define CANCEL		"\033KC"	/* Cancel */	

/*----------------------------------------------------------------------*\
 * main
 *
 * Generates simple test case.
\*----------------------------------------------------------------------*/

int
main(int argc, char *argv[])
{
    short x0 = 300, y0 = 300, l = 100;
    short x1, x2, y1, y2;

/* Optional x0, y0 specification by the command line */

    if (argc > 1)
	x0 = atoi(argv[1]);

    if (argc > 2)
	y0 = atoi(argv[2]);

    plD_init_vlt();

/* Draw boundary */

    plD_line_tek(0, 0, 1023, 0);
    plD_line_tek(1023, 0, 1023, 779);

    plD_line_tek(1023, 779, 0, 779);
    plD_line_tek(0, 779, 0, 0);

/* Draw crosshairs centered around (x0, y0) of length 2l */

    x1 = x0 - l, x2 = x0 + l;
    y1 = y0 - l, y2 = y0 + l;

    plD_line_tek(x1, y0, x2, y0);
    plD_line_tek(x0, y1, x0, y2);

    plD_eop_tek();
    plD_tidy_tek();
    exit(0);
}

/*--------------------------------------------------------------------------*\
 * plD_init_vlt()	VLT emulator (Amiga)
\*--------------------------------------------------------------------------*/

void
plD_init_vlt(void)
{
    tek_graph();
    fprintf(stdout, VECTOR_MODE);	/* Enter vector mode */
    fprintf(stdout, CLEAR_VIEW);	/* erase and home */
}

/*--------------------------------------------------------------------------*\
 * plD_line_tek()
 *
 * Draw a line from (x1,y1) to (x2,y2).
\*--------------------------------------------------------------------------*/

void
plD_line_tek(short x1, short y1, short x2, short y2)
{
    fprintf(stdout, VECTOR_MODE);
    tek_vector(x1, y1);
    tek_vector(x2, y2);
}

/*--------------------------------------------------------------------------*\
 * plD_eop_tek()
 *
 * End of page.  User must hit a <CR> to continue (terminal output).
\*--------------------------------------------------------------------------*/

void
plD_eop_tek(void)
{
    WaitForPage();
    fprintf(stdout, CLEAR_VIEW);		/* erase and home */
}

/*--------------------------------------------------------------------------*\
 * plD_tidy_tek()
 *
 * Close graphics file or otherwise clean up.
\*--------------------------------------------------------------------------*/

void
plD_tidy_tek(void)
{
    tek_text();
}

/*--------------------------------------------------------------------------*\
 * tek_text()
\*--------------------------------------------------------------------------*/

static void 
tek_text(void)
{
    printf("\033[?38l");	/* vt100 screen */
}

/*--------------------------------------------------------------------------*\
 * tek_graph()
\*--------------------------------------------------------------------------*/

static void 
tek_graph(void)
{
    printf("\033[?38h");	/* switch to tek screen */
}

/*--------------------------------------------------------------------------*\
 * encode_int()
 *
 * Encodes a single int into standard tek integer format, storing into a
 * NULL-terminated character string (must be length 4 or greater).  This
 * scheme does not work for negative integers less than 15.
\*--------------------------------------------------------------------------*/

static void
encode_int(char *c, int i)
{
    int negative = 0;

    if (i > 0) {
	if (i & 0x7C00)				/* are any of bits 10-14 set?*/
	    *c++ = ((i >> 10) & 0x1F) | 0x40;
	if (i & 0x03F0)				/* are any of bits 4-9 set? */
	    *c++ = ((i >> 4) & 0x3F) | 0x40;
    } else {
	i = -i;
	negative = 1;
    }

    if (i & 0x000F)				/* are any of bits 0-3 set? */
	*c = (i & 0x0F) | 0x20;
    else					/* if not, put in a space */
	*c = 0x20;
	
    if ( ! negative)				/* if positive, set sign bit */
	*c |= 0x10;

    c++; *c = '\0';				/* NULL-terminate */
    return;
}

/*--------------------------------------------------------------------------*\
 * encode_vector()
 *
 * Encodes an xy vector (2 ints) into standard tek vector format, storing
 * into a NULL-terminated character string of length 5.  Note that the y
 * coordinate always comes first.
\*--------------------------------------------------------------------------*/

static void
encode_vector(char *c, int x, int y)
{
    c[0] = (y >> 5)   + 0x20;		/* hy */
    c[1] = (y & 0x1f) + 0x60;		/* ly */
    c[2] = (x >> 5)   + 0x20;		/* hx */
    c[3] = (x & 0x1f) + 0x40;		/* lx */
    c[4] = '\0';			/* NULL */
}

/*--------------------------------------------------------------------------*\
 * tek_vector()
 *
 * Issues a vector draw command, assuming we are in vector plot mode.  XY
 * coordinates are encoded according to the standard xy encoding scheme.
\*--------------------------------------------------------------------------*/

static void
tek_vector(int x, int y)
{
    char c[5];
    c[0] = (y >> 5)   + 0x20;		/* hy */
    c[1] = (y & 0x1f) + 0x60;		/* ly */
    c[2] = (x >> 5)   + 0x20;		/* hx */
    c[3] = (x & 0x1f) + 0x40;		/* lx */
    c[4] = '\0';			/* NULL */

    fprintf( stdout, "%s", c );
}

/*--------------------------------------------------------------------------*\
 * WaitForPage()
 *
 * This routine waits for the user to advance the plot, while handling
 * all other events.
\*--------------------------------------------------------------------------*/

static void
WaitForPage(void)
{
    printf(ALPHA_MODE);		/* Switch to alpha mode (necessary) */
    printf(RING_BELL);		/* and ring bell */
    printf(VECTOR_MODE);	/* Switch out of alpha mode */
    fflush(stdout);

    while ( ! getchar() )
	;
}


syntax highlighted by Code2HTML, v. 0.9.1