DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T d

⟦34ac934f4⟧ TextFile

    Length: 14471 (0x3887)
    Types: TextFile
    Names: »dmd-sp.c«

Derivation

└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
    └─⟦this⟧ »./DVIware/laser-setters/umd-dvi/dev/dmd-sp.c« 

TextFile

/*
 * Support drawing routines for Chris Torek's DVI->ImPress program.
 */

#include <stdio.h>
#include <ctype.h>
#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<THEIGHT; i++)
		bcopy(btexture[i],stexture[i],TWIDTH);

}

#define	push_location()
#define	pop_location()

#ifdef notdef
/*
 * Push the state of the Imagen and set up a new virtual coord system
 */
static void push_location()
{
    putchar(imP_Push);
    putchar(imP_SetHVSystem);
    putchar(0140);
}


/*
 * Create the pushed virtual page, and pop the state of the printer
 */
static void pop_location()
{
    putchar(imP_Pop);
}
#endif


/*
 * Set the pen size
 * Called as \special{pn size}
 *	 eg: \special{pn 8}
 * The size is the number of milli-inches for the diameter of the pen.
 * This routine converts that value to device-dependent pixels, and makes
 * sure that the resulting value is within legal bounds.
 */
static void im_pensize(cp)
char *cp;
{
    int size;
    
    if (sscanf(cp, " %d ", &size) != 1) return;
    pensize = yconv(size);
    if (pensize < 1) pensize = 1;
    else if (pensize > 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<THEIGHT; i++)/* Do rows */
		for (j=0; j<TWIDTH; j++) putchar(stexture[i][j]);
	}
	putchar(imP_SetTexture);
	putchar((family & 0x7e) >> 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 <inchesperdash>}	(dashed line)
 *	  or \special{dt <inchesperdot>}	(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<numdots-1; i++) {
	    a = i * (pixperdash + spacesize) / d;
	    b = a + pixperdash / d;
	    cx0 = ((float) x0) + (a*dx) + 0.5;
	    cy0 = ((float) y0) + (a*dy) + 0.5;
	    cx1 = ((float) x0) + (b*dx) + 0.5;
	    cy1 = ((float) y0) + (b*dy) + 0.5;
	    connect((int) cx0, (int) cy0, (int) cx1, (int) cy1);
	    b += spacesize / d;
	}
	cx0 = ((float) x0) + (b*dx) + 0.5;
	cy0 = ((float) y0) + (b*dy) + 0.5;
	connect((int) cx0, (int) cy0, x1, y1);
    }
    pathlen = 0;
    pop_location();
}


/*
 * Virtually draw to a given x,y position on the virtual page.
 * X and Y are expressed in thousandths of an inch, and this
 * routine converts them to pixels.
 *
 * Called as \special{pa <x> <y>}
 *	 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<pcount; i++) {
	    ul_one = htonl((unsigned long) bitpattern[i]);
	    bcopy((char *) &ul_one, stexture[j++], TWIDTH);
	}
    }
    texture_defined = FALSE;
#endif
}


/*
 * This routine takes the string argument for a tx command and
 * parses out the separate bitpatterns to call im_texture with.
 * Written by Tinh Tang
 */
static void do_texture(t)
char *t;
{
    int bitpattern[32];
    int pcount = 0;

    while (isspace (*t)) t++;
    while (*t) {
	if (sscanf(t, "%x", &bitpattern[pcount++]) != 1) {
	    error(0, 0, "malformed tx command");
	    return;
	}
	while (*t && !isspace(*t)) t++;/* Skip to space */
	while (*t && isspace(*t)) t++;/* Skip to nonspace */
    }
    if (pcount != 4 && pcount != 8 && pcount != 16 && pcount != 32) {
	error(0, 0, "malformed tx command");
	return;
    }
    im_texture(pcount, bitpattern);
}

	
#define	COMLEN	3		/* Length of a tpic command plus one */

DoSpecial(k)
	i32 k;
{
    char *spstring, *cp, command[COMLEN];
    register int len;

    spstring = malloc((unsigned) (k+1));
    if (spstring == NULL) error(2, 0, "Out of memory");
    len = 0;
    while (k--) spstring[len++] = GetByte(stdin);
    spstring[len] = '\0';
    cp = spstring;
    while (isspace(*cp)) ++cp;
    len = 0;
    while (!isspace(*cp) && *cp && len < COMLEN-1) command[len++] = *cp++;
    command[len] = '\0';

	if (ImHH != hh || ImVV != vv)
		ImSetPosition(hh, vv);

    if (strcmp(command, "pn") == 0) im_pensize(cp);
    else if (strcmp(command, "fp") == 0) im_flushpath();
    else if (strcmp(command, "da") == 0) dashed_line(cp, 0);
    else if (strcmp(command, "dt") == 0) dashed_line(cp, 1);
    else if (strcmp(command, "pa") == 0) im_drawto(cp);
    else if (strcmp(command, "ar") == 0) im_arc(cp);
    else if (strcmp(command, "sp") == 0) flush_spline();
    else if (strcmp(command, "sh") == 0) im_shade();
    else if (strcmp(command, "wh") == 0) im_whiten();
    else if (strcmp(command, "bk") == 0) im_blacken();
    else if (strcmp(command, "tx") == 0) im_texture(cp);
    else error(0, 0, "warning: ignoring \\special");

    free(spstring);
}