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