117280Sopcode /*
2*17644Sopcode  * @(#)graphics.c	1.2	01/03/85
317280Sopcode  *
417280Sopcode  * Graphics routines for the SUN Gremlin picture editor.
517280Sopcode  *
617280Sopcode  * Mark Opperman (opcode@monet.BERKELEY)
717280Sopcode  *
817280Sopcode  */
917280Sopcode 
1017280Sopcode #include <suntool/tool_hs.h>
1117280Sopcode #include <vfont.h>
1217280Sopcode #include "icondata.h"
1317280Sopcode #include "gremlin.h"
1417280Sopcode 
1517280Sopcode /* imports from main.c */
1617280Sopcode 
1717280Sopcode extern error();
1817280Sopcode extern struct pixwin *pix_pw;
1917280Sopcode extern struct rect pix_size;
2017280Sopcode extern struct pixrect *cset_pr;
2117280Sopcode extern struct pixrect *scratch_pr;
2217280Sopcode extern ELT *cset;
2317280Sopcode extern Artmode;
2417280Sopcode extern CSIZE;
2517280Sopcode extern CFONT;
2617280Sopcode extern CsetOn;
2717280Sopcode extern SUN_XORIGIN;
2817280Sopcode extern SUN_YORIGIN;
2917280Sopcode 
3017280Sopcode /* imports from display.c */
3117280Sopcode 
3217280Sopcode extern minsunx, maxsunx, minsuny, maxsuny;
3317280Sopcode 
3417280Sopcode /* imports from C */
3517280Sopcode 
3617280Sopcode extern char *malloc();
3717280Sopcode 
3817280Sopcode /* forward references */
3917280Sopcode 
4017280Sopcode extern char *GRReadFontFile();
4117280Sopcode 
4217280Sopcode /* symbolic font from text.c */
4317280Sopcode 
4417280Sopcode extern struct pixfont *text_pf;
4517280Sopcode 
4617280Sopcode /* locally defined variables */
4717280Sopcode 
4817280Sopcode int charysizes[NFONTS][NSIZES];	/* Character y dimensions for each size */
4917280Sopcode int curve_set;			/* TRUE if spline points pre-computed */
5017280Sopcode 
5117280Sopcode int linestyle;			/* Current line style */
5217280Sopcode int linemod;			/* Type of line (SOLID, DOTTED, ...) */
5317280Sopcode int linethickness;		/* 1, 2, 3 */
5417280Sopcode 
5517280Sopcode char fontdir[128] = "/usr/lib/font/devsun/";
5617280Sopcode char stippledir[128] = "/usr/lib/font/devsun/";
5717280Sopcode char stippletype[32] = "cf";
5817280Sopcode 
5917280Sopcode char *font_types[NFONTS] = { "R", "I", "B", "S" };
6017280Sopcode int font_sizes[NSIZES] = { 7, 10, 14, 24 };
6117280Sopcode int stipple_index[NSTIPPLES] = { 1, 3, 12, 14, 16, 19, 21, 23 };
6217280Sopcode 
6317280Sopcode /* NOTE: all stipple fonts are expected to be 32 x 32 bit rasters */
6417280Sopcode 
6517280Sopcode /* pointers to the stipple pixrects (16 x 16 bits) in the menu ... */
6617280Sopcode struct pixrect *stipple_prs[NSTIPPLES] = {
6717280Sopcode     &stipple1_pr, &stipple2_pr, &stipple3_pr, &stipple4_pr,
6817280Sopcode     &stipple5_pr, &stipple6_pr, &stipple7_pr, &stipple8_pr
6917280Sopcode };
7017280Sopcode 
7117280Sopcode /* ... and the corresponding images (32 x 32 bits) from the vfont file */
7217280Sopcode char stipple_patterns[NSTIPPLES][128];
7317280Sopcode 
74*17644Sopcode /* data used in graphics2.c for drawing polygons */
75*17644Sopcode int rasterlength;		/* real # horizontal bits in scratch_pr */
76*17644Sopcode int bytesperline;		/* rasterlength / 8 */
77*17644Sopcode int nlines;			/* # horizontal bits defined by scratch_pr */
78*17644Sopcode char *fill;			/* pointer to scratch_pr image */
79*17644Sopcode 
8017280Sopcode /*
8117280Sopcode  *  This matrix points to the DISPATCH data for each font/size pair
8217280Sopcode  *  if an unsuccesful attempt is made to open a particular font/size pair,
8317280Sopcode  *  its entry in this table is marked as -1.
8417280Sopcode  */
8517280Sopcode char *font_info[NFONTS][NSIZES] = {
8617280Sopcode     { NULL, NULL, NULL, NULL },
8717280Sopcode     { NULL, NULL, NULL, NULL },
8817280Sopcode     { NULL, NULL, NULL, NULL },
8917280Sopcode     { NULL, NULL, NULL, NULL },
9017280Sopcode };
9117280Sopcode struct pixrect *char_pr;
9217280Sopcode 
9317280Sopcode /* Splines use these global arrays */
9417280Sopcode 
9517280Sopcode static float h[MAXPOINTS];
9617280Sopcode static float x[MAXPOINTS], dx[MAXPOINTS], d2x[MAXPOINTS], d3x[MAXPOINTS];
9717280Sopcode static float y[MAXPOINTS], dy[MAXPOINTS], d2y[MAXPOINTS], d3y[MAXPOINTS];
9817280Sopcode static numpoints;
9917280Sopcode 
10017280Sopcode /* These are used as bit masks to create the right style lines. */
10117280Sopcode #define SOLID -1
10217280Sopcode #define DOTTED 002
10317280Sopcode #define DASHED 004
10417280Sopcode #define DOTDASHED 012
10517280Sopcode 
10617280Sopcode 
10717280Sopcode /*
10817280Sopcode  * This routine sets the current line style.
10917280Sopcode  */
GRSetLineStyle(style)11017280Sopcode GRSetLineStyle(style)
11117280Sopcode int style;			/* new stipple pattern for lines */
11217280Sopcode {
11317280Sopcode     switch (linestyle = style) {
11417280Sopcode 	case 1:			/* dotted */
11517280Sopcode 	    linemod = DOTTED;
11617280Sopcode 	    linethickness = 1;
11717280Sopcode 	    break;
11817280Sopcode 	case 2:			/* broken */
11917280Sopcode 	    linemod = DOTDASHED;
12017280Sopcode 	    linethickness = 1;
12117280Sopcode 	    break;
12217280Sopcode 	case 3:			/* thick */
12317280Sopcode 	    linemod = SOLID;
12417280Sopcode 	    linethickness = 3;
12517280Sopcode 	    break;
12617280Sopcode 	case 4:			/* dashed */
12717280Sopcode 	    linemod = DASHED;
12817280Sopcode 	    linethickness = 1;
12917280Sopcode 	    break;
13017280Sopcode 	case 5:			/* narrow */
13117280Sopcode 	    linemod = SOLID;
13217280Sopcode 	    linethickness = 1;
13317280Sopcode 	    break;
13417280Sopcode 	case 6:			/* medium */
13517280Sopcode 	    linemod = SOLID;
13617280Sopcode 	    linethickness = 2;
13717280Sopcode 	    break;
13817280Sopcode     }
13917280Sopcode }
14017280Sopcode 
14117280Sopcode 
14217280Sopcode /*
14317280Sopcode  * This routine returns the maximum vertical size (in bits) of a character
14417280Sopcode  * of the specified font/size.
14517280Sopcode  */
GRGetCharYSize(font,size)14617280Sopcode GRGetCharYSize(font, size)
14717280Sopcode register font;			/* character font (1 - 4) */
14817280Sopcode register size;			/* character size (1 - 4) */
14917280Sopcode {
15017280Sopcode     return(charysizes[--font][--size]);
15117280Sopcode }
15217280Sopcode 
15317280Sopcode 
15417280Sopcode #define pi 3.14159265359
15517280Sopcode #define twopi 6.28318530718
15617280Sopcode #define log2_10 3.321915
15717280Sopcode 
15817280Sopcode 
15917280Sopcode /*
16017280Sopcode  * Draw arc - always to scratch_pr.
16117280Sopcode  * Note: must check for zero radius before calling.
16217280Sopcode  */
GRArc(center,cpoint,angle,style)16317280Sopcode GRArc(center, cpoint, angle, style)
16417280Sopcode register POINT *center, *cpoint;
16517280Sopcode float angle;
16617280Sopcode register style;
16717280Sopcode {
16817280Sopcode     double radius, resolution, t1, fullcircle;
16917280Sopcode     double degreesperpoint;
17017280Sopcode     float xs, ys, epsilon;
17117280Sopcode     float x1, y1, x2, y2;
17217280Sopcode     register i, extent;
17317280Sopcode 
17417280Sopcode     xs = cpoint->x - center->x;
17517280Sopcode     ys = cpoint->y - center->y;
17617280Sopcode 
17717280Sopcode     /* calculate drawing parameters */
17817280Sopcode 
17917280Sopcode     radius = sqrt((double) (xs * xs + ys * ys));
18017280Sopcode     t1 = floor(log10(radius) * log2_10);
18117280Sopcode     resolution = pow(2.0, t1);
18217280Sopcode     epsilon = (float) 1.0 / resolution;
18317280Sopcode     fullcircle = ceil(twopi * resolution);
18417280Sopcode     degreesperpoint = 360.0 / fullcircle;
18517280Sopcode 
18617280Sopcode     extent = (angle == 0) ? fullcircle : angle/degreesperpoint;
18717280Sopcode 
18817280Sopcode     GRSetLineStyle(style);
18917280Sopcode 
19017280Sopcode     x1 = cpoint->x;
19117280Sopcode     y1 = cpoint->y;
19217280Sopcode 
19317280Sopcode     for (i=0; i<extent; ++i) {
19417280Sopcode 	xs -= epsilon * ys;
19517280Sopcode 	x2 = xs + center->x;
19617280Sopcode 	ys += epsilon * xs;
19717280Sopcode 	y2 = ys + center->y;
19817280Sopcode 
19917280Sopcode 	GRVector(x1, y1, x2, y2);
20017280Sopcode 
20117280Sopcode 	x1 = x2;
20217280Sopcode 	y1 = y2;
20317280Sopcode     }
20417280Sopcode }  /* end GRArc */;
20517280Sopcode 
20617280Sopcode 
20717280Sopcode /* This routine calculates parameteric values for use in calculating
20817280Sopcode  * curves.  The values are an approximation of cumulative arc lengths
20917280Sopcode  * of the curve (uses cord * length).  For additional information,
21017280Sopcode  * see paper cited below.
21117280Sopcode  */
21217280Sopcode static
Paramaterize(x,y,h,n)21317280Sopcode Paramaterize(x, y, h, n)
21417280Sopcode float x[MAXPOINTS];
21517280Sopcode float y[MAXPOINTS];
21617280Sopcode float h[MAXPOINTS];
21717280Sopcode register n;
21817280Sopcode {
21917280Sopcode     register i, j;
22017280Sopcode     float t1, t2;
22117280Sopcode     float u[MAXPOINTS];
22217280Sopcode 
22317280Sopcode     n = numpoints;
22417280Sopcode 
22517280Sopcode     for (i=1; i<=n; ++i) {
22617280Sopcode 	u[i] = 0.0;
22717280Sopcode 	for (j=1; j<i; ++j) {
22817280Sopcode 	    t1 = x[j+1] - x[j];
22917280Sopcode 	    t2 = y[j+1] - y[j];
23017280Sopcode 	    u[i] += (float) sqrt((double) ((t1 * t1) + (t2 * t2)));
23117280Sopcode 	}
23217280Sopcode     }
23317280Sopcode 
23417280Sopcode     for (i=1; i<n; ++i)
23517280Sopcode 	h[i] = u[i+1] - u[i];
23617280Sopcode }  /* end Paramaterize */
23717280Sopcode 
23817280Sopcode 
23917280Sopcode /*
24017280Sopcode  * This routine solves for the cubic polynomial to fit a spline
24117280Sopcode  * curve to the the points  specified by the list of values.
24217280Sopcode  * The curve generated is periodic.  The alogrithms for this
24317280Sopcode  * curve are from the "Spline Curve Techniques" paper cited below.
24417280Sopcode  */
24517280Sopcode static
PeriodicSpline(h,z,dz,d2z,d3z,npoints)24617280Sopcode PeriodicSpline(h, z, dz, d2z, d3z, npoints)
24717280Sopcode float h[MAXPOINTS];		/* paramaterization */
24817280Sopcode float z[MAXPOINTS];		/* point list */
24917280Sopcode float dz[MAXPOINTS];		/* to return the 1st derivative */
25017280Sopcode float d2z[MAXPOINTS];		/* 2nd derivative */
25117280Sopcode float d3z[MAXPOINTS];		/* and 3rd derivative */
25217280Sopcode register npoints;		/* number of valid points */
25317280Sopcode {
25417280Sopcode     float a[MAXPOINTS];
25517280Sopcode     float b[MAXPOINTS];
25617280Sopcode     float c[MAXPOINTS];
25717280Sopcode     float d[MAXPOINTS];
25817280Sopcode     float deltaz[MAXPOINTS];
25917280Sopcode     float r[MAXPOINTS];
26017280Sopcode     float s[MAXPOINTS];
26117280Sopcode     float ftmp;
26217280Sopcode     register i;
26317280Sopcode 
26417280Sopcode     /* step 1 */
26517280Sopcode     for (i=1; i<npoints; ++i) {
26617280Sopcode 	if (h[i] != 0)
26717280Sopcode 	    deltaz[i] = (z[i+1] - z[i]) / h[i];
26817280Sopcode 	else
26917280Sopcode 	    deltaz[i] = 0;
27017280Sopcode     }
27117280Sopcode     h[0] = h[npoints-1];
27217280Sopcode     deltaz[0] = deltaz[npoints-1];
27317280Sopcode 
27417280Sopcode     /* step 2 */
27517280Sopcode     for (i=1; i<npoints-1; ++i) {
27617280Sopcode 	d[i] = deltaz[i+1] - deltaz[i];
27717280Sopcode     }
27817280Sopcode     d[0] = deltaz[1] - deltaz[0];
27917280Sopcode 
28017280Sopcode     /* step 3a */
28117280Sopcode     a[1] = 2 * (h[0] + h[1]);
28217280Sopcode     if (a[1] == 0)
28317280Sopcode 	return(-1);  /* 3 consecutive knots at same point */
28417280Sopcode     b[1] = d[0];
28517280Sopcode     c[1] = h[0];
28617280Sopcode 
28717280Sopcode     for (i=2; i<npoints-1; ++i) {
28817280Sopcode 	ftmp = h[i-1];
28917280Sopcode 	a[i] = ftmp + ftmp + h[i] + h[i] - (ftmp * ftmp)/a[i-1];
29017280Sopcode 	    if (a[i] == 0)
29117280Sopcode 		return(-1);  /* 3 consec knots at same point */
29217280Sopcode 	b[i] = d[i-1] - ftmp * b[i-1]/a[i-1];
29317280Sopcode 	c[i] = -ftmp * c[i-1]/a[i-1];
29417280Sopcode     }
29517280Sopcode 
29617280Sopcode     /* step 3b */
29717280Sopcode     r[npoints-1] = 1;
29817280Sopcode     s[npoints-1] = 0;
29917280Sopcode     for (i=npoints-2; i>0; --i) {
30017280Sopcode 	r[i] = -(h[i] * r[i+1] + c[i])/a[i];
30117280Sopcode 	s[i] = (6 * b[i] - h[i] * s[i+1])/a[i];
30217280Sopcode     }
30317280Sopcode 
30417280Sopcode     /* step 4 */
30517280Sopcode     d2z[npoints-1] = (6 * d[npoints-2] - h[0] * s[1]
30617280Sopcode 		       - h[npoints-1] * s[npoints-2])
30717280Sopcode 		     / (h[0] * r[1] + h[npoints-1] * r[npoints-2]
30817280Sopcode 			+ 2 * (h[npoints-2] + h[0]));
30917280Sopcode     for (i=1; i<npoints-1; ++i) {
31017280Sopcode 	d2z[i] = r[i] * d2z[npoints-1] + s[i];
31117280Sopcode     }
31217280Sopcode     d2z[npoints] = d2z[1];
31317280Sopcode 
31417280Sopcode     /* step 5 */
31517280Sopcode     for (i=1; i<npoints; ++i) {
31617280Sopcode 	dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
31717280Sopcode 	if (h[i] != 0)
31817280Sopcode 	    d3z[i] = (d2z[i+1] - d2z[i])/h[i];
31917280Sopcode 	else
32017280Sopcode 	    d3z[i] = 0;
32117280Sopcode     }
32217280Sopcode 
32317280Sopcode     return(0);
32417280Sopcode }  /* end PeriodicSpline */
32517280Sopcode 
32617280Sopcode 
32717280Sopcode /*
32817280Sopcode  * This routine solves for the cubic polynomial to fit a spline
32917280Sopcode  * curve from the points specified by the list of values.  The alogrithms for
33017280Sopcode  * this curve are from the "Spline Curve Techniques" paper cited below.
33117280Sopcode  */
33217280Sopcode static
NaturalEndSpline(h,z,dz,d2z,d3z,npoints)33317280Sopcode NaturalEndSpline(h, z, dz, d2z, d3z, npoints)
33417280Sopcode float h[MAXPOINTS];		/* paramaterization */
33517280Sopcode float z[MAXPOINTS];		/* point list */
33617280Sopcode float dz[MAXPOINTS];		/* to return the 1st derivative */
33717280Sopcode float d2z[MAXPOINTS];		/* 2nd derivative */
33817280Sopcode float d3z[MAXPOINTS];		/* and 3rd derivative */
33917280Sopcode register npoints;		/* number of valid points */
34017280Sopcode {
34117280Sopcode     float a[MAXPOINTS];
34217280Sopcode     float b[MAXPOINTS];
34317280Sopcode     float d[MAXPOINTS];
34417280Sopcode     float deltaz[MAXPOINTS];
34517280Sopcode     float ftmp;
34617280Sopcode     register i;
34717280Sopcode 
34817280Sopcode     /* step 1 */
34917280Sopcode     for (i=1; i<npoints; ++i) {
35017280Sopcode 	if (h[i] != 0)
35117280Sopcode 	    deltaz[i] = (z[i+1] - z[i]) / h[i];
35217280Sopcode 	else
35317280Sopcode 	    deltaz[i] = 0;
35417280Sopcode     }
35517280Sopcode     deltaz[0] = deltaz[npoints-1];
35617280Sopcode 
35717280Sopcode     /* step 2 */
35817280Sopcode     for (i=1; i<npoints-1; ++i) {
35917280Sopcode 	d[i] = deltaz[i+1] - deltaz[i];
36017280Sopcode     }
36117280Sopcode     d[0] = deltaz[1] - deltaz[0];
36217280Sopcode 
36317280Sopcode     /* step 3 */
36417280Sopcode     a[0] = 2 * (h[2] + h[1]);
36517280Sopcode     if (a[0] == 0)		/* 3 consec knots at same point */
36617280Sopcode 	return(-1);
36717280Sopcode     b[0] = d[1];
36817280Sopcode 
36917280Sopcode     for (i=1; i<npoints-2; ++i) {
37017280Sopcode 	ftmp = h[i+1];
37117280Sopcode 	a[i] = ftmp + ftmp + h[i+2] + h[i+2] - (ftmp * ftmp) / a[i-1];
37217280Sopcode 	if (a[i] == 0)		/* 3 consec knots at same point */
37317280Sopcode 	    return(-1);
37417280Sopcode 	b[i] = d[i+1] - ftmp * b[i-1]/a[i-1];
37517280Sopcode     }
37617280Sopcode 
37717280Sopcode     /* step 4 */
37817280Sopcode     d2z[npoints] = d2z[1] = 0;
37917280Sopcode     for (i=npoints-1; i>1; --i) {
38017280Sopcode 	d2z[i] = (6 * b[i-2] - h[i] *d2z[i+1])/a[i-2];
38117280Sopcode     }
38217280Sopcode 
38317280Sopcode     /* step 5 */
38417280Sopcode     for (i=1; i<npoints; ++i) {
38517280Sopcode 	dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
38617280Sopcode 	if (h[i] != 0)
38717280Sopcode 	    d3z[i] = (d2z[i+1] - d2z[i])/h[i];
38817280Sopcode 	else
38917280Sopcode 	    d3z[i] = 0;
39017280Sopcode     }
39117280Sopcode 
39217280Sopcode     return(0);
39317280Sopcode }  /* end NaturalEndSpline */
39417280Sopcode 
39517280Sopcode 
39617280Sopcode #define PointsPerInterval 16
39717280Sopcode 
39817280Sopcode 
39917280Sopcode /*
40017280Sopcode  * This routine computes a smooth curve through a set of points.
40117280Sopcode  * Returns -1 if there are too many knots to draw the curve.
40217280Sopcode  * Use GRCurve AFTER this routine to actually draw the curve.
40317280Sopcode  * [Formerly the first half of GRCurve()]
40417280Sopcode  *
40517280Sopcode  * The method used is the parametric spline curve on unit knot mesh described
40617280Sopcode  * in "Spline Curve Techniques" by Patrick Baudelaire, Robert Flegal, and
40717280Sopcode  * Robert Sproull -- Xerox Parc.
40817280Sopcode  */
GRSetCurve(pointlist)40917280Sopcode GRSetCurve(pointlist)
41017280Sopcode POINT *pointlist;
41117280Sopcode {
41217280Sopcode     register POINT *ptr;
41317280Sopcode     register i, stat;
41417280Sopcode 
41517280Sopcode     /* Copy point list to array for easier access */
41617280Sopcode     ptr = pointlist;
41717280Sopcode     for (i=1; (!Nullpoint(ptr)); ++i) {
41817280Sopcode 	x[i] = ptr->x;
41917280Sopcode 	y[i] = ptr->y;
42017280Sopcode 	ptr = PTNextPoint(ptr);
42117280Sopcode     }
42217280Sopcode 
42317280Sopcode     /* Solve for derivatives of the curve at each point
42417280Sopcode        separately for x and y (parametric). */
42517280Sopcode 
42617280Sopcode     numpoints = i - 1;		/* set global numpoints */
42717280Sopcode 
42817280Sopcode     Paramaterize(x, y, h, numpoints);
42917280Sopcode 
43017280Sopcode     stat = 0;
43117280Sopcode     if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) { /* closed curve */
43217280Sopcode 	stat |= PeriodicSpline(h, x, dx, d2x, d3x, numpoints);
43317280Sopcode 	stat |= PeriodicSpline(h, y, dy, d2y, d3y, numpoints);
43417280Sopcode     }
43517280Sopcode     else {
43617280Sopcode 	stat |= NaturalEndSpline(h, x, dx, d2x, d3x, numpoints);
43717280Sopcode 	stat |= NaturalEndSpline(h, y, dy, d2y, d3y, numpoints);
43817280Sopcode     }
43917280Sopcode 
44017280Sopcode     curve_set = 1;		/* indicates that paramterization is done */
44117280Sopcode     return(stat);
44217280Sopcode }
44317280Sopcode 
44417280Sopcode 
44517280Sopcode /*
44617280Sopcode  * This routine displays a smooth curve through a set of points.  The
44717280Sopcode  * method used is the parametric spline curve on unit knot mesh described
44817280Sopcode  * in "Spline Curve Techniques" by Patrick Baudelaire, Robert Flegal, and
44917280Sopcode  * Robert Sproull -- Xerox Parc.
45017280Sopcode  * [formerly the second half of GRCurve()]
45117280Sopcode  *
45217280Sopcode  * Uses the data computed first by GRSetCurve().
45317280Sopcode  * GRSetCurve() MUST be called before this routine and have returned a ZERO.
45417280Sopcode  */
GRCurve(style)45517280Sopcode GRCurve(style)
45617280Sopcode int style;
45717280Sopcode {
45817280Sopcode     float t, t2, t3, xinter, yinter;
45917280Sopcode     float x1, y1, x2, y2;
46017280Sopcode     register j, k;
46117280Sopcode 
46217280Sopcode     GRSetLineStyle(style);
46317280Sopcode 
46417280Sopcode     x1 = x[1];
46517280Sopcode     y1 = y[1];
46617280Sopcode 
46717280Sopcode     /* generate the curve using the information from GRSetCurve() and
46817280Sopcode        PointsPerInterval vectors between each specified knot. */
46917280Sopcode 
47017280Sopcode     for (j=1; j<numpoints; ++j) {
47117280Sopcode 	for (k=0; k<=PointsPerInterval; ++k) {
47217280Sopcode 	    t = (float) k * h[j] / (float) PointsPerInterval;
47317280Sopcode 	    t2 = t * t;
47417280Sopcode 	    t3 = t2 * t;
47517280Sopcode 	    x2 = x[j] + t * dx[j] + t2 * d2x[j]/2.0 + t3 * d3x[j]/6.0;
47617280Sopcode 	    y2 = y[j] + t * dy[j] + t2 * d2y[j]/2.0 + t3 * d3y[j]/6.0;
47717280Sopcode 
47817280Sopcode 	    GRVector(x1, y1, x2, y2);
47917280Sopcode 
48017280Sopcode 	    x1 = x2;
48117280Sopcode 	    y1 = y2;
48217280Sopcode 	}
48317280Sopcode     }
48417280Sopcode }  /* end GRCurve */
48517280Sopcode 
48617280Sopcode 
48717280Sopcode /*
48817280Sopcode  * This routine clears the Gremlin pix subwindow or current set
48917280Sopcode  * pixrect image as specified in the mask.
49017280Sopcode  */
GRClear(mask)49117280Sopcode GRClear(mask)
49217280Sopcode register mask;
49317280Sopcode {
49417280Sopcode     if (mask & pixmask)
49517280Sopcode 	pw_writebackground(pix_pw, 0, 0, 2000, 2000, PIX_SRC);
49617280Sopcode 
49717280Sopcode     if (mask & csetmask)
49817280Sopcode 	pr_rop(cset_pr, 0, 0, 2000, 2000, PIX_SRC, NULL, 0, 0);
49917280Sopcode }  /* end GRClear */
50017280Sopcode 
50117280Sopcode 
50217280Sopcode /*
50317280Sopcode  *  Display justification of TEXT element.
50417280Sopcode  */
GRDisplayJustify(elt)50517280Sopcode GRDisplayJustify(elt)
50617280Sopcode register ELT *elt;
50717280Sopcode {
50817280Sopcode     register POINT *point;
50917280Sopcode     register x, y, length, ysize;
51017280Sopcode 
51117280Sopcode     ysize = GRGetCharYSize(elt->brushf, elt->size);
51217280Sopcode     length = GRFontStrlen(elt->textpt, elt->brushf, elt->size);
51317280Sopcode     point = PTNextPoint(elt->ptlist);	/* lower left corner of text */
51417280Sopcode     x = dbx_to_win(point->x);
51517280Sopcode     y = dby_to_win(point->y);
51617280Sopcode 
51717280Sopcode     switch (elt->type) {
51817280Sopcode 	case TOPLEFT:
51917280Sopcode 	    y -= ysize;
52017280Sopcode 	    break;
52117280Sopcode 	case TOPCENT:
52217280Sopcode 	    y -= ysize;
52317280Sopcode 	    x += (length >> 1);
52417280Sopcode 	    break;
52517280Sopcode 	case TOPRIGHT:
52617280Sopcode 	    y -= ysize;
52717280Sopcode 	    x += length;
52817280Sopcode 	    break;
52917280Sopcode 	case CENTLEFT:
53017280Sopcode 	    y -= (ysize >> 1);
53117280Sopcode 	    break;
53217280Sopcode 	case CENTCENT:
53317280Sopcode 	    y -= (ysize >> 1);
53417280Sopcode 	    x += (length >> 1);
53517280Sopcode 	    break;
53617280Sopcode 	case CENTRIGHT:
53717280Sopcode 	    y -= (ysize >> 1);
53817280Sopcode 	    x += length;
53917280Sopcode 	    break;
54017280Sopcode 	case BOTLEFT:
54117280Sopcode 	    break;
54217280Sopcode 	case BOTCENT:
54317280Sopcode 	    x += (length >> 1);
54417280Sopcode 	    break;
54517280Sopcode 	case BOTRIGHT:
54617280Sopcode 	    x += length;
54717280Sopcode 	    break;
54817280Sopcode     }
54917280Sopcode 
55017280Sopcode     pw_write(pix_pw, x - 2, y - 2, 5, 5, PIX_SRC ^ PIX_DST, &dot_pr, 0, 0);
55117280Sopcode     pr_rop(cset_pr, x - 2, y - 2, 5, 5, PIX_SRC ^ PIX_DST, &dot_pr, 0, 0);
55217280Sopcode }
55317280Sopcode 
55417280Sopcode 
55517280Sopcode /*
55617280Sopcode  * This routine displays a point (layed down by the user) in the
55717280Sopcode  * pix subwindow.
55817280Sopcode  */
GRDisplayPoint(dbx,dby,number)55917280Sopcode GRDisplayPoint(dbx, dby, number)
56017280Sopcode float dbx, dby;			/* data base coordinates */
56117280Sopcode register number;		/* point number */
56217280Sopcode {
56317280Sopcode     register x, y;
56417280Sopcode     char numbuf[5];
56517280Sopcode 
56617280Sopcode     x = dbx_to_win(dbx);
56717280Sopcode     y = dby_to_win(dby);
56817280Sopcode 
56917280Sopcode     if (Artmode)
57017280Sopcode 	pw_write(pix_pw, x-1, y-1, 3, 3, PIX_SRC ^ PIX_DST,
57117280Sopcode 				    &littlepoint_pr, 3, 2);
57217280Sopcode     else {
57317280Sopcode 	pw_write(pix_pw, x-3, y-3, 7, 7, PIX_SRC ^ PIX_DST,
57417280Sopcode 				    &littlepoint_pr, 1, 7);
57517280Sopcode 	(void) sprintf(numbuf, "%d", number+1);
57617280Sopcode 	pw_text(pix_pw, x+5, y+3, PIX_SRC^PIX_DST, text_pf, numbuf);
57717280Sopcode     }
57817280Sopcode }  /* end GRDisplayPoint */
57917280Sopcode 
58017280Sopcode 
58117280Sopcode /*
58217280Sopcode  * This routine erases the specified point.
58317280Sopcode  */
GRErasePoint(dbx,dby,number)58417280Sopcode GRErasePoint(dbx, dby, number)
58517280Sopcode float dbx, dby;
58617280Sopcode register number;
58717280Sopcode {
58817280Sopcode     GRDisplayPoint(dbx, dby, number);
58917280Sopcode }  /* end GRErasePoint */
59017280Sopcode 
59117280Sopcode 
59217280Sopcode /*
59317280Sopcode  * This routine clears all points in plist.
59417280Sopcode  */
GRBlankPoints(plist)59517280Sopcode GRBlankPoints(plist)
59617280Sopcode register POINT *plist;
59717280Sopcode {
59817280Sopcode     register i = 0;
59917280Sopcode 
60017280Sopcode     while (!Nullpoint(plist)) {
60117280Sopcode 	GRErasePoint(plist->x, plist->y, i++);
60217280Sopcode 	plist = PTNextPoint(plist);
60317280Sopcode     }
60417280Sopcode }  /* end GRBlankPoints */
60517280Sopcode 
60617280Sopcode 
60717280Sopcode /*
60817280Sopcode  * This routine displays the grid.
60917280Sopcode  */
GRDisplayGrid()61017280Sopcode GRDisplayGrid()
61117280Sopcode {
61217280Sopcode     pw_replrop(pix_pw, 0, 0, 2000, 2000, PIX_SRC ^ PIX_DST,
61317280Sopcode 						&replgrid32_pr, 0, 0);
61417280Sopcode }  /* end GRDisplayGrid */
61517280Sopcode 
61617280Sopcode 
61717280Sopcode /*
61817280Sopcode  * This routine erases the grid.
61917280Sopcode  */
GRBlankGrid()62017280Sopcode GRBlankGrid()
62117280Sopcode {
62217280Sopcode     GRDisplayGrid();
62317280Sopcode }  /* end GRBlankGrid */
62417280Sopcode 
62517280Sopcode 
62617280Sopcode /*
62717280Sopcode  * Flash current set display.
62817280Sopcode  */
GRCurrentSet()62917280Sopcode GRCurrentSet()
63017280Sopcode {
63117280Sopcode     if (DBNullelt(cset))
63217280Sopcode 	return;
63317280Sopcode 
63417280Sopcode     pw_write(pix_pw, 0, 0, pix_size.r_width, pix_size.r_height,
63517280Sopcode 	PIX_SRC ^ PIX_DST, cset_pr, 0, 0);
63617280Sopcode 
63717280Sopcode     CsetOn = !CsetOn;
63817280Sopcode }
63917280Sopcode 
64017280Sopcode 
64117280Sopcode /*
64217280Sopcode  * Make current set on.
64317280Sopcode  */
GRCurrentSetOn()64417280Sopcode GRCurrentSetOn()
64517280Sopcode {
64617280Sopcode     if (!CsetOn)
64717280Sopcode 	GRCurrentSet();
64817280Sopcode }
64917280Sopcode 
65017280Sopcode 
65117280Sopcode /*
65217280Sopcode  * Make current set off.
65317280Sopcode  */
GRCurrentSetOff()65417280Sopcode GRCurrentSetOff()
65517280Sopcode {
65617280Sopcode     if (CsetOn)
65717280Sopcode 	GRCurrentSet();
65817280Sopcode }
65917280Sopcode 
66017280Sopcode 
66117280Sopcode /*
66217280Sopcode  * Return TRUE if font file exists and is readable.
66317280Sopcode  */
GRfontfound(font,size)66417280Sopcode GRfontfound(font, size)
66517280Sopcode register font, size;
66617280Sopcode {
66717280Sopcode     return(font_info[font-1][size-1] != (char *) -1);
66817280Sopcode }
66917280Sopcode 
67017280Sopcode 
67117280Sopcode /*
67217280Sopcode  * Open the default font file on startup.
67317280Sopcode  */
GRFontInit()67417280Sopcode GRFontInit()
67517280Sopcode {
67617280Sopcode     /* create memory pixrect template for displaying text with GRPutText() */
67717280Sopcode     if ((char_pr = mem_create(1, 1, 1)) == NULL) {
67817280Sopcode 	printf("GRFontInit: can't create char_pr\n");
67917280Sopcode 	exit(1);
68017280Sopcode     }
68117280Sopcode 
68217280Sopcode     GROpenFont(CFONT, CSIZE);
68317280Sopcode     GRStippleInit();
68417280Sopcode }  /* end GRFontInit */
68517280Sopcode 
68617280Sopcode 
68717280Sopcode /*
68817280Sopcode  * Initialize stipple patterns from font file.
68917280Sopcode  * Big assumption: all stipples are defined by 32 x 32 bit patterns.
69017280Sopcode  * All fonts do not contain exactly 32 rows of 4 bytes - this is ok -
69117280Sopcode  * Fonts wider than 32 bits will be clipped.
69217280Sopcode  */
GRStippleInit()69317280Sopcode GRStippleInit()
69417280Sopcode {
69517280Sopcode     register struct mpr_data *mpr_data;
69617280Sopcode     register char *from, *to;
69717280Sopcode     register char *fbase;
69817280Sopcode     register i, j, k;
69917280Sopcode     struct dispatch *dispatch, *dstart;
70017280Sopcode     int width, height, bytewidth;
70117280Sopcode     char *stipple_info;
70217280Sopcode     char name[128];
70317280Sopcode 
70417280Sopcode     (void) sprintf(name, "%s%s.0", stippledir, stippletype);
70517280Sopcode 
70617280Sopcode     if ((stipple_info = GRReadFontFile(name)) == (char *) -1) {
70717280Sopcode 	/*
70817280Sopcode 	 * use default stipple pixrects since we can't read the
70917280Sopcode 	 * user specified stipple font file.
71017280Sopcode 	 * copy stipple pixrects to stipple_patterns for display
71117280Sopcode 	 */
71217280Sopcode 	for (i=0; i<NSTIPPLES; i++)
71317280Sopcode 	    GRCopyStipple(i);
71417280Sopcode 
71517280Sopcode 	return;
71617280Sopcode     }
71717280Sopcode 
71817280Sopcode     dstart = (struct dispatch *) (stipple_info + sizeof(struct header));
71917280Sopcode     fbase = (char *) ((char *) dstart + NUM_DISPATCH * sizeof(struct dispatch));
72017280Sopcode 
72117280Sopcode     for (i=0; i<NSTIPPLES; i++) {
72217280Sopcode 	mpr_data = (struct mpr_data *) stipple_prs[i]->pr_data;
72317280Sopcode 	dispatch = dstart + stipple_index[i];
72417280Sopcode 	if (dispatch->nbytes != 0) {
72517280Sopcode 	    width = dispatch->left + dispatch->right;
72617280Sopcode 	    height = dispatch->up + dispatch->down;
72717280Sopcode 	    bytewidth = (width + 7) >> 3;
72817280Sopcode 	    if (bytewidth > 4)		/* force size constraint */
72917280Sopcode 		bytewidth = 4;		/* pattern screwed up if ever > 4 */
73017280Sopcode 
73117280Sopcode 	    from = (char *) ((char *) fbase + dispatch->addr);
73217280Sopcode 	    to = stipple_patterns[i];
73317280Sopcode 
73417280Sopcode 	    for (j=1; j<=height; j++) {	/* copy font entry to known location */
73517280Sopcode 		for (k=1; k<=bytewidth; k++)
73617280Sopcode 		    *to++ = *from++;
73717280Sopcode 		for ( ;k<=4; k++)
73817280Sopcode 		    *to++ = '\0';
73917280Sopcode 	    }
74017280Sopcode 
74117280Sopcode 	    for ( ; j<=32; j++)		/* fix up any non- 32 x 32 font */
74217280Sopcode 		for (k=1; k<=4; k++)
74317280Sopcode 		    *to++ = '\0';
74417280Sopcode 
74517280Sopcode 	    /* copy vfont stipple to stipple pixrect for menu display */
74617280Sopcode 	    /* can only display a 16 x 16 menu icon */
74717280Sopcode 	    from = stipple_patterns[i];
74817280Sopcode 	    to = (char *) mpr_data->md_image;
74917280Sopcode 	    for (j=0; j<16; j++) {
75017280Sopcode 		*to++ = *from++;
75117280Sopcode 		*to++ = *from++;
75217280Sopcode 		from += 2;
75317280Sopcode 	    }
75417280Sopcode 	}
75517280Sopcode 	else {
75617280Sopcode 	    (void) sprintf(name, "stipple index=%d not defined",
75717280Sopcode 							    stipple_index[i]);
75817280Sopcode 	    error(name);
75917280Sopcode 
76017280Sopcode 	    /* copy stipple pixrect to stipple_patterns for display */
76117280Sopcode 	    GRCopyStipple(i);
76217280Sopcode 	}
76317280Sopcode     }
76417280Sopcode 
76517280Sopcode     /* bit maps are all in core now */
76617280Sopcode     free(stipple_info);
767*17644Sopcode 
768*17644Sopcode     /* set up parameters for drawing polygons */
769*17644Sopcode     mpr_data = (struct mpr_data *) scratch_pr->pr_data;
770*17644Sopcode     bytesperline = mpr_data->md_linebytes;
771*17644Sopcode     fill = (char *) mpr_data->md_image;
772*17644Sopcode     rasterlength = bytesperline << 3;
773*17644Sopcode     nlines = scratch_pr->pr_size.x;
77417280Sopcode } /* end GRStippleInit */;
77517280Sopcode 
77617280Sopcode 
77717280Sopcode /*
77817280Sopcode  * Copy the stipple bit map image as defined in the menu pixrect
77917280Sopcode  * to the bit maps used for drawing polygons.  The pixrect bit map
78017280Sopcode  * is 16 x 16 bits and the target bit map is 32 x 32 bits.  The
78117280Sopcode  * image is expanded appropriately.
78217280Sopcode  */
GRCopyStipple(index)78317280Sopcode GRCopyStipple(index)
78417280Sopcode int index;
78517280Sopcode {
78617280Sopcode     register struct mpr_data *mpr_data;
78717280Sopcode     register char *from, *to;
78817280Sopcode     register i, j;
78917280Sopcode 
79017280Sopcode     mpr_data = (struct mpr_data *) stipple_prs[index]->pr_data;
79117280Sopcode     from = (char *) mpr_data->md_image;
79217280Sopcode     to = stipple_patterns[index];
79317280Sopcode 
79417280Sopcode     for (i=0; i<16; i++) {
79517280Sopcode 	j = i << 2;
79617280Sopcode 	to[j]   = to[j+2] = to[j+64] = to[j+66] = *from++;
79717280Sopcode 	to[j+1] = to[j+3] = to[j+65] = to[j+67] = *from++;
79817280Sopcode     }
79917280Sopcode }
80017280Sopcode 
80117280Sopcode 
80217280Sopcode /*
80317280Sopcode  * Open a font file for use by first reading it into memory.
80417280Sopcode  * If the file is read successfully, the appropriate entry in
80517280Sopcode  * font_info[] is set to point to its memory image.  If the
80617280Sopcode  * file cannot be opened or there is a error in reading the
80717280Sopcode  * file, set the font_info[] entry to -1.
80817280Sopcode  */
GROpenFont(font,size)80917280Sopcode GROpenFont(font, size)
81017280Sopcode register font;		/* font is 1 to 4 */
81117280Sopcode register size;		/* size is 1 to 4 */
81217280Sopcode {
81317280Sopcode     char name[128];
81417280Sopcode 
81517280Sopcode     if (font_info[--font][--size] != NULL)	/* already tried to open */
81617280Sopcode 	return;
81717280Sopcode 
81817280Sopcode     sprintf(name, "%s%s.%d", fontdir, font_types[font], font_sizes[size]);
81917280Sopcode 
82017280Sopcode     if ((font_info[font][size] = GRReadFontFile(name)) == (char *) -1)
82117280Sopcode 	return;
82217280Sopcode 
82317280Sopcode     /* height of this font/size combination */
82417280Sopcode     charysizes[font][size] = ((struct header *) font_info[font][size])->maxy;
82517280Sopcode }  /* end GROpenFont */
82617280Sopcode 
82717280Sopcode 
82817280Sopcode /*
82917280Sopcode  * Read a font file into memory and return a pointer to its
83017280Sopcode  * memory image, or -1 if any error occurs.
83117280Sopcode  */
83217280Sopcode char *
GRReadFontFile(file)83317280Sopcode GRReadFontFile(file)
83417280Sopcode char *file;
83517280Sopcode {
83617280Sopcode     char *image;			/* pointer to font memory image */
83717280Sopcode     char msg[128];
83817280Sopcode     struct header header;
83917280Sopcode     int fd, filesize;
84017280Sopcode 
84117280Sopcode     if ((fd = open(file, 0)) < 0) {
84217280Sopcode 	sprintf(msg, "can't open font file: %s", file);
84317280Sopcode 	error(msg);
84417280Sopcode 	return((char *) -1);
84517280Sopcode     }
84617280Sopcode 
84717280Sopcode     if (read(fd, &header, sizeof(struct header)) != sizeof(struct header)) {
84817280Sopcode 	sprintf(msg, "can't read font header: %s\n", file);
84917280Sopcode 	error(msg);
85017280Sopcode 	return((char *) -1);
85117280Sopcode     }
85217280Sopcode 
85317280Sopcode     if (header.magic != VFONT_MAGIC) {
85417280Sopcode 	sprintf(msg, "bad magic number %o in font file\n", header.magic);
85517280Sopcode 	error(msg);
85617280Sopcode 	return((char *) -1);
85717280Sopcode     }
85817280Sopcode 
85917280Sopcode     filesize = (sizeof(struct header) +
86017280Sopcode 		sizeof(struct dispatch) * NUM_DISPATCH + header.size);
86117280Sopcode 
86217280Sopcode     if ((image = malloc(filesize)) == NULL) {
86317280Sopcode 	error("not enough memory for font file");
86417280Sopcode 	return((char *) -1);
86517280Sopcode     }
86617280Sopcode 
86717280Sopcode     lseek(fd, (long) 0, 0);
86817280Sopcode 
86917280Sopcode     if (read(fd, image, filesize) != filesize) {
87017280Sopcode 	error("can't read font file");
87117280Sopcode 	return((char *) -1);
87217280Sopcode     }
87317280Sopcode 
87417280Sopcode     close(fd);
87517280Sopcode     return(image);
87617280Sopcode }  /* end GRReadFontFile */
87717280Sopcode 
87817280Sopcode 
87917280Sopcode /*
88017280Sopcode  * Determine pixel length of string s in font and size.
88117280Sopcode  */
GRFontStrlen(text,font,size)88217280Sopcode GRFontStrlen(text, font, size)
88317280Sopcode char *text;
88417280Sopcode int font;		/* 1 - 4 */
88517280Sopcode int size;		/* 1 - 4 */
88617280Sopcode {
88717280Sopcode     register struct dispatch *dispatch, *start;
88817280Sopcode     register length, spacewidth;
88917280Sopcode 
89017280Sopcode     if (*text == '\0')
89117280Sopcode 	return(0);
89217280Sopcode 
89317280Sopcode     if (font_info[font-1][size-1] == NULL)	/* not open yet */
89417280Sopcode 	GROpenFont(font, size);
89517280Sopcode 
89617280Sopcode     if (!GRfontfound(font, size))		/* unreadable font */
89717280Sopcode 	return(0);
89817280Sopcode 
89917280Sopcode     start = (struct dispatch *) (font_info[font-1][size-1] +
90017280Sopcode 						sizeof(struct header));
90117280Sopcode     spacewidth = font_sizes[size-1] * (120.0 / 216.0) + 0.5;
90217280Sopcode     length = 0;
90317280Sopcode     while (*text != '\0') {
90417280Sopcode 	dispatch = start + (*text);
90517280Sopcode 
90617280Sopcode 	if (*text == ' ')
90717280Sopcode 	    length += spacewidth;
90817280Sopcode 	else if (dispatch->nbytes != 0)
90917280Sopcode 	    length += dispatch->width;
91017280Sopcode 
91117280Sopcode 	text++;
91217280Sopcode     }
91317280Sopcode 
91417280Sopcode     return(length);
91517280Sopcode }
91617280Sopcode 
91717280Sopcode /*
91817280Sopcode  * Display text string of font/size at position pos.
91917280Sopcode  */
GRPutText(text,font,size,pos)92017280Sopcode GRPutText(text, font, size, pos)
92117280Sopcode char *text;
92217280Sopcode int font, size;
92317280Sopcode POINT *pos;
92417280Sopcode {
92517280Sopcode     register struct dispatch *dispatch, *dstart;
92617280Sopcode     register struct mpr_data *mpr_data;
92717280Sopcode     register char *fbase;
92817280Sopcode     register width, height, spacewidth;
92917280Sopcode     int x, y;
93017280Sopcode 
93117280Sopcode     if (font_info[font-1][size-1] == NULL)
93217280Sopcode 	GROpenFont(font, size);
93317280Sopcode 
93417280Sopcode     if (!GRfontfound(font, size))
93517280Sopcode 	return;
93617280Sopcode 
93717280Sopcode     dstart = (struct dispatch *) (font_info[font-1][size-1] +
93817280Sopcode 						    sizeof(struct header));
93917280Sopcode     fbase = (char *) ((char *) dstart + NUM_DISPATCH * sizeof(struct dispatch));
94017280Sopcode 
94117280Sopcode     x = dbx_to_win(pos->x);
94217280Sopcode     y = dby_to_win(pos->y);
94317280Sopcode 
94417280Sopcode     /* define region of screen to be drawn with text */
94517280Sopcode     minsunx = x;
94617280Sopcode     maxsuny = y + 8;	/* catch descenders */
94717280Sopcode     minsuny = y - GRGetCharYSize(font, size);
94817280Sopcode 
94917280Sopcode     spacewidth = font_sizes[size-1] * (120.0 / 216.0) + 0.5;
95017280Sopcode     mpr_data = (struct mpr_data *) char_pr->pr_data;
95117280Sopcode     while (*text != '\0') {
95217280Sopcode 	dispatch = dstart + (*text);
95317280Sopcode 
95417280Sopcode 	if (*text == ' ')
95517280Sopcode 	    x += spacewidth;
95617280Sopcode 	else if (dispatch->nbytes != 0) {
95717280Sopcode 	    mpr_data->md_image = (short *) ((char *) fbase + dispatch->addr);
95817280Sopcode 	    char_pr->pr_size.x = width = dispatch->left + dispatch->right;
95917280Sopcode 	    char_pr->pr_size.y = height = dispatch->up + dispatch->down;
96017280Sopcode 	    mpr_data->md_linebytes = ((width + 15) >> 3) & ~1;
96117280Sopcode 
96217280Sopcode 	    if (*text != ' ')
96317280Sopcode 		pr_rop(scratch_pr, x - dispatch->left, y - dispatch->up,
96417280Sopcode 			    width, height, PIX_SRC ^ PIX_DST, char_pr, 0, 0);
96517280Sopcode 	    x += dispatch->width;
96617280Sopcode 	}
96717280Sopcode 
96817280Sopcode 	text++;
96917280Sopcode     }
97017280Sopcode 
97117280Sopcode     maxsunx = x;
97217280Sopcode } /* end GRPutText */;
97317280Sopcode 
97417280Sopcode 
97517280Sopcode /*
97617280Sopcode  * Set the actual positioning point for text with the justify, font, and
97717280Sopcode  * size attributes.  Point is a pointer to the POINT layed down by the user.
97817280Sopcode  * Pos is a pointer to the returned positioning POINT used in a subsequent
97917280Sopcode  * call to GRPutText().
98017280Sopcode  */
GRSetTextPos(text,justify,font,size,point,pos)98117280Sopcode GRSetTextPos(text, justify, font, size, point, pos)
98217280Sopcode char *text;
98317280Sopcode int justify, font, size;
98417280Sopcode POINT *point, *pos;
98517280Sopcode {
98617280Sopcode     register length;
98717280Sopcode     register charysize;
98817280Sopcode 
98917280Sopcode     charysize = GRGetCharYSize(font, size);
99017280Sopcode     length = GRFontStrlen(text, font, size);
99117280Sopcode 
99217280Sopcode     switch (justify) {
99317280Sopcode 	case BOTLEFT:
99417280Sopcode 	    pos->x = point->x;
99517280Sopcode 	    pos->y = point->y;
99617280Sopcode 	    break;
99717280Sopcode 	case BOTCENT:
99817280Sopcode 	    pos->x = point->x - (length / 2);
99917280Sopcode 	    pos->y = point->y;
100017280Sopcode 	    break;
100117280Sopcode 	case BOTRIGHT:
100217280Sopcode 	    pos->x = point->x - length;
100317280Sopcode 	    pos->y = point->y;
100417280Sopcode 	    break;
100517280Sopcode 	case CENTLEFT:
100617280Sopcode 	    pos->x = point->x;
100717280Sopcode 	    pos->y = point->y - (charysize / 2);
100817280Sopcode 	    break;
100917280Sopcode 	case CENTCENT:
101017280Sopcode 	    pos->x = point->x - (length / 2);
101117280Sopcode 	    pos->y = point->y - (charysize / 2);
101217280Sopcode 	    break;
101317280Sopcode 	case CENTRIGHT:
101417280Sopcode 	    pos->x = point->x - length;
101517280Sopcode 	    pos->y = point->y - (charysize / 2);
101617280Sopcode 	    break;
101717280Sopcode 	case TOPLEFT:
101817280Sopcode 	    pos->x = point->x;
101917280Sopcode 	    pos->y = point->y - charysize;
102017280Sopcode 	    break;
102117280Sopcode 	case TOPCENT:
102217280Sopcode 	    pos->x = point->x - (length / 2);
102317280Sopcode 	    pos->y = point->y - charysize;
102417280Sopcode 	    break;
102517280Sopcode 	case TOPRIGHT:
102617280Sopcode 	    pos->x = point->x - length;
102717280Sopcode 	    pos->y = point->y - charysize;
102817280Sopcode 	    break;
102917280Sopcode     }
103017280Sopcode }
1031