/* * Support drawing routines for Chris Torek's DVI->ImPress program. */ #include #include #include "types.h" #include "dmdcodes.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 PI 3.14157926536 #define TWOPI (PI*2.0) #define MAXPOINTS 300 /* Most number of points in a path */ /* Graphics operations */ #define WHITE 0 #define SHADE 3 #define OR 7 #define BLACK 15 extern double cos(), sin(), sqrt(); extern int DPI; /* Resolution of device */ #define PixPerInX DPI #define PixPerInY DPI extern int UserMag; #define fconv(x, f)\ (((double)(x)/1000.0) * ((double)(f)) * ((double)UserMag/1000.0)) #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 */ static int xx[MAXPOINTS], yy[MAXPOINTS], pathlen, pensize = 1; /* 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(DMD_PENSIZE); 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; #ifdef notdef 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)); #endif putchar(DMD_FILLPATH); putchar(SHADE); glyph_init(); /* reinitialize the array */ } else if (whiten_next) { whiten_next = FALSE; putchar(DMD_FILLPATH); putchar(WHITE); } else if (blacken_next) { blacken_next = FALSE; putchar(DMD_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(DMD_SEGMENT); putword(pathlen); for (i=1; i<=pathlen; i++) { putword(xx[i]); putword(yy[i]); } pathlen = 0; putchar(DMD_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(DMD_SEGMENT); putword(2); /* Path length */ putword(x0); putword(y0);/* The path */ putword(x1); putword(y1); putchar(DMD_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(DMD_SEGMENT); putword(1); /* Path length */ putword(x); putword(y); /* The path */ putchar(DMD_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); if (pixperdash < 2.) pixperdash = 2.; 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) + ImHH; yy[pathlen] = yconv(y) + ImVV; } /* 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, fxrad, fyrad; int xp, yp; if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle, &end_angle) != 6) return; push_location(); set_pen_size(); xc = xconv(xc) + ImHH; yc = yconv(yc) + ImVV; { double temp; temp = start_angle; start_angle = end_angle; end_angle = temp; } if (xrad >= yrad-1 && xrad <= yrad+1) { /* Circle or arc */ putchar(DMD_CIRCLE); putword(xc); putword(yc); /* starting point */ fyrad = fconv(yrad, PixPerInY); xp = fyrad * cos(start_angle) + xc + .5; yp = fyrad * sin(start_angle) + yc + .5; putword(xp); putword(yp); /* finishing point */ xp = fyrad * cos(end_angle) + xc + .5; yp = fyrad * sin(end_angle) + yc + .5; putword(xp); putword(yp); } else { /* Ellipse */ putchar(DMD_ELLIPSE); putword(xc); putword(yc); /* starting point */ fxrad = fconv(xrad, PixPerInX); fyrad = fconv(yrad, PixPerInY); xp = fxrad * cos(start_angle) + xc + .5; yp = fyrad * sin(start_angle) + yc + .5; putword(xp); putword(yp); /* finishing point */ xp = fxrad * cos(end_angle) + xc + .5; yp = fyrad * sin(end_angle) + yc + .5; putword(xp); putword(yp); putword(xconv(xrad)); putword(yconv(yrad)); } putchar(DMD_DRAWPATH); putchar(BLACK); do_attributes(); pop_location(); } /* * 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() { register int i; push_location(); if (pathlen <= 0) return; set_pen_size(); putchar(DMD_SPLINE); putword(pathlen); for (i=1; i<=pathlen; i++) { putword(xx[i]); putword(yy[i]); } pathlen = 0; putchar(DMD_DRAWPATH); putchar(BLACK); do_attributes(); pop_location(); } /* * Whiten the interior of the next figure (path). Command is: * \special{wh} */ static void im_whiten() { whiten_next = TRUE; } /* * Blacken the interior of the next figure (path). Command is: * \special{bk} */ static void im_blacken() { blacken_next = TRUE; } /* * Shade the interior of the next figure (path) with the predefined * texture. Command is: * \special{sh} */ static void im_shade() { shade_next = TRUE; } /* * Define the texture array. Command is: * \special{tx 32bits 32bits ....} */ static void im_texture(pcount,bitpattern) int pcount, bitpattern[32]; { int i,j,k; unsigned long ul_one; #ifdef notdef #ifdef DEBUG if (sizeof ul_one != TWIDTH) error(1, 0, "pointer/size mismatch"); #endif j = 0; for (k=0; k < THEIGHT/pcount; k++) { for (i=0; i