home *** CD-ROM | disk | FTP | other *** search
- Subject: v14i028: Device-independant graphics system, with drivers
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- 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
-