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 */ 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 */ 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 */ 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 620 GRBlankGrid() 621 { 622 GRDisplayGrid(); 623 } /* end GRBlankGrid */ 624 625 626 /* 627 * Flash current set display. 628 */ 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 */ 644 GRCurrentSetOn() 645 { 646 if (!CsetOn) 647 GRCurrentSet(); 648 } 649 650 651 /* 652 * Make current set off. 653 */ 654 GRCurrentSetOff() 655 { 656 if (CsetOn) 657 GRCurrentSet(); 658 } 659 660 661 /* 662 * Return TRUE if font file exists and is readable. 663 */ 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 */ 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 */ 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 */ 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 */ 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 * 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 */ 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 */ 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 */ 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