[comp.sources.unix] v14i029: Device-independant graphics system, with drivers

rsalz@bbn.com (Rich Salz) (04/07/88)

Submitted-by: Joe Dellinger <joe@hanauma.STANFORD.EDU>
Posting-number: Volume 14, Issue 29
Archive-name: vplot/part24

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 24 (of 24)."
# Wrapped by rsalz@fig.bbn.com on Fri Mar 25 11:47:38 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Vplot_Kernel/filters/dovplot.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Vplot_Kernel/filters/dovplot.c'\"
else
echo shar: Extracting \"'Vplot_Kernel/filters/dovplot.c'\" \(51559 characters\)
sed "s/^X//" >'Vplot_Kernel/filters/dovplot.c' <<'END_OF_FILE'
X/*
X * Copyright 1987 the Board of Trustees of the Leland Stanford Junior
X * University. Official permission to use this software is included in
X * the documentation. It authorizes you to use this file for any
X * non-commercial purpose, provided that this copyright notice is not
X * removed and that any modifications made to this file are commented
X * and dated in the style of my example below.
X */
X
X/*
X *
X *  source file:   ./filters/dovplot.c
X *
X * Joe Dellinger (SEP), June 11 1987
X *	Inserted this sample edit history entry.
X *	Please log any further modifications made to this file:
X */
X/*
X * Joe Dellinger Oct 18 1987
X * 	Made text fatness scale with txscale and scale for GKS compatibility
X * Joe Dellinger Nov 9 1987
X *	Changed "\n" to CRLF in MESG_TEXT calls, since newlines are
X *	no longer mapped into Carriage-return linefeeds automatically.
X *	(This was due to Stew's turning off of output translation.)
X * Joe Dellinger Dec 9 1987
X *	Made the "bad color level" error message more verbose.
X * Joe Dellinger Dec 19 1987
X *	Call dev.attributes(NEW_DASH,...) when the dash pattern has
X *	been changed, call dev.attributes(NEW_PAT,...) when a new raster
X *	pattern has been loaded, call dev.attributes(NEW_FONT,...)
X *	when the txfont, txprec, or txovly has been changed,
X *	dev.attributes(NEW_OVERLAY,...) when the overlay mode has
X *	been changed, dev.attributes(NEW_ALIGN) when the text
X *	alignment mode has been changed, dev.attributes(NEW_FAT) when
X *	the fatness has been changed. Call dev.message(MESG_MESSAGE)
X *	when a message is generated via the VP_MESSAGE vplot command.
X * Joe Dellinger Dec 20 1987
X *	It's up to the device to turn around and call gentext if
X *	txfont < NUMGENFONT.
X * Joe Dellinger Jan 8 1988
X *	Added reset_parameters() to frontend and dovplot.
X *	Turn off ALL polygon shading if shade=NO, even that generated
X *	by raster, text, etc.
X * Joe Dellinger Jan 10 1988
X *	Don't blindly scale up fatmult each time dovplot thinks it's
X *	being called for the first time.
X * Joe Dellinger Jan 14 1988
X *	The text alignment should also be reset between plots.
X * Joe Dellinger Jan 20 1988
X *	Added VP_BEGIN_GROUP and VP_END_GROUP. Fixed nplots bug.
X * Joe Dellinger Jan 22 1988
X *	Added xdim_orig and ydim_orig to pat.h.
X * Joe Dellinger Jan 26 1988
X *	Fixed EOF bug in getvpstring(). Changed rule for mapping
X *	colors to grey levels to match how B+W TV's do it.
X * Joe Dellinger Feb 10 1988
X *	Weight color mismatches to tally with grey mapping method.
X * Joe Dellinger Feb 12 1988
X *	Make sure that VP_WINDOW commands that specify an inverted
X *	clipping rectangle cause everything to be clipped away.
X * Joe Dellinger Feb 16 1988
X *	Make number of arguments passed to dev.attributes and dev.raster
X *	constant to head off future catastrophe from Sun IV's.
X * Joe Dellinger Feb 22 1988
X *	Created INT_PAUSE to be separate from INT_GET_STRING.
X * Joe Dellinger Feb 24 1988
X *	Txfont, txprec, txovly, style, dash line style also reset
X *	on erases.
X *	Only the erase command is handled specially at the start
X *	of the file. This was causing initial setstyle commands
X *	to be left out of their groups!
X * Joe Dellinger Feb 26 1988
X *	Allow vpattributes(END_GROUP,...) to signal dovplot whether it
X *	should exit or not after the call.
X * Joe Dellinger Feb 28 1988
X *	Fatness behaves like a geometric attribute.
X *	Can't use the *= operator on the Sun!
X *	if integer i = 10, then i *= .5 sets i to ZERO.
X *	I wish Sun would get their act together.
X *	This explains several mysterious bugs on the Suns.
X */
X
X/*
X * process a vplot file or stream
X * Keywords: vplot pen generic
X */
X
X#include 	<stdio.h>
X#include 	<math.h>
X#include	<ctype.h>
X#include	<strings.h>
X
X#include	<vplot.h>
X
X#include	"./include/params.h"	/* for machine dependencies */
X#include	"./include/enum.h"
X#include	"./include/err.h"
X#include	"./include/attrcom.h"
X#include	"./include/intcom.h"
X#include	"./include/mesgcom.h"
X#include	"./include/erasecom.h"
X#include	"./include/closestat.h"
X#include	"./include/getxy.h"
X#include	"./include/pat.h"
X#include	"./include/vertex.h"
X#include	"./include/extern.h"
X#include	"./include/round.h"
X
X#define COLOR_MAP(A) color_set[A][MAP];
X#define GREY_MAP(A) color_set[A][_GREY];
X
X/*
X * Banished to an include file so that "indent" can't get its hands on it
X */
X#include "./include/readraster.h"
X
extern int      wantras, smart_raster;
extern int      allowecho;
extern int      brake;
extern FILE    *controltty;
extern int      cur_color;
extern int      pat_color;
extern int      epause;
extern int      erase;
extern int      ever_called;
extern int      fatbase;
extern int      ifat;
extern int      first_time;
extern int      framewindows;
extern int      next_color;
extern int      ipat;
extern int      nplots;
extern int      overlay;
extern struct pat pat[];
extern FILE    *pltout, *pltin, *temp;
extern char     group_name[];
extern int      group_number;
extern char    *txbuffer;
extern int      txbuflen;
extern struct vertex *vxbuffer;
extern int      vxbuflen;
extern int      window;
extern int      xwmax, xwmin, ywmax, ywmin;
extern int      xWmax, xWmin, yWmax, yWmin;
int             xwmin_last, xwmax_last, ywmin_last, ywmax_last;
extern int      xnew, ynew;
extern int      xold, yold;
extern int      xorigin, yorigin;
extern float    scale;
extern float    xscale;
extern float    yscale;
extern int      default_style;
extern int      default_txfont, default_txprec, default_txovly;
extern int      default_overlay;
extern int      color_set[MAX_COL + 1][_NUM_PRIM];
extern int      greycorr ();
extern int      num_col_8;
extern int      xret, yret;
extern int      add_a_cor ();
extern char     interact[];
extern float    dashsum;
extern float    dashpos;
extern float    dashes[];
extern struct txalign txalign;
X
char           *malloc ();
char           *calloc ();
char           *realloc ();
long int        ftell ();
extern void     dithline ();
extern void     wlimit ();
X
int             need_devcolor = NO;
X
dovplot ()
X{
int             i, j, k, c;
int             key, size, npts;
int             nmul;
int             nx, ny, nx_orig, ny_orig;
int             orient, ras_orient;
register int   *ptr;
int             nx_mult, ny_mult;
int             nx_temp, ny_temp;
int            *tempbuf, *ptemp;
FILE           *fopen ();
int             new_style;
int             starterase = 0;
int             col_tab_no, red, green, blue, grey, dist, min_dist, best_col;
int             hacol[NHATCH * 2], hafat[NHATCH * 2], haoff[NHATCH * 2], hasiz[NHATCH * 2], numhatch;
float           angle, xrasmult, yrasmult;
int             xpix, ypix, num_pat, num_byte;
int             yrast, lastrast;
int             xvr_min, xvr_max, yvr_min, yvr_max;
int             xr_min, xr_max, yr_min, yr_max;
int             xvru_min, xvru_max, yvru_min, yvru_max;
int             xru_min, yru_max;
int             xxx[4], yyy[4];
int             pos, ii, jj, kk, num_rep, ras_offset, dither_it;
unsigned char  *rasterline, *rasterline2, *outraster, *outraster2;
unsigned char   ibyte;
int             xnewer, ynewer;
int             xtext0, xtext1, xtext2, ytext0, ytext1, ytext2;
int             type;
int            *marker_vec, *mvec;
int             savefat;
float           savefatmult;
char            string[MAXFLEN + 1];
X
X    /*
X     * Check to make sure we really got anything before we claim we've made a
X     * plot. 
X     */
X    if ((c = getc (pltin)) == EOF)
X	return;
X    ungetc ((char) c, pltin);
X
X    while (((c = getc (pltin)) == VP_ERASE) || ((c == VP_BREAK) && brake))
X    {
X	/*
X	 * This is a baby version of the main switch that takes up most of
X	 * this file. 
X	 */
X	switch (c)
X	{
X	case VP_ERASE:
X	case VP_BREAK:
X	    starterase = 1;
X	    break;
X	}
X    }
X
X    /*
X     * Files that consist only of erase characters and nothing else are
X     * ignored. 
X     */
X    if (c == EOF)
X	return;
X    ungetc ((char) c, pltin);
X
X    if (first_time)
X    {
X	dev.reset ();
X/*
X * Device is now officially open for orders.
X */
X	if (dev_xmax <= dev_xmin ||
X	    dev_ymax <= dev_ymin ||
X	    pixels_per_inch == 0. ||
X	    aspect_ratio == 0. ||
X	    num_col == -1)
X	    ERR (FATAL, name, "Critical variables left unset by device!");
X
X/*
X * Set maximum clipping window for dev.attributes(SET_WINDOW)
X */
X	xwmax_last = dev_xmax;
X	xwmin_last = dev_xmin;
X	ywmax_last = dev_ymax;
X	ywmin_last = dev_ymin;
X
X/*
X * Set up color maps
X */
X	init_colors ();
X
X	ever_called = 1;
X    }
X    else
X    {
X	dev.close (CLOSE_FLUSH);
X	if (epause > 0)
X	{
X	    sleep ((unsigned) epause);
X	}
X	else
X	if (epause < 0)
X	{
X	    dev.close (CLOSE_FLUSH);
X	    message (MESG_ERASE);
X	    message (MESG_ON);
X	    message (MESG_HOME);
X	    message (MESG_READY);
X	    message (MESG_HIGHLIGHT_ON);
X	    message (MESG_TEXT, "Type Return to Continue...  ");
X	    message (MESG_DONE);
X	    dev.interact (INT_PAUSE, controltty, string);
X	    message (MESG_HIGHLIGHT_OFF);
X	    if (!allowecho)
X	    {
X		message (MESG_READY);
X		message (MESG_TEXT, CRLF);
X	    }
X	    message (MESG_DONE);
X	    message (MESG_OFF);
X	    message (MESG_ERASE);
X	}
X	/*
X	 * Inquire point back from device 
X	 */
X	if (interact[0] != '\0')
X	{
X	    getapoint ();
X	}
X    }
X
X    /*
X     * Erase the screen to background color 
X     */
X    if (((erase & FORCE_INITIAL) && (first_time || (erase & DO_LITERALS)))
X	|| (starterase && (erase & DO_LITERALS)))
X    {
X	if (first_time)
X	    dev.erase (ERASE_START);
X	else
X	{
X	    dev.erase (ERASE_MIDDLE);
X	    nplots++;
X	}
X	dev.close (CLOSE_FLUSH);
X    }
X
X    first_time = NO;
X
X/*
X * Reset fatness, cur_color, etc.
X */
X    new_style = default_style;
X    setstyle (new_style);
X    reset ();
X
X/*
X * Make SURE the color is what it's supposed to be, just to be safe.
X */
X    dev.attributes (SET_COLOR, cur_color, 0, 0, 0);
X    need_devcolor = NO;
X
X    message (MESG_OFF);
X    dev.close (CLOSE_FLUSH);
X
X/*
X * Start a group that will contain this frame (always group 0).
X */
X    ii = ftell (pltin);
X    sprintf (group_name, "%s.%d", pltname, nplots);
X    dev.attributes (BEGIN_GROUP, group_number, ii, 0, 0);
X    group_number++;
X
X    if (framewindows)
X	outline_window ();
X
X/*
X * Finally, here's the main loop that does the actual processing of vplot.
X * Notice that some tricky commands (VP_DRAW, VP_SET_COLOR_TABLE) look ahead
X * at the next command to try to anticipate often-occuring situations,
X * so things get a little complicated here.
X */
X    while ((c = getc (pltin)) != EOF)
X    {
X	switch (c)		/* command list */
X	{
X	case VP_SETSTYLE:	/* set the style */
X	    c = getc (pltin);
X	    if ((c == 'r') || (c == 'R') || (c == 'm') || (c == 'M'))
X		new_style = ROTATED;
X	    else
X	    if ((c == 'o') || (c == 'O'))
X		new_style = OLD;
X	    else
X	    if ((c == 'a') || (c == 'A'))
X		new_style = ABSOLUTE;
X	    else
X		new_style = STANDARD;
X	    setstyle (new_style);
X
X	    if (framewindows)
X		outline_window ();
X
X	    break;
X	case VP_MOVE:		/* move */
X	    /*
X	     * Reset position in dash pattern. 
X	     */
X	    dashpos = 0.;
X
X	    GETXY (xold, yold);
X	    break;
X	case VP_DRAW:		/* draw */
X	    GETXY (xnew, ynew);
X	    update_color ();
X	    while ((c = getc (pltin)) == VP_DRAW)
X	    {
X		GETXY (xnewer, ynewer);
X		/*
X		 * Is it the same point? 
X		 */
X		if (xnewer == xnew && ynewer == ynew)
X		    continue;
X		/*
X		 * Is it colinear and horizontal or vertical? 
X		 */
X		if ((ynewer == ynew && ynew == yold &&
X		     ((xnewer > xnew) == (xnew > xold))) ||
X		    (xnewer == xnew && xnew == xold &&
X		     ((ynewer > ynew) == (ynew > yold))))
X		{
X		    ynew = ynewer;
X		    xnew = xnewer;
X		    continue;
X		}
X		dev.vector (xold, yold, xnew, ynew, fat, dashon);
X		xold = xnew;
X		yold = ynew;
X		xnew = xnewer;
X		ynew = ynewer;
X	    }
X	    dev.vector (xold, yold, xnew, ynew, fat, dashon);
X	    xold = xnew;
X	    yold = ynew;
X	    if (c == EOF)
X		goto End_of_file;
X	    ungetc ((char) c, pltin);
X	    break;
X	case VP_PLINE:		/* polyline */
X	    /*
X	     * Reset position in dash pattern. 
X	     */
X	    dashpos = 0.;
X
X	    npts = geth (pltin);
X	    if (npts == 0)
X		break;
X	    GETXY (xold, yold);
X	    npts--;
X	    if (npts == 0)
X		break;
X	    GETXY (xnew, ynew);
X	    npts--;
X	    update_color ();
X	    while (npts > 0)
X	    {
X		GETXY (xnewer, ynewer);
X		npts--;
X		/*
X		 * Is it the same point? 
X		 */
X		if (xnewer == xnew && ynewer == ynew)
X		    continue;
X		/*
X		 * Is it colinear and horizontal or vertical? 
X		 */
X		if ((ynewer == ynew && ynew == yold &&
X		     ((xnewer > xnew) == (xnew > xold))) ||
X		    (xnewer == xnew && xnew == xold &&
X		     ((ynewer > ynew) == (ynew > yold))))
X		{
X		    ynew = ynewer;
X		    xnew = xnewer;
X		    continue;
X		}
X		dev.vector (xold, yold, xnew, ynew, fat, dashon);
X		xold = xnew;
X		yold = ynew;
X		xnew = xnewer;
X		ynew = ynewer;
X	    }
X	    dev.vector (xold, yold, xnew, ynew, fat, dashon);
X	    xold = xnew;
X	    yold = ynew;
X	    break;
X	case VP_PMARK:		/* polymarker */
X	    npts = geth (pltin);/* how many markers ? */
X	    type = geth (pltin);/* what symbol? (any positive integer) */
X	    size = geth (pltin);/* How big? */
X	    size = size * mkscale * vdevscale * RPERIN / TXPERIN;
X
X	    if (npts == 0)
X		break;
X	    /* allocate space for the points */
X	    marker_vec = (int *) malloc ((unsigned) (npts * 2 * sizeof (int)));
X	    mvec = marker_vec;
X	    if (mvec == NULL)
X		ERR (FATAL, name, "Can't malloc memory for markers!");
X
X	    /* read the locations, and transform them to device coordinates */
X	    for (ii = 0; ii < npts; ii++)
X	    {
X		GETXY (xnewer, ynewer);
X		*mvec = xnewer;
X		++mvec;
X		*mvec = ynewer;
X		++mvec;
X	    }
X	    update_color ();
X	    /* call the device routine to display the markers */
X	    dev.marker (npts, type, size, marker_vec);
X	    /* release the storage used for the points */
X	    free ((char *) marker_vec);
X	    break;
X	case VP_ORIGIN:	/* set origin */
X	    xorigin = geth (pltin);
X	    yorigin = geth (pltin);
X	    break;
X	case VP_BEGIN_GROUP:
X	    ii = ftell (pltin) - 1;
X	    getvpstring ();
X	    strncpy (group_name, txbuffer, MAXFLEN);
X	    dev.attributes (BEGIN_GROUP, group_number, ii, 0, 0);
X	    group_number++;
X	    break;
X	case VP_END_GROUP:
X	    group_number--;
X	    if (group_number < 1)
X	    {
X		ERR (WARN, name,
X		     "group invalidly nested");
X		group_number = 1;
X	    }
X	    else
X	    {
X		ii = dev.attributes (END_GROUP, group_number, 0, 0, 0);
X		if (ii == DOVPLOT_EXIT)
X		{
X		    dev.close (CLOSE_FLUSH);
X		    return;
X		}
X		if (ii != DOVPLOT_CONT)
X		    ERR (WARN, name, "dev.attributes(END_GROUP,...) returned junk.");
X	    }
X	    break;
X	case VP_GTEXT:		/* GKS-like text */
X	    xtext0 = 0;
X	    ytext0 = 0;
X	    vptodevxy (xtext0, ytext0, &xtext0, &ytext0);
X	    GETXY (xtext1, ytext1);
X	    GETXY (xtext2, ytext2);
X    g_text:
X	    xtext1 -= xtext0;
X	    xtext2 -= xtext0;
X	    ytext1 -= ytext0;
X	    ytext2 -= ytext0;
X
X	    savefat = fat;
X	    savefatmult = fatmult;
X	    fatmult *= txscale;
X	    if (ifat >= 0)
X	    {
X		fat = fatmult * (float) (ifat + fatbase);
X	    }
X	    else
X	    {
X		fat = -1;
X	    }
X	    update_color ();
X	    getvpstring ();
X/*
X * Fonts less than NUMGENFONT reserved for gentext fonts:
X * up to the device to enforce that rule, though.
X */
X	    dev.text (txbuffer,
X		      (float) xtext1 / TEXTVECSCALE,
X		      (float) ytext1 / TEXTVECSCALE,
X		      (float) xtext2 / TEXTVECSCALE,
X		      (float) ytext2 / TEXTVECSCALE);
X	    fat = savefat;
X	    fatmult = savefatmult;
X	    break;
X	case VP_TEXT:		/* text */
X	    size = geth (pltin);
X	    size = size * txscale * (float) RPERIN / (float) TXPERIN;
X	    orient = (int) geth (pltin);
X    new_text:
X	    xtext0 = 0;
X	    ytext0 = 0;
X	    /* Character path direction */
X	    xtext1 =
X	     ROUND (TEXTVECSCALE * size * cos (orient * 3.14159 / 180.));
X	    ytext1 =
X	     ROUND (TEXTVECSCALE * size * sin (orient * 3.14159 / 180.));
X	    /* Character up vector direction */
X	    orient += 90;
X	    xtext2 =
X	     ROUND (TEXTVECSCALE * size * cos (orient * 3.14159 / 180.));
X	    ytext2 =
X	     ROUND (TEXTVECSCALE * size * sin (orient * 3.14159 / 180.));
X	    vptodevxy (xtext0, ytext0, &xtext0, &ytext0);
X	    vptodevxy (xtext1, ytext1, &xtext1, &ytext1);
X	    vptodevxy (xtext2, ytext2, &xtext2, &ytext2);
X	    goto g_text;
X	    break;
X	case VP_OLDTEXT:	/* archaic format text */
X	    if ((key = geth (pltin)) < 0)
X		ERR (FATAL, name, "invalid text key");
X	    size = (key & 037);
X	    size = size * txscale * (float) RPERIN / (float) TXPERIN;
X	    orient = (int) (((key & 0140) >> 5) * 90);
X	    goto new_text;
X	    break;
X	case VP_OLDAREA:	/* polygon */
X	    npts = geth (pltin);
X	    afat = geth (pltin);
X	    if (afat >= 0)
X	    {
X		afat = fatmult * (fatbase + afat);
X	    }
X	    nx_temp = geth (pltin);
X	    ny_temp = geth (pltin);
X
X/*
X * If a monochrome device, then fill with dot pattern.
X * If a color device, fill with solid color.
X */
X	    nx = nx_temp * patternmult;
X	    if (nx_temp == 1 || (nx_temp > 0 && nx == 0))
X		nx = 1;
X	    ny = ny_temp * patternmult;
X	    if (ny_temp == 1 || (ny_temp > 0 && ny == 0))
X		ny = 1;
X
X	    nx_orig = nx;
X	    ny_orig = ny;
X
X	    if (!mono)
X	    {
X		if (nx_temp == 0 || ny_temp == 0)
X		{
X		    nx = 0;
X		    ny = 0;
X		}
X		else
X		{
X		    nx = 1;
X		    ny = 1;
X		}
X	    }
X	    /*
X	     * Create a temporary pattern 
X	     */
X	    ipat = 0;
X	    if (nx * ny > 0)
X	    {
X		if ((ptr = (int *) calloc ((unsigned) nx * ny, sizeof (int))) == NULL)
X		    ERR (FATAL, name, "cannot alloc memory to load pattern");
X		pat[ipat] .patbits = ptr;
X		ptr[(nx * ny) - 1] = cur_color;
X	    }
X	    else
X		pat[ipat] .patbits = NULL;
X
X	    pat[ipat] .xdim = nx;
X	    pat[ipat] .ydim = ny;
X	    pat[ipat] .xdim_orig = nx_orig;
X	    pat[ipat] .ydim_orig = ny_orig;
X	    npts = getpolygon (npts);
X	    update_color ();
X	    if (afat >= 0)
X		vecoutline (vxbuffer);
X	    if (npts > 2 && shade && nx > 0 && ny > 0)
X		dev.area (npts, vxbuffer);
X	    if (nx * ny > 0)
X		free ((char *) ptr);
X	    break;
X	case VP_AREA:		/* polygon fill */
X	    npts = geth (pltin);
X	    ipat = pat_color;
X
X	    if (pat[ipat] .patbits == NULL && shade)
X	    {
X		/*
X		 * Create a default pattern (solid fill with this color) If
X		 * you don't like this default for a particular device, ie, a
X		 * black and white one, then the device itself can set up
X		 * defaults for colors 0 through 7 in dev.open 
X		 */
X		nx = 1;
X		ny = 1;
X
X		if ((ptr = (int *) calloc ((unsigned) nx * ny, sizeof (int))) == NULL)
X		    ERR (FATAL, name, "cannot alloc memory to load pattern");
X		pat[ipat] .patbits = ptr;
X		ptr[(nx * ny) - 1] = cur_color;
X		pat[ipat] .xdim = nx;
X		pat[ipat] .ydim = ny;
X		pat[ipat] .xdim_orig = nx;
X		pat[ipat] .ydim_orig = ny;
X	    }
X
X	    npts = getpolygon (npts);
X
X	    if (!shade)
X	    {
X		/* At least draw the boundary to show where it is */
X		afat = 0;
X		update_color ();
X		vecoutline (vxbuffer);
X	    }
X	    else
X	    {
X		/* See whether raster or hatch area */
X		if (pat[ipat] .xdim >= 0)
X		{
X		    /* raster */
X		    if (npts > 2 && pat[ipat] .ydim > 0 && pat[ipat] .xdim > 0)
X		    {
X			update_color ();
X			dev.area (npts, vxbuffer);
X		    }
X		}
X		else
X		{
X		    /* hatch */
X		    numhatch = -pat[ipat] .xdim;
X		    angle = 3.14159 * pat[ipat] .ydim / 180.;
X		    ptr = pat[ipat] .patbits;
X		    for (i = 0; i < numhatch * 2; i++)
X		    {
X			hafat[i] = (*ptr++);
X			hacol[i] = (*ptr++);
X			haoff[i] = (*ptr++);
X			hasiz[i] = (*ptr++);
X		    }
X		    if (npts > 2)
X		    {
X			/*
X			 * Hatch patterns don't rotate. The polygon does, the
X			 * fill pattern doesn't. 
X			 */
X			genhatch (npts, numhatch, angle, hafat, hacol, haoff, hasiz, vxbuffer);
X		    }
X		}
X	    }
X	    break;
X	case VP_FAT:		/* fat */
X	    /*
X	     * negative fat always means to not draw the line at all. 
X	     */
X	    ifat = geth (pltin);
X	    if (ifat >= 0)
X	    {
X		fat = fatmult * (float) (ifat + fatbase);
X	    }
X	    else
X	    {
X		fat = -1;
X	    }
X	    dev.attributes (NEW_FAT, fat, 0, 0, 0);
X	    break;
X	case VP_COLOR:		/* change color */
X	    pat_color = geth (pltin);
X	    if (pat_color > MAX_COL || pat_color < 0)
X	    {
X		ERR (WARN, name, "bad color number %d (max %d, min 0)",
X		     pat_color, MAX_COL);
X		pat_color = DEFAULT_COLOR;
X	    }
X	    next_color = COLOR_MAP (pat_color);
X	    if (next_color != cur_color)
X	    {
X		cur_color = next_color;
X		need_devcolor = YES;
X	    }
X	    /*
X	     * Pattern zero reserved for the OLD_AREA command, so increment
X	     * the rest by one to make room. 
X	     */
X	    pat_color++;
X	    break;
X	case VP_SET_COLOR_TABLE:	/* set color table entry */
X	    /*
X	     * The logic here is a bit tricky. Basically, it goes like this:
X	     * If the device actually has a settable color of that number,
X	     * then reset the device's color as asked. Otherwise, take the
X	     * closest color that we have and map to that. Color 0 is the
X	     * background color, and is special. Merely "close" colors are
X	     * not mapped to Color 0... it has to be exact. Even devices with
X	     * NO settable colors are still sent colors 0 through 7, and
X	     * these colors are then always left set to their original
X	     * defaults. In this way you can handle terminals like the GIGI
X	     * which have colors but not SETTABLE colors. Also remember that
X	     * the device itself will THEN have to permute colors 0 through 7
X	     * on top of all this to correspond with Vplot's definitions! 
X	     */
X	    col_tab_no = geth (pltin);
X	    if (col_tab_no > MAX_COL || col_tab_no < 0)
X	    {
X		ERR (FATAL, name, "Bad color table value %d (%d max)",
X		     col_tab_no, MAX_COL);
X	    }
X	    red = geth (pltin);
X	    green = geth (pltin);
X	    blue = geth (pltin);
X	    if (red > MAX_GUN || green > MAX_GUN || blue > MAX_GUN
X		|| red < 0 || green < 0 || blue < 0)
X	    {
X		ERR (FATAL, name,
X		     "Bad color level in color %d (%d,%d,%d), %d max",
X		     col_tab_no, red, green, blue, MAX_GUN);
X	    }
X	    if (col_tab_no < num_col)
X	    {
X		dev.attributes (SET_COLOR_TABLE, col_tab_no, red, green, blue);
X		color_set[col_tab_no][STATUS] = SET;
X	    }
X	    else
X	    if (col_tab_no > 7)
X	    {
X		color_set[col_tab_no][STATUS] = MAPPED;
X	    }
X	    else
X	    {
X		if (col_tab_no > 0)
X		{
X		    color_set[col_tab_no][STATUS] = MAP_SET;
X		    /*
X		     * Means that we need to map these but they are still set
X		     * to the original colors and can't be changed. Color 0
X		     * is always background, and any other color exactly the
X		     * same color as color 0 "wants to be", even if color 0
X		     * actually can't be and hasn't been reset, is mapped to
X		     * color zero if it can't be set. 
X		     */
X		}
X	    }
X	    /*
X	     * Save the color that this color table number wants to be 
X	     */
X	    color_set[col_tab_no][_RED] = red;
X	    color_set[col_tab_no][_GREEN] = green;
X	    color_set[col_tab_no][_BLUE] = blue;
X	    /*
X	     * grey level is "Black and White TV style" mapped from color,
X	     * with corrections added by the subroutine greycorr. 
X	     */
X	    grey = (blue * 1 + red * 2 + green * 4 + 6) / 7;
X	    color_set[col_tab_no][_GREY] = greycorr (grey);
X	    /*
X	     * If the next command is also a set color table command, we can
X	     * postpone doing this and kill 2 (or more) birds with one stone. 
X	     */
X	    c = getc (pltin);
X	    if (c == EOF)
X		goto End_of_file;
X	    ungetc ((char) c, pltin);
X	    if (c != VP_SET_COLOR_TABLE)
X	    {
X		if (mono)
X		{
X		    for (ii = 1; ii <= MAX_COL; ii++)
X		    {
X			if (color_set[ii][_RED] == color_set[0][_RED] &&
X			    color_set[ii][_GREEN] == color_set[0][_GREEN] &&
X			    color_set[ii][_BLUE] == color_set[0][_BLUE])
X			{
X			    color_set[ii][MAP] = 0;
X			}
X			else
X			{
X			    color_set[ii][MAP] = 7;
X			}
X		    }
X		}
X		else
X		{
X		    /*
X		     * For all color table entries that aren't set, (because
X		     * we ran out of colors, for example) find the best color
X		     * that IS set and use that instead. 
X		     */
X		    for (ii = num_col; ii <= MAX_COL; ii++)
X		    {
X			if (color_set[ii][STATUS] & MAPPED)
X			{
X			    min_dist = MAX_GUN * MAX_GUN * 8;
X			    for (i = num_col_8 - 1; i >= 0; i--)
X			    {
X				/*
X				 * Colors 1 through 7 are guaranteed SET, So
X				 * we always get an answer. Color zero is
X				 * background and special. To map to it you
X				 * have to hit its color exactly, and no
X				 * other color matched exactly first. 
X				 */
X				if (color_set[i][STATUS] & SET)
X				{
X				    if (color_set[i][STATUS] == SET)
X				    {
X					k = color_set[i][_RED] - color_set[ii][_RED];
X					dist = 2 * k * k;
X					k = color_set[i][_GREEN] - color_set[ii][_GREEN];
X					dist += 4 * k * k;
X					k = color_set[i][_BLUE] - color_set[ii][_BLUE];
X					dist += k * k;
X				    }
X				    else
X				    {
X					k = MAX_GUN * ((i & 2) / 2) - color_set[ii][_RED];
X					dist = 2 * k * k;
X					k = MAX_GUN * ((i & 4) / 4) - color_set[ii][_GREEN];
X					dist += 4 * k * k;
X					k = MAX_GUN * ((i & 1) / 1) - color_set[ii][_BLUE];
X					dist += k * k;
X				    }
X				    if (dist < min_dist && (i != 0 || dist == 0))
X				    {
X					min_dist = dist;
X					best_col = i;
X					if (dist == 0)
X					{
X					    /*
X					     * Might as well look no further 
X					     */
X					    break;
X					}
X				    }
X				}
X			    }
X			    color_set[ii][MAP] = best_col;
X			}
X		    }
X		}
X	    }
X	    break;
X	case VP_PURGE:		/* purge pltout buffers */
X	    dev.close (CLOSE_FLUSH);
X	    break;
X	case VP_BREAK:		/* break */
X	case VP_ERASE:		/* erase */
X	    dev.close (CLOSE_FLUSH);
X
X	    if ((c == VP_ERASE) || brake)
X	    {
X		group_number--;
X		if (group_number != 0)
X		{
X		    ERR (WARN, name,
X			 "group contains erase");
X		    group_number = 0;
X		}
X		else
X		{
X		    ii = dev.attributes (END_GROUP, group_number, 0, 0, 0);
X		    if (ii == DOVPLOT_EXIT)
X			return;
X		    if (ii != DOVPLOT_CONT)
X			ERR (WARN, name, "dev.attributes(END_GROUP,...) returned junk.");
X		}
X	    }
X
X	    if (epause < 0)
X	    {
X		message (MESG_ERASE);
X		message (MESG_ON);
X		message (MESG_HOME);
X		message (MESG_READY);
X		message (MESG_HIGHLIGHT_ON);
X		message (MESG_TEXT, "Type Return to Continue...  ");
X		message (MESG_DONE);
X		dev.interact (INT_PAUSE, controltty, string);
X		message (MESG_HIGHLIGHT_OFF);
X		if (!allowecho)
X		{
X		    message (MESG_READY);
X		    message (MESG_TEXT, CRLF);
X		}
X		message (MESG_DONE);
X		message (MESG_OFF);
X		message (MESG_ERASE);
X	    }
X	    else
X	    {
X		if (epause > 0)
X		    sleep ((unsigned) epause);
X	    }
X	    /*
X	     * Inquire point back from device 
X	     */
X	    if (interact[0] != '\0')
X	    {
X		getapoint ();
X	    }
X
X	    if (erase & DO_LITERALS)
X		if ((c == VP_ERASE) || brake)
X		{
X		    dev.erase (ERASE_MIDDLE);
X		    nplots++;
X		}
X		else
X		{
X		    dev.erase (ERASE_BREAK);
X		    nplots++;
X		}
X
X	    new_style = default_style;
X	    setstyle (new_style);
X	    reset ();
X
X	    if ((c == VP_ERASE) || brake)
X	    {
X		ii = ftell (pltin);
X		sprintf (group_name, "%s.%d", pltname, nplots);
X		dev.attributes (BEGIN_GROUP, group_number, ii, 0, 0);
X		group_number++;
X	    }
X
X	    if (framewindows)
X		outline_window ();
X
X	    break;
X	case VP_WINDOW:	/* window */
X	    if (window)
X	    {
X		xwmin = geth (pltin);
X		ywmin = geth (pltin);
X		xwmax = geth (pltin);
X		ywmax = geth (pltin);
X
X		if (xwmin > xwmax || ywmin > ywmax)
X		{
X/*
X * vptodevw will always return a window that is the "right way around",
X * even if the original window was inverted. So produce an inside-out
X * window which will clip everything away to nothing.
X */
X
X		    xwmin = xWmax + 1;
X		    xwmax = xWmin - 1;
X		    ywmin = yWmax + 1;
X		    ywmax = yWmin - 1;
X		}
X		else
X		{
X
X		    vptodevw (xwmin, ywmin, xwmax, ywmax, &xwmin, &ywmin, &xwmax, &ywmax);
X
X		    wlimit (xWmin, xWmax, &xwmin, &xwmax);
X		    wlimit (yWmin, yWmax, &ywmin, &ywmax);
X		}
X	    }
X	    else
X	    {
X		geth (pltin);
X		geth (pltin);
X		geth (pltin);
X		geth (pltin);
X	    }
X	    reset_windows ();
X	    if (framewindows)
X		outline_window ();
X	    break;
X	case VP_NOOP:		/* no op */
X	    break;
X	case VP_TXALIGN:	/* set text alignment */
X	    /*
X	     * These are made available to the device text routine 
X	     */
X	    txalign.hor = geth (pltin);
X	    txalign.ver = geth (pltin);
X	    dev.attributes (NEW_ALIGN, txalign.hor, txalign.ver, 0, 0);
X	    break;
X	case VP_TXFONTPREC:	/* set text font */
X	    /*
X	     * These are made available to the device text routine 
X	     */
X	    ii = geth (pltin);
X	    if (ii >= 0)
X		txfont = ii;
X	    else
X		ii = -1;
X
X	    jj = geth (pltin);
X	    if (jj >= 0)
X		txprec = jj;
X	    else
X		jj = -1;
X
X	    kk = geth (pltin);
X	    if (kk >= 0)
X		txovly = kk;
X	    else
X		kk = -1;
X
X	    /*
X	     * Another way for the device to keep track of changes. 
X	     */
X	    dev.attributes (NEW_FONT, ii, jj, kk, 0);
X	    break;
X	case VP_OVERLAY:	/* change overlay mode */
X	    /*
X	     * This is made available to the device dependent subroutines 
X	     */
X	    overlay = geth (pltin);
X	    dev.attributes (NEW_OVERLAY, overlay, 0, 0, 0);
X	    break;
X	case VP_PATLOAD:	/* load a pattern */
X	    nmul = geth (pltin);
X	    ny = geth (pltin);
X
X	    /* See whether Raster or Hatch */
X	    if (ny >= 0)
X	    {
X		/* Raster */
X		/* nmul gives pixels_per_inch pattern is designed for */
X		ny_mult = ny * (pixels_per_inch / nmul) * patternmult / aspect_ratio;
X		if (ny_mult == 0 && ny > 0)
X		    ny_mult = 1;
X		nx = geth (pltin);
X		nx_mult = nx * (pixels_per_inch / nmul) * patternmult;
X		if (nx_mult == 0 && nx > 0)
X		    nx_mult = 1;
X
X		ipat = geth (pltin) + 1;
X		if (ipat > NPAT || ipat < 1)
X		    ERR (FATAL, name, "bad pattern number %d (max %d, min 1)", ipat, NPAT);
X		/*
X		 * Free up pattern that may already be there 
X		 */
X		if (pat[ipat] .patbits != NULL)
X		{
X		    free ((char *) pat[ipat] .patbits);
X		}
X
X		if (nx_mult * ny_mult > 0)
X		{
X		    if ((ptr = (int *) malloc ((unsigned) (nx_mult * ny_mult * sizeof (int)))) == NULL)
X			ERR (FATAL, name, "cannot alloc memory to load pattern");
X		    pat[ipat] .patbits = ptr;
X		}
X		else
X		{
X		    if ((ptr = (int *) malloc ((unsigned) (1 * sizeof (int)))) == NULL)
X			ERR (FATAL, name, "cannot alloc memory to load dummy pattern");
X		    pat[ipat] .patbits = ptr;
X		    ptr[0] = 0;
X		}
X
X		if (nx * ny > 0)
X		{
X		    if ((tempbuf = (int *) malloc ((unsigned) (nx * ny * sizeof (int)))) == NULL)
X			ERR (FATAL, name,
X			     "cannot alloc memory to load pattern's temporary buffer");
X		}
X		else
X		    tempbuf = NULL;
X
X		/*
X		 * read in pattern 
X		 */
X		ptemp = tempbuf;
X		for (j = 0; j < nx * ny; j++)
X		{
X		    k = geth (pltin);
X		    if (k > MAX_COL || k < 0)
X		    {
X			ERR (WARN, name, "bad color number in pattern %d (max %d, min 0)",
X			     k, MAX_COL);
X			k = DEFAULT_COLOR;
X		    }
X		    *ptemp++ = COLOR_MAP (k);
X		}
X
X		/*
X		 * copy into patbits, with "stretching" 
X		 */
X		for (i = 0; i < ny_mult; i++)
X		{
X		    ny_temp = i * ny / ny_mult;
X		    for (j = 0; j < nx_mult; j++)
X		    {
X			nx_temp = j * nx / nx_mult;
X			ptr[j + nx_mult * i] = tempbuf[nx_temp + nx * ny_temp];
X		    }
X		}
X		/*
X		 * set dimensions of pattern 
X		 */
X		pat[ipat] .xdim = nx_mult;
X		pat[ipat] .ydim = ny_mult;
X		pat[ipat] .xdim_orig = nx_mult;
X		pat[ipat] .ydim_orig = ny_mult;
X
X		if (tempbuf != NULL)
X		    free ((char *) tempbuf);
X
X		dev.attributes (NEW_PAT, ipat, 0, 0, 0);
X	    }
X	    else
X	    {
X		/* Hatch Pattern */
X		/* nmul gives angle, ny is merely a flag */
X		nx = geth (pltin);
X		if (nx <= 0 || nx * 2 > NHATCH)
X		    ERR (FATAL, name, "bad numhatch %d (max %d/2, min 1)", nx, NHATCH);
X		ipat = geth (pltin) + 1;
X		if (ipat > NPAT || ipat < 1)
X		    ERR (FATAL, name, "bad pattern number %d (max %d, min 1)", ipat, NPAT);
X		/*
X		 * Free up pattern that may already be there 
X		 */
X		if (pat[ipat] .patbits != NULL)
X		{
X		    free ((char *) pat[ipat] .patbits);
X		}
X		if ((ptr = (int *) malloc ((unsigned) (nx * 4 * 2 * sizeof (int)))) == NULL)
X		    ERR (FATAL, name, "cannot alloc memory to load pattern");
X		pat[ipat] .patbits = ptr;
X
X		for (i = 0; i < nx * 2; i++)
X		{
X		    hafat[i] = geth (pltin);
X		    if (hafat[i] >= 0)
X		    {
X			hafat[i] = fatmult * (fatbase + hafat[i]);
X		    }
X		    k = geth (pltin);
X		    if (k > MAX_COL || k < 0)
X		    {
X			ERR (WARN, name, "bad color number in hatch %d (max %d, min 0)",
X			     k, MAX_COL);
X			k = DEFAULT_COLOR;
X		    }
X		    hacol[i] = COLOR_MAP (k);
X		    haoff[i] = geth (pltin) * patternmult * pixels_per_inch / RPERIN;
X		    hasiz[i] = geth (pltin);
X		}
X		/*
X		 * Find the smallest hatch interval. 1/2 that, and then force
X		 * everything to be a multiple of that. If this were not
X		 * done, then hatch intervals that originally differed by
X		 * some simple fraction might end up slightly off, causing
X		 * very unsightly beats. 
X		 */
X		/*
X		 * Upper quantization limit of 1/10 inch 
X		 */
X		k = (RPERIN / 10) * 2;
X		for (i = 0; i < nx * 2; i++)
X		{
X		    if (hasiz[i] > 0 && hasiz[i] < k)
X			k = hasiz[i];
X		}
X		j = k * (patternmult * pixels_per_inch / RPERIN) / 2.;
X		if (j < 1)
X		    j = 1;
X		for (i = 0; i < nx * 2; i++)
X		{
X		    hasiz[i] = ((int) ((hasiz[i] * 2) / k)) * j;
X		}
X		/*
X		 * The above algorithm also means that you can't have a hatch
X		 * pattern come out on any device with a repetition rate of
X		 * faster than once per two pixels. 
X		 */
X
X		for (i = 0; i < nx * 2; i++)
X		{
X/*
X * Make sure haoff < hasiz
X */
X		    if (haoff[i] >= hasiz[i])
X			haoff[i] = 0;
X		    *ptr++ = hafat[i];
X		    *ptr++ = hacol[i];
X		    *ptr++ = haoff[i];
X		    *ptr++ = hasiz[i];
X		}
X		/*
X		 * set numhatch and angle... dimensions are 2 * numhatch by 4
X		 * . pat[ipat].xdim negative is a flag that this is a hatch
X		 * pattern, not raster, and so must be treated differently. 
X		 */
X		/*
X		 * numhatch, with neg as flag for hatch numhatch = 0 is OK,
X		 * because that means don't fill, same as nx = 0. 
X		 */
X		pat[ipat] .xdim = -nx;
X		pat[ipat] .ydim = nmul;	/* angle */
X	    }
X	    break;
X	case VP_BIT_RASTER:	/* bit raster data */
X	case VP_BYTE_RASTER:	/* byte raster data */
X	    ras_orient = geth (pltin);
X	    if (rotate % 90 != 0)
X	    {
X		if (wantras)
X		{
X		    ERR (WARN, name, "Raster only possible in 4 principal orientations");
X		    wantras = NO;
X		}
X	    }
X	    else
X	    {
X		ras_orient += rotate / 90;
X		if (ras_orient >= 0)
X		    ras_orient = ras_orient % 4;
X		else
X		    ras_orient = ((ras_orient % 4) + 4) % 4;
X	    }
X
X	    /*
X	     * They're on their honor to not go out of bounds. This check is
X	     * just for things that HAVE to go out of bounds. 
X	     */
X	    ras_offset = geth (pltin);
X
X	    if (ras_offset + 0 > MAX_COL || ras_offset + 255 < 0)
X	    {
X		ERR (FATAL, name, "Absurd raster offset %d", ras_offset);
X	    }
X
X	    xvr_min = geth (pltin);
X	    yvr_min = geth (pltin);
X	    xvr_max = geth (pltin);
X	    yvr_max = geth (pltin);
X	    vptodevw (xvr_min, yvr_min, xvr_max, yvr_max,
X		      &xvr_min, &yvr_min, &xvr_max, &yvr_max);
X	    xvru_min = xvr_min;
X	    yvru_min = yvr_min;
X	    xvru_max = xvr_max;
X	    yvru_max = yvr_max;
X
X	    xpix = geth (pltin);
X	    ypix = geth (pltin);
X
X	    switch (ras_orient)
X	    {
X	    case 0:
X		xrasmult = (float) xpix / (float) (xvr_max - xvr_min);
X		yrasmult = (float) ypix / (float) (yvr_max - yvr_min);
X		xvr_max--;
X		yvr_max--;
X		break;
X	    case 1:
X		yrasmult = (float) ypix / (float) (xvr_max - xvr_min);
X		xrasmult = (float) xpix / (float) (yvr_max - yvr_min);
X		xvr_max--;
X		yvr_min++;
X		break;
X	    case 2:
X		xrasmult = (float) xpix / (float) (xvr_max - xvr_min);
X		yrasmult = (float) ypix / (float) (yvr_max - yvr_min);
X		xvr_min++;
X		yvr_min++;
X		break;
X	    case 3:
X		yrasmult = (float) ypix / (float) (xvr_max - xvr_min);
X		xrasmult = (float) xpix / (float) (yvr_max - yvr_min);
X		xvr_min++;
X		yvr_max--;
X		break;
X	    }
X
X	    if (wantras && smart_raster)
X	    {
X		rasterline = (unsigned char *) malloc ((unsigned) ((xpix + 7 + 2) * sizeof (unsigned char)));
X		rasterline2 = (unsigned char *) malloc ((unsigned) ((xpix + 7 + 2) * sizeof (unsigned char)));
X		if (rasterline == NULL || rasterline2 == NULL)
X		    ERR (FATAL, name, "cannot alloc memory to load raster line");
X
X		outraster = (unsigned char *) malloc ((unsigned) (xpix * ypix) * sizeof (unsigned char));
X		if (outraster == NULL)
X		    ERR (FATAL, name, "cannot alloc memory to load raster image");
X
X/*
X * See whether we want to dither or not.
X * Dither if monochrome device and dithering has been asked for.
X * It's up to the device to decide whether to actually do this.
X */
X		dither_it = dither && mono;
X
X		/*
X		 * Read in the Raster data for "Smart" devices, ie, those
X		 * which can stretch (and dither) their own raster. 
X		 */
X		num_rep = 0;
X		for (yrast = 0; yrast < ypix; yrast++)
X		{
X		    /*
X		     * Read in the next raster line, if we have a new one 
X		     */
X		    if (num_rep <= 0)
X		    {
X			num_rep = geth (pltin);
X			if (num_rep <= 0)
X			    ERR (FATAL, name, "Bad Raster line multiplier");
X			pos = 0;
X		new_pat:num_pat = geth (pltin);
X			num_byte = geth (pltin);
X			if (num_pat <= 0 || num_byte <= 0 ||
X			    pos + num_pat * num_byte > xpix)
X			    ERR (FATAL, name, "Raster line not length promised");
X
X			if (num_pat > 1)
X			{
X			    if (dither_it)
X			    {
X				READ_RASTER (
X					     rasterline2[j] = GREY_MAP (ras_offset + (int) fgetc (pltin)),
X					     rasterline2[j + jj] = GREY_MAP (ras_offset * ((ibyte & (001 << (7 - j))) != 0))
X				 );
X			    }
X			    else
X			    {
X				READ_RASTER (
X					     rasterline2[j] = COLOR_MAP (ras_offset + (int) fgetc (pltin)),
X					     rasterline2[j + jj] = COLOR_MAP (ras_offset * ((ibyte & (001 << (7 - j))) != 0))
X				 );
X			    }
X			    for (j = 0; j < num_pat; j++)
X			    {
X				for (k = 0; k < num_byte; k++)
X				{
X				    rasterline[pos] = rasterline2[k];
X				    pos++;
X				}
X			    }
X			}
X			else
X			{
X			    if (dither_it)
X			    {
X				READ_RASTER (
X					     rasterline[pos + j] = GREY_MAP (ras_offset + (int) fgetc (pltin)),
X					     rasterline[pos + j + jj] = GREY_MAP (ras_offset * ((ibyte & (001 << (7 - j))) != 0))
X				 );
X			    }
X			    else
X			    {
X				READ_RASTER (
X					     rasterline[pos + j] = COLOR_MAP (ras_offset + (int) fgetc (pltin)),
X					     rasterline[pos + j + jj] = COLOR_MAP (ras_offset * ((ibyte & (001 << (7 - j))) != 0))
X				 );
X			    }
X			    pos += num_byte;
X			}
X
X			if (pos < xpix)
X			    goto new_pat;
X			if (pos != xpix)
X			    ERR (FATAL, name, "Raster line not length promised");
X		    }
X		    num_rep--;
X		    for (ii = 0; ii < xpix; ii++)
X		    {
X			outraster[ii + yrast * xpix] = rasterline[ii];
X		    }
X		}
X
X		/* Smart form */
X		dev.raster (xpix, ypix, xvr_min, yvr_min, xvr_max, yvr_max,
X			    outraster, ras_orient, dither_it);
X
X		free ((char *) rasterline);
X		free ((char *) rasterline2);
X		free ((char *) outraster);
X	    }
X	    else
X	    {
X		wlimit (xwmin, xwmax, &xvr_min, &xvr_max);
X		wlimit (ywmin, ywmax, &yvr_min, &yvr_max);
X
X		switch (ras_orient)
X		{
X		case 0:
X		    xvr_max++;
X		    yvr_max++;
X		    xr_max = xvr_max - xvru_min;
X		    xr_min = xvr_min - xvru_min;
X		    yr_max = yvr_max - yvru_min;
X		    yr_min = yvr_min - yvru_min;
X		    yru_max = yvru_max - yvru_min;
X		    break;
X		case 1:
X		    xvr_max++;
X		    yvr_min--;
X		    xr_max = yvru_max - yvr_min;
X		    xr_min = yvru_max - yvr_max;
X		    yr_max = xvr_max - xvru_min;
X		    yr_min = xvr_min - xvru_min;
X		    yru_max = xvru_max - xvru_min;
X		    break;
X		case 2:
X		    xvr_min--;
X		    yvr_min--;
X		    xr_max = xvru_max - xvr_min;
X		    xr_min = xvru_max - xvr_max;
X		    yr_max = yvru_max - yvr_min;
X		    yr_min = yvru_max - yvr_max;
X		    yru_max = yvru_max - yvru_min;
X		    break;
X		case 3:
X		    xvr_min--;
X		    yvr_max++;
X		    xr_max = yvr_max - yvru_min;
X		    xr_min = yvr_min - yvru_min;
X		    yr_max = xvru_max - xvr_min;
X		    yr_min = xvru_max - xvr_max;
X		    yru_max = xvru_max - xvru_min;
X		    break;
X		}
X		xru_min = 0;
X
X		if (yr_max < yr_min || xr_max < xr_min || !wantras)
X		{
X		    /*
X		     * We need to read through all the raster stuff, even if
X		     * we never use it. 
X		     */
X		    yr_max = yr_min;
X		    xr_max = xr_min;
X		}
X
X		rasterline = (unsigned char *) malloc ((unsigned) ((xpix + 7 + 2) * sizeof (unsigned char)));
X		rasterline2 = (unsigned char *) malloc ((unsigned) ((xpix + 7 + 2) * sizeof (unsigned char)));
X		if (rasterline == NULL || rasterline2 == NULL)
X		    ERR (FATAL, name, "cannot alloc memory to load raster line");
X
X/*
X * See whether we need to dither or not.
X * Dither if monochrome device and dithering has been asked for,
X * Except if it is black-and-white bit raster already anyway.
X * For some reason putting "GREY_MAP" directly in the if makes a
X * syntax error. I think it is a compiler bug.
X */
X		dither_it = dither && mono;
X		if (dither_it && c == VP_BIT_RASTER)
X		{
X		    j = GREY_MAP (0 * ras_offset);
X		    k = GREY_MAP (1 * ras_offset);
X		    if ((j == 0 || j == 255) && (k == 0 || k == 255))
X			dither_it = NO;
X		}
X
X		if (xr_max > xr_min)
X		{
X		    outraster2 = (unsigned char *) malloc ((unsigned) ((xr_max - xr_min) * sizeof (char)));
X		    if (dither_it)
X		    {
X			outraster = (unsigned char *) malloc ((unsigned) ((xr_max - xr_min) * sizeof (char)));
X		    }
X		    else
X		    {
X			outraster = outraster2;
X		    }
X		    if (outraster2 == NULL || outraster == NULL)
X			ERR (FATAL, name, "cannot alloc memory to load raster line");
X		}
X		else
X		{
X		    outraster2 = NULL;
X		    outraster = NULL;
X		}
X
X		/*
X		 * Read in the Raster data 
X		 */
X		lastrast = -1;
X		num_rep = 0;
X		for (i = yr_max - 1; i >= yr_min - 1; i--)
X		{
X		    yrast = (yru_max - 1 - i) * yrasmult;
X		    if (i == yr_min - 1)
X		    {
X			/*
X			 * Assure that the last bit of unused raster, if any,
X			 * is read. This last time through the loop is a
X			 * "dummy". 
X			 */
X			yrast = ypix - 1;
X		    }
X
X		    for (ii = 0; ii < (yrast - lastrast); ii++)
X		    {
X			/*
X			 * Read in the next raster line, if we have a new one 
X			 */
X			if (num_rep <= 0)
X			{
X			    num_rep = geth (pltin);
X			    if (num_rep <= 0)
X				ERR (FATAL, name, "Bad Raster line multiplier");
X			    pos = 0;
X		    new_pat2:num_pat = geth (pltin);
X			    num_byte = geth (pltin);
X			    if (num_pat <= 0 || num_byte <= 0 ||
X				pos + num_pat * num_byte > xpix)
X				ERR (FATAL, name, "Raster line not length promised");
X
X/*
X * Only bother with it if we're actually going to use it
X */
X			    if (ii + num_rep >= yrast - lastrast
X				&& xr_max > xr_min && i >= yr_min)
X			    {
X				if (num_pat > 1)
X				{
X				    if (dither_it)
X				    {
X					READ_RASTER (
X						     rasterline2[j] = GREY_MAP (ras_offset + (int) fgetc (pltin)),
X						     rasterline2[j + jj] = GREY_MAP (ras_offset * ((ibyte & (001 << (7 - j))) != 0))
X					 );
X				    }
X				    else
X				    {
X					READ_RASTER (
X						     rasterline2[j] = COLOR_MAP (ras_offset + (int) fgetc (pltin)),
X						     rasterline2[j + jj] = COLOR_MAP (ras_offset * ((ibyte & (001 << (7 - j))) != 0))
X					 );
X				    }
X				    for (j = 0; j < num_pat; j++)
X				    {
X					for (k = 0; k < num_byte; k++)
X					{
X					    rasterline[pos] = rasterline2[k];
X					    pos++;
X					}
X				    }
X				}
X				else
X				{
X				    if (dither_it)
X				    {
X					READ_RASTER (
X						     rasterline[pos + j] = GREY_MAP (ras_offset + (int) fgetc (pltin)),
X						     rasterline[pos + j + jj] = GREY_MAP (ras_offset * ((ibyte & (001 << (7 - j))) != 0))
X					 );
X				    }
X				    else
X				    {
X					READ_RASTER (
X						     rasterline[pos + j] = COLOR_MAP (ras_offset + (int) fgetc (pltin)),
X						     rasterline[pos + j + jj] = COLOR_MAP (ras_offset * ((ibyte & (001 << (7 - j))) != 0))
X					 );
X				    }
X				    pos += num_byte;
X				}
X			    }
X			    else
X			    {
X/*
X * We're just going to turn right around and read another one,
X * So throw this away!
X */
X				if (c == VP_BYTE_RASTER)
X				{
X				    for (j = 0; j < num_byte; j++)
X				    {
X					fgetc (pltin);
X				    }
X				}
X				else
X				{
X				    for (j = 0; j < num_byte; j += 8)
X				    {
X					fgetc (pltin);
X				    }
X				}
X				pos += num_pat * num_byte;
X			    }
X			    if (pos < xpix)
X				goto new_pat2;
X			    if (pos != xpix)
X				ERR (FATAL, name, "Raster line not length promised");
X
X			    if (wantras && xr_max > xr_min && i >= yr_min)
X			    {
X				for (j = xr_min; j < xr_max; j++)
X				{
X				    outraster2[j - xr_min] =
X				     rasterline[(int) ((j - xru_min) * xrasmult)];
X				}
X			    }
X			}
X			num_rep--;
X		    }
X		    lastrast = yrast;
X
X		    if (xr_max > xr_min && i >= yr_min)
X		    {
X			if (dither_it)
X			{
X			    dithline (outraster2, outraster, xr_max - xr_min, yr_max - 1 - i, dither);
X			}
X			/* Dumb forms */
X			switch (ras_orient)
X			{
X			case 0:
X			    dev.raster (yr_max - 1 - i, yr_max - yr_min,
X					xvr_min, i + yvru_min,
X				     xr_max - xr_min, ras_orient, outraster,
X					0, 0);
X			    break;
X			case 1:
X			    dev.raster (yr_max - 1 - i, yr_max - yr_min,
X					xvru_min + i, yvr_max,
X				     xr_max - xr_min, ras_orient, outraster,
X					0, 0);
X			    break;
X			case 2:
X			    dev.raster (yr_max - 1 - i, yr_max - yr_min,
X					xvr_max, yvru_max - i,
X				     xr_max - xr_min, ras_orient, outraster,
X					0, 0);
X			    break;
X			case 3:
X			    dev.raster (yr_max - 1 - i, yr_max - yr_min,
X					xvru_max - i, yvr_min,
X				     xr_max - xr_min, ras_orient, outraster,
X					0, 0);
X			    break;
X			}
X		    }
X		}
X		free ((char *) rasterline);
X		free ((char *) rasterline2);
X		if (outraster2 != NULL)
X		{
X		    free ((char *) outraster2);
X		    if (dither_it)
X			free ((char *) outraster);
X		}
X		if (!wantras)
X		{
X		    xxx[0] = xvru_min;
X		    yyy[0] = yvru_min;
X		    xxx[1] = xvru_min;
X		    yyy[1] = yvru_max;
X		    xxx[2] = xvru_max;
X		    yyy[2] = yvru_max;
X		    xxx[3] = xvru_max;
X		    yyy[3] = yvru_min;
X		    drawpolygon (4, xxx, yyy);
X		}
X	    }
X	    break;
X	case VP_MESSAGE:	/* Text message */
X	    getvpstring ();
X	    message (MESG_READY);
X	    message (MESG_MESSAGE);
X	    message (MESG_TEXT, txbuffer);
X	    message (MESG_TEXT, CRLF);
X	    message (MESG_DONE);
X	    break;
X	case VP_SETDASH:
X	    npts = geth (pltin);
X	    if (npts > MAXDASH)
X	    {
X		ERR (FATAL, name, "Too complicated a dash line pattern.");
X	    }
X	    dashon = npts;
X	    k = 0;
X	    dashsum = 0.;
X	    for (ii = 0; ii < npts * 2; ii++)
X	    {
X		dashes[ii] = dashscale * (float) geth (pltin) / RPERIN;
X		if (dashes[ii] < 0.)
X		    ERR (FATAL, name, "Negative dash distance.");
X
X		if (dashes[ii] != 0.)
X		    k = 1;
X
X		dashsum += dashes[ii];
X	    }
X	    if (!k)
X		dashon = NO;
X	    dev.attributes (NEW_DASH, dashon, 0, 0, 0);
X	    break;
X	default:		/* error */
X	    ERR (FATAL, name,
X		 "invalid VPLOT command decimal %d character %c",
X		 (int) c, (char) c);
X	    break;
X	}
X    }
End_of_file:
X/*
X * End of main while loop. Either fall out here or jump here when you hit
X * the end of the file somewhere.
X */
X
X    dev.close (CLOSE_FLUSH);	/* force last vector out */
X
X/*
X * End the group for this frame
X */
X    group_number--;
X    if (group_number != 0)
X    {
X	ERR (WARN, name,
X	     "group left unclosed at end of file");
X	group_number = 0;
X    }
X    else
X    {
X	ii = dev.attributes (END_GROUP, group_number, 0, 0, 0);
X	if (ii == DOVPLOT_EXIT)
X	    return;
X	if (ii != DOVPLOT_CONT)
X	    ERR (WARN, name, "dev.attributes(END_GROUP,...) returned junk.");
X    }
X
X/*
X * Exit of dovplot
X */
X    return;
X}
X
X/*
X * reset variables that can be affected by vplot commands when
X * processing multiple plots, and don't stay set across pages
X */
reset ()
X{
int             ii, jj, kk;
X
X    xwmin = xWmin;		/* plot window parameters defaulted */
X    xwmax = xWmax;		/* to maximum size	 */
X    ywmin = yWmin;
X    ywmax = yWmax;
X
X    reset_windows ();
X
X    fat = fatmult * (float) (fatbase);
X    dev.attributes (NEW_FAT, fat, 0, 0, 0);
X
X    if (cur_color != DEFAULT_COLOR)
X    {
X	need_devcolor = YES;
X	cur_color = DEFAULT_COLOR;
X    }
X
X    txalign.hor = TH_NORMAL;
X    txalign.ver = TV_NORMAL;
X    dev.attributes (NEW_ALIGN, txalign.hor, txalign.ver, 0, 0);
X
X    ii = -1;
X    jj = -1;
X    kk = -1;
X    if (txfont != default_txfont)
X    {
X	txfont = default_txfont;
X	ii = txfont;
X    }
X    if (txprec != default_txprec)
X    {
X	txprec = default_txprec;
X	jj = txprec;
X    }
X    if (txovly != default_txovly)
X    {
X	txovly = default_txovly;
X	kk = txovly;
X    }
X    dev.attributes (NEW_FONT, ii, jj, kk, 0);
X
X    dashon = NO;
X    dev.attributes (NEW_DASH, dashon, 0, 0, 0);
X
X    overlay = default_overlay;
X    dev.attributes (NEW_OVERLAY, overlay, 0, 0, 0);
X}
X
reset_windows ()
X{
extern int      xwmax_last, ywmax_last, xwmin_last, ywmin_last;
X
X    if (xwmax != xwmax_last || ywmax != ywmax_last
X	|| xwmin != xwmin_last || ywmin != ywmin_last)
X	dev.attributes (SET_WINDOW, xwmin, ywmin, xwmax, ywmax);
X
X    xwmin_last = xwmin;
X    ywmin_last = ywmin;
X    xwmax_last = xwmax;
X    ywmax_last = ywmax;
X}
X
outline_window ()
X{
X    if (need_devcolor == YES || cur_color != DEFAULT_COLOR)
X    {
X	dev.attributes (SET_COLOR, DEFAULT_COLOR, 0, 0, 0);
X	need_devcolor = NO;
X    }
X    dev.vector (xwmin, ywmin, xwmax, ywmin, 0, 0);
X    dev.vector (xwmax, ywmin, xwmax, ywmax, 0, 0);
X    dev.vector (xwmax, ywmax, xwmin, ywmax, 0, 0);
X    dev.vector (xwmin, ywmax, xwmin, ywmin, 0, 0);
X    if (cur_color != DEFAULT_COLOR)
X    {
X	dev.attributes (SET_COLOR, cur_color, 0, 0, 0);
X	need_devcolor = NO;
X    }
X}
X
getvpstring ()
X{
char           *txptr;
int             ii;
X
X    txptr = txbuffer;
X
X    while (1)
X    {
X	ii = getc (pltin);
X
X	if (ii == EOF)
X	{
X	    ERR (FATAL, name,
X		 "Unexpected EOF encountered in Text string");
X	}
X
X	*txptr = ii;
X	txptr++;
X
X	if (ii == 0)
X	{
X	    break;
X	}
X
X	if ((txptr - txbuffer) == txbuflen)
X	{
X	    txbuffer = realloc (txbuffer, (unsigned) (txbuflen + TXBUFLEN));
X	    txptr = txbuffer + txbuflen;
X	    txbuflen += TXBUFLEN;
X	}
X    }
X    return;
X}
X
drawpolygon (npts, x, y)
X    int             npts, *x, *y;
X{
int             i, j;
struct vertex  *vertex;
static int      point;
X
X    j = 0;
X    if (npts > (vxbuflen - 1))
X    {
X	free ((char *) vxbuffer);
X	vxbuffer =
X	 (struct vertex *) malloc ((unsigned) ((npts + 1) * sizeof (struct vertex)));
X    }
X    vertex = vxbuffer;
X    xnew = x[j];
X    ynew = y[j];
X    j++;
X    vertex->x = xnew;
X    vertex->y = ynew;
X    vertex->next = vertex + 1;
X    vertex++;
X    i = npts - 1;
X    while (i--)
X    {
X	vertex->x = x[j];
X	vertex->y = y[j];
X	j++;
X	if ((vertex->x != xnew) || (vertex->y != ynew))
X	{
X	    xnew = vertex->x;
X	    ynew = vertex->y;
X	    vertex->next = vertex + 1;
X	    vertex->last = vertex - 1;
X	    vertex++;
X	    continue;
X	}
X	npts--;
X    }
X    vertex--;
X    vxbuffer->last = vertex;
X    vertex->next = vxbuffer;
X
X    ipat = 0;
X    point = cur_color;
X    pat[ipat] .patbits = &point;
X    pat[ipat] .xdim = 1;
X    pat[ipat] .ydim = 1;
X    pat[ipat] .xdim_orig = 1;
X    pat[ipat] .ydim_orig = 1;
X    update_color ();
X    if (npts > 2)
X    {
X	if (shade)
X	    dev.area (npts, vxbuffer);
X	else
X	    vecoutline (vxbuffer);
X    }
X}
X
getpolygon (npts)
X    int             npts;
X{
int             i;
struct vertex  *vertex;
X
X    if (npts > (vxbuflen - 1))
X    {
X	free ((char *) vxbuffer);
X	vxbuffer =
X	 (struct vertex *) malloc ((unsigned) ((npts + 1) * sizeof (struct vertex)));
X    }
X    vertex = vxbuffer;
X    GETXY (xnew, ynew);
X    vertex->x = xnew;
X    vertex->y = ynew;
X    vertex->next = vertex + 1;
X    vertex++;
X    i = npts - 1;
X    while (i--)
X    {
X	GETXY (vertex->x, vertex->y);
X	if ((vertex->x != xnew) || (vertex->y != ynew))
X	{
X	    xnew = vertex->x;
X	    ynew = vertex->y;
X	    vertex->next = vertex + 1;
X	    vertex->last = vertex - 1;
X	    vertex++;
X	    continue;
X	}
X	npts--;
X    }
X    vertex--;
X    vxbuffer->last = vertex;
X    vertex->next = vxbuffer;
X    return (npts);
X}
X
update_color ()
X{
X    if (need_devcolor)
X    {
X	dev.attributes (SET_COLOR, cur_color, 0, 0, 0);
X	need_devcolor = NO;
X    }
X}
X
getapoint ()
X{
X    while (1)
X    {
X	xret = dev_xmax + 1;
X	yret = dev_ymax + 1;
X	if ((int) dev.getpoint (controltty, &xret, &yret) ||
X	    (xret > dev_xmax - 5 && yret > dev_ymax - 5))
X	    break;
X	devtovpxy (xret, yret, &xret, &yret);
X	add_a_cor (interact, xret, yret);
X    }
X}
END_OF_FILE
if test 51559 -ne `wc -c <'Vplot_Kernel/filters/dovplot.c'`; then
    echo shar: \"'Vplot_Kernel/filters/dovplot.c'\" unpacked with wrong size!
fi
# end of 'Vplot_Kernel/filters/dovplot.c'
fi
echo shar: End of archive 24 \(of 24\).
cp /dev/null ark24isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 24 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.