v14i028: Device-independant graphics system, with drivers
Rich Salz
rsalz at bbn.com
Thu Apr 7 08:03:47 AEST 1988
Submitted-by: Joe Dellinger <joe at 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 at 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 at uunet.uu.net.
More information about the Comp.sources.unix
mailing list