1 /*
2 * plotRastUtils.c --
3 *
4 * This file contains several procedures for manipulating rasters.
5 * The procedures are used to create bitmaps to directly drive
6 * printers such as the black-and-white Versatec. For example,
7 * the procedures draw stippled areas and raster-ize text strings
8 * using fonts.
9 *
10 * *********************************************************************
11 * * Copyright (C) 1985, 1990 Regents of the University of California. *
12 * * Permission to use, copy, modify, and distribute this *
13 * * software and its documentation for any purpose and without *
14 * * fee is hereby granted, provided that the above copyright *
15 * * notice appear in all copies. The University of California *
16 * * makes no representations about the suitability of this *
17 * * software for any purpose. It is provided "as is" without *
18 * * express or implied warranty. Export of this software outside *
19 * * of the United States of America may require an export license. *
20 * *********************************************************************
21 */
22
23 #ifndef lint
24 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/plot/plotRutils.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
25 #endif /* not lint */
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "utils/magic.h"
32 #include "utils/geometry.h"
33 #include "utils/geofast.h"
34 #include "tiles/tile.h"
35 #include "utils/hash.h"
36 #include "database/database.h"
37 #include "utils/malloc.h"
38 #include "plot/plotInt.h"
39 #include "textio/textio.h"
40 #include "utils/utils.h"
41
42 extern double sqrt();
43
44 int rasFileByteCount = 0;
45 /* A solid black stipple: */
46
47 Stipple PlotBlackStipple =
48 {
49 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
50 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
51 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
52 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
53 };
54
55 /* The following two arrays are used to select a range of bits within
56 * a word. The first array selects all the bits at or to the left of
57 * the given bit-position. "To the left" means in a lower-numbered
58 * byte (according to byte order) or in a more significant bit of the
59 * same byte. The second array selects the bits at or to the right of
60 * the given bit-position. Bit position 0 is considered to be the
61 * leftmost bit of the word; it's the highest-order bit in the 0th
62 * byte.
63 */
64
65 static unsigned int leftBits[32] =
66 {
67 0x00000080, 0x000000c0, 0x000000e0, 0x000000f0,
68 0x000000f8, 0x000000fc, 0x000000fe, 0x000000ff,
69 0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff,
70 0x0000f8ff, 0x0000fcff, 0x0000feff, 0x0000ffff,
71 0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff,
72 0x00f8ffff, 0x00fcffff, 0x00feffff, 0x00ffffff,
73 0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff,
74 0xf8ffffff, 0xfcffffff, 0xfeffffff, 0xffffffff
75 };
76 static unsigned int rightBits[32] =
77 {
78 0xffffffff, 0xffffff7f, 0xffffff3f, 0xffffff1f,
79 0xffffff0f, 0xffffff07, 0xffffff03, 0xffffff01,
80 0xffffff00, 0xffff7f00, 0xffff3f00, 0xffff1f00,
81 0xffff0f00, 0xffff0700, 0xffff0300, 0xffff0100,
82 0xffff0000, 0xff7f0000, 0xff3f0000, 0xff1f0000,
83 0xff0f0000, 0xff070000, 0xff030000, 0xff010000,
84 0xff000000, 0x7f000000, 0x3f000000, 0x1f000000,
85 0x0f000000, 0x07000000, 0x03000000, 0x01000000
86 };
87
88 /* The following arrray selects a single bit within a word. The
89 * zeroth entry selects the bit that will be leftmost in the plot.
90 */
91 static unsigned int singleBit[32] =
92 {
93 0x00000080, 0x00000040, 0x00000020, 0x00000010,
94 0x00000008, 0x00000004, 0x00000002, 0x00000001,
95 0x00008000, 0x00004000, 0x00002000, 0x00001000,
96 0x00000800, 0x00000400, 0x00000200, 0x00000100,
97 0x00800000, 0x00400000, 0x00200000, 0x00100000,
98 0x00080000, 0x00040000, 0x00020000, 0x00010000,
99 0x80000000, 0x40000000, 0x20000000, 0x10000000,
100 0x08000000, 0x04000000, 0x02000000, 0x01000000
101 };
102
103 RasterFont *PlotFontList; /* Linked list of all fonts that have
104 * been read in so far.
105 */
106
107 /*
108 * ----------------------------------------------------------------------------
109 *
110 * PlotRastInit --
111 *
112 * Initialize data structures related to rasters.
113 *
114 * Results:
115 * None.
116 *
117 * Side effects:
118 * All this procedure does is to swap bytes in the stipple
119 * masks if we're running on a non-VAX.
120 *
121 * ----------------------------------------------------------------------------
122 */
123
124 void
PlotRastInit()125 PlotRastInit()
126 {
127 #ifdef WORDS_BIGENDIAN
128 int i;
129
130 for (i = 0; i < 32; i++)
131 {
132 leftBits[i] = PlotSwapBytes(leftBits[i]);
133 rightBits[i] = PlotSwapBytes(rightBits[i]);
134 singleBit[i] = PlotSwapBytes(singleBit[i]);
135 }
136 #endif /* WORDS_BIGENDIAN */
137 }
138
139 /*
140 * ----------------------------------------------------------------------------
141 *
142 * PlotNewRaster --
143 *
144 * Allocate and initialize a new raster structure.
145 *
146 * Results:
147 * The return value is a pointer to the new raster object.
148 *
149 * Side effects:
150 * Memory is allocated.
151 *
152 * ----------------------------------------------------------------------------
153 */
154
155 Raster *
PlotNewRaster(height,width)156 PlotNewRaster(height, width)
157 int height; /* Raster's height in pixels. Should generally
158 * be a multiple of 16.
159 */
160 int width; /* Raster's width in pixels. Should generally
161 * be a multiple of 32 bits.
162 */
163 {
164 Raster *new;
165
166 new = (Raster *) mallocMagic(sizeof(Raster));
167 new->ras_width = width;
168 new->ras_intsPerLine = (width+31)/32;
169 new->ras_bytesPerLine = new->ras_intsPerLine*4;
170 new->ras_height = height;
171 new->ras_bits = (int *) mallocMagic(
172 (unsigned) (height * new->ras_intsPerLine * 4));
173
174 return new;
175 }
176
177 /*
178 * ----------------------------------------------------------------------------
179 *
180 * PlotFreeRaster --
181 *
182 * Frees up the memory associated with an existing raster structure.
183 *
184 * Results:
185 * None.
186 *
187 * Side effects:
188 * The storage associated with raster is returned to the allocator.
189 *
190 * ----------------------------------------------------------------------------
191 */
192
193 void
PlotFreeRaster(raster)194 PlotFreeRaster(raster)
195 Raster *raster; /* Raster whose memory is to be freed. Should
196 * have been created with PlotNewRaster.
197 */
198 {
199 if (raster == NULL) return;
200 freeMagic((char *) raster->ras_bits);
201 freeMagic((char *) raster);
202 }
203
204 /*
205 * ----------------------------------------------------------------------------
206 *
207 * PlotClearRaster --
208 *
209 * This procedure clears out an area of the raster.
210 *
211 * Results:
212 * None.
213 *
214 * Side effects:
215 * The area of the raster indicated by "area" is set to all zeroes.
216 *
217 * ----------------------------------------------------------------------------
218 */
219
220 void
PlotClearRaster(raster,area)221 PlotClearRaster(raster, area)
222 Raster *raster; /* Raster that's to be cleared. */
223 Rect *area; /* Area to be cleared, in raster
224 * coords. NULL means clear the
225 * whole raster.
226 */
227 {
228 int *left, *right, *cur;
229 int leftMask, rightMask, line;
230
231 if (area == NULL)
232 {
233 bzero((char *) raster->ras_bits,
234 raster->ras_bytesPerLine * raster->ras_height);
235 return;
236 }
237
238 /* Compute the address of the leftmost word in the topmost line
239 * to be cleared, and the rightmost word in the topmost line to
240 * be cleared.
241 */
242
243 left = raster->ras_bits +
244 ((raster->ras_height-1) - area->r_ytop)*raster->ras_intsPerLine;
245 right = left + area->r_xtop/32;
246 left += area->r_xbot/32;
247
248 /* Divide the x-span of the area into three parts: the leftmost
249 * word, of which only the rightmost bits are cleared, the
250 * rightmost word, of which only the leftmost bits are cleared,
251 * and the middle section, in which all bits of each word are
252 * cleared. Compute masks that determine which bits of the end
253 * words will be cleared. There's a special case when the left
254 * and right ends are in the same word.
255 */
256
257 leftMask = rightBits[area->r_xbot&037];
258 rightMask = leftBits[area->r_xtop&037];
259 if (left == right)
260 leftMask &= rightMask;
261
262 /* Clear the area one raster line at a time, top to bottom. */
263
264 for (line = area->r_ytop; line >= area->r_ybot; line -= 1)
265 {
266 /* Clear the leftmost word on this line. */
267
268 *left &= ~leftMask;
269
270 if (left != right)
271 {
272 /* Clear the center of the line. */
273
274 for (cur = left+1; cur < right; cur += 1)
275 *cur = 0;
276
277 /* Clear the rightmost word on this line. */
278
279 *cur &= ~rightMask;
280 }
281
282 left += raster->ras_intsPerLine;
283 right += raster->ras_intsPerLine;
284 }
285 }
286
287 /*
288 * ----------------------------------------------------------------------------
289 *
290 * PlotPolyRaster --
291 *
292 * Fill a polygonal raster area, given the area of a triangular
293 * tile (in pixel coordinates), information about what side and
294 * direction are filled, and the area to clip to (also in raster
295 * coordinates). This is *not* a general-purpose polygon-filling
296 * routine. It can only handle clipped right triangles.
297 *
298 * Results:
299 * None.
300 *
301 * Side effects:
302 * None.
303 *
304 * ----------------------------------------------------------------------------
305 */
306
307 void
PlotPolyRaster(raster,tileArea,clipArea,dinfo,stipple)308 PlotPolyRaster(raster, tileArea, clipArea, dinfo, stipple)
309 Raster *raster; /* Pointer to raster whose bits are
310 * to be filled in.
311 */
312 Rect *tileArea; /* Area of split tile, in pixel coordinates */
313 Rect *clipArea; /* Area to clip, in pixel coordinates */
314 TileType dinfo; /* Split tile side and direction information */
315 Stipple stipple; /* Stipple pattern to be used to fill
316 * in the raster area.
317 */
318 {
319 int *cur, *rasleft, *tbase, *right, *left;
320 int leftMask, rightMask, curStipple;
321 int line, width, height, locleft, locright;
322 Rect area;
323
324 /* Compute the address of the leftmost word in the topmost line
325 * to be filled, and the rightmost word in the topmost line to
326 * be filled.
327 */
328
329 area = *tileArea;
330 GEOCLIP(&area, clipArea);
331
332 /* Ensure that we have not been clipped out of existence */
333 if (area.r_xbot > area.r_xtop) return;
334 if (area.r_ybot >= area.r_ytop) return;
335
336 rasleft = raster->ras_bits +
337 ((raster->ras_height-1) - area.r_ytop)*raster->ras_intsPerLine;
338 width = tileArea->r_xtop - tileArea->r_xbot;
339 height = tileArea->r_ytop - tileArea->r_ybot;
340
341 /* Process the stippled area one raster line at a time, top to bottom. */
342
343 if (dinfo & TT_SIDE)
344 {
345 locright = area.r_xtop;
346 tbase = rasleft + area.r_xtop / 32; /* base is on right */
347 }
348 else
349 {
350 locleft = area.r_xbot;
351 tbase = rasleft + area.r_xbot / 32; /* base is on left */
352 }
353
354 for (line = area.r_ytop; line >= area.r_ybot; line -= 1)
355 {
356 if (dinfo & TT_SIDE)
357 {
358 if (dinfo & TT_DIRECTION)
359 locleft = tileArea->r_xbot + (((tileArea->r_ytop - line) * width)
360 / height);
361 else
362 locleft = tileArea->r_xbot + (((line - tileArea->r_ybot) * width)
363 / height);
364 right = tbase;
365 left = rasleft + locleft / 32;
366 }
367 else
368 {
369 if (dinfo & TT_DIRECTION)
370 locright = tileArea->r_xbot + (((tileArea->r_ytop - line) * width)
371 / height);
372 else
373 locright = tileArea->r_xbot + (((line - tileArea->r_ybot) * width)
374 / height);
375 right = rasleft + locright / 32;
376 left = tbase;
377 }
378 if (left > right) continue;
379
380 leftMask = rightBits[locleft & 037];
381 rightMask = leftBits[locright & 037];
382 if (left == right)
383 leftMask &= rightMask;
384
385 curStipple = stipple[(-line)&017];
386
387 /* Fill the leftmost word on this line. */
388
389 *left |= curStipple & leftMask;
390
391 if (left != right)
392 {
393 /* Fill the center of the line. */
394
395 for (cur = left+1; cur < right; cur += 1)
396 *cur |= curStipple;
397
398 /* Fill the rightmost word on this line. */
399
400 *cur |= curStipple & rightMask;
401 }
402
403 rasleft += raster->ras_intsPerLine;
404 tbase += raster->ras_intsPerLine;
405 }
406 }
407
408 /*
409 * ----------------------------------------------------------------------------
410 *
411 * PlotFillRaster --
412 *
413 * Given a raster and an area, this procedure fills the given area
414 * of the raster with a particular stipple pattern.
415 *
416 * Results:
417 * None.
418 *
419 * Side effects:
420 * None.
421 *
422 * ----------------------------------------------------------------------------
423 */
424
425 void
PlotFillRaster(raster,area,stipple)426 PlotFillRaster(raster, area, stipple)
427 Raster *raster; /* Pointer to raster whose bits are
428 * to be filled in.
429 */
430 Rect *area; /* Area to be filled in pixel coords.
431 * This is an inclusive area: it
432 * includes the boundary pixels. The
433 * caller must ensure that it is
434 * clipped to the raster area.
435 */
436 Stipple stipple; /* Stipple pattern to be used to fill
437 * in the raster area.
438 */
439 {
440 int *left, *cur, line;
441 int *right;
442 int leftMask, rightMask, curStipple;
443
444 /* Compute the address of the leftmost word in the topmost line
445 * to be filled, and the rightmost word in the topmost line to
446 * be filled.
447 */
448
449 left = raster->ras_bits +
450 ((raster->ras_height-1) - area->r_ytop)*raster->ras_intsPerLine;
451 right = left + area->r_xtop/32;
452 left += area->r_xbot/32;
453
454 /* Divide the x-span of the area into three parts: the leftmost
455 * word, of which only the rightmost bits are modified, the
456 * rightmost word, of which only the leftmost bits are modified,
457 * and the middle section, in which all bits of each word are
458 * modified. Compute masks that determine which bits of the end
459 * words will be modified. There's a special case when the left
460 * and right ends are in the same word.
461 */
462
463 leftMask = rightBits[area->r_xbot&037];
464 rightMask = leftBits[area->r_xtop&037];
465 if (left == right)
466 leftMask &= rightMask;
467
468 /* Process the stippled area one raster line at a time, top to bottom. */
469
470 for (line = area->r_ytop; line >= area->r_ybot; line -= 1)
471 {
472 curStipple = stipple[(-line)&017];
473
474 /* Fill the leftmost word on this line. */
475
476 *left |= curStipple & leftMask;
477
478 if (left != right)
479 {
480 /* Fill the center of the line. */
481
482 for (cur = left+1; cur < right; cur += 1)
483 *cur |= curStipple;
484
485 /* Fill the rightmost word on this line. */
486
487 *cur |= curStipple & rightMask;
488 }
489
490 left += raster->ras_intsPerLine;
491 right += raster->ras_intsPerLine;
492 }
493 }
494
495 /*
496 * ----------------------------------------------------------------------------
497 *
498 * PlotDumpRaster --
499 *
500 * Writes out the contents of the given raster to the given file,
501 * in binary format.
502 *
503 * Results:
504 * Returns 0 if all was well. Returns non-zero if there was
505 * an I/O error. In this event, this procedure prints an
506 * error message before returning.
507 *
508 * Side effects:
509 * Information is added to file.
510 *
511 * ----------------------------------------------------------------------------
512 */
513
514 int
PlotDumpRaster(raster,file)515 PlotDumpRaster(raster, file)
516 Raster *raster; /* Raster to be dumped. */
517 FILE *file; /* File in which to dump it. */
518 {
519 int count;
520
521 count = write(fileno(file), (char *) raster->ras_bits,
522 raster->ras_bytesPerLine*raster->ras_height);
523 if (count < 0)
524 {
525 TxError("I/O error in writing raster file: %s.\n",
526 strerror(errno));
527 return 1;
528 }
529 rasFileByteCount += count;
530 return 0;
531 }
532
533 /*
534 * ----------------------------------------------------------------------------
535 *
536 * PlotLoadFont --
537 *
538 * Loads a font into memory, if it isn't already there.
539 *
540 ** Patched to accommodate both VAX format and Sun format vfont(5) files,
541 ** regardless of the native byte order of the processor. J. Gealow 3/30/94
542 *
543 * Results:
544 * The return value is a pointer to the font. This must be used
545 * when calling procedures like PlotTextSize. If the font file
546 * couldn't be found, an error message is output and NULL is
547 * returned.
548 *
549 * Side effects:
550 * New memory gets allocated.
551 *
552 * ----------------------------------------------------------------------------
553 */
554
555 RasterFont *
PlotLoadFont(name)556 PlotLoadFont(name)
557 char *name; /* Name of font file. */
558 {
559 FILE *f;
560 RasterFont *new;
561 struct dispatch *d;
562
563 /* See if we've already got the font. */
564
565 for (new = PlotFontList; new != NULL; new = new->fo_next)
566 {
567 if (strcmp(new->fo_name, name) == 0)
568 return new;
569 }
570
571 f = PaOpen(name, "r", (char *) NULL, ".", SysLibPath, (char **) NULL);
572 if (f == NULL)
573 {
574 TxError("Couldn't read font file \"%s\".\n", name);
575 return NULL;
576 }
577
578 new = (RasterFont *) mallocMagic(sizeof(RasterFont));
579 new->fo_name = NULL;
580 StrDup(&new->fo_name, name);
581
582 /* Read in the font's header and check the magic number. */
583
584 if (read(fileno(f), (char *) &new->fo_hdr, sizeof(new->fo_hdr))
585 != sizeof(new->fo_hdr))
586 {
587 fontError:
588 TxError("Error in reading font file \"%s\".\n", name);
589 fclose(f);
590 return NULL;
591 }
592 if (PlotSwapShort(new->fo_hdr.magic) == 0436)
593 {
594 new->fo_hdr.size = (PlotSwapShort(new->fo_hdr.size));
595 new->fo_hdr.maxx = (PlotSwapShort(new->fo_hdr.maxx));
596 new->fo_hdr.maxy = (PlotSwapShort(new->fo_hdr.maxy));
597 new->fo_hdr.xtend = (PlotSwapShort(new->fo_hdr.xtend));
598 }
599 else if (new->fo_hdr.magic != 0436)
600 {
601 TxError("Bad magic number in font file \"%s\".\n", name);
602 fclose(f);
603 return NULL;
604 }
605
606 /* Read the character descriptors and the bit map. */
607
608 if (read(fileno(f), (char *) new->fo_chars, sizeof(new->fo_chars))
609 != sizeof(new->fo_chars))
610 goto fontError;
611 new->fo_bits = mallocMagic(new->fo_hdr.size);
612 if (read(fileno(f), new->fo_bits, (unsigned) new->fo_hdr.size)
613 != new->fo_hdr.size)
614 goto fontError;
615 fclose(f);
616
617 /* Compute the bounding box of all characters in the font. */
618
619 new->fo_bbox.r_xbot = new->fo_bbox.r_xtop = 0;
620 new->fo_bbox.r_ybot = new->fo_bbox.r_ytop = 0;
621 for (d = &new->fo_chars[0]; d < &new->fo_chars[256]; d++)
622 {
623 if (PlotSwapShort(new->fo_hdr.magic) == 0436)
624 {
625 d->addr = PlotSwapShort(d->addr);
626 d->nbytes = PlotSwapShort(d->nbytes);
627 d->width = PlotSwapShort(d->width);
628 }
629 if (d->nbytes == 0) continue;
630 if (d->up > new->fo_bbox.r_ytop)
631 new->fo_bbox.r_ytop = d->up;
632 if (d->down > new->fo_bbox.r_ybot)
633 new->fo_bbox.r_ybot = d->down;
634 if (d->right > new->fo_bbox.r_xtop)
635 new->fo_bbox.r_xtop = d->right;
636 if (d->left > new->fo_bbox.r_xbot)
637 new->fo_bbox.r_xbot = d->left;
638 #ifdef DEBUG_FONT
639 if (d == &new->fo_chars['d'])
640 {
641 char *fontcp;
642 int count;
643
644 TxError("Character 'd' in font '%s' is at addr 0x%x, bytes %d, width %d\n",
645 new->fo_name, d->addr, d->nbytes, d->width);
646 count = 0;
647 for (fontcp = new->fo_bits + d->addr;
648 fontcp < new->fo_bits + d->addr + d->nbytes; fontcp++)
649 {
650 int i;
651 char ch;
652 ch = *fontcp;
653 for (i = 0; i < 8; i++)
654 {
655 TxError("%c", ((ch & 0x80) ? 'X' : '.'));
656 ch = (ch << 1);
657 }
658 count++;
659 if (count >= (d->left + d->right + 7) >> 3)
660 {
661 TxError("\n");
662 count = 0;
663 }
664 }
665 TxError("\n");
666 }
667 #endif /* DEBUG_FONT */
668 }
669 new->fo_bbox.r_xbot = - new->fo_bbox.r_xbot;
670 new->fo_bbox.r_ybot = - new->fo_bbox.r_ybot;
671
672 new->fo_next = PlotFontList;
673 PlotFontList = new;
674 return new;
675 }
676
677 /*
678 * ----------------------------------------------------------------------------
679 *
680 * PlotTextSize --
681 *
682 * Compute the area that a string will occupy.
683 *
684 * Results:
685 * None.
686 *
687 * Side effects:
688 * The rectangle "area" is filled in with the bounding
689 * box of the bits in "string", assuming that the origin
690 * for the text is (0,0) and the text is rendered in font
691 * "font".
692 *
693 * ----------------------------------------------------------------------------
694 */
695
696 void
PlotTextSize(font,string,area)697 PlotTextSize(font, string, area)
698 RasterFont *font; /* Font to use in computing text size. */
699 char *string; /* String to compute size of. */
700 Rect *area; /* Place to store bounding box. */
701 {
702 int x;
703 struct dispatch *d;
704
705 area->r_xbot = area->r_xtop = 0;
706 area->r_ybot = area->r_ytop = 0;
707 x = 0;
708
709 for ( ; *string != 0; string ++)
710 {
711 if ((*string == ' ') || (*string == '\t'))
712 d = &font->fo_chars['t'];
713 else d = &font->fo_chars[*string];
714 if (d->nbytes == 0) continue;
715 if (d->up > area->r_ytop)
716 area->r_ytop = d->up;
717 if (d->down > area->r_ybot)
718 area->r_ybot = d->down;
719 if ((x+d->right) > area->r_xtop)
720 area->r_xtop = x + d->right;
721 if ((x-d->left) < area->r_ybot)
722 area->r_ybot = x - d->left;
723 x += d->width;
724 }
725 area->r_ybot = -area->r_ybot;
726 }
727
728 /*
729 * ----------------------------------------------------------------------------
730 *
731 * PlotRasterText --
732 *
733 * Given a text string and a font, this procedure scan-converts
734 * the string and sets bits in the current raster that correspond
735 * to on-bits in the text.
736 *
737 * Results:
738 * None.
739 *
740 * Side effects:
741 * Bits are modified in the raster.
742 *
743 * ----------------------------------------------------------------------------
744 */
745
746 void
PlotRasterText(raster,clip,font,string,point)747 PlotRasterText(raster, clip, font, string, point)
748 Raster *raster; /* Raster whose bits are to be filled in. */
749 Rect *clip; /* Area to which to clip the text. Must be
750 * entirely within the area of the raster.
751 */
752 RasterFont *font; /* Font to use for rasterizing string. Must
753 * have been obtained by calling PlotLoadFont.
754 */
755 char *string; /* String of text to rasterize. */
756 Point *point; /* X-Y coordinates of origin of text. The
757 * origin need not be inside the area of
758 * the raster, but only raster points inside
759 * the area will be modified.
760 */
761 {
762 int xOrig; /* X-origin for current character. */
763
764
765 /* Outer loop: process each character. */
766
767 xOrig = point->p_x;
768 for ( ; *string != 0; string++)
769 {
770 int cBytesPerLine, i;
771 struct dispatch *d; /* Descriptor for current character. */
772
773 /* Handle spaces and tabs specially by just spacing over. */
774
775 if ((*string == ' ') || (*string == '\t'))
776 {
777 xOrig += font->fo_chars['t'].width;
778 continue;
779 }
780
781 /* Middle loop: render each character one raster line at a
782 * time, from top to bottom. Skip rows that are outside the
783 * area of the raster.
784 */
785
786 d = &font->fo_chars[*string];
787 cBytesPerLine = (d->left + d->right + 7) >> 3;
788 for (i = 0; i < d->up + d->down; i++)
789 {
790 int y, j;
791 char *charBitPtr;
792
793 y = point->p_y + d->up - 1 - i;
794 if (y < clip->r_ybot) break;
795 if (y > clip->r_ytop) continue;
796
797 /* Inner loop: process a series of bytes in a row to
798 * render one raster line of one character. Be sure
799 * to skip areas that fall outside the raster to the
800 * left or right.
801 */
802
803 for (j = -d->left,
804 charBitPtr = font->fo_bits + d->addr + i*cBytesPerLine;
805 j < d->right;
806 j += 8, charBitPtr++)
807 {
808 char *rPtr;
809 int charBits, x;
810
811 x = xOrig + j;
812 if (x > clip->r_xtop) break;
813 if (x < clip->r_xbot - 7) continue;
814
815 rPtr = (char *) raster->ras_bits;
816 rPtr += (raster->ras_height - 1 - y)*raster->ras_bytesPerLine
817 + (x>>3);
818 charBits = *charBitPtr & 0xff;
819
820 /* One byte of the character's bit map may span two
821 * bytes of the raster, so process each of the two
822 * raster bytes separately. Either of the two bytes
823 * may be off the edge of the raster, in which case
824 * it must be skipped.
825 */
826
827 if (x >= 0)
828 *rPtr |= charBits >> (x & 0x7);
829 rPtr += 1;
830 if (x+8 <= clip->r_xtop)
831 {
832 charBits = charBits << (8 - (x & 0x7));
833 *rPtr |= charBits;
834 }
835 }
836 }
837
838 xOrig += d->width;
839 }
840 }
841
842 /*
843 * ----------------------------------------------------------------------------
844 *
845 * PlotRastPoint --
846 *
847 * Sets a particular pixel of a raster.
848 *
849 * Results:
850 * None.
851 *
852 * Side effects:
853 * If x and y lie inside the raster then the pixel that they select
854 * is set to 1. If x or y is outside the raster area then nothing
855 * happens.
856 *
857 * ----------------------------------------------------------------------------
858 */
859
860 void
PlotRastPoint(raster,x,y)861 PlotRastPoint(raster, x, y)
862 Raster *raster; /* Raster containing pixel to be
863 * filled.
864 */
865 int x, y; /* Coordinates of pixel. */
866 {
867 if ((x < 0) || (x >= raster->ras_width)) return;
868 y = (raster->ras_height - 1) - y;
869 if ((y < 0) || (y >= raster->ras_height)) return;
870
871 raster->ras_bits[((y*raster->ras_intsPerLine) + (x>>5))]
872 |= singleBit[x&037];
873 }
874
875 /*
876 * ----------------------------------------------------------------------------
877 *
878 * PlotRastLine --
879 *
880 * Draws a one-pixel-wide line between two points.
881 *
882 * Results:
883 * None.
884 *
885 * Side effects:
886 * A line is drawn between pixels src and dst. Only the portion
887 * of the line that lies inside the raster is drawn; the endpoints
888 * may lie outside the raster (this feature is necessary to draw
889 * straight lines that cross multiple swaths).
890 *
891 * ----------------------------------------------------------------------------
892 */
893
894 void
PlotRastLine(raster,src,dst)895 PlotRastLine(raster, src, dst)
896 Raster *raster; /* Where to render the line. */
897 Point *src; /* One endpoint of line, in raster coords. */
898 Point *dst; /* The other endpoint, in raster coords. */
899 {
900 int x, y, dx, dy, xinc, incr1, incr2, d, done;
901
902 /* Compute the total x- and y-motions, and arrange for the line to be
903 * drawn in increasing order of y-coordinate.
904 */
905
906 dx = dst->p_x - src->p_x;
907 dy = dst->p_y - src->p_y;
908 if (dy < 0)
909 {
910 dy = -dy;
911 dx = -dx;
912 x = dst->p_x;
913 y = dst->p_y;
914 dst = src;
915 }
916 else
917 {
918 x = src->p_x;
919 y = src->p_y;
920 }
921
922 /* The code below is just the Bresenham algorithm from Foley and
923 * Van Dam (pp. 435), modified slightly so that it can work in
924 * all directions.
925 */
926
927 if (dx < 0)
928 {
929 xinc = -1;
930 dx = -dx;
931 }
932 else xinc = 1;
933 if (dx >= dy)
934 {
935 d = 2*dy - dx;
936 incr1 = 2*dy;
937 incr2 = 2*(dy - dx);
938 done = dst->p_x;
939 for ( ; x != done ; x += xinc)
940 {
941 PlotRastPoint(raster, x, y);
942 if (d < 0)
943 d += incr1;
944 else
945 {
946 d += incr2;
947 y += 1;
948 }
949 }
950 }
951 else
952 {
953 d = 2*dx - dy;
954 incr1 = 2*dx;
955 incr2 = 2*(dx - dy);
956 done = dst->p_y;
957 for ( ; y != done ; y += 1)
958 {
959 PlotRastPoint(raster, x, y);
960 if (d < 0)
961 d += incr1;
962 else
963 {
964 d += incr2;
965 x += xinc;
966 }
967 }
968 }
969 PlotRastPoint(raster, x, y);
970 }
971
972 /*
973 * ----------------------------------------------------------------------------
974 *
975 * PlotRastFatLine --
976 *
977 * Draws a line many pixels wide between two points.
978 *
979 * Results:
980 * None.
981 *
982 * Side effects:
983 * A line is drawn between pixels src and dst. Only the portion
984 * of the line that lies inside the raster is drawn; the endpoints
985 * may lie outside the raster (this feature is necessary to draw
986 * straight lines that cross multiple swaths). The line is drawn
987 * several pixels wide, as determined by the "widen" parameter.
988 * The ends of the line are square, not rounded, which may cause
989 * upleasant effects for some uses. If the line is Manhattan,
990 * this procedure is very inefficient: it's better to use the
991 * PlotFillRaster procedure.
992 *
993 * ----------------------------------------------------------------------------
994 */
995
996 void
PlotRastFatLine(raster,src,dst,widen)997 PlotRastFatLine(raster, src, dst, widen)
998 Raster *raster; /* Where to render the line. */
999 Point *src; /* One endpoint of line, in raster coords. */
1000 Point *dst; /* The other endpoint, in raster coords. */
1001 int widen; /* How much to widen the line. 0 means the
1002 * line is one pixel wide, 1 means it's 3
1003 * pixels wide, and so on.
1004 */
1005 {
1006 double dx, dy, x, y;
1007 int nLines;
1008
1009 /* Just draw (2*widen) + 1 lines spaced about one pixel apart.
1010 * The first lines here compute how far apart to space the lines.
1011 */
1012
1013 nLines = (2*widen) + 1;
1014 x = dst->p_x - src->p_x;
1015 y = dst->p_y - src->p_y;
1016 dy = sqrt(x*x + y*y);
1017 dx = y/dy;
1018 dy = -x/dy;
1019 x = -dy*(widen);
1020 y = dx*(widen);
1021
1022 for (x = -dx*widen, y = -dy*widen;
1023 nLines > 0;
1024 nLines -= 1, x += dx, y += dy)
1025 {
1026 Point newSrc, newDst;
1027
1028 if (x > 0)
1029 newSrc.p_x = (x + .5);
1030 else newSrc.p_x = (x - .5);
1031 if (y > 0)
1032 newSrc.p_y = (y + .5);
1033 else newSrc.p_y = (y - .5);
1034 newDst.p_x = dst->p_x + newSrc.p_x;
1035 newDst.p_y = dst->p_y + newSrc.p_y;
1036 newSrc.p_x += src->p_x;
1037 newSrc.p_y += src->p_y;
1038
1039 PlotRastLine(raster, &newSrc, &newDst);
1040 }
1041 }
1042
1043 /*
1044 * ----------------------------------------------------------------------------
1045 *
1046 * PlotSwapBytes --
1047 * PlotSwapShort --
1048 *
1049 * These two procedures do byte swapping in the way that's
1050 * required when moving binary files between VAXes and Suns.
1051 *
1052 * Results:
1053 * Each procedure returns a value in which the order of bytes
1054 * has been reversed. PlotSwapBytes takes an integer and returns
1055 * an integer with the four bytes in reverse order; PlotSwapShort
1056 * takes a short and swaps the two bytes.
1057 *
1058 * Side effects:
1059 * None.
1060 *
1061 * ----------------------------------------------------------------------------
1062 */
1063
1064 int
PlotSwapBytes(value)1065 PlotSwapBytes(value)
1066 int value; /* 4-byte Value whose bytes are to
1067 * be reversed.
1068 */
1069 {
1070 int result;
1071
1072 #define src ((char *) &value)
1073 #define dst ((char *) &result)
1074
1075 dst[0] = src[3];
1076 dst[1] = src[2];
1077 dst[2] = src[1];
1078 dst[3] = src[0];
1079
1080 return result;
1081 }
1082
1083 short
PlotSwapShort(value)1084 PlotSwapShort(value)
1085 short value; /* Value whose bytes are to be swapped. */
1086 {
1087 short result;
1088
1089 #define src ((char *) &value)
1090 #define dst ((char *) &result)
1091
1092 dst[0] = src[1];
1093 dst[1] = src[0];
1094
1095 return result;
1096 }
1097
1098
1099
1100 /*
1101 * ----------------------------------------------------------------------------
1102 *
1103 * PlotDumpColorPreamble --
1104 *
1105 * Dump a color preamble in vdmpc format for the color Versatec. See
1106 * the vdmpc(5) man page for details on the format.
1107 *
1108 * Format:
1109 * preamble is a 1K block
1110 * first word is 0xA5CF4DFB (a magic number)
1111 * second word gives the number of scan lines
1112 * third word gives width of the plot in pixels (must be multiple of 8)
1113 * rest of the words are zero
1114 *
1115 * ----------------------------------------------------------------------------
1116 */
1117
1118 #define VERSATEC_BLOCK 1024
1119 #define VERSATEC_MAGIC_WORD 0xA5CF4DFB
1120 unsigned int VersHeader[VERSATEC_BLOCK/sizeof(unsigned int)] = {VERSATEC_MAGIC_WORD};
1121
1122 int
PlotDumpColorPreamble(color,file,lines,columns)1123 PlotDumpColorPreamble(color, file, lines, columns)
1124 VersatecColor color; /* The color that the following raster will
1125 * be printed in.
1126 */
1127 FILE *file; /* file in which to place header */
1128 int lines; /* number of scan lines */
1129 int columns; /* Width in pixels. */
1130 {
1131
1132 int count;
1133
1134 if (color == BLACK)
1135 {
1136 VersHeader[1] = lines;
1137 VersHeader[2] = columns;
1138 count = write(fileno(file), &VersHeader[0], sizeof(VersHeader));
1139 TxPrintf("Wrote %d bytes of control.\n", count);
1140 }
1141 return 0;
1142 }
1143