[comp.sources.unix] v14i028: 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 28
Archive-name: vplot/part23

#! /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 23 (of 24)."
# Contents:  Vplot_Kernel/filters/genlib/gentext.c
# Wrapped by rsalz@fig.bbn.com on Fri Mar 25 11:47:35 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Vplot_Kernel/filters/genlib/gentext.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Vplot_Kernel/filters/genlib/gentext.c'\"
else
echo shar: Extracting \"'Vplot_Kernel/filters/genlib/gentext.c'\" \(37130 characters\)
sed "s/^X//" >'Vplot_Kernel/filters/genlib/gentext.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/genlib/gentext.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 * 	Keep track of fatness as a float, not an int. Round when needed.
X * Joe Dellinger Jan 16 1988
X *	Allow user-defined fonts. As a check, require that they have a
X *	magic sequence on the front. If they ask for a font >= NUMGENFONT,
X *	modulo back into range.
X * Joe Dellinger Feb 16 1988
X *	Make number of arguments to dev.attributes consistent.
X */
X
X/*
X * VPLOT soft text plotting
X *
X * Keywords: vplot text vector hershey font
X */
X#include	<stdio.h>
X#include	<math.h>
X#include	<strings.h>
X#include	<sys/file.h>
X#include	<vplot.h>
X#include	"../include/extern.h"
X#include	"../include/err.h"
X#include	"../include/enum.h"
X#include	"../include/params.h"
X#include	"../include/font_definitions.h"
X#include	"../include/attrcom.h"
X#include	"../include/round.h"
X
X#define		NMARK   8	/* Maximum number of marks to use */
X#define		MAXPOLY 100	/* Maximum number of points in polygon */
X
X/*
X * The font to use for undefined fonts.
X * It should NOT be a runtime-loaded font!
X */
X#define ERRFONT		0
X/*
X * The glyph to use for undefined glyphs.
X * It must be a glyph in the font ERRFONT.
X * Needless to say, this glyph at least had better exist or you're
X * in real trouble.
X */
X/* We use Glyph 30 in font 0, which is a '?' with a square around it. */
X#define ERRGLYPH 	(30-font[0].dim[START])
X
X/* Fraction of height of capital letter to use as vertical padding for box */
X#define VSPACE_FRAC  .20
X/* Fraction of inter-letter space to use for horizontal padding of box */
X#define HSPACE_FRAC  0.5
X
X#define EOC 0x8000	/* END OF CHARACTER BIT */
X#define DRAWBIT 0x4000	/* DRAW BIT */
X#define POLYBITS (EOC | DRAWBIT)	/* Polygon */
X#define XBIT 0x0040
X#define YBIT 0x2000
X#define UNDEFINED	-1
X
X#define SIGN_X (glyph_stroke & XBIT)
X#define SIGN_Y (glyph_stroke & YBIT)
X#define DRAW (glyph_stroke & DRAWBIT)
X#define INPOLY ((glyph_stroke & POLYBITS) == POLYBITS)
X
X#define COLOR_MAP(A) color_set[A][MAP];
X
X/*
X * Correct for difference in size between what you want and what you've got
X */
X#define SIZE_FACTOR(A) (((double)tsize/100.)*(A)/(double)(font[ttxfont].dim[CAP]-font[ttxfont].dim[BASE]))
X
X/*
X * When you change sizes or fonts in midstream, what level do you line up on?
X */
X#define ALIGN_HEIGHT	(font[ttxfont].dim[BASE])
X
X#define CONTROL 001
X#define BS	010
X#define CR	015
X#define NL	012
X
static double   path_orient_dx, path_orient_dy;
static double   up_orient_dx, up_orient_dy;
static double   xorigin_f, yorigin_f, xold_f, yold_f;
static int      ttxfont, cur_color_save, overlay_save;
extern int      cur_color, ipat, need_devcolor, overlay;
extern int      color_set[MAX_COL + 1][_NUM_PRIM];
X
extern char    *malloc ();
extern char    *calloc ();
X
X/*
X * interpret characters into vectors
X */
gentext (string, pathx, pathy, upx, upy)
X    char           *string;
X    float           pathx, pathy, upx, upy;
X{
double          fpathx, fpathy, fupx, fupy;
double          up, path;
double          xp, yp;
float           tfat;
int             add;
int             ixp, iyp;
int            *istring;
unsigned short *glyphptr, glyph_stroke;
double          xtxshift, ytxshift;
int             a, b, ii, jj, kk;
int             string_length;
double          last_widthl, last_widthr;
double          widthl_1st_char, char_width, total_width = 0.;
int             tsize, first, ttxfont_save, txfont_checked;
int             ghost = 0;
double          th_symb, th_symb_s, tv_symb, tv_symb_s;
double          char_width_s[NMARK];
double          total_width_s[NMARK];
int             mark_flag[NMARK];
double          last_widthl_s[NMARK], last_widthr_s[NMARK];
double          xold_f_s[NMARK];
double          yold_f_s[NMARK];
double          maxtop, minbot;
double          vspace, hspace, vline;
int             flag;
char           *charp;
int             polycount, xxx[MAXPOLY], yyy[MAXPOLY];
int            *ligp;
static int      one_error = YES;
int             linecount;
X
X    if (*string == '\0')
X	return;
X
X/*
X * Set the initial parameters
X */
X
X/*
X * Convert the input float path vectors to doubles.
X */
X    fpathx = (double) pathx;
X    fpathy = (double) pathy;
X    fupx = (double) upx;
X    fupy = (double) upy;
X
X    path = sqrt ((double) (fpathx * fpathx + fpathy * fpathy));
X    up = sqrt ((double) (fupx * fupx + fupy * fupy));
X
X    if (path == 0. || up == 0.)
X    {
X/* Text got squashed away to nothing */
X	return;
X    }
X
X    path_orient_dx = fpathx / path;
X    path_orient_dy = fpathy / path;
X    up_orient_dx = fupx / up;
X    up_orient_dy = fupy / up;
X
X/*
X * We didn't bomb out right away, so save things we may change so
X * they can be restored at exit
X */
X    cur_color_save = cur_color;
X    overlay_save = overlay;
X
X    overlay = NO;
X
X    for (ii = 0; ii < NMARK; ii++)
X	mark_flag[ii] = 0;
X
X/* Text starts out in the default font at 100% of the requested size */
X    tsize = 100;
X    txfont_checked = txfont;
X
X    if (txfont_checked >= 0)
X    {
X	ttxfont = txfont_checked % NUMGENFONT;
X	if (font[ttxfont] .load == NO)
X	{
X	    load_font (txfont_checked);
X	}
X	txfont_checked = ttxfont;
X    }
X    else
X    {
X	txfont_checked = ERRFONT;
X    }
X
X    ttxfont = txfont_checked;
X    total_width = 0.;
X    char_width = font[ttxfont] .dim[SPACE] * SIZE_FACTOR (path);
X    th_symb = char_width / 2.;
X    last_widthl = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path);
X    last_widthr = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path);
X    widthl_1st_char = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path);
X    tv_symb = (font[ttxfont] .dim[HALF] - ALIGN_HEIGHT) * SIZE_FACTOR (up);
X    maxtop = (font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up);
X    minbot = (font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT) * SIZE_FACTOR (up);
X
X/* These used in making the bounding box */
X    vline = (font[ttxfont] .dim[TOP] - font[ttxfont] .dim[BOTTOM] + font[ttxfont] .dim[LINE]) * SIZE_FACTOR (up);
X    vspace = VSPACE_FRAC * (font[ttxfont] .dim[CAP] - font[ttxfont] .dim[BASE]) * SIZE_FACTOR (up);
X    hspace = (HSPACE_FRAC * font[ttxfont] .dim[SPACE] + font[ttxfont] .dim[LETTER]) * SIZE_FACTOR (path);
X
X/*
X * Parse ligatures, control sequences, etc.
X * each object gets 2 ints;
X * The first tells what sort of object it is.
X * Positive == printing character
X * Negative == command
X * The second is there for any parameters that are associated.
X * For normal characters, it gives the glyph number in this font.
X * For commands it gives any parameter the command may have.
X */
X    string_length = strlen (string);
X    istring = (int *) calloc ((unsigned) 2 * (string_length + 1), sizeof (int));
X
X    for (ii = 0, charp = string; (charp - string) < string_length; ii++, charp++)
X    {
X	switch ((int) (*charp))
X	{
X/* Check for special ASCII characters first */
X	case ' ':
X	case NL:
X	case CR:
X	case BS:
X	    istring[2 * ii] = -(int) (*charp);
X	    continue;
X	    break;
X/* Check for \ commands */
X	case '\\':
X	    charp++;
X	    switch (*charp)
X	    {
X/* \\ just falls through and makes a \ with no special properties */
X	    case '\\':
X		break;
X/* \ commands with no arguments */
X	    case '-':
X	    case '>':
X	    case '<':
X	    case '^':
X	    case '_':
X	    case 'g':
X	    case 'G':
X	    case 'n':
X	    case 'h':
X		istring[2 * ii] = -(int) (*charp);
X		continue;
X		break;
X/* \ commands with arguments */
X	    case 's':
X	    case 'f':
X	    case 'F':
X	    case 'k':
X	    case 'r':
X	    case 'm':
X	    case 'M':
X	    case 'v':
X	    case 'c':
X		istring[2 * ii] = -(int) (*charp);
X		charp++;
X/* default value of the argument is 0 if they just leave a space */
X		istring[2 * ii + 1] = 0;
X/* read the argument */
X		sscanf (charp, "%d ", &istring[2 * ii + 1]);
X/* skip past it and check for syntax */
X		do
X		{
X		    if ((*charp >= '0' && *charp <= '9') ||
X			*charp == '-' || *charp == '+')
X		    {
X			charp++;
X		    }
X		    else
X			ERR (FATAL, name, "In text \\%c must be followed by an integer and then a space.", (char) (-istring[2 * ii]));
X		} while (*charp != ' ');
X
X		if (istring[2 * ii] == -(int) ('v'))
X		{
X/*
X * The \v command.
X * Make an ordinary character with the proper value.
X */
X		    istring[2 * ii] = istring[2 * ii + 1];
X		    istring[2 * ii + 1] = 0;
X		}
X		else
X		if (istring[2 * ii] == -(int) ('F'))
X		{
X/* Font change command */
X		    if (istring[2 * ii + 1] >= 0)
X		    {
X			ttxfont = istring[2 * ii + 1] % NUMGENFONT;
X/* On this first pass through, load all the fonts we're going to need */
X			if (font[ttxfont] .load == NO)
X			{
X			    load_font (istring[2 * ii + 1]);
X			}
X			istring[2 * ii + 1] = ttxfont;
X		    }
X		    else
X		    {
X/* \F-1  means the default font again. */
X			if (istring[2 * ii + 1] == -1)
X			    istring[2 * ii + 1] = txfont_checked;
X			else
X			    istring[2 * ii + 1] = ERRFONT;
X		    }
X		}
X		else
X		if (istring[2 * ii] == -(int) ('c'))
X		{
X/* Color change command */
X		    if (istring[2 * ii + 1] == -1)
X		    {
X/*
X * They want to return to the original text color.
X * This has already been checked to be within range and
X * properly mapped, so just use it!
X */
X			istring[2 * ii + 1] = cur_color_save;
X		    }
X		    else
X		    {
X/*
X * Map from the color asked for to the colors that are available.
X * Normally only dovplot is allowed to do this, but this is an
X * unusual case where dovplot can't do it for us.
X */
X			if (istring[2 * ii + 1] > MAX_COL || istring[2 * ii + 1] < 0)
X			    ERR (FATAL, name, "(gentext) bad color number %d (max %d, min 0)",
X				 istring[2 * ii + 1], MAX_COL);
X			istring[2 * ii + 1] = COLOR_MAP (istring[2 * ii + 1]);
X		    }
X		}
X		continue;
X		break;
X	    default:
X		ERR (WARN, name, "(gentext) Unknown command \\%c.", *charp);
X		charp--;
X		break;
X	    }
X	default:
X	    break;
X	}
X/* Normal character */
X	istring[2 * ii] = (int) (*charp);
X    }
X    string_length = ii;
X
X/* Ligatures */
X    if (txprec > 1)
X    {
X	ttxfont = txfont_checked;
X/*
X * Turning things into ligatures can only make the string shorter.
X * ii keeps track of where we are without ligatures,
X * kk keeps track of where we are with ligatures included.
X * The string is copied back into itself. Since ii >= kk, there is
X * no recursion problem.
X */
X	for (ii = 0, kk = 0; ii < string_length; ii++, kk++)
X	{
X	    if (istring[2 * ii] < 0)
X	    {
X/*
X * The only special command we care about for constructing ligatures
X * is the font change command, since ligatures are font dependent.
X * The commands WILL break up a ligature, but other than that aren't
X * interpreted at all here.
X */
X		if (-istring[2 * ii] == 'F')
X		    ttxfont = istring[2 * ii + 1];
X		istring[2 * kk] = istring[2 * ii];
X		istring[2 * kk + 1] = istring[2 * ii + 1];
X		continue;
X	    }
X
X/*
X * Take the first ligature that matches. This means that longer ligatures
X * MUST be listed first in the font data!
X */
X/*
X * Loop over ligatures.
X * Each ligature has 1 number at the beginning giving the number of characters
X * in this ligature. The next number gives the glyph that is drawn for this
X * ligature. The next several numbers give the glyphs that are combined.
X * ligp points to the ligature we are currently searching for.
X * ligp += 2 + ligp[0] moves to the beginning of the next ligature:
X * 2 places for the 2 numbers at the beginning plus the ligp[0] characters
X * making up the ligature.
X */
X	    for (ligp = font[ttxfont] .lig; ligp[0] > 0; ligp += 2 + ligp[0])
X	    {
X/* Is there enough room before the end to possibly make this? */
X		if (ii + ligp[0] - 1 < string_length)
X		{
X/* Loop over the characters in the ligature */
X		    for (jj = 0; jj < ligp[0]; jj++)
X		    {
X/* Didn't match. Stop looking on this one. */
X			if (ligp[jj + 2] != istring[2 * (ii + jj)])
X			    goto failed;
X		    }
X/* Got to the end and so it worked. Put in the glyph for the ligature */
X		    istring[2 * kk] = ligp[1];
X/* skip past the ligp[0] characters in the original string that went into it */
X		    ii += ligp[0] - 1;
X		    goto success;
X		}
X	failed:
X		continue;
X	    }
X/* No ligatures for this one. Copy it across unchanged */
X	    istring[2 * kk] = istring[2 * ii];
X/*
X * Don't need to look at any more ligatures for this character
X * (Ligatures don't nest)
X */
X    success:
X	    continue;
X	}
X/* Update the length of the string */
X	string_length = kk;
X    }
X
X
X/************************************************************************/
X/************************************************************************/
X
X/*
X * This section conducts a "dry run" through the text string to determine
X * its length.
X *
X * Each character has a left half-width (widthl) and a right half-width (widthr).
X * These give the left and right half-widths of the character's bounding box
X * away from the character's origin.
X * The vertical dimensions of each character's bounding box are a function of
X * the font only; font[font_number].dim[TOP] and font[font_number].dim[BOTTOM]
X * give the coordinates in font units of the top and bottom of the character's box.
X *
X * Each character is also separated from its neighbors by an inter-letter space
X * (font[font_number].dim[LETTER]). This is effectively tacked onto the beginning
X * of each new character, with the exception of the first.
X *
X * When we actually output vectors we will start with the center of the
X * 1st character as our origin. (So we have to remember the left half-width
X * in order to be able to compensate for the fact that we measure the length
X * of the string starting from the left hand edge of the first character.)
X * Variables like "char_width" keep track of the latest character's width
X * in case we have to back up over it again.
X *
X * Multiplying by SIZE_FACTOR converts from the Font's units to Vplot's.
X * (Horizontal scales with "path", vertical scales with "up". These simply
X * give the length of the path and up vectors.)
X * All variables except for those in the font structure itself are in Vplot units.
X *
X * Left and right the total width of everything (characters and inter-spaces
X * between them) is summed into total_width. This is used to do the horizontal
X * text justification.
X *
X * Up and down the highest top and lowest bottom to date are saved in "maxtop" and
X * "minbot". These are used for vertical text justification. "ALIGN_HEIGHT"
X * gives the effective origin for vertical glyph positioning.
X *
X * The "symb" variables keep track of the symbol position of the latest character.
X */
X    first = 1;
X    flag = 1;
X    linecount = 1;
X    ttxfont = txfont_checked;
X    for (ii = 0; ii < string_length; ii++)
X    {
X/* 
X * Figure the lenth of the message string.
X * Justification is based on the first line of text only
X * (That's what "flag" is for)
X */
X
X/*
X * Check for special characters
X */
X	if (istring[2 * ii] < 0)
X	{
X	    switch (-istring[2 * ii])
X	    {
X	    case 'n':
X	    case NL:
X		linecount++;
X	    case CR:
X		flag = 0;
X		break;
X	    case 'h':
X	    case BS:
X		total_width -= font[ttxfont] .dim[LETTER] *
X		 SIZE_FACTOR (path) + char_width;
X		break;
X	    case 'F':
X/* Change the font */
X		ttxfont = istring[2 * ii + 1];
X		break;
X	    case 's':
X/* Change the size. This affects the SIZE_FACTOR. */
X		tsize = istring[2 * ii + 1];
X		break;
X	    case 'k':
X		if (flag)
X		{
X/*
X * Add in the blank space created by horizontal 'k'earning.
X * This is measured in percent of the width of a space in this font.
X *
X * Similar vertical movements are ignored for the purposes of justification.
X */
X		    total_width += font[ttxfont] .dim[SPACE]
X		     * SIZE_FACTOR (path) * (istring[2 * ii + 1] / 100.);
X		}
X		break;
X	    case 'm':
X		if (istring[2 * ii + 1] < 0 || istring[2 * ii + 1] >= NMARK)
X		    ERR (FATAL, name,
X			 "(gentext) Too high a mark number %d", istring[2 * ii + 1]);
X/* Save all relevant parameters as they are at this instant */
X		if (flag)
X		{
X/* Vertical symbol alignment position */
X		    tv_symb_s = tv_symb;
X/* Horizontal symbol alignment position */
X		    th_symb_s = th_symb;
X/* Width of this character (in case the next thing is a backspace) */
X		    char_width_s[istring[2 * ii + 1]] = char_width;
X/* The width so far up to this point */
X		    total_width_s[istring[2 * ii + 1]] = total_width;
X		}
X		mark_flag[istring[2 * ii + 1]] = 1;
X		break;
X	    case 'M':
X		if (istring[2 * ii + 1] < 0 || istring[2 * ii + 1] >= NMARK)
X		    ERR (FATAL, name,
X			 "(gentext) Too high a mark number %d", istring[2 * ii + 1]);
X/* Make sure it isn't junk */
X		if (!mark_flag[istring[2 * ii + 1]])
X		    ERR (FATAL, name,
X			 "(gentext) Attempt to use undefined mark number %d",
X			 istring[2 * ii + 1]);
X/*
X * Restore the parameters previously saved. All events after that point
X * are now ignored for the purposes of justification.
X */
X		if (flag)
X		{
X		    tv_symb = tv_symb_s;
X		    th_symb = th_symb_s;
X		    char_width = char_width_s[istring[2 * ii + 1]];
X		    total_width = total_width_s[istring[2 * ii + 1]];
X		}
X		break;
X	    case '-':		/* Nothing */
X		break;
X	    case '>':		/* Forward one inter-letter space */
X		if (flag)
X		    total_width += font[ttxfont] .dim[LETTER]
X		     * SIZE_FACTOR (path);
X		break;
X	    case '<':		/* Remove one inter-letter space */
X		if (flag)
X		    total_width -= font[ttxfont] .dim[LETTER]
X		     * SIZE_FACTOR (path);
X		break;
X	    case '^':		/* Up a half letter */
X	    case '_':		/* Down a half letter */
X	    case 'g':		/* Make text invisible */
X	    case 'G':		/* Make text visible again */
X		break;
X	    case ' ':		/* Space */
X		if (flag)
X		{
X		    char_width = font[ttxfont] .dim[SPACE]
X		     * SIZE_FACTOR (path);
X		    th_symb = char_width / 2.;
X		    tv_symb = (font[ttxfont] .dim[HALF] - ALIGN_HEIGHT)
X		     * SIZE_FACTOR (up);
X		    total_width += char_width;
X		    if (first)
X		    {
X/* If it is the first character, remember the left half width */
X			widthl_1st_char = font[ttxfont] .dim[SPACE] * .5
X			 * SIZE_FACTOR (path);
X/* No longer at the first printable character */
X			first = 0;
X		    }
X		    else
X		    {
X/* else add inter-letter space between it and the previous character */
X			total_width += font[ttxfont] .dim[LETTER]
X			 * SIZE_FACTOR (path);
X		    }
X		}
X		break;
X	    }
X	    continue;
X	}
X
X	if (flag)
X	{
X/*
X * There are 2 ways a glyph can be undefined: it can be outside the range of
X * the font, OR it can have no data associated with it
X */
X	    if (istring[2 * ii] >= font[ttxfont] .dim[START] && istring[2 * ii] <= font[ttxfont] .dim[END])
X	    {
X/* Find the glyph number, and save it so we don't have to recalculate it */
X		istring[2 * ii + 1] = istring[2 * ii] - font[ttxfont] .dim[START];
X		if (font[ttxfont] .saddr[istring[2 * ii + 1]] != UNDEFINED)
X		{
X/* OK glyph */
X/* In case it's the last one, save its vertical symbol position */
X		    tv_symb = (font[ttxfont] .symbol[istring[2 * ii + 1]] - ALIGN_HEIGHT)
X		     * SIZE_FACTOR (up);
X/* And in case we back up later its width */
X		    char_width = (font[ttxfont] .swidthl[istring[2 * ii + 1]] +
X				font[ttxfont] .swidthr[istring[2 * ii + 1]])
X		     * SIZE_FACTOR (path);
X/* and horizontal symbol position */
X		    th_symb = font[ttxfont] .swidthr[istring[2 * ii + 1]]
X		     * SIZE_FACTOR (path);
X/* See if it sets a new record high */
X		    if ((font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up) > maxtop)
X			maxtop = (font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up);
X/* Or a record low */
X		    if ((font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT)
X			* SIZE_FACTOR (up) < minbot)
X			minbot = (font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT)
X			 * SIZE_FACTOR (up);
X/* Add it into the total width */
X		    total_width += char_width;
X		    if (first)
X		    {
X/* If it's the first remember its left half width */
X			widthl_1st_char = font[ttxfont] .swidthl[istring[2 * ii + 1]]
X			 * SIZE_FACTOR (path);
X		    }
X		    else
X		    {
X/* or if not first add in the space between it and the previous glyph */
X			total_width += font[ttxfont] .dim[LETTER]
X			 * SIZE_FACTOR (path);
X		    }
X		}
X		else
X		{
X/* Second way to be undefined. Turn it into a "special" character */
X		    istring[2 * ii] = UNDEFINED;
X		}
X	    }
X	    else
X	    {
X/* First way to be undefined. Turn it into a "special" character */
X		istring[2 * ii] = UNDEFINED;
X	    }
X
X	    if (istring[2 * ii] == UNDEFINED)
X	    {
X/*
X * If it is undefined, use the special "ERROR" glyph and then
X * treat that just like we would treat a regular character.
X */
X		ttxfont_save = ttxfont;
X		ttxfont = ERRFONT;
X		istring[2 * ii + 1] = ERRGLYPH;
X		char_width = (font[ttxfont] .swidthl[ERRGLYPH] +
X			      font[ttxfont] .swidthr[ERRGLYPH])
X		 * SIZE_FACTOR (path);
X		th_symb = font[ttxfont] .swidthr[ERRGLYPH] * SIZE_FACTOR (path);
X		tv_symb = (font[ttxfont] .symbol[ERRGLYPH] - ALIGN_HEIGHT)
X		 * SIZE_FACTOR (up);
X		if ((font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up) > maxtop)
X		    maxtop = (font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up);
X		if ((font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT) * SIZE_FACTOR (up) < minbot)
X		    minbot = (font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT) * SIZE_FACTOR (up);
X		total_width += char_width;
X		if (first)
X		{
X		    widthl_1st_char = font[ttxfont] .swidthl[ERRGLYPH] * SIZE_FACTOR (path);
X		}
X		else
X		    total_width += font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path);
X		ttxfont = ttxfont_save;
X	    }
X
X/* We printed something, so we aren't at the first character anymore */
X	    first = 0;
X	}
X	else
X	{
X/*
X * If we're past the first line of text, do the few things that aren't related
X * to justification (looking for undefined glyphs, finding the glyph numbers)
X */
X	    if (istring[2 * ii] >= font[ttxfont] .dim[START] && istring[2 * ii] <= font[ttxfont] .dim[END])
X	    {
X		istring[2 * ii + 1] = istring[2 * ii] - font[ttxfont] .dim[START];
X		if (font[ttxfont] .saddr[istring[2 * ii + 1]] == UNDEFINED)
X		{
X		    istring[2 * ii] = UNDEFINED;
X		}
X	    }
X	    else
X	    {
X		istring[2 * ii] = UNDEFINED;
X	    }
X	    if (istring[2 * ii] == UNDEFINED)
X	    {
X		istring[2 * ii + 1] = ERRGLYPH;
X	    }
X	}
X    }
X
X/*
X *  Set the proper alignment from the calculated length of the 
X *  text string. Remember that when we plot zero will be in the center
X *  of the first character and not the left hand edge of the first character,
X *  so we have to use widthl_1st_char to compensate for that.
X */
X    switch (txalign.hor)
X    {
X    case TH_SYMBOL:
X	xtxshift = total_width - widthl_1st_char - th_symb;
X	break;
X    case TH_CENTER:
X	xtxshift = total_width / 2. - widthl_1st_char;
X	break;
X    case TH_RIGHT:
X	xtxshift = total_width - widthl_1st_char;
X	break;
X    case TH_NORMAL:
X    case TH_LEFT:
X    default:
X	xtxshift = -widthl_1st_char;
X	break;
X    }
X
X    tsize = 100;
X    ttxfont = txfont_checked;
X    tfat = fat;
X
X/*
X * CAP, HALF, and BASE are calculated based on font and size of default
X * TOP and BOTTOM are based on highest TOP and lowest BOTTOM of all
X * glyphs in string.
X */
X    switch (txalign.ver)
X    {
X    case TV_SYMBOL:
X	ytxshift = tv_symb;
X	break;
X    case TV_TOP:
X	ytxshift = maxtop;
X	break;
X    case TV_CAP:
X	ytxshift = (font[ttxfont] .dim[CAP] - ALIGN_HEIGHT) * SIZE_FACTOR (up);
X	break;
X    case TV_HALF:
X	ytxshift = (font[ttxfont] .dim[HALF] - ALIGN_HEIGHT) * SIZE_FACTOR (up);
X	break;
X    case TV_BOTTOM:
X	ytxshift = minbot;
X	break;
X    case TV_NORMAL:
X    case TV_BASE:
X    default:
X	ytxshift = (font[ttxfont] .dim[BASE] - ALIGN_HEIGHT) * SIZE_FACTOR (up);
X	break;
X    }
X
X
X/************************************************************************/
X/************************************************************************/
X
X
X/*
X * This part of the code draws the characters.
X *
X * The complexity arises because when we do each character we have to
X * be at its CENTER in the left-right direction and at its ALIGN_HEIGHT
X * in the up-down direction.
X * So to move from one character to the next we have to move over by
X * the right half-width of the previous character, an inter-letter space,
X * and then the left half-width of the character we're on!
X * This helps to make the code confusing.
X *
X * We also have to always be ready to unexpectedly back up over the last
X * character, so we also have to keep around the left half-width of the
X * previous character as well.
X */
X    xold_f = xold;
X    yold_f = yold;
X
X/*
X * The "mov" routine moves us around in the cock-eyed coordinate system
X * determined by the up and path vectors. There's no problem if these
X * vectors aren't orthogonal!
X */
X    mov (-xtxshift, -ytxshift);
X    xorigin_f = xold_f;
X    yorigin_f = yold_f;
X
X    if (txovly)
X    {
X	mov (-widthl_1st_char - hspace, minbot - vline * (linecount - 1) - vspace);
X	xxx[0] = ROUND (xold_f);
X	yyy[0] = ROUND (yold_f);
X	mov (0., maxtop - minbot + vline * (linecount - 1) + 2. * vspace);
X	xxx[1] = ROUND (xold_f);
X	yyy[1] = ROUND (yold_f);
X	mov (total_width + 2. * hspace, 0.);
X	xxx[2] = ROUND (xold_f);
X	yyy[2] = ROUND (yold_f);
X	mov (0., -(maxtop - minbot + vline * (linecount - 1) + 2. * vspace));
X	xxx[3] = ROUND (xold_f);
X	yyy[3] = ROUND (yold_f);
X
X	if (txovly == 2 || txovly == 3)
X	{
X	    if (cur_color != 0 || need_devcolor)
X	    {
X		cur_color = 0;
X		dev.attributes (SET_COLOR, cur_color, 0, 0, 0);
X		need_devcolor = NO;
X	    }
X	    drawpolygon (4, xxx, yyy);
X	    if (cur_color != cur_color_save || need_devcolor)
X	    {
X		cur_color = cur_color_save;
X		dev.attributes (SET_COLOR, cur_color, 0, 0, 0);
X		need_devcolor = NO;
X	    }
X	}
X
X	if (txovly == 1 || txovly == 3)
X	{
X	    dev.vector (xxx[0], yyy[0], xxx[1], yyy[1], ROUND (tfat), 0);
X	    dev.vector (xxx[1], yyy[1], xxx[2], yyy[2], ROUND (tfat), 0);
X	    dev.vector (xxx[2], yyy[2], xxx[3], yyy[3], ROUND (tfat), 0);
X	    dev.vector (xxx[3], yyy[3], xxx[0], yyy[0], ROUND (tfat), 0);
X	}
X
X	xold_f = xorigin_f;
X	yold_f = yorigin_f;
X    }
X
X    first = 1;
X
X/*
X * This is where the actual drawing of the characters takes place.
X * Loop over all the characters in the string
X */
X    for (ii = 0; ii < string_length; ii++)
X    {
X/*
X * Check for special characters first
X */
X	if (istring[2 * ii] < 0)
X	{
X	    switch (-istring[2 * ii])
X	    {			/* standard carriage controls */
X	    case 'h':
X	    case BS:
X		mov (-font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path) -
X		     (last_widthl + last_widthr), 0.);
X		break;
X	    case NL:
X	    case 'n':
X		xold_f = xorigin_f;
X		yold_f = yorigin_f;
X		mov (0., -(
X			   (font[ttxfont] .dim[TOP] - font[ttxfont] .dim[BOTTOM] + font[ttxfont] .dim[LINE])
X			   * SIZE_FACTOR (up)));
X		xorigin_f = xold_f;
X		yorigin_f = yold_f;
X		first = 1;
X		break;
X	    case CR:
X		xold_f = xorigin_f;
X		yold_f = yorigin_f;
X		first = 1;
X		break;
X	    case 'F':
X		ttxfont = istring[2 * ii + 1];
X		break;
X	    case 'c':
X		if (cur_color != istring[2 * ii + 1] || need_devcolor)
X		{
X		    cur_color = istring[2 * ii + 1];
X		    dev.attributes (SET_COLOR, cur_color, 0, 0, 0);
X		    need_devcolor = NO;
X		}
X		break;
X	    case 's':
X		tsize = istring[2 * ii + 1];
X		break;
X	    case 'f':
X		tfat += istring[2 * ii + 1] * fatmult;
X		break;
X	    case 'k':
X/* Horizontal motion */
X		mov (font[ttxfont] .dim[SPACE] * SIZE_FACTOR (path) *
X		     (istring[2 * ii + 1] / 100.), 0.);
X		break;
X	    case 'r':
X/* Vertical motion */
X		mov (0., (font[ttxfont] .dim[CAP] - font[ttxfont] .dim[BASE])
X		     * SIZE_FACTOR (up) * (istring[2 * ii + 1] / 100.));
X		break;
X	    case 'm':
X/*
X * Save the current position. No need to check mark number valid; this
X * was checked when we did the justification
X */
X		last_widthl_s[istring[2 * ii + 1]] = last_widthl;
X		last_widthr_s[istring[2 * ii + 1]] = last_widthr;
X		xold_f_s[istring[2 * ii + 1]] = xold_f;
X		yold_f_s[istring[2 * ii + 1]] = yold_f;
X		break;
X	    case 'M':
X/*
X * Restore the current position
X */
X		last_widthl = last_widthl_s[istring[2 * ii + 1]];
X		last_widthr = last_widthr_s[istring[2 * ii + 1]];
X		xold_f = xold_f_s[istring[2 * ii + 1]];
X		yold_f = yold_f_s[istring[2 * ii + 1]];
X		break;
X	    case 'G':
X		ghost = 0;
X		break;
X	    case 'g':
X		ghost = 1;
X		break;
X	    case '^':
X/* Up half a character */
X		mov (0.,
X		     (font[ttxfont] .dim[CAP] - font[ttxfont] .dim[BASE])
X		     * (.5) * SIZE_FACTOR (up));
X		break;
X	    case '_':
X/* Down half a character */
X		mov (0., -(
X			(font[ttxfont] .dim[CAP] - font[ttxfont] .dim[BASE])
X			   * (.5) * SIZE_FACTOR (up)));
X		break;
X	    case '-':
X		break;
X	    case '>':
X/* Right an inter-letter space */
X		mov (font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path), 0.);
X		break;
X	    case '<':
X/* Left an inter-letter space */
X		mov (-(font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path)), 0.);
X		break;
X	    case -(UNDEFINED):
X		/* Don't overload them with error messages */
X		if (one_error)
X		{
X		    ERR (WARN, name,
X			 "(gentext) Attempt(s) to use undefined glyph(s) in font %d",
X			 ttxfont);
X		    one_error = NO;
X		}
X/* Switch to use the ERROR glyph, and the treat it as a regular glyph */
X		ttxfont_save = ttxfont;
X		ttxfont = ERRFONT;
X		goto not_special;
X		break;
X	    case ' ':
X	    default:
X		if (!first)
X		{
X		    mov (
X			 (font[ttxfont] .dim[SPACE] * .5 +
X			  font[ttxfont] .dim[LETTER])
X			 * SIZE_FACTOR (path)
X			 + last_widthr
X			 ,0.);
X		}
X		else
X		{
X		    first = 0;
X		}
X		last_widthl = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path);
X		last_widthr = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path);
X		break;
X	    }
X	}
X	else
X	{
X    not_special:
X/*
X *  Printable character.
X *  Pull out the actual strokes that make up each glyph.
X *  First get the address of the character from the address array
X *  Get the address by adding the offset (add) to the base array address
X *  (font[ttxfont].svec).
X */
X	    add = font[ttxfont] .saddr[istring[2 * ii + 1]];
X	    glyphptr = font[ttxfont] .svec + add;
X/*
X * Now that we have the address of the fonts,
X * we position the pen at the beginning of the next character
X * (Unless it's the first printable character in which case we are already
X *  there)
X */
X	    if (!first)
X	    {
X		mov (
X		     (font[ttxfont] .swidthl[istring[2 * ii + 1]] +
X		      font[ttxfont] .dim[LETTER])
X		     * SIZE_FACTOR (path)
X		     + last_widthr
X		     ,0.);
X	    }
X	    else
X		first = 0;
X
X/* Save the left and right half-widths of this glyph */
X	    last_widthl = font[ttxfont] .swidthl[istring[2 * ii + 1]]
X	     * SIZE_FACTOR (path);
X	    last_widthr = font[ttxfont] .swidthr[istring[2 * ii + 1]]
X	     * SIZE_FACTOR (path);
X
X/*
X * Calculate where to position each character in high precision.
X */
X	    xnew = ROUND (xold_f);
X	    ynew = ROUND (yold_f);
X/*
X * This loop contains the structure for the actual drawing of the characters
X * We go through this block until an "END OF CHARACTER" is read
X *
X *  Strokes are kept in a packed format to save
X *  space. Each stroke is packed into an unsigned
X *  short int with the following format: 
X *
X *         edsyyyyyysxxxxxx
X *         ||||____|||____|--> The x-coordinate value
X *         |||   |  `--------> Set if X < 0			
X *         |||   `-----------> The y-coordinate value
X *         ||`---------------> Set if Y < 0
X *         |`----------------> Draw bit, set if
X *         |                    command is draw.
X *         |                    Clear, if move.
X *         `-----------------> End of Character Bit
X *
X *  This is enough bits per coordinate to accomodate all the "Hershey" fonts.
X *
X *  Polygons are also encoded into this scheme. If the EOC and DRAW bits
X *  are simultaneously on, then we are inside a polygon. The last point of
X *  the polygon will only have the draw flag on, and at that point the entire
X *  polygon will be outputted.
X */
X
X	    polycount = 0;
X
X	    while ((glyph_stroke = *glyphptr++) != EOC)
X	    {
X		a = glyph_stroke & 077;
X		if (SIGN_X)
X		    a = -a;
X		b = (glyph_stroke >> 7) & 077;
X		if (SIGN_Y)
X		    b = -b;
X		b -= ALIGN_HEIGHT;
X
X/*
X * Here is the correct place to insert code to rotate a glyph.
X * You want to do that before it gets distorted by the global coordinate
X * transformation. The "ALIGN_HEIGHT" defines where the vertical origin
X * is for a glyph in a font. Note that we are in the font's coordinate
X * system units at this point.
X */
X		xp = xold_f;
X		yp = yold_f;
X/*
X * Cock-eyed coordinate system.
X * "up" is in the direction of the up vector,
X * "right" is in the direction of the path vector.
X * These can be screwy, and thus distort the glyph.
X *
X * "path" and "up" contain the magnitude, and the
X * "orient_dx"'s and "orient_dy"'s contain the direction cosines
X */
X		xp += SIZE_FACTOR (path) * a * path_orient_dx +
X		 SIZE_FACTOR (up) * b * up_orient_dx;
X		yp += SIZE_FACTOR (path) * a * path_orient_dy +
X		 SIZE_FACTOR (up) * b * up_orient_dy;
X		ixp = ROUND (xp);
X		iyp = ROUND (yp);
X
X		if (polycount > 0 && !INPOLY)
X		{
X/*
X * If we just WERE in a polygon, but are not now, then we must have just
X * finished one. Plot it out.
X */
X		    xxx[polycount] = ixp;
X		    yyy[polycount] = iyp;
X		    polycount++;
X		    if (!ghost)
X		    {
X			drawpolygon (polycount, xxx, yyy);
X		    }
X/*
X * Done with this one, reset the vertex counter
X */
X		    polycount = 0;
X		}
X		else
X		if (INPOLY)
X		{
X/*
X * We're still saving up the polygon. Save this vertex.
X */
X		    xxx[polycount] = ixp;
X		    yyy[polycount] = iyp;
X		    polycount++;
X		    if (polycount > MAXPOLY - 1)
X		    {
X			ERR (FATAL, name,
X			     "(gentext) Too many points in polygon.");
X		    }
X		}
X		else
X		{
X/* No polygons, just output the vector */
X		    if (DRAW && !ghost)
X			dev.vector (xnew, ynew, ixp, iyp, ROUND (tfat), 0);
X		}
X
X		xnew = ixp;
X		ynew = iyp;
X	    }
X
X/*
X * If we switched to the error font just to plot the error glyph,
X * then switch back to the correct font
X */
X	    if (istring[2 * ii] == UNDEFINED)
X	    {
X		ttxfont = ttxfont_save;
X	    }
X	}
X    }
X
X/* Restore the correct color, if necessary */
X    if (cur_color != cur_color_save)
X    {
X	cur_color = cur_color_save;
X	need_devcolor = YES;
X    }
X
X/* Restore overlay mode */
X    overlay = overlay_save;
X
X/*
X * If they jump back into text they can continue right where they left off
X * (As long as they do nothing to move the pen between now and then.)
X */
X    mov (last_widthr + font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path),
X	 ytxshift);
X    xold = ROUND (xold_f);
X    yold = ROUND (yold_f);
X    cfree ((char *) istring);
X}
X
mov (hadd, vadd)
X    double          hadd, vadd;
X{
X    xold_f += hadd * path_orient_dx + vadd * up_orient_dx;
X    yold_f += hadd * path_orient_dy + vadd * up_orient_dy;
X}
X
load_font (ifont)
X    int             ifont;
X{
int             fd, length;
char            filename[120];
char            string[80];
char           *newfont;
int             offs[7];
static int      done[NUMGENFONT];
X
X    if (done[ttxfont])
X    {
X	ttxfont = ERRFONT;
X	return;
X    }
X
X    done[ttxfont] = YES;
X
X    sprintf (string, "font%d", ifont);
X
X    if (ttxfont < NUM_FONTS)
X	sprintf (filename, "%s%s.bin", SYSTEM_FONT_DIRECTORY, font[ttxfont] .name);
X    else
X	strcpy (filename, string);
X
X    getpar (string, "s", filename);
X
X    if ((fd = open (filename, O_RDONLY)) == -1)
X    {
X	ERR (WARN, name,
X	     "(gentext) Couldn't find font %d, file %s",
X	     ttxfont, filename);
X	ttxfont = ERRFONT;
X	return;
X    }
X    else
X    {
X/*
X * First check to make sure it has the magic sequence "Vplot Binary fonT  \n"
X * followed by the binary integer FONTCHECK at the beginning.
X * If it doesn't, it's junk, so don't read it in.
X */
X	read (fd, string, 20);
X	read (fd, (char *) &length, sizeof (int));
X
X	if (strncmp ("Vplot Binary fonT  \n", string, 20) != 0 || length != FONTCHECK)
X	{
X	    close (fd);
X	    ERR (WARN, name,
X		 "(gentext) Font %d file %s is garbled.",
X		 ttxfont, filename);
X	    ttxfont = ERRFONT;
X	    return;
X	}
X
X/*
X *  Binary fonts are machine-specific. Just suck it into memory.
X *  The start of the file contains the length and then the
X *  offsets from the beginning to the 7 structures defining the font.
X */
X	read (fd, (char *) &length, sizeof (int));
X	newfont = (char *) malloc ((unsigned) (length * sizeof (char)));
X	if (newfont == NULL)
X	{
X	    close (fd);
X	    ERR (WARN, name,
X		 "(gentext) Font %d file %s is too big.",
X		 ttxfont, filename);
X	    ttxfont = ERRFONT;
X	    return;
X	}
X	read (fd, (char *) offs, 7 * sizeof (int));
X	read (fd, (char *) newfont, length);
X	close (fd);
X/* The 7 structures defining the font... */
X
X/* The vital parameters (dimensions, bounds, and lengths) */
X	font[ttxfont] .dim = (short *) (newfont + offs[0]);
X/* Pointers to the addresses of the glyphs themselves */
X	font[ttxfont] .saddr = (int *) (newfont + offs[1]);
X/* Left widths */
X	font[ttxfont] .swidthl = (short *) (newfont + offs[2]);
X/* Right widths */
X	font[ttxfont] .swidthr = (short *) (newfont + offs[3]);
X/* Vertical symbol hot-spot position */
X	font[ttxfont] .symbol = (short *) (newfont + offs[4]);
X/* The actual glyph strokes */
X	font[ttxfont] .svec = (unsigned short *) (newfont + offs[5]);
X/* Ligature data */
X	font[ttxfont] .lig = (int *) (newfont + offs[6]);
X
X/* Whether or not this font has been loaded into memory or not yet */
X	font[ttxfont] .load = YES;
X    }
X}
END_OF_FILE
if test 37130 -ne `wc -c <'Vplot_Kernel/filters/genlib/gentext.c'`; then
    echo shar: \"'Vplot_Kernel/filters/genlib/gentext.c'\" unpacked with wrong size!
fi
# end of 'Vplot_Kernel/filters/genlib/gentext.c'
fi
echo shar: End of archive 23 \(of 24\).
cp /dev/null ark23isdone
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.