From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- dviware/umddvi/dev/imagen1-special.c | 718 +++++++++++++++++++++++++++++++++++ 1 file changed, 718 insertions(+) create mode 100644 dviware/umddvi/dev/imagen1-special.c (limited to 'dviware/umddvi/dev/imagen1-special.c') diff --git a/dviware/umddvi/dev/imagen1-special.c b/dviware/umddvi/dev/imagen1-special.c new file mode 100644 index 0000000000..628b26c483 --- /dev/null +++ b/dviware/umddvi/dev/imagen1-special.c @@ -0,0 +1,718 @@ +/* + * Support drawing routines for Chris Torek's DVI->ImPress program. + * + * Requires v1.7 or later ImPress to handle paths. + * Better if v1.9 or later for arc, circle, and ellipse primitives + * (define USEGRAPHICS). + * + * Tim Morgan, UC Irvine, 11/17/85 + * + * + * At the time these routines are called, the position of the Imagen should + * have been updated to the upper left corner of the graph (the position + * the \special appears at in the dvi file). Then the coordinates in the + * graphics commands are in terms of a virtual page with axes oriented the + * same as the Imagen normally has: + * + * 0,0 + * +-----------> +x + * | + * | + * | + * \ / + * +y + * + * Angles are measured in the conventional way, from +x towards +y. + * Unfortunately, that reverses the meaning of "counterclockwise" from + * what you see in the output. + * + * Unfortunately, some 8/300's don't have an aspect ratio which is 1:1. + * One of ours appears to be 295 dpi in the horizontal direction and 300dpi + * vertically. If ASPECT is defined, then dviimp/imagen1 and draw_imp/special + * use two different variables for the horizontal and vertical resolution, and + * otherwise, just one. Because the drawing routines which are defined + * in ImPress for circles, arcs, and ellipses in V1.9 and later assume that + * the output device is 1:1, they can't be used if ASPECT is defined, and + * because I don't want to hack up imagen1 to understand different horizontal + * and vertical resolutions, we're currently ignoring this problem, and not + * defining ASPECT. + */ + +#define USEGRAPHICS /* Only if v1.9 or later imPRESS */ +#undef ASPECT + +#ifdef ASPECT /* Can't have both! */ +#undef USEGRAPHICS +#endif + +#include +#include +#include "types.h" +#include "imPcodes.h" + +/* Put a two-byte (word) value to the Imagen */ +#define putword(w) (putchar((w) >> 8), putchar(w)) + +extern char *malloc(); + + +#define TRUE 1 +#define FALSE 0 + +#define TWOPI (3.14157926536*2.0) +#define MAXPOINTS 300 /* Most number of points in a path */ +#define SPLINEPOINTS 900 /* Most points in a spline */ +#define RADTOPXL 2607.435436 /* (16383 / (2pi)). This + converts from radians to the + angle units used by ImPress */ + +/* Convert radian angles to 2**-14 angle units used by ImPress */ +#define RadToImpUnits(a) ((short) ((a)*RADTOPXL + 0.5)) + +/* Graphics operations */ +#define WHITE 0 +#define SHADE 3 +#define OR 7 +#define BLACK 15 + +extern double cos(), sin(), sqrt(); +#ifndef ASPECT +extern int DPI; /* Resolution of device */ +#define PixPerInX DPI +#define PixPerInY DPI +#else +extern int DPIx, DPIy; /* x,y resolution of device */ +#define PixPerInX DPIx +#define PixPerInY DPIy +#endif + +extern int UserMag; +#define conv(x, f)\ + ((int) ((((double)(x)/1000.0) * ((double)(f)) * ((double)UserMag/1000.0)) + 0.5)) +#define xconv(x) conv(x, PixPerInX) +#define yconv(y) conv(y, PixPerInY) + +extern int ImHH; /* Imagen horizontal position */ +extern int ImVV; /* Imagen vertical position */ +extern int hh; /* current horizontal position, in DEVs */ +extern int vv; /* current vertical position, in DEVs */ + +extern int NextFamilyNumber; /* Number of next ImPress family to use */ +#define fnum NextFamilyNumber + +static int xx[MAXPOINTS], yy[MAXPOINTS], pathlen, + pensize = 2; /* Size we want Imagen to draw at, default 2 pixels */ + +#define MAXPENSIZE 20 /* Imagen restriction */ + +static int + family_defined = FALSE, /* Have we chosen family yet? */ + texture_defined = FALSE,/* Have we done a set_texture yet? */ + whiten_next = FALSE, /* Should next object be whitened? */ + blacken_next = FALSE, /* Should next object be blackened? */ + shade_next = FALSE; /* Should next object be shaded? */ + +/* Predefined shading (texture) glyph */ +/* First, define size of glyph */ +#define THEIGHT 32 /* bits high */ +#define TWIDTH 4 /* bytes wide */ +/* Next, declare the bit map for the glyph */ +static char stexture[THEIGHT][TWIDTH]={ + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}}; + +/* + * Copy a default texture into the stexture array + */ +static void glyph_init() +{ + static char btexture[THEIGHT][TWIDTH]={ + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}, + {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}}; + + int i; + for (i=0; i MAXPENSIZE) pensize = MAXPENSIZE; +} + + +/* + * Make sure the pen size is set. Since we push and pop the state, + * this has to be sent for each different object (I think). + */ +static void set_pen_size() +{ + putchar(imP_SetPen); + putchar(pensize); +} + + +/* + * Actually apply the attributes (shade, whiten, or blacken) to the currently + * defined path/figure. + */ +static void do_attributes() +{ + static int family; /* Family of downloaded texture glyph */ + static int member; /* Member of family */ + int i,j; /* Loop through glyph array */ + + if (shade_next) { + shade_next = FALSE; + if (!family_defined) { + family_defined = TRUE; + family = fnum++; + member = -1; + } + if (!texture_defined) { + texture_defined = TRUE; + member++; + putchar(imP_DefGlyph); + putchar((family & 0x7e) >> 1); + putchar((family & 0x01) << 7 | (member & 0x7f)); + /*putword(0); */ /* Advance width */ + putword(32); + putword(TWIDTH*8); /* pixel width (8 x number of bytes) */ + /*putword(0); */ /* left offset */ + putword(32); + putword(THEIGHT); /* and height of glyph */ + /*putword(0); */ /* top offset */ + putword(32); + for (i=0; i> 1); + putchar((family & 0x01) << 7 | (member & 0x7f)); + putchar(imP_FillPath); + putchar(SHADE); + glyph_init(); /* reinitialize the array */ + } + else if (whiten_next) { + whiten_next = FALSE; + putchar(imP_FillPath); + putchar(WHITE); + } + else if (blacken_next) { + blacken_next = FALSE; + putchar(imP_FillPath); + putchar(BLACK); + } +} + + +/* + * Flush the path that we've built up with im_drawto() + * Called as \special{fp} + */ +static void im_flushpath() +{ + register int i; + + push_location(); + if (pathlen <= 0) return; + set_pen_size(); + putchar(imP_CreatePath); + putword(pathlen); + for (i=1; i<=pathlen; i++) { + putword(xx[i]); + putword(yy[i]); + } + pathlen = 0; + putchar(imP_DrawPath); + putchar(BLACK); + do_attributes(); + pop_location(); +} + + +/* Helper routine for dashed_line() */ +static void connect(x0, y0, x1, y1) +int x0, y0, x1, y1; +{ + set_pen_size(); + putchar(imP_CreatePath); + putword(2); /* Path length */ + putword(x0); putword(y0);/* The path */ + putword(x1); putword(y1); + putchar(imP_DrawPath); + putchar(BLACK); +} + + +/* Another helper. Draw a dot at the indicated point */ +static void dot_at(x, y) +int x,y; +{ + set_pen_size(); + putchar(imP_CreatePath); + putword(1); /* Path length */ + putword(x); putword(y); /* The path */ + putchar(imP_DrawPath); + putchar(BLACK); +} + + +/* + * Draw a dashed or dotted line between the first pair of points in the array + * Called as \special{da } (dashed line) + * or \special{dt } (dotted line) + * eg: \special{da 0.05} + */ +static void dashed_line(cp, dotted) +char *cp; +int dotted; /* boolean */ +{ + int i, numdots, x0, y0, x1, y1; + double cx0, cy0, cx1, cy1; + double d, spacesize, a, b, dx, dy, pixperdash; + float inchesperdash; + + if (sscanf(cp, " %f ", &inchesperdash) != 1) return; + if (pathlen <= 1) return; + pixperdash = inchesperdash * ((float) PixPerInY); + x0 = xx[1]; x1 = xx[2]; + y0 = yy[1]; y1 = yy[2]; + dx = x1 - x0; + dy = y1 - y0; + push_location(); + if (dotted) { + numdots = sqrt(dx*dx + dy*dy) / pixperdash + 0.5; + if (numdots > 0) + for (i = 0; i <= numdots; i++) { + a = (float) i / (float) numdots; + cx0 = ((float) x0) + (a*dx) + 0.5; + cy0 = ((float) y0) + (a*dy) + 0.5; + dot_at((int) cx0, (int) cy0); + } + } + else { + d = sqrt(dx*dx + dy*dy); + if (d <= 2 * pixperdash) { + connect(x0, y0, x1, y1); + pathlen = 0; + pop_location(); + return; + } + numdots = d / (2 * pixperdash) + 1; + spacesize = (d - numdots * pixperdash) / (numdots - 1); + for (i=0; i } + * eg: \special{pa 0 1200} + */ +static void im_drawto(cp) +char *cp; +{ + int x,y; + + if (sscanf(cp, " %d %d ", &x, &y) != 2) return; + + if (++pathlen >= MAXPOINTS) + error(1, 0, "Too many points specified"); + xx[pathlen] = xconv(x); + yy[pathlen] = yconv(y); +} + +#ifndef USEGRAPHICS +/* + * Helper routine for im_arc(). + * Convert x and y to integers, then call im_drawto() normally. + */ +static void im_fdraw(x, y) +float x, y; +{ + int ix,iy; + + ix = (int) x + 0.5; + iy = (int) y + 0.5; + im_drawto(ix, iy); +} + + +/* + * Draw the indicated arc on the virtual page and flush it. + * The arc is always drawn counter clockwise from start_angle to end_angle on + * the virtual page. That is, clockwise in the real world (since +y is down). + * It is assumed that start_angle has been adjusted to be in the range + * 0.0 <= start_angle < 2*PI + * and that end_angle is the smallest suitable angle >= start_angle. Thus + * end_angle MAY be >= 2*PI. + * + * Called as \special{ar + * } + * + * ,,, are in 1/1000's of an inch. + * and are in radians. + * + * eg: \special{ar 240 240 30 30 0.000 6.283} + */ +static void im_arc(cp) +char *cp; +{ + int xc, yc, xrad, yrad; + float start_angle, end_angle; + double angle, theta, r, xcenter, ycenter, xradius, yradius; + int n; + + if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle, + &end_angle) != 6) return; + xcenter = xc; /* Convert to floating point */ + ycenter = yc; + xradius = xrad; + yradius = yrad; + r = (xradius+yradius)/2.0; + theta = sqrt(1.0 / r); + n = TWOPI / theta + 0.5; + if (n<6) n = 6; + if (n>80) n = 80; + theta = TWOPI / n; + + im_fdraw( xcenter + xradius*cos(start_angle), + ycenter + yradius*sin(start_angle) ); + angle = start_angle + theta; + while (angle < end_angle) { + im_fdraw(xcenter + xradius*cos(angle), + ycenter + yradius*sin(angle) ); + angle += theta; + } + im_fdraw( xcenter + xradius*cos(end_angle), + ycenter + yradius*sin(end_angle) ); + im_flushpath(); +} + +#else USEGRAPHICS + +/* Same routine as above, but it uses the special graphics primitives */ +static void im_arc(cp) +char *cp; +{ + int xc, yc, xrad, yrad; + float start_angle, end_angle; + short alpha0, alpha1; + + if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle, + &end_angle) != 6) return; + push_location(); + set_pen_size(); + putchar(imP_SetHAbs); + putword(xconv(xc)); + putchar(imP_SetVAbs); + putword(yconv(yc)); + +/* + * If end_angle > TWOPI, we can't simply use it, since it will be > 16383, + * and thus an illegal angle. Simply subtracting TWOPI will make it < + * start_angle, which will reverse the direction the arc is drawn, resulting + * in the wrong arc. So we also exchange start_angle and end_angle. But then + * start_angle < end_angle, so the arc goes back to its original direction! + * So we also subtract TWOPI from the original start_angle, foring end_angle + * to be negative (since 0<=start_angle TWOPI) { + double temp; + temp = end_angle - TWOPI; + end_angle = start_angle - TWOPI; + start_angle = temp; + } + if (xrad >= yrad-1 && xrad <= yrad+1) { /* Circle or arc */ + alpha0 = RadToImpUnits(start_angle); + alpha1 = RadToImpUnits(end_angle); + putchar(imP_CircleArc); + putword(xconv((double) xrad)); + putword(alpha0); + putword(alpha1); + } + else { /* Ellipse */ + putchar(imP_EllipseArc); + putword(xconv((double) xrad)); + putword(yconv((double) yrad)); + putword(0); /* alphaoff */ + putword(0); /* zero start angle */ + putword(16383); /* two pi end angle */ + } + putchar(imP_DrawPath); + putchar(BLACK); + do_attributes(); + pop_location(); +} +#endif USEGRAPHICS + + +/* + * Create a spline through the points in the array. + * Called like flush path (fp) command, after points + * have been defined via pa command(s). + * + * eg: \special{sp} + */ +static void flush_spline() +{ + int xp, yp, N; + float t1, t2, t3, w; + int i, j, steps; + int splinex[SPLINEPOINTS], spliney[SPLINEPOINTS], splinelen; + + push_location(); + set_pen_size(); + putchar(imP_CreatePath); + splinelen = 0; + N = pathlen + 1; + xx[0] = xx[1]; + yy[0] = yy[1]; + xx[N] = xx[N-1]; + yy[N] = yy[N-1]; + for (i = 0; i < N-1; i++) { /* interval */ + steps = (dist(xx[i],yy[i], xx[i+1],yy[i+1]) + + dist(xx[i+1],yy[i+1], xx[i+2],yy[i+2])) / 20; + for (j = 0; j < steps; j++) { /* points within */ + w = ((float) j) / ((float) steps); + t1 = 0.5 * w * w; + w -= 0.5; + t2 = 0.75 - w * w; + w -= 0.5; + t3 = 0.5 * w * w; + xp = t1 * xx[i+2] + t2 * xx[i+1] + t3 * xx[i] + 0.5; + yp = t1 * yy[i+2] + t2 * yy[i+1] + t3 * yy[i] + 0.5; + if (splinelen >= SPLINEPOINTS) + error(1, 0, "Too many points in spline"); + splinex[splinelen] = xp; + spliney[splinelen++] = yp; + } + } + putword(splinelen); + for (i=0; i