The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/*
 * $Id: atarivdi.trm,v 1.13 1999/06/22 11:54:14 lhecking Exp $
 *
 */

/* GNUPLOT - atari.trm */

/*[
 * Copyright 1992, 1993, 1998
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the complete modified source code.  Modifications are to
 * be distributed as patches to the released version.  Permission to
 * distribute binaries produced by compiling modified sources is granted,
 * provided you
 *   1. distribute the corresponding source modifications from the
 *    released version in the form of a patch file along with the binaries,
 *   2. add special version identification to distinguish your version
 *    in addition to the base release version number,
 *   3. provide your name and address as the primary contact for the
 *    support of your modified version, and
 *   4. retain our contact information in regard to use of the base
 *    software.
 * Permission to distribute the released version of the source code along
 * with corresponding source modifications in the form of a patch file is
 * granted with same provisions 2 through 4 for binary distributions.
 *
 * This software is provided "as is" without express or implied warranty
 * to the extent permitted by applicable law.
]*/

/*
 * This file is included by ../term.c.
 *
 * This terminal driver supports:
 *   Atari Screens working with the normal VDI
 *     (this should include TT and big screens)
 *
 * AUTHORS
 *  Alexander Lehmann
 *  HE Koechling
 *
 * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
 *
 * ATARI-related comments please to alexlehm@iti.informatik.th-darmstadt.de
 *
 */

#include "driver.h"

#ifdef TERM_REGISTER
register_term(vdi)
#endif

#ifdef TERM_PROTO

/* function-prototypes */
TERM_PUBLIC void VDI_options(void);
TERM_PUBLIC void VDI_init(void);
TERM_PUBLIC void VDI_reset(void);
TERM_PUBLIC void VDI_graphics(void);
TERM_PUBLIC void VDI_text(void);
TERM_PUBLIC void VDI_move(unsigned int x, unsigned int y);
TERM_PUBLIC void VDI_vector(unsigned int x, unsigned int y);
TERM_PUBLIC void VDI_linetype(int lt);
TERM_PUBLIC int VDI_text_angle(int ang);
TERM_PUBLIC void VDI_put_text(unsigned int x, unsigned int y, const char *str);
TERM_PUBLIC int VDI_justify_text(enum JUSTIFY mode);
TERM_PUBLIC void VDI_point(unsigned int x, unsigned int y, int number);

/* default to hi-res */
#define VDI_XMAX 640
#define VDI_YMAX 400
#define VDI_VCHAR 16
#define VDI_HCHAR 8
#define VDI_HTIC (VDI_XMAX/100)
#define VDI_VTIC VDI_HTIC

#endif /* TERM_PROTO */

#ifndef TERM_PROTO_ONLY
#ifdef TERM_BODY

#ifdef __PUREC__
/* why did they have to change these names ??? */
# include <aes.h>
# include <vdi.h>
# include <tos.h>
#else /* !__PUREC__ i.e. __GNUC__, maybe others */
# include <aesbind.h>
# include <vdibind.h>
# include <osbind.h>
#endif

#define VDI_yc(y) (VDI_maxycoord-(y))
#define VDI_LINETYPES_MAX	11

static int VDI_linetypes[VDI_LINETYPES_MAX] =
{
    0xffff, 0x1111,
    0xffff, 0x5555, 0x3333, 0x7777,
    0x3f3f, 0x0f0f, 0x5f5f, 0xe4e4, 0x55f5
};

static int VDI_lt;
static int vdi_vdi_handle = -1;
static int VDI_maxycoord;
static int VDI_rotation;
static int VDI_numcolors;
static int pxy[128];		/* Maximum of 64 pixels per v_pline */
static int pxy_index;
static int VDI_colors[16];
static int VDI_savecolors[16][3];
static int VDI_numpalette;

#define VDI_c_height_default 6	/* well, well ...               */

static int VDI_c_height = VDI_c_height_default;

static void vdi_flush_line(void);

TERM_PUBLIC void
VDI_options()
{
#define VDIHEXERROR "palette values 3 hex digits, please"
#define VDIHEIGHTERROR "expecting a character height"
    char opt[4];
    int i;
    char *tok_end;

    term_options[0] = NUL;
    VDI_c_height = VDI_c_height_default;

    for (i = 0; i < 17; i++) {
	if (END_OF_COMMAND)
	    break;
	if (token[c_token].length > 3) {
	    VDI_numpalette = 0;
	    VDI_c_height = VDI_c_height_default;
	    term_options[0] = NUL;
	    int_error(c_token, VDIHEXERROR);
	}
	capture(opt, c_token, c_token, 6);
	if (!i) {
	    VDI_c_height = strtoul(opt, &tok_end, 10);
	    if (*tok_end != NUL) {
		VDI_numpalette = 0;
		VDI_c_height = VDI_c_height_default;
		term_options[0] = NUL;
		int_error(c_token, VDIHEIGHTERROR);
	    }
	    if (VDI_c_height > 999)
		VDI_c_height = 999;	/* avoid opt length overflow */
	    sprintf(opt, "%d ", VDI_c_height);
	} else {
	    VDI_colors[i - 1] = strtoul(opt, &tok_end, 16);
	    if (*tok_end != NUL) {
		VDI_numpalette = 0;
		VDI_c_height = VDI_c_height_default;
		term_options[0] = NUL;
		int_error(c_token, VDIHEXERROR);
	    }
	    sprintf(opt, "%03X ", VDI_colors[i - 1]);
	}
	strcat(term_options, opt);
	c_token++;
    }
    VDI_numpalette = (i == 0 ? 0 : i - 1);
}

TERM_PUBLIC void
VDI_init()
{
    int work_in[11];
    int work_out[57];
    int i;
    int hchar, wchar, dummy;
    int rgb[3];
    int num_save;
    char *colors, *tok_end;

    if (VDI_numpalette == 0 && (colors = getenv("GNUCOLORS")) && *colors) {
	for (i = 0; i < 17; i++) {
	    if (!i) {
		VDI_c_height = strtoul(colors, &tok_end, 10);
		if (colors == tok_end) {
		    i = 0;
		    VDI_c_height = VDI_c_height_default;
		    break;
		}
	    } else {
		if (*colors == NUL)
		    break;
		VDI_colors[i] = strtoul(colors, &tok_end, 16);
		if (colors == tok_end || (unsigned) VDI_colors[i] > 0xfff) {
		    i = 0;
		    break;
		}
	    }
	    colors = tok_end;

	    while (*colors == ' ')
		colors++;
	}
	VDI_numpalette = (i == 0 ? 0 : i - 1);
    }
    vdi_vdi_handle = graf_handle(&wchar, &hchar, &dummy, &dummy);
    if (!vdi_vdi_handle)
	int_error(NO_CARET, "Fatal error opening virtual workstation");

    for (i = 0; i < 10; work_in[i++] = 1);
    work_in[10] = 2;		/* use raster coordinates */
    v_opnvwk(work_in, &vdi_vdi_handle, work_out);
    if (!vdi_vdi_handle)
	int_error(NO_CARET, "Fatal error opening virtual workstation");

    vst_height(vdi_vdi_handle, VDI_c_height, &dummy, &dummy, &wchar, &hchar);

    vs_clip(vdi_vdi_handle, 0, work_in);	/* turn clipping off */

    term->xmax = work_out[0] + 1;
    term->ymax = work_out[1] + 1;
    term->h_char = wchar;
    term->v_char = hchar;	/* hchar stands for height this time */
    term->h_tic = (work_out[0] + 1) / 100;
    term->v_tic = term->h_tic;

    VDI_maxycoord = work_out[1];
    VDI_numcolors = work_out[13];
    pxy_index = 0;

    for (i = 0; i < VDI_numpalette; i++) {
	vq_color(vdi_vdi_handle, i, 1, VDI_savecolors[i]);

	rgb[0] = 1000 * (VDI_colors[i] >> 8);
	rgb[0] /= 15;
	rgb[1] = 1000 * ((VDI_colors[i] >> 4) & 15);
	rgb[1] /= 15;
	rgb[2] = 1000 * (VDI_colors[i] & 15);
	rgb[2] /= 15;
	vs_color(vdi_vdi_handle, i, rgb);
    }
#ifdef __PUREC__
/* currently the PureC version runs as .prg and the GCC version runs as .ttp.
   Let's hope that we soon figure out which way is the best */
    v_hide_c(vdi_vdi_handle);
#endif
}

TERM_PUBLIC void
VDI_reset()
{
    int i;

    if (vdi_vdi_handle != -1) {
	for (i = 0; i < VDI_numpalette; i++) {
	    vs_color(vdi_vdi_handle, i, VDI_savecolors[i]);
	}
#ifdef __PUREC__
/* see above */
	v_show_c(vdi_vdi_handle, 0);
#endif
	v_clsvwk(vdi_vdi_handle);
	vdi_vdi_handle = -1;
    }
}

TERM_PUBLIC void
VDI_graphics()
{
    int pxy[8];
    MFDB mfdb;

    fflush(stdout);
    fflush(stderr);
    Cconws("\033f");		/* turn cursor off */
/*  apparently v_clrwk doesn't work with overscan. We'll blit the screen clear.
    v_clrwk( vdi_vdi_handle );
*/
    mfdb.fd_addr = NULL;	/* NULL means actual screen. So we don't need size etc. */

    pxy[0] = pxy[4] = 0;
    pxy[1] = pxy[5] = 0;
    pxy[2] = pxy[6] = term->xmax - 1;
    pxy[3] = pxy[7] = term->ymax - 1;

    vro_cpyfm(vdi_vdi_handle, ALL_WHITE /*0 */ ,
	      pxy, &mfdb, &mfdb);

    pxy_index = 0;
}

TERM_PUBLIC void
VDI_text()
{
    vdi_flush_line();
    Cnecin();			/* wait for any char --> enable screen dump */
    Cconws("\033e");		/* turn cursor on again */
}

TERM_PUBLIC void
VDI_move(unsigned int x, unsigned int y)
{
    vdi_flush_line();

    pxy_index = 1;
    pxy[0] = x;
    pxy[1] = VDI_yc(y);
}

TERM_PUBLIC void
VDI_vector(unsigned int x, unsigned int y)
{
    pxy[2 * pxy_index] = x;
    pxy[2 * pxy_index + 1] = VDI_yc(y);
    pxy_index++;

    if (pxy_index == 64) {	/* we're all full */
	vdi_flush_line();
    }
}

TERM_PUBLIC void
VDI_linetype(int lt)
{
    vdi_flush_line();

    VDI_lt = lt;
}

TERM_PUBLIC void
VDI_put_text(unsigned int x, unsigned int y, const char *str)
{
    int vchar = term->v_char;
    int dummy;

    if (!strlen(str))
	return;

    if (x < 0)
	x = 0;
    if (y < 0)
	y = 0;

    /* align text left and to middle of char height */
    vst_alignment(vdi_vdi_handle, 0, 5, &dummy, &dummy);
    vst_rotation(vdi_vdi_handle, (VDI_rotation ? 900 : 0));
    if (VDI_rotation)
	v_gtext(vdi_vdi_handle, x - vchar / 2 + 1, VDI_yc(y) - 1, str);
    else
	v_gtext(vdi_vdi_handle, x + 1, VDI_yc(y) - vchar / 2 + 1, str);
}

TERM_PUBLIC int
VDI_text_angle(int ang)
{
    VDI_rotation = ang;

    return TRUE;
}

TERM_PUBLIC int
VDI_justify_text(enum JUSTIFY mode)
{
    return FALSE;
}

TERM_PUBLIC void
VDI_point(unsigned int x, unsigned int y, int number)
{
    int old_linetype;

    if (VDI_numcolors == 2) {
	line_and_point(x, y, number);	/* monochrome */
    } else {
	/* we map colors that exceed our limit to dotted lines, but we can't do
	   that with the markers (sortof a generalized line_and_point) */
	old_linetype = VDI_lt;
	if (VDI_lt > VDI_numcolors - 2) {
	    /* same color, but no dots */
	    VDI_linetype(VDI_lt % (VDI_numcolors - 2));
	}
	do_point(x, y, number);
	VDI_linetype(old_linetype);
    }
}

static void
vdi_flush_line()
{
    int line_type;
    int color_index;
    int i;

    if (pxy_index >= 2) {
	if (VDI_numcolors == 2) {	/* Monochrome */
	    color_index = 1;
	    line_type = VDI_lt;
	    if (line_type >= 0)
		line_type %= (VDI_LINETYPES_MAX - 2);
	} else {		/* Color */
	    if (VDI_lt < 0) {
		color_index = 1;
		line_type = VDI_lt;
	    } else {
		color_index = 2 + VDI_lt % (VDI_numcolors - 2);
		line_type = (VDI_lt / (VDI_numcolors - 2)) % (VDI_LINETYPES_MAX - 2);
	    }
	}

	vswr_mode(vdi_vdi_handle, MD_TRANS);
	vsl_color(vdi_vdi_handle, color_index);

	vsl_type(vdi_vdi_handle, 7);
	vsl_udsty(vdi_vdi_handle, VDI_linetypes[line_type + 2]);

	v_pline(vdi_vdi_handle, pxy_index, pxy);
    }
    if (pxy_index >= 1) {
	pxy[0] = pxy[2 * (pxy_index - 1)];
	pxy[1] = pxy[2 * (pxy_index - 1) + 1];
	pxy_index = 1;
    }
}

#endif /* TERM_BODY */

#ifdef TERM_TABLE

TERM_TABLE_START(vdi_driver)
    "vdi", "Atari VDI-Terminal",
    VDI_XMAX, VDI_YMAX, VDI_VCHAR, VDI_HCHAR,
    VDI_VTIC, VDI_HTIC, VDI_options, VDI_init, VDI_reset,
    VDI_text, null_scale, VDI_graphics, VDI_move, VDI_vector,
    VDI_linetype, VDI_put_text, VDI_text_angle,
    VDI_justify_text, VDI_point, do_arrow, set_font_null,
    0, TERM_CAN_MULTIPLOT, 0, 0
TERM_TABLE_END(vdi_driver)

#undef LAST_TERM
#define LAST_TERM vdi_driver

#endif /* TERM_TABLE */

#endif /* TERM_PROTO_ONLY */

#ifdef TERM_HELP
START_HELP(vdi)
"1 atari ST (via VDI)",
"?commands set terminal vdi",
"?set terminal vdi",
"?set term vdi",
"?terminal vdi",
"?term vdi",
"?vdi",
" The `vdi` terminal is the same as the `atari` terminal, except that it sends",
" output to the screen via the VDI and not into AES-Windows.",
"",
" The `vdi` terminal has options to set the character size and the screen",
" colors.",
"",
" Syntax:",
"       set terminal vdi {<fontsize>} {<col0> <col1> ... <col15.}",
"",
" The character size must appear if any colors are to be specified.  Each of",
" the (up to 16) colors is given as a three-digit hex number, where the digits",
" represent RED, GREEN and BLUE (in that order).  The range of 0--15 is scaled",
" to whatever color range the screen actually has.  On a normal ST screen, odd",
" and even intensities are the same.",
"",
" Examples:",
"       set terminal vdi 4    # use small (6x6) font",
"       set terminal vdi 6 0  # set monochrome screen to white on black",
"       set terminal vdi 13 0 fff f00 f0 f ff f0f",
"                  # set first seven colors to black, white, green, blue,",
"                  # cyan, purple, and yellow and use large font (8x16).",
"",
" Additionally, if an environment variable GNUCOLORS exists, its contents are",
" interpreted as an options string, but an explicit terminal option takes",
" precedence."
END_HELP(vdi)
#endif /* TERM_HELP */