11fc75efeSopcode /*
2*45a94882Sopcode  * @(#)graphics.c	1.2	01/03/85
31fc75efeSopcode  *
41fc75efeSopcode  * Graphics routines for the SUN Gremlin picture editor.
51fc75efeSopcode  *
61fc75efeSopcode  * Mark Opperman (opcode@monet.BERKELEY)
71fc75efeSopcode  *
81fc75efeSopcode  */
91fc75efeSopcode 
101fc75efeSopcode #include <suntool/tool_hs.h>
111fc75efeSopcode #include <vfont.h>
121fc75efeSopcode #include "icondata.h"
131fc75efeSopcode #include "gremlin.h"
141fc75efeSopcode 
151fc75efeSopcode /* imports from main.c */
161fc75efeSopcode 
171fc75efeSopcode extern error();
181fc75efeSopcode extern struct pixwin *pix_pw;
191fc75efeSopcode extern struct rect pix_size;
201fc75efeSopcode extern struct pixrect *cset_pr;
211fc75efeSopcode extern struct pixrect *scratch_pr;
221fc75efeSopcode extern ELT *cset;
231fc75efeSopcode extern Artmode;
241fc75efeSopcode extern CSIZE;
251fc75efeSopcode extern CFONT;
261fc75efeSopcode extern CsetOn;
271fc75efeSopcode extern SUN_XORIGIN;
281fc75efeSopcode extern SUN_YORIGIN;
291fc75efeSopcode 
301fc75efeSopcode /* imports from display.c */
311fc75efeSopcode 
321fc75efeSopcode extern minsunx, maxsunx, minsuny, maxsuny;
331fc75efeSopcode 
341fc75efeSopcode /* imports from C */
351fc75efeSopcode 
361fc75efeSopcode extern char *malloc();
371fc75efeSopcode 
381fc75efeSopcode /* forward references */
391fc75efeSopcode 
401fc75efeSopcode extern char *GRReadFontFile();
411fc75efeSopcode 
421fc75efeSopcode /* symbolic font from text.c */
431fc75efeSopcode 
441fc75efeSopcode extern struct pixfont *text_pf;
451fc75efeSopcode 
461fc75efeSopcode /* locally defined variables */
471fc75efeSopcode 
481fc75efeSopcode int charysizes[NFONTS][NSIZES];	/* Character y dimensions for each size */
491fc75efeSopcode int curve_set;			/* TRUE if spline points pre-computed */
501fc75efeSopcode 
511fc75efeSopcode int linestyle;			/* Current line style */
521fc75efeSopcode int linemod;			/* Type of line (SOLID, DOTTED, ...) */
531fc75efeSopcode int linethickness;		/* 1, 2, 3 */
541fc75efeSopcode 
551fc75efeSopcode char fontdir[128] = "/usr/lib/font/devsun/";
561fc75efeSopcode char stippledir[128] = "/usr/lib/font/devsun/";
571fc75efeSopcode char stippletype[32] = "cf";
581fc75efeSopcode 
591fc75efeSopcode char *font_types[NFONTS] = { "R", "I", "B", "S" };
601fc75efeSopcode int font_sizes[NSIZES] = { 7, 10, 14, 24 };
611fc75efeSopcode int stipple_index[NSTIPPLES] = { 1, 3, 12, 14, 16, 19, 21, 23 };
621fc75efeSopcode 
631fc75efeSopcode /* NOTE: all stipple fonts are expected to be 32 x 32 bit rasters */
641fc75efeSopcode 
651fc75efeSopcode /* pointers to the stipple pixrects (16 x 16 bits) in the menu ... */
661fc75efeSopcode struct pixrect *stipple_prs[NSTIPPLES] = {
671fc75efeSopcode     &stipple1_pr, &stipple2_pr, &stipple3_pr, &stipple4_pr,
681fc75efeSopcode     &stipple5_pr, &stipple6_pr, &stipple7_pr, &stipple8_pr
691fc75efeSopcode };
701fc75efeSopcode 
711fc75efeSopcode /* ... and the corresponding images (32 x 32 bits) from the vfont file */
721fc75efeSopcode char stipple_patterns[NSTIPPLES][128];
731fc75efeSopcode 
74*45a94882Sopcode /* data used in graphics2.c for drawing polygons */
75*45a94882Sopcode int rasterlength;		/* real # horizontal bits in scratch_pr */
76*45a94882Sopcode int bytesperline;		/* rasterlength / 8 */
77*45a94882Sopcode int nlines;			/* # horizontal bits defined by scratch_pr */
78*45a94882Sopcode char *fill;			/* pointer to scratch_pr image */
79*45a94882Sopcode 
801fc75efeSopcode /*
811fc75efeSopcode  *  This matrix points to the DISPATCH data for each font/size pair
821fc75efeSopcode  *  if an unsuccesful attempt is made to open a particular font/size pair,
831fc75efeSopcode  *  its entry in this table is marked as -1.
841fc75efeSopcode  */
851fc75efeSopcode char *font_info[NFONTS][NSIZES] = {
861fc75efeSopcode     { NULL, NULL, NULL, NULL },
871fc75efeSopcode     { NULL, NULL, NULL, NULL },
881fc75efeSopcode     { NULL, NULL, NULL, NULL },
891fc75efeSopcode     { NULL, NULL, NULL, NULL },
901fc75efeSopcode };
911fc75efeSopcode struct pixrect *char_pr;
921fc75efeSopcode 
931fc75efeSopcode /* Splines use these global arrays */
941fc75efeSopcode 
951fc75efeSopcode static float h[MAXPOINTS];
961fc75efeSopcode static float x[MAXPOINTS], dx[MAXPOINTS], d2x[MAXPOINTS], d3x[MAXPOINTS];
971fc75efeSopcode static float y[MAXPOINTS], dy[MAXPOINTS], d2y[MAXPOINTS], d3y[MAXPOINTS];
981fc75efeSopcode static numpoints;
991fc75efeSopcode 
1001fc75efeSopcode /* These are used as bit masks to create the right style lines. */
1011fc75efeSopcode #define SOLID -1
1021fc75efeSopcode #define DOTTED 002
1031fc75efeSopcode #define DASHED 004
1041fc75efeSopcode #define DOTDASHED 012
1051fc75efeSopcode 
1061fc75efeSopcode 
1071fc75efeSopcode /*
1081fc75efeSopcode  * This routine sets the current line style.
1091fc75efeSopcode  */
GRSetLineStyle(style)1101fc75efeSopcode GRSetLineStyle(style)
1111fc75efeSopcode int style;			/* new stipple pattern for lines */
1121fc75efeSopcode {
1131fc75efeSopcode     switch (linestyle = style) {
1141fc75efeSopcode 	case 1:			/* dotted */
1151fc75efeSopcode 	    linemod = DOTTED;
1161fc75efeSopcode 	    linethickness = 1;
1171fc75efeSopcode 	    break;
1181fc75efeSopcode 	case 2:			/* broken */
1191fc75efeSopcode 	    linemod = DOTDASHED;
1201fc75efeSopcode 	    linethickness = 1;
1211fc75efeSopcode 	    break;
1221fc75efeSopcode 	case 3:			/* thick */
1231fc75efeSopcode 	    linemod = SOLID;
1241fc75efeSopcode 	    linethickness = 3;
1251fc75efeSopcode 	    break;
1261fc75efeSopcode 	case 4:			/* dashed */
1271fc75efeSopcode 	    linemod = DASHED;
1281fc75efeSopcode 	    linethickness = 1;
1291fc75efeSopcode 	    break;
1301fc75efeSopcode 	case 5:			/* narrow */
1311fc75efeSopcode 	    linemod = SOLID;
1321fc75efeSopcode 	    linethickness = 1;
1331fc75efeSopcode 	    break;
1341fc75efeSopcode 	case 6:			/* medium */
1351fc75efeSopcode 	    linemod = SOLID;
1361fc75efeSopcode 	    linethickness = 2;
1371fc75efeSopcode 	    break;
1381fc75efeSopcode     }
1391fc75efeSopcode }
1401fc75efeSopcode 
1411fc75efeSopcode 
1421fc75efeSopcode /*
1431fc75efeSopcode  * This routine returns the maximum vertical size (in bits) of a character
1441fc75efeSopcode  * of the specified font/size.
1451fc75efeSopcode  */
GRGetCharYSize(font,size)1461fc75efeSopcode GRGetCharYSize(font, size)
1471fc75efeSopcode register font;			/* character font (1 - 4) */
1481fc75efeSopcode register size;			/* character size (1 - 4) */
1491fc75efeSopcode {
1501fc75efeSopcode     return(charysizes[--font][--size]);
1511fc75efeSopcode }
1521fc75efeSopcode 
1531fc75efeSopcode 
1541fc75efeSopcode #define pi 3.14159265359
1551fc75efeSopcode #define twopi 6.28318530718
1561fc75efeSopcode #define log2_10 3.321915
1571fc75efeSopcode 
1581fc75efeSopcode 
1591fc75efeSopcode /*
1601fc75efeSopcode  * Draw arc - always to scratch_pr.
1611fc75efeSopcode  * Note: must check for zero radius before calling.
1621fc75efeSopcode  */
GRArc(center,cpoint,angle,style)1631fc75efeSopcode GRArc(center, cpoint, angle, style)
1641fc75efeSopcode register POINT *center, *cpoint;
1651fc75efeSopcode float angle;
1661fc75efeSopcode register style;
1671fc75efeSopcode {
1681fc75efeSopcode     double radius, resolution, t1, fullcircle;
1691fc75efeSopcode     double degreesperpoint;
1701fc75efeSopcode     float xs, ys, epsilon;
1711fc75efeSopcode     float x1, y1, x2, y2;
1721fc75efeSopcode     register i, extent;
1731fc75efeSopcode 
1741fc75efeSopcode     xs = cpoint->x - center->x;
1751fc75efeSopcode     ys = cpoint->y - center->y;
1761fc75efeSopcode 
1771fc75efeSopcode     /* calculate drawing parameters */
1781fc75efeSopcode 
1791fc75efeSopcode     radius = sqrt((double) (xs * xs + ys * ys));
1801fc75efeSopcode     t1 = floor(log10(radius) * log2_10);
1811fc75efeSopcode     resolution = pow(2.0, t1);
1821fc75efeSopcode     epsilon = (float) 1.0 / resolution;
1831fc75efeSopcode     fullcircle = ceil(twopi * resolution);
1841fc75efeSopcode     degreesperpoint = 360.0 / fullcircle;
1851fc75efeSopcode 
1861fc75efeSopcode     extent = (angle == 0) ? fullcircle : angle/degreesperpoint;
1871fc75efeSopcode 
1881fc75efeSopcode     GRSetLineStyle(style);
1891fc75efeSopcode 
1901fc75efeSopcode     x1 = cpoint->x;
1911fc75efeSopcode     y1 = cpoint->y;
1921fc75efeSopcode 
1931fc75efeSopcode     for (i=0; i<extent; ++i) {
1941fc75efeSopcode 	xs -= epsilon * ys;
1951fc75efeSopcode 	x2 = xs + center->x;
1961fc75efeSopcode 	ys += epsilon * xs;
1971fc75efeSopcode 	y2 = ys + center->y;
1981fc75efeSopcode 
1991fc75efeSopcode 	GRVector(x1, y1, x2, y2);
2001fc75efeSopcode 
2011fc75efeSopcode 	x1 = x2;
2021fc75efeSopcode 	y1 = y2;
2031fc75efeSopcode     }
2041fc75efeSopcode }  /* end GRArc */;
2051fc75efeSopcode 
2061fc75efeSopcode 
2071fc75efeSopcode /* This routine calculates parameteric values for use in calculating
2081fc75efeSopcode  * curves.  The values are an approximation of cumulative arc lengths
2091fc75efeSopcode  * of the curve (uses cord * length).  For additional information,
2101fc75efeSopcode  * see paper cited below.
2111fc75efeSopcode  */
2121fc75efeSopcode static
Paramaterize(x,y,h,n)2131fc75efeSopcode Paramaterize(x, y, h, n)
2141fc75efeSopcode float x[MAXPOINTS];
2151fc75efeSopcode float y[MAXPOINTS];
2161fc75efeSopcode float h[MAXPOINTS];
2171fc75efeSopcode register n;
2181fc75efeSopcode {
2191fc75efeSopcode     register i, j;
2201fc75efeSopcode     float t1, t2;
2211fc75efeSopcode     float u[MAXPOINTS];
2221fc75efeSopcode 
2231fc75efeSopcode     n = numpoints;
2241fc75efeSopcode 
2251fc75efeSopcode     for (i=1; i<=n; ++i) {
2261fc75efeSopcode 	u[i] = 0.0;
2271fc75efeSopcode 	for (j=1; j<i; ++j) {
2281fc75efeSopcode 	    t1 = x[j+1] - x[j];
2291fc75efeSopcode 	    t2 = y[j+1] - y[j];
2301fc75efeSopcode 	    u[i] += (float) sqrt((double) ((t1 * t1) + (t2 * t2)));
2311fc75efeSopcode 	}
2321fc75efeSopcode     }
2331fc75efeSopcode 
2341fc75efeSopcode     for (i=1; i<n; ++i)
2351fc75efeSopcode 	h[i] = u[i+1] - u[i];
2361fc75efeSopcode }  /* end Paramaterize */
2371fc75efeSopcode 
2381fc75efeSopcode 
2391fc75efeSopcode /*
2401fc75efeSopcode  * This routine solves for the cubic polynomial to fit a spline
2411fc75efeSopcode  * curve to the the points  specified by the list of values.
2421fc75efeSopcode  * The curve generated is periodic.  The alogrithms for this
2431fc75efeSopcode  * curve are from the "Spline Curve Techniques" paper cited below.
2441fc75efeSopcode  */
2451fc75efeSopcode static
PeriodicSpline(h,z,dz,d2z,d3z,npoints)2461fc75efeSopcode PeriodicSpline(h, z, dz, d2z, d3z, npoints)
2471fc75efeSopcode float h[MAXPOINTS];		/* paramaterization */
2481fc75efeSopcode float z[MAXPOINTS];		/* point list */
2491fc75efeSopcode float dz[MAXPOINTS];		/* to return the 1st derivative */
2501fc75efeSopcode float d2z[MAXPOINTS];		/* 2nd derivative */
2511fc75efeSopcode float d3z[MAXPOINTS];		/* and 3rd derivative */
2521fc75efeSopcode register npoints;		/* number of valid points */
2531fc75efeSopcode {
2541fc75efeSopcode     float a[MAXPOINTS];
2551fc75efeSopcode     float b[MAXPOINTS];
2561fc75efeSopcode     float c[MAXPOINTS];
2571fc75efeSopcode     float d[MAXPOINTS];
2581fc75efeSopcode     float deltaz[MAXPOINTS];
2591fc75efeSopcode     float r[MAXPOINTS];
2601fc75efeSopcode     float s[MAXPOINTS];
2611fc75efeSopcode     float ftmp;
2621fc75efeSopcode     register i;
2631fc75efeSopcode 
2641fc75efeSopcode     /* step 1 */
2651fc75efeSopcode     for (i=1; i<npoints; ++i) {
2661fc75efeSopcode 	if (h[i] != 0)
2671fc75efeSopcode 	    deltaz[i] = (z[i+1] - z[i]) / h[i];
2681fc75efeSopcode 	else
2691fc75efeSopcode 	    deltaz[i] = 0;
2701fc75efeSopcode     }
2711fc75efeSopcode     h[0] = h[npoints-1];
2721fc75efeSopcode     deltaz[0] = deltaz[npoints-1];
2731fc75efeSopcode 
2741fc75efeSopcode     /* step 2 */
2751fc75efeSopcode     for (i=1; i<npoints-1; ++i) {
2761fc75efeSopcode 	d[i] = deltaz[i+1] - deltaz[i];
2771fc75efeSopcode     }
2781fc75efeSopcode     d[0] = deltaz[1] - deltaz[0];
2791fc75efeSopcode 
2801fc75efeSopcode     /* step 3a */
2811fc75efeSopcode     a[1] = 2 * (h[0] + h[1]);
2821fc75efeSopcode     if (a[1] == 0)
2831fc75efeSopcode 	return(-1);  /* 3 consecutive knots at same point */
2841fc75efeSopcode     b[1] = d[0];
2851fc75efeSopcode     c[1] = h[0];
2861fc75efeSopcode 
2871fc75efeSopcode     for (i=2; i<npoints-1; ++i) {
2881fc75efeSopcode 	ftmp = h[i-1];
2891fc75efeSopcode 	a[i] = ftmp + ftmp + h[i] + h[i] - (ftmp * ftmp)/a[i-1];
2901fc75efeSopcode 	    if (a[i] == 0)
2911fc75efeSopcode 		return(-1);  /* 3 consec knots at same point */
2921fc75efeSopcode 	b[i] = d[i-1] - ftmp * b[i-1]/a[i-1];
2931fc75efeSopcode 	c[i] = -ftmp * c[i-1]/a[i-1];
2941fc75efeSopcode     }
2951fc75efeSopcode 
2961fc75efeSopcode     /* step 3b */
2971fc75efeSopcode     r[npoints-1] = 1;
2981fc75efeSopcode     s[npoints-1] = 0;
2991fc75efeSopcode     for (i=npoints-2; i>0; --i) {
3001fc75efeSopcode 	r[i] = -(h[i] * r[i+1] + c[i])/a[i];
3011fc75efeSopcode 	s[i] = (6 * b[i] - h[i] * s[i+1])/a[i];
3021fc75efeSopcode     }
3031fc75efeSopcode 
3041fc75efeSopcode     /* step 4 */
3051fc75efeSopcode     d2z[npoints-1] = (6 * d[npoints-2] - h[0] * s[1]
3061fc75efeSopcode 		       - h[npoints-1] * s[npoints-2])
3071fc75efeSopcode 		     / (h[0] * r[1] + h[npoints-1] * r[npoints-2]
3081fc75efeSopcode 			+ 2 * (h[npoints-2] + h[0]));
3091fc75efeSopcode     for (i=1; i<npoints-1; ++i) {
3101fc75efeSopcode 	d2z[i] = r[i] * d2z[npoints-1] + s[i];
3111fc75efeSopcode     }
3121fc75efeSopcode     d2z[npoints] = d2z[1];
3131fc75efeSopcode 
3141fc75efeSopcode     /* step 5 */
3151fc75efeSopcode     for (i=1; i<npoints; ++i) {
3161fc75efeSopcode 	dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
3171fc75efeSopcode 	if (h[i] != 0)
3181fc75efeSopcode 	    d3z[i] = (d2z[i+1] - d2z[i])/h[i];
3191fc75efeSopcode 	else
3201fc75efeSopcode 	    d3z[i] = 0;
3211fc75efeSopcode     }
3221fc75efeSopcode 
3231fc75efeSopcode     return(0);
3241fc75efeSopcode }  /* end PeriodicSpline */
3251fc75efeSopcode 
3261fc75efeSopcode 
3271fc75efeSopcode /*
3281fc75efeSopcode  * This routine solves for the cubic polynomial to fit a spline
3291fc75efeSopcode  * curve from the points specified by the list of values.  The alogrithms for
3301fc75efeSopcode  * this curve are from the "Spline Curve Techniques" paper cited below.
3311fc75efeSopcode  */
3321fc75efeSopcode static
NaturalEndSpline(h,z,dz,d2z,d3z,npoints)3331fc75efeSopcode NaturalEndSpline(h, z, dz, d2z, d3z, npoints)
3341fc75efeSopcode float h[MAXPOINTS];		/* paramaterization */
3351fc75efeSopcode float z[MAXPOINTS];		/* point list */
3361fc75efeSopcode float dz[MAXPOINTS];		/* to return the 1st derivative */
3371fc75efeSopcode float d2z[MAXPOINTS];		/* 2nd derivative */
3381fc75efeSopcode float d3z[MAXPOINTS];		/* and 3rd derivative */
3391fc75efeSopcode register npoints;		/* number of valid points */
3401fc75efeSopcode {
3411fc75efeSopcode     float a[MAXPOINTS];
3421fc75efeSopcode     float b[MAXPOINTS];
3431fc75efeSopcode     float d[MAXPOINTS];
3441fc75efeSopcode     float deltaz[MAXPOINTS];
3451fc75efeSopcode     float ftmp;
3461fc75efeSopcode     register i;
3471fc75efeSopcode 
3481fc75efeSopcode     /* step 1 */
3491fc75efeSopcode     for (i=1; i<npoints; ++i) {
3501fc75efeSopcode 	if (h[i] != 0)
3511fc75efeSopcode 	    deltaz[i] = (z[i+1] - z[i]) / h[i];
3521fc75efeSopcode 	else
3531fc75efeSopcode 	    deltaz[i] = 0;
3541fc75efeSopcode     }
3551fc75efeSopcode     deltaz[0] = deltaz[npoints-1];
3561fc75efeSopcode 
3571fc75efeSopcode     /* step 2 */
3581fc75efeSopcode     for (i=1; i<npoints-1; ++i) {
3591fc75efeSopcode 	d[i] = deltaz[i+1] - deltaz[i];
3601fc75efeSopcode     }
3611fc75efeSopcode     d[0] = deltaz[1] - deltaz[0];
3621fc75efeSopcode 
3631fc75efeSopcode     /* step 3 */
3641fc75efeSopcode     a[0] = 2 * (h[2] + h[1]);
3651fc75efeSopcode     if (a[0] == 0)		/* 3 consec knots at same point */
3661fc75efeSopcode 	return(-1);
3671fc75efeSopcode     b[0] = d[1];
3681fc75efeSopcode 
3691fc75efeSopcode     for (i=1; i<npoints-2; ++i) {
3701fc75efeSopcode 	ftmp = h[i+1];
3711fc75efeSopcode 	a[i] = ftmp + ftmp + h[i+2] + h[i+2] - (ftmp * ftmp) / a[i-1];
3721fc75efeSopcode 	if (a[i] == 0)		/* 3 consec knots at same point */
3731fc75efeSopcode 	    return(-1);
3741fc75efeSopcode 	b[i] = d[i+1] - ftmp * b[i-1]/a[i-1];
3751fc75efeSopcode     }
3761fc75efeSopcode 
3771fc75efeSopcode     /* step 4 */
3781fc75efeSopcode     d2z[npoints] = d2z[1] = 0;
3791fc75efeSopcode     for (i=npoints-1; i>1; --i) {
3801fc75efeSopcode 	d2z[i] = (6 * b[i-2] - h[i] *d2z[i+1])/a[i-2];
3811fc75efeSopcode     }
3821fc75efeSopcode 
3831fc75efeSopcode     /* step 5 */
3841fc75efeSopcode     for (i=1; i<npoints; ++i) {
3851fc75efeSopcode 	dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
3861fc75efeSopcode 	if (h[i] != 0)
3871fc75efeSopcode 	    d3z[i] = (d2z[i+1] - d2z[i])/h[i];
3881fc75efeSopcode 	else
3891fc75efeSopcode 	    d3z[i] = 0;
3901fc75efeSopcode     }
3911fc75efeSopcode 
3921fc75efeSopcode     return(0);
3931fc75efeSopcode }  /* end NaturalEndSpline */
3941fc75efeSopcode 
3951fc75efeSopcode 
3961fc75efeSopcode #define PointsPerInterval 16
3971fc75efeSopcode 
3981fc75efeSopcode 
3991fc75efeSopcode /*
4001fc75efeSopcode  * This routine computes a smooth curve through a set of points.
4011fc75efeSopcode  * Returns -1 if there are too many knots to draw the curve.
4021fc75efeSopcode  * Use GRCurve AFTER this routine to actually draw the curve.
4031fc75efeSopcode  * [Formerly the first half of GRCurve()]
4041fc75efeSopcode  *
4051fc75efeSopcode  * The method used is the parametric spline curve on unit knot mesh described
4061fc75efeSopcode  * in "Spline Curve Techniques" by Patrick Baudelaire, Robert Flegal, and
4071fc75efeSopcode  * Robert Sproull -- Xerox Parc.
4081fc75efeSopcode  */
GRSetCurve(pointlist)4091fc75efeSopcode GRSetCurve(pointlist)
4101fc75efeSopcode POINT *pointlist;
4111fc75efeSopcode {
4121fc75efeSopcode     register POINT *ptr;
4131fc75efeSopcode     register i, stat;
4141fc75efeSopcode 
4151fc75efeSopcode     /* Copy point list to array for easier access */
4161fc75efeSopcode     ptr = pointlist;
4171fc75efeSopcode     for (i=1; (!Nullpoint(ptr)); ++i) {
4181fc75efeSopcode 	x[i] = ptr->x;
4191fc75efeSopcode 	y[i] = ptr->y;
4201fc75efeSopcode 	ptr = PTNextPoint(ptr);
4211fc75efeSopcode     }
4221fc75efeSopcode 
4231fc75efeSopcode     /* Solve for derivatives of the curve at each point
4241fc75efeSopcode        separately for x and y (parametric). */
4251fc75efeSopcode 
4261fc75efeSopcode     numpoints = i - 1;		/* set global numpoints */
4271fc75efeSopcode 
4281fc75efeSopcode     Paramaterize(x, y, h, numpoints);
4291fc75efeSopcode 
4301fc75efeSopcode     stat = 0;
4311fc75efeSopcode     if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) { /* closed curve */
4321fc75efeSopcode 	stat |= PeriodicSpline(h, x, dx, d2x, d3x, numpoints);
4331fc75efeSopcode 	stat |= PeriodicSpline(h, y, dy, d2y, d3y, numpoints);
4341fc75efeSopcode     }
4351fc75efeSopcode     else {
4361fc75efeSopcode 	stat |= NaturalEndSpline(h, x, dx, d2x, d3x, numpoints);
4371fc75efeSopcode 	stat |= NaturalEndSpline(h, y, dy, d2y, d3y, numpoints);
4381fc75efeSopcode     }
4391fc75efeSopcode 
4401fc75efeSopcode     curve_set = 1;		/* indicates that paramterization is done */
4411fc75efeSopcode     return(stat);
4421fc75efeSopcode }
4431fc75efeSopcode 
4441fc75efeSopcode 
4451fc75efeSopcode /*
4461fc75efeSopcode  * This routine displays a smooth curve through a set of points.  The
4471fc75efeSopcode  * method used is the parametric spline curve on unit knot mesh described
4481fc75efeSopcode  * in "Spline Curve Techniques" by Patrick Baudelaire, Robert Flegal, and
4491fc75efeSopcode  * Robert Sproull -- Xerox Parc.
4501fc75efeSopcode  * [formerly the second half of GRCurve()]
4511fc75efeSopcode  *
4521fc75efeSopcode  * Uses the data computed first by GRSetCurve().
4531fc75efeSopcode  * GRSetCurve() MUST be called before this routine and have returned a ZERO.
4541fc75efeSopcode  */
GRCurve(style)4551fc75efeSopcode GRCurve(style)
4561fc75efeSopcode int style;
4571fc75efeSopcode {
4581fc75efeSopcode     float t, t2, t3, xinter, yinter;
4591fc75efeSopcode     float x1, y1, x2, y2;
4601fc75efeSopcode     register j, k;
4611fc75efeSopcode 
4621fc75efeSopcode     GRSetLineStyle(style);
4631fc75efeSopcode 
4641fc75efeSopcode     x1 = x[1];
4651fc75efeSopcode     y1 = y[1];
4661fc75efeSopcode 
4671fc75efeSopcode     /* generate the curve using the information from GRSetCurve() and
4681fc75efeSopcode        PointsPerInterval vectors between each specified knot. */
4691fc75efeSopcode 
4701fc75efeSopcode     for (j=1; j<numpoints; ++j) {
4711fc75efeSopcode 	for (k=0; k<=PointsPerInterval; ++k) {
4721fc75efeSopcode 	    t = (float) k * h[j] / (float) PointsPerInterval;
4731fc75efeSopcode 	    t2 = t * t;
4741fc75efeSopcode 	    t3 = t2 * t;
4751fc75efeSopcode 	    x2 = x[j] + t * dx[j] + t2 * d2x[j]/2.0 + t3 * d3x[j]/6.0;
4761fc75efeSopcode 	    y2 = y[j] + t * dy[j] + t2 * d2y[j]/2.0 + t3 * d3y[j]/6.0;
4771fc75efeSopcode 
4781fc75efeSopcode 	    GRVector(x1, y1, x2, y2);
4791fc75efeSopcode 
4801fc75efeSopcode 	    x1 = x2;
4811fc75efeSopcode 	    y1 = y2;
4821fc75efeSopcode 	}
4831fc75efeSopcode     }
4841fc75efeSopcode }  /* end GRCurve */
4851fc75efeSopcode 
4861fc75efeSopcode 
4871fc75efeSopcode /*
4881fc75efeSopcode  * This routine clears the Gremlin pix subwindow or current set
4891fc75efeSopcode  * pixrect image as specified in the mask.
4901fc75efeSopcode  */
GRClear(mask)4911fc75efeSopcode GRClear(mask)
4921fc75efeSopcode register mask;
4931fc75efeSopcode {
4941fc75efeSopcode     if (mask & pixmask)
4951fc75efeSopcode 	pw_writebackground(pix_pw, 0, 0, 2000, 2000, PIX_SRC);
4961fc75efeSopcode 
4971fc75efeSopcode     if (mask & csetmask)
4981fc75efeSopcode 	pr_rop(cset_pr, 0, 0, 2000, 2000, PIX_SRC, NULL, 0, 0);
4991fc75efeSopcode }  /* end GRClear */
5001fc75efeSopcode 
5011fc75efeSopcode 
5021fc75efeSopcode /*
5031fc75efeSopcode  *  Display justification of TEXT element.
5041fc75efeSopcode  */
GRDisplayJustify(elt)5051fc75efeSopcode GRDisplayJustify(elt)
5061fc75efeSopcode register ELT *elt;
5071fc75efeSopcode {
5081fc75efeSopcode     register POINT *point;
5091fc75efeSopcode     register x, y, length, ysize;
5101fc75efeSopcode 
5111fc75efeSopcode     ysize = GRGetCharYSize(elt->brushf, elt->size);
5121fc75efeSopcode     length = GRFontStrlen(elt->textpt, elt->brushf, elt->size);
5131fc75efeSopcode     point = PTNextPoint(elt->ptlist);	/* lower left corner of text */
5141fc75efeSopcode     x = dbx_to_win(point->x);
5151fc75efeSopcode     y = dby_to_win(point->y);
5161fc75efeSopcode 
5171fc75efeSopcode     switch (elt->type) {
5181fc75efeSopcode 	case TOPLEFT:
5191fc75efeSopcode 	    y -= ysize;
5201fc75efeSopcode 	    break;
5211fc75efeSopcode 	case TOPCENT:
5221fc75efeSopcode 	    y -= ysize;
5231fc75efeSopcode 	    x += (length >> 1);
5241fc75efeSopcode 	    break;
5251fc75efeSopcode 	case TOPRIGHT:
5261fc75efeSopcode 	    y -= ysize;
5271fc75efeSopcode 	    x += length;
5281fc75efeSopcode 	    break;
5291fc75efeSopcode 	case CENTLEFT:
5301fc75efeSopcode 	    y -= (ysize >> 1);
5311fc75efeSopcode 	    break;
5321fc75efeSopcode 	case CENTCENT:
5331fc75efeSopcode 	    y -= (ysize >> 1);
5341fc75efeSopcode 	    x += (length >> 1);
5351fc75efeSopcode 	    break;
5361fc75efeSopcode 	case CENTRIGHT:
5371fc75efeSopcode 	    y -= (ysize >> 1);
5381fc75efeSopcode 	    x += length;
5391fc75efeSopcode 	    break;
5401fc75efeSopcode 	case BOTLEFT:
5411fc75efeSopcode 	    break;
5421fc75efeSopcode 	case BOTCENT:
5431fc75efeSopcode 	    x += (length >> 1);
5441fc75efeSopcode 	    break;
5451fc75efeSopcode 	case BOTRIGHT:
5461fc75efeSopcode 	    x += length;
5471fc75efeSopcode 	    break;
5481fc75efeSopcode     }
5491fc75efeSopcode 
5501fc75efeSopcode     pw_write(pix_pw, x - 2, y - 2, 5, 5, PIX_SRC ^ PIX_DST, &dot_pr, 0, 0);
5511fc75efeSopcode     pr_rop(cset_pr, x - 2, y - 2, 5, 5, PIX_SRC ^ PIX_DST, &dot_pr, 0, 0);
5521fc75efeSopcode }
5531fc75efeSopcode 
5541fc75efeSopcode 
5551fc75efeSopcode /*
5561fc75efeSopcode  * This routine displays a point (layed down by the user) in the
5571fc75efeSopcode  * pix subwindow.
5581fc75efeSopcode  */
GRDisplayPoint(dbx,dby,number)5591fc75efeSopcode GRDisplayPoint(dbx, dby, number)
5601fc75efeSopcode float dbx, dby;			/* data base coordinates */
5611fc75efeSopcode register number;		/* point number */
5621fc75efeSopcode {
5631fc75efeSopcode     register x, y;
5641fc75efeSopcode     char numbuf[5];
5651fc75efeSopcode 
5661fc75efeSopcode     x = dbx_to_win(dbx);
5671fc75efeSopcode     y = dby_to_win(dby);
5681fc75efeSopcode 
5691fc75efeSopcode     if (Artmode)
5701fc75efeSopcode 	pw_write(pix_pw, x-1, y-1, 3, 3, PIX_SRC ^ PIX_DST,
5711fc75efeSopcode 				    &littlepoint_pr, 3, 2);
5721fc75efeSopcode     else {
5731fc75efeSopcode 	pw_write(pix_pw, x-3, y-3, 7, 7, PIX_SRC ^ PIX_DST,
5741fc75efeSopcode 				    &littlepoint_pr, 1, 7);
5751fc75efeSopcode 	(void) sprintf(numbuf, "%d", number+1);
5761fc75efeSopcode 	pw_text(pix_pw, x+5, y+3, PIX_SRC^PIX_DST, text_pf, numbuf);
5771fc75efeSopcode     }
5781fc75efeSopcode }  /* end GRDisplayPoint */
5791fc75efeSopcode 
5801fc75efeSopcode 
5811fc75efeSopcode /*
5821fc75efeSopcode  * This routine erases the specified point.
5831fc75efeSopcode  */
GRErasePoint(dbx,dby,number)5841fc75efeSopcode GRErasePoint(dbx, dby, number)
5851fc75efeSopcode float dbx, dby;
5861fc75efeSopcode register number;
5871fc75efeSopcode {
5881fc75efeSopcode     GRDisplayPoint(dbx, dby, number);
5891fc75efeSopcode }  /* end GRErasePoint */
5901fc75efeSopcode 
5911fc75efeSopcode 
5921fc75efeSopcode /*
5931fc75efeSopcode  * This routine clears all points in plist.
5941fc75efeSopcode  */
GRBlankPoints(plist)5951fc75efeSopcode GRBlankPoints(plist)
5961fc75efeSopcode register POINT *plist;
5971fc75efeSopcode {
5981fc75efeSopcode     register i = 0;
5991fc75efeSopcode 
6001fc75efeSopcode     while (!Nullpoint(plist)) {
6011fc75efeSopcode 	GRErasePoint(plist->x, plist->y, i++);
6021fc75efeSopcode 	plist = PTNextPoint(plist);
6031fc75efeSopcode     }
6041fc75efeSopcode }  /* end GRBlankPoints */
6051fc75efeSopcode 
6061fc75efeSopcode 
6071fc75efeSopcode /*
6081fc75efeSopcode  * This routine displays the grid.
6091fc75efeSopcode  */
GRDisplayGrid()6101fc75efeSopcode GRDisplayGrid()
6111fc75efeSopcode {
6121fc75efeSopcode     pw_replrop(pix_pw, 0, 0, 2000, 2000, PIX_SRC ^ PIX_DST,
6131fc75efeSopcode 						&replgrid32_pr, 0, 0);
6141fc75efeSopcode }  /* end GRDisplayGrid */
6151fc75efeSopcode 
6161fc75efeSopcode 
6171fc75efeSopcode /*
6181fc75efeSopcode  * This routine erases the grid.
6191fc75efeSopcode  */
GRBlankGrid()6201fc75efeSopcode GRBlankGrid()
6211fc75efeSopcode {
6221fc75efeSopcode     GRDisplayGrid();
6231fc75efeSopcode }  /* end GRBlankGrid */
6241fc75efeSopcode 
6251fc75efeSopcode 
6261fc75efeSopcode /*
6271fc75efeSopcode  * Flash current set display.
6281fc75efeSopcode  */
GRCurrentSet()6291fc75efeSopcode GRCurrentSet()
6301fc75efeSopcode {
6311fc75efeSopcode     if (DBNullelt(cset))
6321fc75efeSopcode 	return;
6331fc75efeSopcode 
6341fc75efeSopcode     pw_write(pix_pw, 0, 0, pix_size.r_width, pix_size.r_height,
6351fc75efeSopcode 	PIX_SRC ^ PIX_DST, cset_pr, 0, 0);
6361fc75efeSopcode 
6371fc75efeSopcode     CsetOn = !CsetOn;
6381fc75efeSopcode }
6391fc75efeSopcode 
6401fc75efeSopcode 
6411fc75efeSopcode /*
6421fc75efeSopcode  * Make current set on.
6431fc75efeSopcode  */
GRCurrentSetOn()6441fc75efeSopcode GRCurrentSetOn()
6451fc75efeSopcode {
6461fc75efeSopcode     if (!CsetOn)
6471fc75efeSopcode 	GRCurrentSet();
6481fc75efeSopcode }
6491fc75efeSopcode 
6501fc75efeSopcode 
6511fc75efeSopcode /*
6521fc75efeSopcode  * Make current set off.
6531fc75efeSopcode  */
GRCurrentSetOff()6541fc75efeSopcode GRCurrentSetOff()
6551fc75efeSopcode {
6561fc75efeSopcode     if (CsetOn)
6571fc75efeSopcode 	GRCurrentSet();
6581fc75efeSopcode }
6591fc75efeSopcode 
6601fc75efeSopcode 
6611fc75efeSopcode /*
6621fc75efeSopcode  * Return TRUE if font file exists and is readable.
6631fc75efeSopcode  */
GRfontfound(font,size)6641fc75efeSopcode GRfontfound(font, size)
6651fc75efeSopcode register font, size;
6661fc75efeSopcode {
6671fc75efeSopcode     return(font_info[font-1][size-1] != (char *) -1);
6681fc75efeSopcode }
6691fc75efeSopcode 
6701fc75efeSopcode 
6711fc75efeSopcode /*
6721fc75efeSopcode  * Open the default font file on startup.
6731fc75efeSopcode  */
GRFontInit()6741fc75efeSopcode GRFontInit()
6751fc75efeSopcode {
6761fc75efeSopcode     /* create memory pixrect template for displaying text with GRPutText() */
6771fc75efeSopcode     if ((char_pr = mem_create(1, 1, 1)) == NULL) {
6781fc75efeSopcode 	printf("GRFontInit: can't create char_pr\n");
6791fc75efeSopcode 	exit(1);
6801fc75efeSopcode     }
6811fc75efeSopcode 
6821fc75efeSopcode     GROpenFont(CFONT, CSIZE);
6831fc75efeSopcode     GRStippleInit();
6841fc75efeSopcode }  /* end GRFontInit */
6851fc75efeSopcode 
6861fc75efeSopcode 
6871fc75efeSopcode /*
6881fc75efeSopcode  * Initialize stipple patterns from font file.
6891fc75efeSopcode  * Big assumption: all stipples are defined by 32 x 32 bit patterns.
6901fc75efeSopcode  * All fonts do not contain exactly 32 rows of 4 bytes - this is ok -
6911fc75efeSopcode  * Fonts wider than 32 bits will be clipped.
6921fc75efeSopcode  */
GRStippleInit()6931fc75efeSopcode GRStippleInit()
6941fc75efeSopcode {
6951fc75efeSopcode     register struct mpr_data *mpr_data;
6961fc75efeSopcode     register char *from, *to;
6971fc75efeSopcode     register char *fbase;
6981fc75efeSopcode     register i, j, k;
6991fc75efeSopcode     struct dispatch *dispatch, *dstart;
7001fc75efeSopcode     int width, height, bytewidth;
7011fc75efeSopcode     char *stipple_info;
7021fc75efeSopcode     char name[128];
7031fc75efeSopcode 
7041fc75efeSopcode     (void) sprintf(name, "%s%s.0", stippledir, stippletype);
7051fc75efeSopcode 
7061fc75efeSopcode     if ((stipple_info = GRReadFontFile(name)) == (char *) -1) {
7071fc75efeSopcode 	/*
7081fc75efeSopcode 	 * use default stipple pixrects since we can't read the
7091fc75efeSopcode 	 * user specified stipple font file.
7101fc75efeSopcode 	 * copy stipple pixrects to stipple_patterns for display
7111fc75efeSopcode 	 */
7121fc75efeSopcode 	for (i=0; i<NSTIPPLES; i++)
7131fc75efeSopcode 	    GRCopyStipple(i);
7141fc75efeSopcode 
7151fc75efeSopcode 	return;
7161fc75efeSopcode     }
7171fc75efeSopcode 
7181fc75efeSopcode     dstart = (struct dispatch *) (stipple_info + sizeof(struct header));
7191fc75efeSopcode     fbase = (char *) ((char *) dstart + NUM_DISPATCH * sizeof(struct dispatch));
7201fc75efeSopcode 
7211fc75efeSopcode     for (i=0; i<NSTIPPLES; i++) {
7221fc75efeSopcode 	mpr_data = (struct mpr_data *) stipple_prs[i]->pr_data;
7231fc75efeSopcode 	dispatch = dstart + stipple_index[i];
7241fc75efeSopcode 	if (dispatch->nbytes != 0) {
7251fc75efeSopcode 	    width = dispatch->left + dispatch->right;
7261fc75efeSopcode 	    height = dispatch->up + dispatch->down;
7271fc75efeSopcode 	    bytewidth = (width + 7) >> 3;
7281fc75efeSopcode 	    if (bytewidth > 4)		/* force size constraint */
7291fc75efeSopcode 		bytewidth = 4;		/* pattern screwed up if ever > 4 */
7301fc75efeSopcode 
7311fc75efeSopcode 	    from = (char *) ((char *) fbase + dispatch->addr);
7321fc75efeSopcode 	    to = stipple_patterns[i];
7331fc75efeSopcode 
7341fc75efeSopcode 	    for (j=1; j<=height; j++) {	/* copy font entry to known location */
7351fc75efeSopcode 		for (k=1; k<=bytewidth; k++)
7361fc75efeSopcode 		    *to++ = *from++;
7371fc75efeSopcode 		for ( ;k<=4; k++)
7381fc75efeSopcode 		    *to++ = '\0';
7391fc75efeSopcode 	    }
7401fc75efeSopcode 
7411fc75efeSopcode 	    for ( ; j<=32; j++)		/* fix up any non- 32 x 32 font */
7421fc75efeSopcode 		for (k=1; k<=4; k++)
7431fc75efeSopcode 		    *to++ = '\0';
7441fc75efeSopcode 
7451fc75efeSopcode 	    /* copy vfont stipple to stipple pixrect for menu display */
7461fc75efeSopcode 	    /* can only display a 16 x 16 menu icon */
7471fc75efeSopcode 	    from = stipple_patterns[i];
7481fc75efeSopcode 	    to = (char *) mpr_data->md_image;
7491fc75efeSopcode 	    for (j=0; j<16; j++) {
7501fc75efeSopcode 		*to++ = *from++;
7511fc75efeSopcode 		*to++ = *from++;
7521fc75efeSopcode 		from += 2;
7531fc75efeSopcode 	    }
7541fc75efeSopcode 	}
7551fc75efeSopcode 	else {
7561fc75efeSopcode 	    (void) sprintf(name, "stipple index=%d not defined",
7571fc75efeSopcode 							    stipple_index[i]);
7581fc75efeSopcode 	    error(name);
7591fc75efeSopcode 
7601fc75efeSopcode 	    /* copy stipple pixrect to stipple_patterns for display */
7611fc75efeSopcode 	    GRCopyStipple(i);
7621fc75efeSopcode 	}
7631fc75efeSopcode     }
7641fc75efeSopcode 
7651fc75efeSopcode     /* bit maps are all in core now */
7661fc75efeSopcode     free(stipple_info);
767*45a94882Sopcode 
768*45a94882Sopcode     /* set up parameters for drawing polygons */
769*45a94882Sopcode     mpr_data = (struct mpr_data *) scratch_pr->pr_data;
770*45a94882Sopcode     bytesperline = mpr_data->md_linebytes;
771*45a94882Sopcode     fill = (char *) mpr_data->md_image;
772*45a94882Sopcode     rasterlength = bytesperline << 3;
773*45a94882Sopcode     nlines = scratch_pr->pr_size.x;
7741fc75efeSopcode } /* end GRStippleInit */;
7751fc75efeSopcode 
7761fc75efeSopcode 
7771fc75efeSopcode /*
7781fc75efeSopcode  * Copy the stipple bit map image as defined in the menu pixrect
7791fc75efeSopcode  * to the bit maps used for drawing polygons.  The pixrect bit map
7801fc75efeSopcode  * is 16 x 16 bits and the target bit map is 32 x 32 bits.  The
7811fc75efeSopcode  * image is expanded appropriately.
7821fc75efeSopcode  */
GRCopyStipple(index)7831fc75efeSopcode GRCopyStipple(index)
7841fc75efeSopcode int index;
7851fc75efeSopcode {
7861fc75efeSopcode     register struct mpr_data *mpr_data;
7871fc75efeSopcode     register char *from, *to;
7881fc75efeSopcode     register i, j;
7891fc75efeSopcode 
7901fc75efeSopcode     mpr_data = (struct mpr_data *) stipple_prs[index]->pr_data;
7911fc75efeSopcode     from = (char *) mpr_data->md_image;
7921fc75efeSopcode     to = stipple_patterns[index];
7931fc75efeSopcode 
7941fc75efeSopcode     for (i=0; i<16; i++) {
7951fc75efeSopcode 	j = i << 2;
7961fc75efeSopcode 	to[j]   = to[j+2] = to[j+64] = to[j+66] = *from++;
7971fc75efeSopcode 	to[j+1] = to[j+3] = to[j+65] = to[j+67] = *from++;
7981fc75efeSopcode     }
7991fc75efeSopcode }
8001fc75efeSopcode 
8011fc75efeSopcode 
8021fc75efeSopcode /*
8031fc75efeSopcode  * Open a font file for use by first reading it into memory.
8041fc75efeSopcode  * If the file is read successfully, the appropriate entry in
8051fc75efeSopcode  * font_info[] is set to point to its memory image.  If the
8061fc75efeSopcode  * file cannot be opened or there is a error in reading the
8071fc75efeSopcode  * file, set the font_info[] entry to -1.
8081fc75efeSopcode  */
GROpenFont(font,size)8091fc75efeSopcode GROpenFont(font, size)
8101fc75efeSopcode register font;		/* font is 1 to 4 */
8111fc75efeSopcode register size;		/* size is 1 to 4 */
8121fc75efeSopcode {
8131fc75efeSopcode     char name[128];
8141fc75efeSopcode 
8151fc75efeSopcode     if (font_info[--font][--size] != NULL)	/* already tried to open */
8161fc75efeSopcode 	return;
8171fc75efeSopcode 
8181fc75efeSopcode     sprintf(name, "%s%s.%d", fontdir, font_types[font], font_sizes[size]);
8191fc75efeSopcode 
8201fc75efeSopcode     if ((font_info[font][size] = GRReadFontFile(name)) == (char *) -1)
8211fc75efeSopcode 	return;
8221fc75efeSopcode 
8231fc75efeSopcode     /* height of this font/size combination */
8241fc75efeSopcode     charysizes[font][size] = ((struct header *) font_info[font][size])->maxy;
8251fc75efeSopcode }  /* end GROpenFont */
8261fc75efeSopcode 
8271fc75efeSopcode 
8281fc75efeSopcode /*
8291fc75efeSopcode  * Read a font file into memory and return a pointer to its
8301fc75efeSopcode  * memory image, or -1 if any error occurs.
8311fc75efeSopcode  */
8321fc75efeSopcode char *
GRReadFontFile(file)8331fc75efeSopcode GRReadFontFile(file)
8341fc75efeSopcode char *file;
8351fc75efeSopcode {
8361fc75efeSopcode     char *image;			/* pointer to font memory image */
8371fc75efeSopcode     char msg[128];
8381fc75efeSopcode     struct header header;
8391fc75efeSopcode     int fd, filesize;
8401fc75efeSopcode 
8411fc75efeSopcode     if ((fd = open(file, 0)) < 0) {
8421fc75efeSopcode 	sprintf(msg, "can't open font file: %s", file);
8431fc75efeSopcode 	error(msg);
8441fc75efeSopcode 	return((char *) -1);
8451fc75efeSopcode     }
8461fc75efeSopcode 
8471fc75efeSopcode     if (read(fd, &header, sizeof(struct header)) != sizeof(struct header)) {
8481fc75efeSopcode 	sprintf(msg, "can't read font header: %s\n", file);
8491fc75efeSopcode 	error(msg);
8501fc75efeSopcode 	return((char *) -1);
8511fc75efeSopcode     }
8521fc75efeSopcode 
8531fc75efeSopcode     if (header.magic != VFONT_MAGIC) {
8541fc75efeSopcode 	sprintf(msg, "bad magic number %o in font file\n", header.magic);
8551fc75efeSopcode 	error(msg);
8561fc75efeSopcode 	return((char *) -1);
8571fc75efeSopcode     }
8581fc75efeSopcode 
8591fc75efeSopcode     filesize = (sizeof(struct header) +
8601fc75efeSopcode 		sizeof(struct dispatch) * NUM_DISPATCH + header.size);
8611fc75efeSopcode 
8621fc75efeSopcode     if ((image = malloc(filesize)) == NULL) {
8631fc75efeSopcode 	error("not enough memory for font file");
8641fc75efeSopcode 	return((char *) -1);
8651fc75efeSopcode     }
8661fc75efeSopcode 
8671fc75efeSopcode     lseek(fd, (long) 0, 0);
8681fc75efeSopcode 
8691fc75efeSopcode     if (read(fd, image, filesize) != filesize) {
8701fc75efeSopcode 	error("can't read font file");
8711fc75efeSopcode 	return((char *) -1);
8721fc75efeSopcode     }
8731fc75efeSopcode 
8741fc75efeSopcode     close(fd);
8751fc75efeSopcode     return(image);
8761fc75efeSopcode }  /* end GRReadFontFile */
8771fc75efeSopcode 
8781fc75efeSopcode 
8791fc75efeSopcode /*
8801fc75efeSopcode  * Determine pixel length of string s in font and size.
8811fc75efeSopcode  */
GRFontStrlen(text,font,size)8821fc75efeSopcode GRFontStrlen(text, font, size)
8831fc75efeSopcode char *text;
8841fc75efeSopcode int font;		/* 1 - 4 */
8851fc75efeSopcode int size;		/* 1 - 4 */
8861fc75efeSopcode {
8871fc75efeSopcode     register struct dispatch *dispatch, *start;
8881fc75efeSopcode     register length, spacewidth;
8891fc75efeSopcode 
8901fc75efeSopcode     if (*text == '\0')
8911fc75efeSopcode 	return(0);
8921fc75efeSopcode 
8931fc75efeSopcode     if (font_info[font-1][size-1] == NULL)	/* not open yet */
8941fc75efeSopcode 	GROpenFont(font, size);
8951fc75efeSopcode 
8961fc75efeSopcode     if (!GRfontfound(font, size))		/* unreadable font */
8971fc75efeSopcode 	return(0);
8981fc75efeSopcode 
8991fc75efeSopcode     start = (struct dispatch *) (font_info[font-1][size-1] +
9001fc75efeSopcode 						sizeof(struct header));
9011fc75efeSopcode     spacewidth = font_sizes[size-1] * (120.0 / 216.0) + 0.5;
9021fc75efeSopcode     length = 0;
9031fc75efeSopcode     while (*text != '\0') {
9041fc75efeSopcode 	dispatch = start + (*text);
9051fc75efeSopcode 
9061fc75efeSopcode 	if (*text == ' ')
9071fc75efeSopcode 	    length += spacewidth;
9081fc75efeSopcode 	else if (dispatch->nbytes != 0)
9091fc75efeSopcode 	    length += dispatch->width;
9101fc75efeSopcode 
9111fc75efeSopcode 	text++;
9121fc75efeSopcode     }
9131fc75efeSopcode 
9141fc75efeSopcode     return(length);
9151fc75efeSopcode }
9161fc75efeSopcode 
9171fc75efeSopcode /*
9181fc75efeSopcode  * Display text string of font/size at position pos.
9191fc75efeSopcode  */
GRPutText(text,font,size,pos)9201fc75efeSopcode GRPutText(text, font, size, pos)
9211fc75efeSopcode char *text;
9221fc75efeSopcode int font, size;
9231fc75efeSopcode POINT *pos;
9241fc75efeSopcode {
9251fc75efeSopcode     register struct dispatch *dispatch, *dstart;
9261fc75efeSopcode     register struct mpr_data *mpr_data;
9271fc75efeSopcode     register char *fbase;
9281fc75efeSopcode     register width, height, spacewidth;
9291fc75efeSopcode     int x, y;
9301fc75efeSopcode 
9311fc75efeSopcode     if (font_info[font-1][size-1] == NULL)
9321fc75efeSopcode 	GROpenFont(font, size);
9331fc75efeSopcode 
9341fc75efeSopcode     if (!GRfontfound(font, size))
9351fc75efeSopcode 	return;
9361fc75efeSopcode 
9371fc75efeSopcode     dstart = (struct dispatch *) (font_info[font-1][size-1] +
9381fc75efeSopcode 						    sizeof(struct header));
9391fc75efeSopcode     fbase = (char *) ((char *) dstart + NUM_DISPATCH * sizeof(struct dispatch));
9401fc75efeSopcode 
9411fc75efeSopcode     x = dbx_to_win(pos->x);
9421fc75efeSopcode     y = dby_to_win(pos->y);
9431fc75efeSopcode 
9441fc75efeSopcode     /* define region of screen to be drawn with text */
9451fc75efeSopcode     minsunx = x;
9461fc75efeSopcode     maxsuny = y + 8;	/* catch descenders */
9471fc75efeSopcode     minsuny = y - GRGetCharYSize(font, size);
9481fc75efeSopcode 
9491fc75efeSopcode     spacewidth = font_sizes[size-1] * (120.0 / 216.0) + 0.5;
9501fc75efeSopcode     mpr_data = (struct mpr_data *) char_pr->pr_data;
9511fc75efeSopcode     while (*text != '\0') {
9521fc75efeSopcode 	dispatch = dstart + (*text);
9531fc75efeSopcode 
9541fc75efeSopcode 	if (*text == ' ')
9551fc75efeSopcode 	    x += spacewidth;
9561fc75efeSopcode 	else if (dispatch->nbytes != 0) {
9571fc75efeSopcode 	    mpr_data->md_image = (short *) ((char *) fbase + dispatch->addr);
9581fc75efeSopcode 	    char_pr->pr_size.x = width = dispatch->left + dispatch->right;
9591fc75efeSopcode 	    char_pr->pr_size.y = height = dispatch->up + dispatch->down;
9601fc75efeSopcode 	    mpr_data->md_linebytes = ((width + 15) >> 3) & ~1;
9611fc75efeSopcode 
9621fc75efeSopcode 	    if (*text != ' ')
9631fc75efeSopcode 		pr_rop(scratch_pr, x - dispatch->left, y - dispatch->up,
9641fc75efeSopcode 			    width, height, PIX_SRC ^ PIX_DST, char_pr, 0, 0);
9651fc75efeSopcode 	    x += dispatch->width;
9661fc75efeSopcode 	}
9671fc75efeSopcode 
9681fc75efeSopcode 	text++;
9691fc75efeSopcode     }
9701fc75efeSopcode 
9711fc75efeSopcode     maxsunx = x;
9721fc75efeSopcode } /* end GRPutText */;
9731fc75efeSopcode 
9741fc75efeSopcode 
9751fc75efeSopcode /*
9761fc75efeSopcode  * Set the actual positioning point for text with the justify, font, and
9771fc75efeSopcode  * size attributes.  Point is a pointer to the POINT layed down by the user.
9781fc75efeSopcode  * Pos is a pointer to the returned positioning POINT used in a subsequent
9791fc75efeSopcode  * call to GRPutText().
9801fc75efeSopcode  */
GRSetTextPos(text,justify,font,size,point,pos)9811fc75efeSopcode GRSetTextPos(text, justify, font, size, point, pos)
9821fc75efeSopcode char *text;
9831fc75efeSopcode int justify, font, size;
9841fc75efeSopcode POINT *point, *pos;
9851fc75efeSopcode {
9861fc75efeSopcode     register length;
9871fc75efeSopcode     register charysize;
9881fc75efeSopcode 
9891fc75efeSopcode     charysize = GRGetCharYSize(font, size);
9901fc75efeSopcode     length = GRFontStrlen(text, font, size);
9911fc75efeSopcode 
9921fc75efeSopcode     switch (justify) {
9931fc75efeSopcode 	case BOTLEFT:
9941fc75efeSopcode 	    pos->x = point->x;
9951fc75efeSopcode 	    pos->y = point->y;
9961fc75efeSopcode 	    break;
9971fc75efeSopcode 	case BOTCENT:
9981fc75efeSopcode 	    pos->x = point->x - (length / 2);
9991fc75efeSopcode 	    pos->y = point->y;
10001fc75efeSopcode 	    break;
10011fc75efeSopcode 	case BOTRIGHT:
10021fc75efeSopcode 	    pos->x = point->x - length;
10031fc75efeSopcode 	    pos->y = point->y;
10041fc75efeSopcode 	    break;
10051fc75efeSopcode 	case CENTLEFT:
10061fc75efeSopcode 	    pos->x = point->x;
10071fc75efeSopcode 	    pos->y = point->y - (charysize / 2);
10081fc75efeSopcode 	    break;
10091fc75efeSopcode 	case CENTCENT:
10101fc75efeSopcode 	    pos->x = point->x - (length / 2);
10111fc75efeSopcode 	    pos->y = point->y - (charysize / 2);
10121fc75efeSopcode 	    break;
10131fc75efeSopcode 	case CENTRIGHT:
10141fc75efeSopcode 	    pos->x = point->x - length;
10151fc75efeSopcode 	    pos->y = point->y - (charysize / 2);
10161fc75efeSopcode 	    break;
10171fc75efeSopcode 	case TOPLEFT:
10181fc75efeSopcode 	    pos->x = point->x;
10191fc75efeSopcode 	    pos->y = point->y - charysize;
10201fc75efeSopcode 	    break;
10211fc75efeSopcode 	case TOPCENT:
10221fc75efeSopcode 	    pos->x = point->x - (length / 2);
10231fc75efeSopcode 	    pos->y = point->y - charysize;
10241fc75efeSopcode 	    break;
10251fc75efeSopcode 	case TOPRIGHT:
10261fc75efeSopcode 	    pos->x = point->x - length;
10271fc75efeSopcode 	    pos->y = point->y - charysize;
10281fc75efeSopcode 	    break;
10291fc75efeSopcode     }
10301fc75efeSopcode }
1031