1 /*
2 * @(#)graphics.c 1.2 01/03/85
3 *
4 * Graphics routines for the SUN Gremlin picture editor.
5 *
6 * Mark Opperman (opcode@monet.BERKELEY)
7 *
8 */
9
10 #include <suntool/tool_hs.h>
11 #include <vfont.h>
12 #include "icondata.h"
13 #include "gremlin.h"
14
15 /* imports from main.c */
16
17 extern error();
18 extern struct pixwin *pix_pw;
19 extern struct rect pix_size;
20 extern struct pixrect *cset_pr;
21 extern struct pixrect *scratch_pr;
22 extern ELT *cset;
23 extern Artmode;
24 extern CSIZE;
25 extern CFONT;
26 extern CsetOn;
27 extern SUN_XORIGIN;
28 extern SUN_YORIGIN;
29
30 /* imports from display.c */
31
32 extern minsunx, maxsunx, minsuny, maxsuny;
33
34 /* imports from C */
35
36 extern char *malloc();
37
38 /* forward references */
39
40 extern char *GRReadFontFile();
41
42 /* symbolic font from text.c */
43
44 extern struct pixfont *text_pf;
45
46 /* locally defined variables */
47
48 int charysizes[NFONTS][NSIZES]; /* Character y dimensions for each size */
49 int curve_set; /* TRUE if spline points pre-computed */
50
51 int linestyle; /* Current line style */
52 int linemod; /* Type of line (SOLID, DOTTED, ...) */
53 int linethickness; /* 1, 2, 3 */
54
55 char fontdir[128] = "/usr/lib/font/devsun/";
56 char stippledir[128] = "/usr/lib/font/devsun/";
57 char stippletype[32] = "cf";
58
59 char *font_types[NFONTS] = { "R", "I", "B", "S" };
60 int font_sizes[NSIZES] = { 7, 10, 14, 24 };
61 int stipple_index[NSTIPPLES] = { 1, 3, 12, 14, 16, 19, 21, 23 };
62
63 /* NOTE: all stipple fonts are expected to be 32 x 32 bit rasters */
64
65 /* pointers to the stipple pixrects (16 x 16 bits) in the menu ... */
66 struct pixrect *stipple_prs[NSTIPPLES] = {
67 &stipple1_pr, &stipple2_pr, &stipple3_pr, &stipple4_pr,
68 &stipple5_pr, &stipple6_pr, &stipple7_pr, &stipple8_pr
69 };
70
71 /* ... and the corresponding images (32 x 32 bits) from the vfont file */
72 char stipple_patterns[NSTIPPLES][128];
73
74 /* data used in graphics2.c for drawing polygons */
75 int rasterlength; /* real # horizontal bits in scratch_pr */
76 int bytesperline; /* rasterlength / 8 */
77 int nlines; /* # horizontal bits defined by scratch_pr */
78 char *fill; /* pointer to scratch_pr image */
79
80 /*
81 * This matrix points to the DISPATCH data for each font/size pair
82 * if an unsuccesful attempt is made to open a particular font/size pair,
83 * its entry in this table is marked as -1.
84 */
85 char *font_info[NFONTS][NSIZES] = {
86 { NULL, NULL, NULL, NULL },
87 { NULL, NULL, NULL, NULL },
88 { NULL, NULL, NULL, NULL },
89 { NULL, NULL, NULL, NULL },
90 };
91 struct pixrect *char_pr;
92
93 /* Splines use these global arrays */
94
95 static float h[MAXPOINTS];
96 static float x[MAXPOINTS], dx[MAXPOINTS], d2x[MAXPOINTS], d3x[MAXPOINTS];
97 static float y[MAXPOINTS], dy[MAXPOINTS], d2y[MAXPOINTS], d3y[MAXPOINTS];
98 static numpoints;
99
100 /* These are used as bit masks to create the right style lines. */
101 #define SOLID -1
102 #define DOTTED 002
103 #define DASHED 004
104 #define DOTDASHED 012
105
106
107 /*
108 * This routine sets the current line style.
109 */
GRSetLineStyle(style)110 GRSetLineStyle(style)
111 int style; /* new stipple pattern for lines */
112 {
113 switch (linestyle = style) {
114 case 1: /* dotted */
115 linemod = DOTTED;
116 linethickness = 1;
117 break;
118 case 2: /* broken */
119 linemod = DOTDASHED;
120 linethickness = 1;
121 break;
122 case 3: /* thick */
123 linemod = SOLID;
124 linethickness = 3;
125 break;
126 case 4: /* dashed */
127 linemod = DASHED;
128 linethickness = 1;
129 break;
130 case 5: /* narrow */
131 linemod = SOLID;
132 linethickness = 1;
133 break;
134 case 6: /* medium */
135 linemod = SOLID;
136 linethickness = 2;
137 break;
138 }
139 }
140
141
142 /*
143 * This routine returns the maximum vertical size (in bits) of a character
144 * of the specified font/size.
145 */
GRGetCharYSize(font,size)146 GRGetCharYSize(font, size)
147 register font; /* character font (1 - 4) */
148 register size; /* character size (1 - 4) */
149 {
150 return(charysizes[--font][--size]);
151 }
152
153
154 #define pi 3.14159265359
155 #define twopi 6.28318530718
156 #define log2_10 3.321915
157
158
159 /*
160 * Draw arc - always to scratch_pr.
161 * Note: must check for zero radius before calling.
162 */
GRArc(center,cpoint,angle,style)163 GRArc(center, cpoint, angle, style)
164 register POINT *center, *cpoint;
165 float angle;
166 register style;
167 {
168 double radius, resolution, t1, fullcircle;
169 double degreesperpoint;
170 float xs, ys, epsilon;
171 float x1, y1, x2, y2;
172 register i, extent;
173
174 xs = cpoint->x - center->x;
175 ys = cpoint->y - center->y;
176
177 /* calculate drawing parameters */
178
179 radius = sqrt((double) (xs * xs + ys * ys));
180 t1 = floor(log10(radius) * log2_10);
181 resolution = pow(2.0, t1);
182 epsilon = (float) 1.0 / resolution;
183 fullcircle = ceil(twopi * resolution);
184 degreesperpoint = 360.0 / fullcircle;
185
186 extent = (angle == 0) ? fullcircle : angle/degreesperpoint;
187
188 GRSetLineStyle(style);
189
190 x1 = cpoint->x;
191 y1 = cpoint->y;
192
193 for (i=0; i<extent; ++i) {
194 xs -= epsilon * ys;
195 x2 = xs + center->x;
196 ys += epsilon * xs;
197 y2 = ys + center->y;
198
199 GRVector(x1, y1, x2, y2);
200
201 x1 = x2;
202 y1 = y2;
203 }
204 } /* end GRArc */;
205
206
207 /* This routine calculates parameteric values for use in calculating
208 * curves. The values are an approximation of cumulative arc lengths
209 * of the curve (uses cord * length). For additional information,
210 * see paper cited below.
211 */
212 static
Paramaterize(x,y,h,n)213 Paramaterize(x, y, h, n)
214 float x[MAXPOINTS];
215 float y[MAXPOINTS];
216 float h[MAXPOINTS];
217 register n;
218 {
219 register i, j;
220 float t1, t2;
221 float u[MAXPOINTS];
222
223 n = numpoints;
224
225 for (i=1; i<=n; ++i) {
226 u[i] = 0.0;
227 for (j=1; j<i; ++j) {
228 t1 = x[j+1] - x[j];
229 t2 = y[j+1] - y[j];
230 u[i] += (float) sqrt((double) ((t1 * t1) + (t2 * t2)));
231 }
232 }
233
234 for (i=1; i<n; ++i)
235 h[i] = u[i+1] - u[i];
236 } /* end Paramaterize */
237
238
239 /*
240 * This routine solves for the cubic polynomial to fit a spline
241 * curve to the the points specified by the list of values.
242 * The curve generated is periodic. The alogrithms for this
243 * curve are from the "Spline Curve Techniques" paper cited below.
244 */
245 static
PeriodicSpline(h,z,dz,d2z,d3z,npoints)246 PeriodicSpline(h, z, dz, d2z, d3z, npoints)
247 float h[MAXPOINTS]; /* paramaterization */
248 float z[MAXPOINTS]; /* point list */
249 float dz[MAXPOINTS]; /* to return the 1st derivative */
250 float d2z[MAXPOINTS]; /* 2nd derivative */
251 float d3z[MAXPOINTS]; /* and 3rd derivative */
252 register npoints; /* number of valid points */
253 {
254 float a[MAXPOINTS];
255 float b[MAXPOINTS];
256 float c[MAXPOINTS];
257 float d[MAXPOINTS];
258 float deltaz[MAXPOINTS];
259 float r[MAXPOINTS];
260 float s[MAXPOINTS];
261 float ftmp;
262 register i;
263
264 /* step 1 */
265 for (i=1; i<npoints; ++i) {
266 if (h[i] != 0)
267 deltaz[i] = (z[i+1] - z[i]) / h[i];
268 else
269 deltaz[i] = 0;
270 }
271 h[0] = h[npoints-1];
272 deltaz[0] = deltaz[npoints-1];
273
274 /* step 2 */
275 for (i=1; i<npoints-1; ++i) {
276 d[i] = deltaz[i+1] - deltaz[i];
277 }
278 d[0] = deltaz[1] - deltaz[0];
279
280 /* step 3a */
281 a[1] = 2 * (h[0] + h[1]);
282 if (a[1] == 0)
283 return(-1); /* 3 consecutive knots at same point */
284 b[1] = d[0];
285 c[1] = h[0];
286
287 for (i=2; i<npoints-1; ++i) {
288 ftmp = h[i-1];
289 a[i] = ftmp + ftmp + h[i] + h[i] - (ftmp * ftmp)/a[i-1];
290 if (a[i] == 0)
291 return(-1); /* 3 consec knots at same point */
292 b[i] = d[i-1] - ftmp * b[i-1]/a[i-1];
293 c[i] = -ftmp * c[i-1]/a[i-1];
294 }
295
296 /* step 3b */
297 r[npoints-1] = 1;
298 s[npoints-1] = 0;
299 for (i=npoints-2; i>0; --i) {
300 r[i] = -(h[i] * r[i+1] + c[i])/a[i];
301 s[i] = (6 * b[i] - h[i] * s[i+1])/a[i];
302 }
303
304 /* step 4 */
305 d2z[npoints-1] = (6 * d[npoints-2] - h[0] * s[1]
306 - h[npoints-1] * s[npoints-2])
307 / (h[0] * r[1] + h[npoints-1] * r[npoints-2]
308 + 2 * (h[npoints-2] + h[0]));
309 for (i=1; i<npoints-1; ++i) {
310 d2z[i] = r[i] * d2z[npoints-1] + s[i];
311 }
312 d2z[npoints] = d2z[1];
313
314 /* step 5 */
315 for (i=1; i<npoints; ++i) {
316 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
317 if (h[i] != 0)
318 d3z[i] = (d2z[i+1] - d2z[i])/h[i];
319 else
320 d3z[i] = 0;
321 }
322
323 return(0);
324 } /* end PeriodicSpline */
325
326
327 /*
328 * This routine solves for the cubic polynomial to fit a spline
329 * curve from the points specified by the list of values. The alogrithms for
330 * this curve are from the "Spline Curve Techniques" paper cited below.
331 */
332 static
NaturalEndSpline(h,z,dz,d2z,d3z,npoints)333 NaturalEndSpline(h, z, dz, d2z, d3z, npoints)
334 float h[MAXPOINTS]; /* paramaterization */
335 float z[MAXPOINTS]; /* point list */
336 float dz[MAXPOINTS]; /* to return the 1st derivative */
337 float d2z[MAXPOINTS]; /* 2nd derivative */
338 float d3z[MAXPOINTS]; /* and 3rd derivative */
339 register npoints; /* number of valid points */
340 {
341 float a[MAXPOINTS];
342 float b[MAXPOINTS];
343 float d[MAXPOINTS];
344 float deltaz[MAXPOINTS];
345 float ftmp;
346 register i;
347
348 /* step 1 */
349 for (i=1; i<npoints; ++i) {
350 if (h[i] != 0)
351 deltaz[i] = (z[i+1] - z[i]) / h[i];
352 else
353 deltaz[i] = 0;
354 }
355 deltaz[0] = deltaz[npoints-1];
356
357 /* step 2 */
358 for (i=1; i<npoints-1; ++i) {
359 d[i] = deltaz[i+1] - deltaz[i];
360 }
361 d[0] = deltaz[1] - deltaz[0];
362
363 /* step 3 */
364 a[0] = 2 * (h[2] + h[1]);
365 if (a[0] == 0) /* 3 consec knots at same point */
366 return(-1);
367 b[0] = d[1];
368
369 for (i=1; i<npoints-2; ++i) {
370 ftmp = h[i+1];
371 a[i] = ftmp + ftmp + h[i+2] + h[i+2] - (ftmp * ftmp) / a[i-1];
372 if (a[i] == 0) /* 3 consec knots at same point */
373 return(-1);
374 b[i] = d[i+1] - ftmp * b[i-1]/a[i-1];
375 }
376
377 /* step 4 */
378 d2z[npoints] = d2z[1] = 0;
379 for (i=npoints-1; i>1; --i) {
380 d2z[i] = (6 * b[i-2] - h[i] *d2z[i+1])/a[i-2];
381 }
382
383 /* step 5 */
384 for (i=1; i<npoints; ++i) {
385 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
386 if (h[i] != 0)
387 d3z[i] = (d2z[i+1] - d2z[i])/h[i];
388 else
389 d3z[i] = 0;
390 }
391
392 return(0);
393 } /* end NaturalEndSpline */
394
395
396 #define PointsPerInterval 16
397
398
399 /*
400 * This routine computes a smooth curve through a set of points.
401 * Returns -1 if there are too many knots to draw the curve.
402 * Use GRCurve AFTER this routine to actually draw the curve.
403 * [Formerly the first half of GRCurve()]
404 *
405 * The method used is the parametric spline curve on unit knot mesh described
406 * in "Spline Curve Techniques" by Patrick Baudelaire, Robert Flegal, and
407 * Robert Sproull -- Xerox Parc.
408 */
GRSetCurve(pointlist)409 GRSetCurve(pointlist)
410 POINT *pointlist;
411 {
412 register POINT *ptr;
413 register i, stat;
414
415 /* Copy point list to array for easier access */
416 ptr = pointlist;
417 for (i=1; (!Nullpoint(ptr)); ++i) {
418 x[i] = ptr->x;
419 y[i] = ptr->y;
420 ptr = PTNextPoint(ptr);
421 }
422
423 /* Solve for derivatives of the curve at each point
424 separately for x and y (parametric). */
425
426 numpoints = i - 1; /* set global numpoints */
427
428 Paramaterize(x, y, h, numpoints);
429
430 stat = 0;
431 if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) { /* closed curve */
432 stat |= PeriodicSpline(h, x, dx, d2x, d3x, numpoints);
433 stat |= PeriodicSpline(h, y, dy, d2y, d3y, numpoints);
434 }
435 else {
436 stat |= NaturalEndSpline(h, x, dx, d2x, d3x, numpoints);
437 stat |= NaturalEndSpline(h, y, dy, d2y, d3y, numpoints);
438 }
439
440 curve_set = 1; /* indicates that paramterization is done */
441 return(stat);
442 }
443
444
445 /*
446 * This routine displays a smooth curve through a set of points. The
447 * method used is the parametric spline curve on unit knot mesh described
448 * in "Spline Curve Techniques" by Patrick Baudelaire, Robert Flegal, and
449 * Robert Sproull -- Xerox Parc.
450 * [formerly the second half of GRCurve()]
451 *
452 * Uses the data computed first by GRSetCurve().
453 * GRSetCurve() MUST be called before this routine and have returned a ZERO.
454 */
GRCurve(style)455 GRCurve(style)
456 int style;
457 {
458 float t, t2, t3, xinter, yinter;
459 float x1, y1, x2, y2;
460 register j, k;
461
462 GRSetLineStyle(style);
463
464 x1 = x[1];
465 y1 = y[1];
466
467 /* generate the curve using the information from GRSetCurve() and
468 PointsPerInterval vectors between each specified knot. */
469
470 for (j=1; j<numpoints; ++j) {
471 for (k=0; k<=PointsPerInterval; ++k) {
472 t = (float) k * h[j] / (float) PointsPerInterval;
473 t2 = t * t;
474 t3 = t2 * t;
475 x2 = x[j] + t * dx[j] + t2 * d2x[j]/2.0 + t3 * d3x[j]/6.0;
476 y2 = y[j] + t * dy[j] + t2 * d2y[j]/2.0 + t3 * d3y[j]/6.0;
477
478 GRVector(x1, y1, x2, y2);
479
480 x1 = x2;
481 y1 = y2;
482 }
483 }
484 } /* end GRCurve */
485
486
487 /*
488 * This routine clears the Gremlin pix subwindow or current set
489 * pixrect image as specified in the mask.
490 */
GRClear(mask)491 GRClear(mask)
492 register mask;
493 {
494 if (mask & pixmask)
495 pw_writebackground(pix_pw, 0, 0, 2000, 2000, PIX_SRC);
496
497 if (mask & csetmask)
498 pr_rop(cset_pr, 0, 0, 2000, 2000, PIX_SRC, NULL, 0, 0);
499 } /* end GRClear */
500
501
502 /*
503 * Display justification of TEXT element.
504 */
GRDisplayJustify(elt)505 GRDisplayJustify(elt)
506 register ELT *elt;
507 {
508 register POINT *point;
509 register x, y, length, ysize;
510
511 ysize = GRGetCharYSize(elt->brushf, elt->size);
512 length = GRFontStrlen(elt->textpt, elt->brushf, elt->size);
513 point = PTNextPoint(elt->ptlist); /* lower left corner of text */
514 x = dbx_to_win(point->x);
515 y = dby_to_win(point->y);
516
517 switch (elt->type) {
518 case TOPLEFT:
519 y -= ysize;
520 break;
521 case TOPCENT:
522 y -= ysize;
523 x += (length >> 1);
524 break;
525 case TOPRIGHT:
526 y -= ysize;
527 x += length;
528 break;
529 case CENTLEFT:
530 y -= (ysize >> 1);
531 break;
532 case CENTCENT:
533 y -= (ysize >> 1);
534 x += (length >> 1);
535 break;
536 case CENTRIGHT:
537 y -= (ysize >> 1);
538 x += length;
539 break;
540 case BOTLEFT:
541 break;
542 case BOTCENT:
543 x += (length >> 1);
544 break;
545 case BOTRIGHT:
546 x += length;
547 break;
548 }
549
550 pw_write(pix_pw, x - 2, y - 2, 5, 5, PIX_SRC ^ PIX_DST, &dot_pr, 0, 0);
551 pr_rop(cset_pr, x - 2, y - 2, 5, 5, PIX_SRC ^ PIX_DST, &dot_pr, 0, 0);
552 }
553
554
555 /*
556 * This routine displays a point (layed down by the user) in the
557 * pix subwindow.
558 */
GRDisplayPoint(dbx,dby,number)559 GRDisplayPoint(dbx, dby, number)
560 float dbx, dby; /* data base coordinates */
561 register number; /* point number */
562 {
563 register x, y;
564 char numbuf[5];
565
566 x = dbx_to_win(dbx);
567 y = dby_to_win(dby);
568
569 if (Artmode)
570 pw_write(pix_pw, x-1, y-1, 3, 3, PIX_SRC ^ PIX_DST,
571 &littlepoint_pr, 3, 2);
572 else {
573 pw_write(pix_pw, x-3, y-3, 7, 7, PIX_SRC ^ PIX_DST,
574 &littlepoint_pr, 1, 7);
575 (void) sprintf(numbuf, "%d", number+1);
576 pw_text(pix_pw, x+5, y+3, PIX_SRC^PIX_DST, text_pf, numbuf);
577 }
578 } /* end GRDisplayPoint */
579
580
581 /*
582 * This routine erases the specified point.
583 */
GRErasePoint(dbx,dby,number)584 GRErasePoint(dbx, dby, number)
585 float dbx, dby;
586 register number;
587 {
588 GRDisplayPoint(dbx, dby, number);
589 } /* end GRErasePoint */
590
591
592 /*
593 * This routine clears all points in plist.
594 */
GRBlankPoints(plist)595 GRBlankPoints(plist)
596 register POINT *plist;
597 {
598 register i = 0;
599
600 while (!Nullpoint(plist)) {
601 GRErasePoint(plist->x, plist->y, i++);
602 plist = PTNextPoint(plist);
603 }
604 } /* end GRBlankPoints */
605
606
607 /*
608 * This routine displays the grid.
609 */
GRDisplayGrid()610 GRDisplayGrid()
611 {
612 pw_replrop(pix_pw, 0, 0, 2000, 2000, PIX_SRC ^ PIX_DST,
613 &replgrid32_pr, 0, 0);
614 } /* end GRDisplayGrid */
615
616
617 /*
618 * This routine erases the grid.
619 */
GRBlankGrid()620 GRBlankGrid()
621 {
622 GRDisplayGrid();
623 } /* end GRBlankGrid */
624
625
626 /*
627 * Flash current set display.
628 */
GRCurrentSet()629 GRCurrentSet()
630 {
631 if (DBNullelt(cset))
632 return;
633
634 pw_write(pix_pw, 0, 0, pix_size.r_width, pix_size.r_height,
635 PIX_SRC ^ PIX_DST, cset_pr, 0, 0);
636
637 CsetOn = !CsetOn;
638 }
639
640
641 /*
642 * Make current set on.
643 */
GRCurrentSetOn()644 GRCurrentSetOn()
645 {
646 if (!CsetOn)
647 GRCurrentSet();
648 }
649
650
651 /*
652 * Make current set off.
653 */
GRCurrentSetOff()654 GRCurrentSetOff()
655 {
656 if (CsetOn)
657 GRCurrentSet();
658 }
659
660
661 /*
662 * Return TRUE if font file exists and is readable.
663 */
GRfontfound(font,size)664 GRfontfound(font, size)
665 register font, size;
666 {
667 return(font_info[font-1][size-1] != (char *) -1);
668 }
669
670
671 /*
672 * Open the default font file on startup.
673 */
GRFontInit()674 GRFontInit()
675 {
676 /* create memory pixrect template for displaying text with GRPutText() */
677 if ((char_pr = mem_create(1, 1, 1)) == NULL) {
678 printf("GRFontInit: can't create char_pr\n");
679 exit(1);
680 }
681
682 GROpenFont(CFONT, CSIZE);
683 GRStippleInit();
684 } /* end GRFontInit */
685
686
687 /*
688 * Initialize stipple patterns from font file.
689 * Big assumption: all stipples are defined by 32 x 32 bit patterns.
690 * All fonts do not contain exactly 32 rows of 4 bytes - this is ok -
691 * Fonts wider than 32 bits will be clipped.
692 */
GRStippleInit()693 GRStippleInit()
694 {
695 register struct mpr_data *mpr_data;
696 register char *from, *to;
697 register char *fbase;
698 register i, j, k;
699 struct dispatch *dispatch, *dstart;
700 int width, height, bytewidth;
701 char *stipple_info;
702 char name[128];
703
704 (void) sprintf(name, "%s%s.0", stippledir, stippletype);
705
706 if ((stipple_info = GRReadFontFile(name)) == (char *) -1) {
707 /*
708 * use default stipple pixrects since we can't read the
709 * user specified stipple font file.
710 * copy stipple pixrects to stipple_patterns for display
711 */
712 for (i=0; i<NSTIPPLES; i++)
713 GRCopyStipple(i);
714
715 return;
716 }
717
718 dstart = (struct dispatch *) (stipple_info + sizeof(struct header));
719 fbase = (char *) ((char *) dstart + NUM_DISPATCH * sizeof(struct dispatch));
720
721 for (i=0; i<NSTIPPLES; i++) {
722 mpr_data = (struct mpr_data *) stipple_prs[i]->pr_data;
723 dispatch = dstart + stipple_index[i];
724 if (dispatch->nbytes != 0) {
725 width = dispatch->left + dispatch->right;
726 height = dispatch->up + dispatch->down;
727 bytewidth = (width + 7) >> 3;
728 if (bytewidth > 4) /* force size constraint */
729 bytewidth = 4; /* pattern screwed up if ever > 4 */
730
731 from = (char *) ((char *) fbase + dispatch->addr);
732 to = stipple_patterns[i];
733
734 for (j=1; j<=height; j++) { /* copy font entry to known location */
735 for (k=1; k<=bytewidth; k++)
736 *to++ = *from++;
737 for ( ;k<=4; k++)
738 *to++ = '\0';
739 }
740
741 for ( ; j<=32; j++) /* fix up any non- 32 x 32 font */
742 for (k=1; k<=4; k++)
743 *to++ = '\0';
744
745 /* copy vfont stipple to stipple pixrect for menu display */
746 /* can only display a 16 x 16 menu icon */
747 from = stipple_patterns[i];
748 to = (char *) mpr_data->md_image;
749 for (j=0; j<16; j++) {
750 *to++ = *from++;
751 *to++ = *from++;
752 from += 2;
753 }
754 }
755 else {
756 (void) sprintf(name, "stipple index=%d not defined",
757 stipple_index[i]);
758 error(name);
759
760 /* copy stipple pixrect to stipple_patterns for display */
761 GRCopyStipple(i);
762 }
763 }
764
765 /* bit maps are all in core now */
766 free(stipple_info);
767
768 /* set up parameters for drawing polygons */
769 mpr_data = (struct mpr_data *) scratch_pr->pr_data;
770 bytesperline = mpr_data->md_linebytes;
771 fill = (char *) mpr_data->md_image;
772 rasterlength = bytesperline << 3;
773 nlines = scratch_pr->pr_size.x;
774 } /* end GRStippleInit */;
775
776
777 /*
778 * Copy the stipple bit map image as defined in the menu pixrect
779 * to the bit maps used for drawing polygons. The pixrect bit map
780 * is 16 x 16 bits and the target bit map is 32 x 32 bits. The
781 * image is expanded appropriately.
782 */
GRCopyStipple(index)783 GRCopyStipple(index)
784 int index;
785 {
786 register struct mpr_data *mpr_data;
787 register char *from, *to;
788 register i, j;
789
790 mpr_data = (struct mpr_data *) stipple_prs[index]->pr_data;
791 from = (char *) mpr_data->md_image;
792 to = stipple_patterns[index];
793
794 for (i=0; i<16; i++) {
795 j = i << 2;
796 to[j] = to[j+2] = to[j+64] = to[j+66] = *from++;
797 to[j+1] = to[j+3] = to[j+65] = to[j+67] = *from++;
798 }
799 }
800
801
802 /*
803 * Open a font file for use by first reading it into memory.
804 * If the file is read successfully, the appropriate entry in
805 * font_info[] is set to point to its memory image. If the
806 * file cannot be opened or there is a error in reading the
807 * file, set the font_info[] entry to -1.
808 */
GROpenFont(font,size)809 GROpenFont(font, size)
810 register font; /* font is 1 to 4 */
811 register size; /* size is 1 to 4 */
812 {
813 char name[128];
814
815 if (font_info[--font][--size] != NULL) /* already tried to open */
816 return;
817
818 sprintf(name, "%s%s.%d", fontdir, font_types[font], font_sizes[size]);
819
820 if ((font_info[font][size] = GRReadFontFile(name)) == (char *) -1)
821 return;
822
823 /* height of this font/size combination */
824 charysizes[font][size] = ((struct header *) font_info[font][size])->maxy;
825 } /* end GROpenFont */
826
827
828 /*
829 * Read a font file into memory and return a pointer to its
830 * memory image, or -1 if any error occurs.
831 */
832 char *
GRReadFontFile(file)833 GRReadFontFile(file)
834 char *file;
835 {
836 char *image; /* pointer to font memory image */
837 char msg[128];
838 struct header header;
839 int fd, filesize;
840
841 if ((fd = open(file, 0)) < 0) {
842 sprintf(msg, "can't open font file: %s", file);
843 error(msg);
844 return((char *) -1);
845 }
846
847 if (read(fd, &header, sizeof(struct header)) != sizeof(struct header)) {
848 sprintf(msg, "can't read font header: %s\n", file);
849 error(msg);
850 return((char *) -1);
851 }
852
853 if (header.magic != VFONT_MAGIC) {
854 sprintf(msg, "bad magic number %o in font file\n", header.magic);
855 error(msg);
856 return((char *) -1);
857 }
858
859 filesize = (sizeof(struct header) +
860 sizeof(struct dispatch) * NUM_DISPATCH + header.size);
861
862 if ((image = malloc(filesize)) == NULL) {
863 error("not enough memory for font file");
864 return((char *) -1);
865 }
866
867 lseek(fd, (long) 0, 0);
868
869 if (read(fd, image, filesize) != filesize) {
870 error("can't read font file");
871 return((char *) -1);
872 }
873
874 close(fd);
875 return(image);
876 } /* end GRReadFontFile */
877
878
879 /*
880 * Determine pixel length of string s in font and size.
881 */
GRFontStrlen(text,font,size)882 GRFontStrlen(text, font, size)
883 char *text;
884 int font; /* 1 - 4 */
885 int size; /* 1 - 4 */
886 {
887 register struct dispatch *dispatch, *start;
888 register length, spacewidth;
889
890 if (*text == '\0')
891 return(0);
892
893 if (font_info[font-1][size-1] == NULL) /* not open yet */
894 GROpenFont(font, size);
895
896 if (!GRfontfound(font, size)) /* unreadable font */
897 return(0);
898
899 start = (struct dispatch *) (font_info[font-1][size-1] +
900 sizeof(struct header));
901 spacewidth = font_sizes[size-1] * (120.0 / 216.0) + 0.5;
902 length = 0;
903 while (*text != '\0') {
904 dispatch = start + (*text);
905
906 if (*text == ' ')
907 length += spacewidth;
908 else if (dispatch->nbytes != 0)
909 length += dispatch->width;
910
911 text++;
912 }
913
914 return(length);
915 }
916
917 /*
918 * Display text string of font/size at position pos.
919 */
GRPutText(text,font,size,pos)920 GRPutText(text, font, size, pos)
921 char *text;
922 int font, size;
923 POINT *pos;
924 {
925 register struct dispatch *dispatch, *dstart;
926 register struct mpr_data *mpr_data;
927 register char *fbase;
928 register width, height, spacewidth;
929 int x, y;
930
931 if (font_info[font-1][size-1] == NULL)
932 GROpenFont(font, size);
933
934 if (!GRfontfound(font, size))
935 return;
936
937 dstart = (struct dispatch *) (font_info[font-1][size-1] +
938 sizeof(struct header));
939 fbase = (char *) ((char *) dstart + NUM_DISPATCH * sizeof(struct dispatch));
940
941 x = dbx_to_win(pos->x);
942 y = dby_to_win(pos->y);
943
944 /* define region of screen to be drawn with text */
945 minsunx = x;
946 maxsuny = y + 8; /* catch descenders */
947 minsuny = y - GRGetCharYSize(font, size);
948
949 spacewidth = font_sizes[size-1] * (120.0 / 216.0) + 0.5;
950 mpr_data = (struct mpr_data *) char_pr->pr_data;
951 while (*text != '\0') {
952 dispatch = dstart + (*text);
953
954 if (*text == ' ')
955 x += spacewidth;
956 else if (dispatch->nbytes != 0) {
957 mpr_data->md_image = (short *) ((char *) fbase + dispatch->addr);
958 char_pr->pr_size.x = width = dispatch->left + dispatch->right;
959 char_pr->pr_size.y = height = dispatch->up + dispatch->down;
960 mpr_data->md_linebytes = ((width + 15) >> 3) & ~1;
961
962 if (*text != ' ')
963 pr_rop(scratch_pr, x - dispatch->left, y - dispatch->up,
964 width, height, PIX_SRC ^ PIX_DST, char_pr, 0, 0);
965 x += dispatch->width;
966 }
967
968 text++;
969 }
970
971 maxsunx = x;
972 } /* end GRPutText */;
973
974
975 /*
976 * Set the actual positioning point for text with the justify, font, and
977 * size attributes. Point is a pointer to the POINT layed down by the user.
978 * Pos is a pointer to the returned positioning POINT used in a subsequent
979 * call to GRPutText().
980 */
GRSetTextPos(text,justify,font,size,point,pos)981 GRSetTextPos(text, justify, font, size, point, pos)
982 char *text;
983 int justify, font, size;
984 POINT *point, *pos;
985 {
986 register length;
987 register charysize;
988
989 charysize = GRGetCharYSize(font, size);
990 length = GRFontStrlen(text, font, size);
991
992 switch (justify) {
993 case BOTLEFT:
994 pos->x = point->x;
995 pos->y = point->y;
996 break;
997 case BOTCENT:
998 pos->x = point->x - (length / 2);
999 pos->y = point->y;
1000 break;
1001 case BOTRIGHT:
1002 pos->x = point->x - length;
1003 pos->y = point->y;
1004 break;
1005 case CENTLEFT:
1006 pos->x = point->x;
1007 pos->y = point->y - (charysize / 2);
1008 break;
1009 case CENTCENT:
1010 pos->x = point->x - (length / 2);
1011 pos->y = point->y - (charysize / 2);
1012 break;
1013 case CENTRIGHT:
1014 pos->x = point->x - length;
1015 pos->y = point->y - (charysize / 2);
1016 break;
1017 case TOPLEFT:
1018 pos->x = point->x;
1019 pos->y = point->y - charysize;
1020 break;
1021 case TOPCENT:
1022 pos->x = point->x - (length / 2);
1023 pos->y = point->y - charysize;
1024 break;
1025 case TOPRIGHT:
1026 pos->x = point->x - length;
1027 pos->y = point->y - charysize;
1028 break;
1029 }
1030 }
1031