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