1 /* grClip.c -
2 *
3 * *********************************************************************
4 * * Copyright (C) 1985, 1990 Regents of the University of California. *
5 * * Permission to use, copy, modify, and distribute this *
6 * * software and its documentation for any purpose and without *
7 * * fee is hereby granted, provided that the above copyright *
8 * * notice appear in all copies. The University of California *
9 * * makes no representations about the suitability of this *
10 * * software for any purpose. It is provided "as is" without *
11 * * express or implied warranty. Export of this software outside *
12 * * of the United States of America may require an export license. *
13 * *********************************************************************
14 *
15 * This file contains additional functions to manipulate a
16 * color display. Included here are rectangle clipping and
17 * drawing routines.
18 */
19
20
21 #ifndef lint
22 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/graphics/grClip.c,v 1.4 2010/06/24 12:37:18 tim Exp $";
23 #endif /* not lint */
24
25 #include <stdio.h>
26
27 #include "utils/magic.h"
28 #include "textio/textio.h"
29 #include "utils/geometry.h"
30 #include "tiles/tile.h"
31 #include "utils/hash.h"
32 #include "utils/styles.h"
33 #include "database/database.h"
34 #include "windows/windows.h"
35 #include "graphics/graphics.h"
36 #include "graphics/graphicsInt.h"
37 #include "utils/malloc.h"
38
39 /* Forward declaration: */
40
41 extern bool GrDisjoint();
42 extern void GrClipTriangle();
43
44 /* The following rectangle defines the size of the cross drawn for
45 * zero-size rectangles. This must be all on one line to keep
46 * lintpick happy!
47 */
48
49 global Rect GrCrossRect = {-GR_CROSSSIZE, -GR_CROSSSIZE, GR_CROSSSIZE, GR_CROSSSIZE};
50 global int GrNumClipBoxes = 0; /* for benchmarking */
51 global int grCurDStyle;
52 global unsigned char GrGridMultiple = 1;
53
54 /* A rectangle that is one square of the grid */
55 static Rect *grGridRect;
56
57 /*
58 * ----------------------------------------------------------------------------
59 * GrSetStuff --
60 *
61 * Set up current drawing style.
62 *
63 * Results:
64 * None.
65 *
66 * Side effects:
67 * Variables are changed. If anything is drawn, it will appear in the
68 * specified style.
69 * ----------------------------------------------------------------------------
70 */
71
72 /* Current state for rectangle and text drawing */
73 static int grCurWMask, grCurStipple;
74 #ifndef MAGIC_WRAPPER
75 static /* Used in grTkCommon.c, so don't make static */
76 #endif
77 int grCurOutline, grCurFill, grCurColor;
78
79 /* Has the device driver been informed of the above? We only inform it
80 * when we actually need to draw something -- this makes it harmless (in terms
81 * of graphics bandwidth) to call GrSetStuff extra times.
82 */
83 bool grDriverInformed = TRUE;
84
85 void
GrSetStuff(style)86 GrSetStuff(style)
87 int style;
88 {
89 grCurDStyle = style;
90 grCurWMask = GrStyleTable[style].mask;
91 grCurColor = GrStyleTable[style].color;
92 grCurOutline = GrStyleTable[style].outline;
93 grCurStipple = GrStyleTable[style].stipple;
94 grCurFill = GrStyleTable[style].fill;
95 grDriverInformed = FALSE;
96 }
97
98 /*---------------------------------------------------------------------------
99 * grInformDriver:
100 *
101 * Inform the driver about the last GrSetStuff call.
102 *
103 * Results:
104 * None.
105 *
106 * Side Effects:
107 * None.
108 *
109 *----------------------------------------------------------------------------
110 */
111
112 void
grInformDriver()113 grInformDriver()
114 {
115 /* Now let the device drivers know */
116 (*grSetWMandCPtr)(grCurWMask, grCurColor);
117 (*grSetLineStylePtr)(grCurOutline);
118 (*grSetStipplePtr)(grCurStipple);
119 grDriverInformed = TRUE;
120 }
121
122
123 /*
124 * ----------------------------------------------------------------------------
125 * grClipAgainst --
126 *
127 * Clip a linked list of rectangles against a single rectangle. This
128 * may result in the list getting longer or shorter.
129 *
130 * Results:
131 * None.
132 *
133 * Side effects:
134 * The original list may change.
135 * ----------------------------------------------------------------------------
136 */
137
138 void
grClipAgainst(startllr,clip)139 grClipAgainst(startllr, clip)
140 LinkedRect **startllr; /* A pointer to the pointer that heads
141 * the list .
142 */
143 Rect *clip; /* The rectangle to clip against */
144 {
145 extern bool grClipAddFunc(); /* forward declaration */
146 LinkedRect **llr, *lr;
147
148 for (llr = startllr; *llr != (LinkedRect *) NULL; /*nop*/ )
149 {
150 if ( GEO_TOUCH(&(*llr)->r_r, clip) )
151 {
152 lr = *llr;
153 *llr = lr->r_next;
154 /* this will modify the list that we are traversing! */
155 (void) GrDisjoint(&lr->r_r, clip, grClipAddFunc,
156 (ClientData) &llr);
157 freeMagic( (char *) lr);
158 }
159 else
160 llr = &((*llr)->r_next);
161 }
162 }
163
164
165 /* Add a box to our linked list, and advance
166 * our pointer into the list
167 */
168
grClipAddFunc(box,cd)169 bool grClipAddFunc(box, cd)
170 Rect *box;
171 ClientData cd;
172 {
173 LinkedRect ***lllr, *lr;
174
175 lllr = (LinkedRect ***) cd;
176
177 lr = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
178 lr->r_r = *box;
179 lr->r_next = **lllr;
180 **lllr = lr;
181 *lllr = &lr->r_next;
182
183 return TRUE;
184 }
185
186
187 void
grObsBox(r)188 grObsBox(r)
189 Rect *r;
190 {
191 LinkedRect *ob;
192 LinkedRect *ar;
193 LinkedRect **areas;
194
195 ar = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
196 ar->r_r = *r;
197 ar->r_next = NULL;
198 areas = &ar;
199
200 /* clip against obscuring areas */
201 for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
202 {
203 if ( GEO_TOUCH(r, &(ob->r_r)) )
204 grClipAgainst(areas, &(ob->r_r));
205 }
206
207 while (*areas != NULL)
208 {
209 LinkedRect *oldarea;
210 if (grCurFill == GR_STGRID)
211 (*grDrawGridPtr)(grGridRect, grCurOutline, &((*areas)->r_r));
212 else
213 (*grFillRectPtr)(&((*areas)->r_r));
214 oldarea = *areas;
215 *areas = (*areas)->r_next;
216 freeMagic( (char *) oldarea );
217 }
218 }
219
220
221 /*---------------------------------------------------------
222 * grClipPoints:
223 * This routine computes the 0, 1, or 2 intersection points
224 * between a line and a box.
225 *
226 * Results:
227 * FALSE if the line is completely outside of the box.
228 *
229 * Side Effects:
230 *---------------------------------------------------------
231 */
232
233 bool
grClipPoints(line,box,p1,p1OK,p2,p2OK)234 grClipPoints(line, box, p1, p1OK, p2, p2OK)
235 Rect *line; /* Actually a line from line->r_ll to
236 * line->r_ur. It is assumed that r_ll is to
237 * the left of r_ur, but we don't assume that
238 * r_ll is below r_ur.
239 */
240 Rect *box; /* A box to check intersections with */
241 Point *p1, *p2; /* To be filled in with 0, 1, or 2 points
242 * that are on the border of the box as well as
243 * on the line.
244 */
245 bool *p1OK, *p2OK; /* Says if the point was filled in */
246 {
247 int tmp, delx, dely;
248 bool delyneg;
249 int x1, x2, y1, y2;
250 bool ok1, ok2;
251
252 if (p1OK != NULL) *p1OK = FALSE;
253 ok1 = FALSE;
254 if (p2OK != NULL) *p2OK = FALSE;
255 ok2 = FALSE;
256
257 x1 = line->r_xbot;
258 x2 = line->r_xtop;
259 y1 = line->r_ybot;
260 y2 = line->r_ytop;
261
262 delx = x2-x1;
263 dely = y2-y1;
264
265 /* We have to be careful because of machine-dependent problems
266 * with rounding during division by negative numbers.
267 */
268
269 if (dely<0)
270 {
271 dely = -dely;
272 delyneg = TRUE;
273 }
274 else
275 delyneg = FALSE;
276 /* we know that delx is nonnegative if this is a real (non-empty) line */
277 if (delx < 0) return FALSE;
278
279 if (x1 < box->r_xbot)
280 {
281 if (delx == 0) return FALSE;
282 tmp = (((box->r_xbot-x1)*dely) + (delx>>1))/delx;
283 if (delyneg) y1 -= tmp;
284 else y1 += tmp;
285 x1 = box->r_xbot;
286 }
287 else
288 if (x1 > box->r_xtop) return FALSE;
289
290 if (x2 > box->r_xtop)
291 {
292 if (delx == 0) return FALSE;
293 tmp = ((x2-box->r_xtop)*dely + (delx>>1))/delx;
294 if (delyneg) y2 += tmp;
295 else y2 -= tmp;
296 x2 = box->r_xtop;
297 }
298 else
299 if (x2 < box->r_xbot) return FALSE;
300
301 if (y2 > y1)
302 {
303 if (y1 < box->r_ybot)
304 {
305 x1 += (((box->r_ybot-y1)*delx) + (dely>>1))/dely;
306 y1 = box->r_ybot;
307 }
308 else if (y1 > box->r_ytop) return FALSE;
309 if (y2 > box->r_ytop)
310 {
311 x2 -= (((y2 - box->r_ytop)*delx) + (dely>>1))/dely;
312 y2 = box->r_ytop;
313 }
314 else if (y2 < box->r_ybot) return FALSE;
315 }
316 else
317 {
318 if (y1 > box->r_ytop)
319 {
320 if (dely == 0) return FALSE;
321 x1 += (((y1-box->r_ytop)*delx) + (dely>>1))/dely;
322 y1 = box->r_ytop;
323 }
324 else if (y1 < box->r_ybot) return FALSE;
325 if (y2 < box->r_ybot)
326 {
327 if (dely == 0) return FALSE;
328 x2 -= (((box->r_ybot-y2)*delx) + (dely>>1))/dely;
329 y2 = box->r_ybot;
330 }
331 else if (y2 > box->r_ytop) return FALSE;
332 }
333
334 if ( (x1 == box->r_xbot) || (y1 == box->r_ybot) || (y1 == box->r_ytop) )
335 {
336 if (p1 != NULL)
337 {
338 p1->p_x = x1;
339 p1->p_y = y1;
340 }
341 if (p1OK != NULL) *p1OK = TRUE;
342 ok1 = TRUE;
343 }
344 if ( (x2 == box->r_xtop) || (y2 == box->r_ybot) || (y2 == box->r_ytop) )
345 {
346 if (p2 != NULL)
347 {
348 p2->p_x = x2;
349 p2->p_y = y2;
350 }
351 if (p2OK != NULL) *p2OK = TRUE;
352 ok2 = TRUE;
353 }
354 /* is part of the line in the box? */
355 return ok1 || ok2 ||
356 ((x1 >= box->r_xbot) && (x1 <= box->r_xtop) && (y1 >= box->r_ybot)
357 && (y1 <= box->r_ytop));
358 }
359
360
361 #define NEWAREA(lr,x1,y1,x2,y2) {LinkedRect *tmp; \
362 tmp = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect))); \
363 tmp->r_r.r_xbot = x1; tmp->r_r.r_xtop = x2; \
364 tmp->r_r.r_ybot = y1; tmp->r_r.r_ytop = y2; tmp->r_next = lr; lr = tmp;}
365
366 /*---------------------------------------------------------
367 * GrClipLine:
368 * GrClipLine will draw a line on the screen in the current
369 * style and clip stuff.
370 *
371 * Results: None.
372 *
373 * Side Effects:
374 * The line is drawn in the current style.
375 *---------------------------------------------------------
376 */
377
378 void
GrClipLine(x1,y1,x2,y2)379 GrClipLine(x1, y1, x2, y2)
380 int x1, y1, x2, y2;
381 {
382 LinkedRect **ar;
383 LinkedRect *ob;
384 LinkedRect *areas;
385
386 GR_CHECK_LOCK();
387 if (!grDriverInformed) grInformDriver();
388
389 /* we will pretend the the ll corner of a rectangle is the
390 * left endpoint of a line, and the ur corner the right endpoint
391 * of the line.
392 */
393 areas = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
394 areas->r_next = NULL;
395 if (x1 < x2)
396 {
397 areas->r_r.r_xbot = x1;
398 areas->r_r.r_ybot = y1;
399 areas->r_r.r_xtop = x2;
400 areas->r_r.r_ytop = y2;
401 }
402 else
403 {
404 areas->r_r.r_xtop = x1;
405 areas->r_r.r_ytop = y1;
406 areas->r_r.r_xbot = x2;
407 areas->r_r.r_ybot = y2;
408 }
409
410 /* clip against the clip box */
411 for (ar = &areas; *ar != NULL; )
412 {
413 Rect *l;
414 Rect canonRect;
415 l = &((*ar)->r_r);
416 GeoCanonicalRect(l, &canonRect);
417 if (!GEO_TOUCH(&canonRect, &grCurClip))
418 {
419 /* line is totally outside of clip area */
420 goto deleteit;
421 }
422 else
423 {
424 /* is there some intersection with clip area? */
425 if (!grClipPoints(l, &grCurClip, &(l->r_ll), (bool *) NULL,
426 &(l->r_ur), (bool*) NULL))
427 {
428 /* no intersection */
429 goto deleteit;
430 }
431
432 /* clip against obscuring areas */
433 for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
434 {
435 Point p1, p2;
436 Rect c;
437 bool ok1, ok2;
438 c = ob->r_r;
439 c.r_xbot--; c.r_ybot--;
440 c.r_xtop++; c.r_ytop++;
441 if (grClipPoints(l, &c, &p1, &ok1, &p2, &ok2) &&
442 !ok1 && !ok2)
443 {
444 /* Line is not completely outside of the box,
445 * nor does it intersect it.
446 * Therefore, line is completely obscured.
447 */
448 goto deleteit;
449 }
450
451 if (ok1 &&
452 ( ((l->r_xbot == p1.p_x) && (l->r_ybot == p1.p_y)) ||
453 ((l->r_xtop == p1.p_x) && (l->r_ytop == p1.p_y)) ) )
454 {
455 ok1 = FALSE; /* do not split or clip at an endpoint */
456 }
457 if (ok2 &&
458 ( ((l->r_xbot == p2.p_x) && (l->r_ybot == p2.p_y)) ||
459 ((l->r_xtop == p2.p_x) && (l->r_ytop == p2.p_y)) ) )
460 {
461 ok2 = FALSE; /* do not split or clip at an endpoint */
462 }
463
464 if (ok1 ^ ok2)
465 {
466 /* one segment to deal with */
467 if (ok1)
468 l->r_ur = p1;
469 else
470 l->r_ll = p2;
471 }
472 else if (ok1 && ok2)
473 {
474 /* clip both sides */
475 LinkedRect *new;
476 new = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
477 new->r_r.r_ur = l->r_ur;
478 new->r_r.r_ll = p2;
479 new->r_next = (*ar);
480 l->r_ur = p1;
481 (*ar) = new;
482 }
483 }
484
485 }
486
487 ar = &((*ar)->r_next);
488 continue;
489
490 deleteit: {
491 LinkedRect *reclaim;
492 reclaim = (*ar);
493 *ar = reclaim->r_next;
494 freeMagic( (char *) reclaim);
495 }
496
497 } /* for ar */
498
499
500 /* draw the lines */
501 while (areas != NULL)
502 {
503 LinkedRect *oldarea;
504 (*grDrawLinePtr)(areas->r_r.r_xbot, areas->r_r.r_ybot,
505 areas->r_r.r_xtop, areas->r_r.r_ytop);
506 oldarea = areas;
507 areas = areas->r_next;
508 freeMagic( (char *) oldarea );
509 }
510 }
511
512 /*
513 *---------------------------------------------------------
514 * grAddSegment:
515 * Add a segment to a linked list of rectangles
516 *
517 * Results:
518 * None.
519 *
520 * Side effects:
521 * Allocates memory; appends LinkedRect structure to
522 * list "segments".
523 *
524 * Notes:
525 * INLINE this for speedup?
526 *---------------------------------------------------------
527 */
528
529 void
grAddSegment(llx,lly,urx,ury,segments)530 grAddSegment(llx, lly, urx, ury, segments)
531 int llx, lly, urx, ury;
532 LinkedRect **segments;
533 {
534 LinkedRect *curseg;
535
536 curseg = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
537 curseg->r_r.r_xbot = llx;
538 curseg->r_r.r_ybot = lly;
539 curseg->r_r.r_xtop = urx;
540 curseg->r_r.r_ytop = ury;
541 curseg->r_next = *segments;
542 *segments = curseg;
543 }
544
545 /*---------------------------------------------------------
546 * GrBoxOutline:
547 * For box outlines, works around the boundary of
548 * the box according to the associated tile structure,
549 * and returns a linked rect list defining all the
550 * segments which need to be drawn.
551 *
552 * Results:
553 * TRUE if tile is isolated (GrFastBox can be used).
554 * Otherwise, result is FALSE.
555 *
556 * Side Effects:
557 * May allocate memory for a linked rect structure,
558 * with pointer returned in tilesegs. If non-NULL,
559 * the calling function needs to free memory for the
560 * linked rect structure.
561 *
562 * Implementation notes:
563 * Standard tech files define most bordered styles as
564 * contact types, and most if not all contacts are
565 * required to be square. So we want the case of an
566 * isolated tile to go fast, avoiding any calls to
567 * allocate memory. This complicates the routine but
568 * keeps the routine from slowing down the layout
569 * rendering.
570 *---------------------------------------------------------
571 */
572
573 bool
GrBoxOutline(tile,tilesegs)574 GrBoxOutline(tile, tilesegs)
575 Tile *tile;
576 LinkedRect **tilesegs;
577 {
578 Rect rect;
579 TileType ttype;
580 LinkedRect *curseg;
581 Tile *tpleft, *tpright, *tptop, *tpbot;
582 int edgeTop, edgeBot, edgeRight, edgeLeft;
583 int isolate = 0;
584 bool sense;
585
586 *tilesegs = NULL;
587 TiToRect(tile, &rect);
588
589 if (IsSplit(tile) && SplitSide(tile))
590 isolate |= 0x1;
591 else
592 {
593 ttype = TiGetLeftType(tile);
594 edgeBot = rect.r_ybot;
595 sense = TRUE;
596 for (tpleft = BL(tile); BOTTOM(tpleft) < rect.r_ytop; tpleft = RT(tpleft))
597 {
598 if (TiGetRightType(tpleft) != ttype)
599 {
600 if (!sense)
601 {
602 edgeBot = BOTTOM(tpleft);
603 if (TOP(tpleft) >= rect.r_ytop)
604 grAddSegment(rect.r_xbot, edgeBot, rect.r_xbot, rect.r_ytop,
605 tilesegs);
606 sense = TRUE;
607 }
608 }
609 else
610 {
611 if (sense)
612 {
613 edgeTop = BOTTOM(tpleft);
614 if (edgeTop > edgeBot)
615 grAddSegment(rect.r_xbot, edgeBot, rect.r_xbot, edgeTop,
616 tilesegs);
617 isolate |= 0x1;
618 sense = FALSE;
619 }
620 }
621 }
622 }
623 if (IsSplit(tile) && !SplitSide(tile))
624 isolate |= 0x2;
625 else
626 {
627 ttype = TiGetRightType(tile);
628 edgeTop = rect.r_ytop;
629 sense = TRUE;
630 for (tpright = TR(tile); TOP(tpright) > rect.r_ybot; tpright = LB(tpright))
631 {
632 if (TiGetLeftType(tpright) != ttype)
633 {
634 if (!sense)
635 {
636 edgeTop = TOP(tpright);
637 if (BOTTOM(tpright) <= rect.r_ybot)
638 grAddSegment(rect.r_xtop, rect.r_ybot, rect.r_xtop, edgeTop,
639 tilesegs);
640 sense = TRUE;
641 }
642 }
643 else
644 {
645 if (sense)
646 {
647 edgeBot = TOP(tpright);
648 if (edgeBot < edgeTop)
649 grAddSegment(rect.r_xtop, edgeBot, rect.r_xtop, edgeTop,
650 tilesegs);
651 isolate |= 0x2;
652 sense = FALSE;
653 }
654 }
655 }
656 }
657
658 if (IsSplit(tile) &&
659 (SplitSide(tile) == SplitDirection(tile)))
660 isolate |= 0x4;
661 else
662 {
663 ttype = TiGetBottomType(tile);
664 edgeLeft = rect.r_xbot;
665 sense = TRUE;
666 for (tpbot = LB(tile); LEFT(tpbot) < rect.r_xtop; tpbot = TR(tpbot))
667 {
668 if (TiGetTopType(tpbot) != ttype)
669 {
670 if (!sense)
671 {
672 edgeLeft = LEFT(tpbot);
673 if (RIGHT(tpbot) >= rect.r_xtop)
674 grAddSegment(edgeLeft, rect.r_ybot, rect.r_xtop, rect.r_ybot,
675 tilesegs);
676 sense = TRUE;
677 }
678 }
679 else
680 {
681 if (sense)
682 {
683 edgeRight = LEFT(tpbot);
684 if (edgeRight > edgeLeft)
685 grAddSegment(edgeLeft, rect.r_ybot, edgeRight, rect.r_ybot,
686 tilesegs);
687 isolate |= 0x4;
688 sense = FALSE;
689 }
690 }
691 }
692 }
693
694 if (IsSplit(tile) &&
695 (SplitSide(tile) != SplitDirection(tile)))
696 isolate |= 0x8;
697 else
698 {
699 ttype = TiGetTopType(tile);
700 edgeRight = rect.r_xtop;
701 sense = TRUE;
702 for (tptop = RT(tile); RIGHT(tptop) > rect.r_xbot; tptop = BL(tptop))
703 {
704 if (TiGetBottomType(tptop) != ttype)
705 {
706 if (!sense)
707 {
708 edgeRight = RIGHT(tptop);
709 if (LEFT(tptop) <= rect.r_xbot)
710 grAddSegment(rect.r_xbot, rect.r_ytop, edgeRight, rect.r_ytop,
711 tilesegs);
712 sense = TRUE;
713 }
714 }
715 else
716 {
717 if (sense)
718 {
719 edgeLeft = RIGHT(tptop);
720 if (edgeLeft < edgeRight)
721 grAddSegment(edgeLeft, rect.r_ytop, edgeRight, rect.r_ytop,
722 tilesegs);
723 isolate |= 0x8;
724 sense = FALSE;
725 }
726 }
727 }
728 }
729
730 if (isolate == 0) /* Common case */
731 return TRUE;
732 else
733 {
734 /* Need to malloc segments for isolated sides */
735 if (!(isolate & 0x1)) /* Left */
736 grAddSegment(rect.r_xbot, rect.r_ybot, rect.r_xbot, rect.r_ytop,
737 tilesegs);
738 if (!(isolate & 0x2)) /* Right */
739 grAddSegment(rect.r_xtop, rect.r_ybot, rect.r_xtop, rect.r_ytop,
740 tilesegs);
741 if (!(isolate & 0x4)) /* Bottom */
742 grAddSegment(rect.r_xbot, rect.r_ybot, rect.r_xtop, rect.r_ybot,
743 tilesegs);
744 if (!(isolate & 0x8)) /* Top */
745 grAddSegment(rect.r_xbot, rect.r_ytop, rect.r_xtop, rect.r_ytop,
746 tilesegs);
747 return FALSE;
748 }
749 }
750
751 /* Threshold for determining if outlines are too small to draw */
752 #define GR_THRESH 4
753
754 /*---------------------------------------------------------
755 * GrBox --
756 *
757 * GrBox draws a rectangle on the screen in the style
758 * set by the previous call to GrSetStuff. It will
759 * be clipped against the rectangles passed to GrSetStuff.
760 *
761 * Unlike GrFastBox (see below), GrBox makes no assumptions
762 * about how the outline will be drawn. If there is no
763 * outline, GrFastBox is called. The tile border is checked,
764 * and if the tile outline is simple, GrFastBox is called.
765 * Otherwise, we do a fast fill a la GrFastBox but draw the
766 * outline segment by segment.
767 *
768 * Results: None.
769 *
770 * Side Effects:
771 * The rectangle is drawn in the style specified.
772 * The rectangle may be clipped before being drawn.
773 *---------------------------------------------------------
774 */
775 void
GrBox(MagWindow * mw,Transform * trans,Tile * tile)776 GrBox(MagWindow *mw, Transform *trans, Tile *tile)
777 {
778 Rect r, r2, clipr;
779 bool needClip, needObscure, simpleBox;
780 LinkedRect *ob, *tilesegs, *segptr;
781 Point polyp[5];
782 int np;
783
784 r.r_xbot = LEFT(tile);
785 r.r_ybot = BOTTOM(tile);
786 r.r_xtop = RIGHT(tile);
787 r.r_ytop = TOP(tile);
788
789 GeoTransRect(trans, &r, &r2);
790 if (IsSplit(tile))
791 WindSurfaceToScreenNoClip(mw, &r2, &r);
792 else
793 WindSurfaceToScreen(mw, &r2, &r);
794
795 GR_CHECK_LOCK();
796 if (!grDriverInformed) grInformDriver();
797 GrNumClipBoxes++;
798
799 if (!GEO_TOUCH(&r, &grCurClip)) return;
800
801 /* Do a quick check to make the (very common) special case of
802 * no clipping go fast.
803 */
804 needClip = !GEO_SURROUND(&grCurClip, &r);
805 needObscure = FALSE;
806 for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
807 needObscure |= GEO_TOUCH(&r, &(ob->r_r));
808
809 /* Nonmanhattan tiles: */
810 /* Expects one of the two tile types to be masked out before */
811 /* this procedure is called. */
812
813 if (IsSplit(tile))
814 {
815 /* Perform matrix transformations on split tiles */
816 TileType dinfo;
817 Rect fullr;
818
819 dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);
820 clipr = fullr = r;
821
822 if (needClip)
823 GeoClip(&clipr, &grCurClip);
824
825 GrClipTriangle(&fullr, &clipr, needClip, dinfo, polyp, &np);
826
827 if ((grCurFill == GR_STSOLID) ||
828 (grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
829 {
830 if (needObscure)
831 grObsBox(&clipr);
832 else if (grFillPolygonPtr)
833 (void) (*grFillPolygonPtr)(polyp, np);
834 }
835 }
836 else
837 {
838
839 /* do solid areas (same as GrFastBox) */
840
841 if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE))
842 {
843 /* We have a filled area to deal with */
844 clipr = r;
845 if (needClip)
846 GeoClip(&clipr, &grCurClip);
847 if (needObscure)
848 grObsBox(&clipr);
849 else
850 (void) (*grFillRectPtr)(&clipr);
851 }
852 }
853
854 /* return if outline is too small to be worth drawing */
855
856 if ((r.r_xtop - r.r_xbot < GR_THRESH)
857 && (r.r_ytop - r.r_ybot < GR_THRESH)
858 && (grCurFill != GR_STOUTLINE))
859 return;
860
861 /* do diagonal lines for contacts */
862
863 if (grCurFill == GR_STCROSS)
864 {
865 Rect rnc;
866 /* don't clip contact diagonals */
867 if (needClip || needObscure)
868 {
869 WindSurfaceToScreenNoClip(mw, &r2, &rnc);
870 /*
871 (*grDrawLinePtr)(rnc.r_xbot, rnc.r_ybot, rnc.r_xtop, rnc.r_ytop);
872 (*grDrawLinePtr)(rnc.r_xbot, rnc.r_ytop, rnc.r_xtop, rnc.r_ybot);
873 */
874 if (!IsSplit(tile))
875 {
876 GrClipLine(rnc.r_xbot, rnc.r_ybot, rnc.r_xtop, rnc.r_ytop);
877 GrClipLine(rnc.r_xbot, rnc.r_ytop, rnc.r_xtop, rnc.r_ybot);
878 }
879 }
880 else
881 {
882 if (!IsSplit(tile))
883 {
884 (*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
885 (*grDrawLinePtr)(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ybot);
886 }
887 }
888 }
889
890 /* draw outlines */
891
892 if (grCurOutline != 0)
893 {
894 if (GrBoxOutline(tile, &tilesegs))
895 {
896 /* simple box (from GrFastBox)*/
897
898 if (needClip || needObscure)
899 {
900 GrClipLine(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ytop);
901 GrClipLine(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ybot);
902 GrClipLine(r.r_xbot, r.r_ybot, r.r_xbot, r.r_ytop);
903 GrClipLine(r.r_xtop, r.r_ybot, r.r_xtop, r.r_ytop);
904 }
905 else
906 {
907 (*grDrawLinePtr)(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ytop);
908 (*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ybot);
909 (*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xbot, r.r_ytop);
910 (*grDrawLinePtr)(r.r_xtop, r.r_ybot, r.r_xtop, r.r_ytop);
911 }
912 }
913 else
914 {
915 /* non-rectangular box; requires drawing segments */
916 for (segptr = tilesegs; segptr != NULL; segptr = segptr->r_next)
917 {
918 GeoTransRect(trans, &segptr->r_r, &r2);
919 WindSurfaceToScreen(mw, &r2, &r);
920
921 if (needClip || needObscure)
922 GrClipLine(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
923 else
924 (*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
925
926 /* Free memory, if it was allocated for outline segments */
927 freeMagic(segptr);
928 }
929
930 /* For non-manhattan tiles, the manhattan parts of the */
931 /* boundary have already been drawn. The diagonal boundary */
932 /* is guaranteed to be continuous by definition, and it has */
933 /* already undergone clipping with GrClipTriangle. So just */
934 /* draw it, now. */
935
936 if (IsSplit(tile))
937 {
938 int cp;
939 for (cp = 0; cp < np - 1; cp++)
940 {
941 if ((polyp[cp].p_x != polyp[cp + 1].p_x) &&
942 (polyp[cp].p_y != polyp[cp + 1].p_y))
943 {
944 (*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
945 polyp[cp + 1].p_x, polyp[cp + 1].p_y);
946 break; /* only 1 diagonal line to draw */
947 }
948 }
949 if (cp == (np - 1))
950 {
951 if ((polyp[cp].p_x != polyp[0].p_x) &&
952 (polyp[cp].p_y != polyp[0].p_y))
953 (*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
954 polyp[0].p_x, polyp[0].p_y);
955 }
956 }
957 }
958 }
959 }
960
961 /*---------------------------------------------------------
962 * GrDrawFastBox:
963 * GrDrawFastBox will draw a rectangle on the screen in the
964 * style set by the previous call to GrSetStuff. It will also
965 * be clipped against the rectangles passed to GrSetStuff.
966 *
967 * If GrClipBox is called between GrDrawFastBox calls then GrSetStuff
968 * must be called to set the parameters back.
969 *
970 * Usually this is called as GrFastBox, defined as GrDrawFastBox(p, 0).
971 * The "scale" is only used to reduce the size of crosses drawn at
972 * point positions, to prevent point labels from dominating a layout
973 * in top-level views.
974 *
975 * Results: None.
976 *
977 * Side Effects:
978 * The rectangle is drawn in the style specified.
979 * The rectangle is clipped before being drawn.
980 *---------------------------------------------------------
981 */
982
983 void
GrDrawFastBox(prect,scale)984 GrDrawFastBox(prect, scale)
985 Rect *prect; /* The rectangle to be drawn, given in
986 * screen coordinates.
987 */
988 int scale; /* If < 0, we reduce the cross size for
989 * points according to the (negative) scale,
990 * so point labels don't dominate a top-level
991 * layout.
992 */
993 {
994 Rect *r;
995 bool needClip, needObscure;
996 LinkedRect *ob;
997
998 GR_CHECK_LOCK();
999 if (!grDriverInformed) grInformDriver();
1000 GrNumClipBoxes++;
1001 if (grCurFill == GR_STGRID)
1002 {
1003 r = &grCurClip;
1004 grGridRect = prect;
1005 }
1006 else
1007 {
1008 r = prect;
1009 if (!GEO_TOUCH(r, &grCurClip)) return;
1010 }
1011
1012 /* Do a quick check to make the (very common) special case of
1013 * no clipping go fast.
1014 */
1015 needClip = !GEO_SURROUND(&grCurClip, r);
1016 needObscure = FALSE;
1017 for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
1018 needObscure |= GEO_TOUCH(r, &(ob->r_r));
1019
1020 /* do solid areas */
1021 if ( (grCurFill == GR_STSOLID) ||
1022 (grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
1023 {
1024 Rect clipr;
1025 /* We have a filled area to deal with */
1026 clipr = *r;
1027 if (needClip)
1028 GeoClip(&clipr, &grCurClip);
1029 if (needObscure)
1030 grObsBox(&clipr);
1031 else
1032 {
1033 if (grCurFill == GR_STGRID)
1034 (*grDrawGridPtr)(grGridRect, grCurOutline, &clipr);
1035 else
1036 (void) (*grFillRectPtr)(&clipr);
1037 }
1038 }
1039
1040 /* return if rectangle is too small to see */
1041 if ((r->r_xtop - r->r_xbot < GR_THRESH)
1042 && (r->r_ytop - r->r_ybot < GR_THRESH)
1043 && (grCurFill != GR_STOUTLINE))
1044 return;
1045
1046 /* draw outlines */
1047
1048 if ( (grCurOutline != 0) && (grCurFill != GR_STGRID) )
1049 {
1050 if ( (grCurFill == GR_STOUTLINE) && (r->r_xbot == r->r_xtop) &&
1051 (r->r_ybot == r->r_ytop) )
1052 {
1053 int crossSize = GR_CROSSSIZE;
1054
1055 if (scale < 0)
1056 {
1057 crossSize += scale;
1058 if (crossSize < 0)
1059 goto endit;
1060 }
1061
1062 /* turn the outline into a cross */
1063 if (needClip || needObscure)
1064 goto clipit;
1065 else
1066 {
1067 bool crossClip, crossObscure;
1068 Rect crossBox;
1069
1070 /* check the larger cross area for clipping */
1071 crossBox.r_xbot = r->r_xbot - crossSize;
1072 crossBox.r_ybot = r->r_ybot - crossSize;
1073 crossBox.r_xtop = r->r_xtop + crossSize;
1074 crossBox.r_ytop = r->r_ytop + crossSize;
1075
1076 crossClip = !GEO_SURROUND(&grCurClip, &crossBox);
1077 crossObscure = FALSE;
1078 for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
1079 crossObscure |= GEO_TOUCH(&crossBox, &(ob->r_r));
1080
1081 if (crossClip || crossObscure)
1082 goto clipit;
1083 else
1084 goto noclipit;
1085 }
1086
1087 clipit:
1088 GrClipLine(r->r_xbot, r->r_ybot - crossSize,
1089 r->r_xtop, r->r_ytop + crossSize - 1 + GrPixelCorrect);
1090 GrClipLine(r->r_xbot - crossSize, r->r_ybot,
1091 r->r_xtop + crossSize - 1 + GrPixelCorrect, r->r_ytop);
1092 goto endit;
1093
1094 noclipit:
1095 (*grDrawLinePtr)(r->r_xbot, r->r_ybot - crossSize,
1096 r->r_xtop, r->r_ytop + crossSize - 1 + GrPixelCorrect);
1097 (*grDrawLinePtr)(r->r_xbot - crossSize, r->r_ybot,
1098 r->r_xtop + crossSize - 1 + GrPixelCorrect, r->r_ytop);
1099
1100 endit: ;
1101 }
1102 else
1103 {
1104 if (needClip || needObscure)
1105 {
1106 GrClipLine(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ytop);
1107 GrClipLine(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ybot);
1108 GrClipLine(r->r_xbot, r->r_ybot, r->r_xbot, r->r_ytop);
1109 GrClipLine(r->r_xtop, r->r_ybot, r->r_xtop, r->r_ytop);
1110 }
1111 else
1112 {
1113 (*grDrawLinePtr)(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ytop);
1114 (*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ybot);
1115 (*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xbot, r->r_ytop);
1116 (*grDrawLinePtr)(r->r_xtop, r->r_ybot, r->r_xtop, r->r_ytop);
1117 }
1118 }
1119 }
1120
1121 /* do diagonal lines for contacts */
1122 if (grCurFill == GR_STCROSS)
1123 {
1124 if (needClip || needObscure)
1125 {
1126 GrClipLine(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop);
1127 GrClipLine(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ybot);
1128 }
1129 else
1130 {
1131 (*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop);
1132 (*grDrawLinePtr)(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ybot);
1133 }
1134 }
1135 }
1136
1137 /*---------------------------------------------------------
1138 * GrClipTriangle:
1139 * Returns an array of points representing a clipped
1140 * triangle. These are always arranged in counter-
1141 * clockwise order.
1142 *
1143 * Results:
1144 * None.
1145 *
1146 * Side effects:
1147 * Returns array of points and modifies int * np
1148 * to hold the number of points in the array.
1149 *---------------------------------------------------------
1150 */
1151
1152 #define xround(d) (int)(((((d % height) << 1) >= height) ? 1 : 0) + (d / height))
1153 #define yround(d) (int)(((((d % width) << 1) >= width) ? 1 : 0) + (d / width))
1154
1155 void
GrClipTriangle(r,c,clipped,dinfo,points,np)1156 GrClipTriangle(r, c, clipped, dinfo, points, np)
1157 Rect *r; /* Bounding box of triangle, in screen coords */
1158 Rect *c; /* Clipping rectangle */
1159 bool clipped; /* Boolean, if bounding box is clipped */
1160 TileType dinfo; /* Split side and direction information */
1161 Point *points; /* Point array (up to 5 points) to fill */
1162 int *np; /* Number of points in the clipped polygon */
1163 {
1164 if (!(dinfo & TT_SIDE))
1165 {
1166 points[1].p_x = r->r_xbot;
1167 points[0].p_y = r->r_ytop;
1168 points[2].p_y = r->r_ybot;
1169 points[0].p_x = points[2].p_x = r->r_xtop;
1170 }
1171 else
1172 {
1173 points[1].p_x = r->r_xtop;
1174 points[0].p_y = r->r_ybot;
1175 points[2].p_y = r->r_ytop;
1176 points[0].p_x = points[2].p_x = r->r_xbot;
1177 }
1178
1179 if (!(dinfo & TT_DIRECTION))
1180 {
1181 points[1].p_y = points[0].p_y;
1182 points[2].p_x = points[1].p_x;
1183 }
1184 else
1185 {
1186 points[0].p_x = points[1].p_x;
1187 points[1].p_y = points[2].p_y;
1188 }
1189
1190 *np = 3;
1191
1192 /* Clip the triangle to the clipping rectangle. Result is */
1193 /* a 3- to 5-sided polygon, or empty. */
1194
1195 if (clipped)
1196 {
1197 dlong delx, dely;
1198 dlong width = (dlong)(r->r_xtop - r->r_xbot);
1199 dlong height = (dlong)(r->r_ytop - r->r_ybot);
1200
1201 switch(dinfo & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE))
1202 {
1203 case TT_DIAGONAL: /* nw */
1204 if (c->r_ytop < r->r_ytop) /* clip top */
1205 {
1206 delx = (dlong)(points[1].p_y - c->r_ytop) * width;
1207 points[1].p_y = c->r_ytop;
1208 points[0].p_y = c->r_ytop;
1209 points[0].p_x -= xround(delx);
1210 }
1211 if (c->r_xbot > r->r_xbot) /* clip left */
1212 {
1213 dely = (dlong)(c->r_xbot - points[2].p_x) * height;
1214 points[1].p_x = c->r_xbot;
1215 points[2].p_x = c->r_xbot;
1216 points[2].p_y += yround(dely);
1217 }
1218 if (c->r_ybot > points[2].p_y) /* clip bottom */
1219 {
1220 delx = (dlong)(c->r_ybot - points[2].p_y) * width;
1221 points[2].p_y = c->r_ybot;
1222 points[3].p_y = c->r_ybot;
1223 points[3].p_x = points[2].p_x + xround(delx);
1224 *np = 4;
1225
1226 if (c->r_xtop < points[3].p_x) /* clip right, rectangle */
1227 {
1228 points[3].p_x = c->r_xtop;
1229 points[0].p_x = c->r_xtop;
1230 }
1231 else if (c->r_xtop < points[0].p_x) /* clip right, pentagon */
1232 {
1233 dely = (dlong)(points[0].p_x - c->r_xtop) * height;
1234 points[0].p_x = c->r_xtop;
1235 points[4].p_x = c->r_xtop;
1236 points[4].p_y = points[0].p_y - yround(dely);
1237 *np = 5;
1238 }
1239 }
1240 else if (c->r_xtop < points[0].p_x) /* clip right, quadrangle */
1241 {
1242 dely = (dlong)(points[0].p_x - c->r_xtop) * height;
1243 points[0].p_x = c->r_xtop;
1244 points[3].p_x = c->r_xtop;
1245 points[3].p_y = points[0].p_y - yround(dely);
1246 *np = 4;
1247 }
1248 if (points[1].p_x > points[0].p_x || points[2].p_y > points[1].p_y)
1249 *np = 0; /* clipped out of existence */
1250 break;
1251
1252 case TT_DIAGONAL | TT_DIRECTION: /* sw */
1253 if (c->r_xbot > r->r_xbot) /* clip LEFT */
1254 {
1255 dely = (dlong)(c->r_xbot - points[1].p_x) * height;
1256 points[1].p_x = c->r_xbot;
1257 points[0].p_x = c->r_xbot;
1258 points[0].p_y -= yround(dely);
1259 }
1260 if (c->r_ybot > r->r_ybot) /* clip BOTTOM */
1261 {
1262 delx = (dlong)(c->r_ybot - points[2].p_y) * width;
1263 points[1].p_y = c->r_ybot;
1264 points[2].p_y = c->r_ybot;
1265 points[2].p_x -= xround(delx);
1266 }
1267 if (c->r_xtop < points[2].p_x) /* clip RIGHT */
1268 {
1269 dely = (dlong)(points[2].p_x - c->r_xtop) * height;
1270 points[2].p_x = c->r_xtop;
1271 points[3].p_x = c->r_xtop;
1272 points[3].p_y = points[1].p_y + yround(dely);
1273 *np = 4;
1274
1275 if (c->r_ytop < points[3].p_y) /* clip TOP, rectangle */
1276 {
1277 points[3].p_y = c->r_ytop;
1278 points[0].p_y = c->r_ytop;
1279 }
1280 else if (c->r_ytop < points[0].p_y) /* clip TOP, pentagon */
1281 {
1282 delx = (dlong)(points[0].p_y - c->r_ytop) * width;
1283 points[0].p_y = c->r_ytop;
1284 points[4].p_y = c->r_ytop;
1285 points[4].p_x = points[0].p_x + xround(delx);
1286 *np = 5;
1287 }
1288 }
1289 else if (c->r_ytop < points[0].p_y) /* clip TOP, quadrangle */
1290 {
1291 delx = (dlong)(points[0].p_y - c->r_ytop) * width;
1292 points[0].p_y = c->r_ytop;
1293 points[3].p_y = c->r_ytop;
1294 points[3].p_x = points[0].p_x + xround(delx);
1295 *np = 4;
1296 }
1297 if (points[1].p_y > points[0].p_y || points[2].p_x < points[1].p_x)
1298 *np = 0; /* clipped out of existence */
1299 break;
1300
1301 case TT_DIAGONAL | TT_SIDE: /* se */
1302 /* order: (bottom, right), (top, left) */
1303 if (c->r_ybot > r->r_ybot) /* clip BOTTOM */
1304 {
1305 delx = (dlong)(c->r_ybot - points[1].p_y) * width;
1306 points[1].p_y = c->r_ybot;
1307 points[0].p_y = c->r_ybot;
1308 points[0].p_x += xround(delx);
1309 }
1310 if (c->r_xtop < r->r_xtop) /* clip RIGHT */
1311 {
1312 dely = (dlong)(points[2].p_x - c->r_xtop) * height;
1313 points[1].p_x = c->r_xtop;
1314 points[2].p_x = c->r_xtop;
1315 points[2].p_y -= yround(dely);
1316 }
1317 if (c->r_ytop < points[2].p_y) /* clip TOP */
1318 {
1319 delx = (dlong)(points[2].p_y - c->r_ytop) * width;
1320 points[2].p_y = c->r_ytop;
1321 points[3].p_y = c->r_ytop;
1322 points[3].p_x = points[2].p_x - xround(delx);
1323 *np = 4;
1324
1325 if (c->r_xbot > points[3].p_x) /* clip LEFT, rectangle */
1326 {
1327 points[3].p_x = c->r_xbot;
1328 points[0].p_x = c->r_xbot;
1329 }
1330 else if (c->r_xbot > points[0].p_x) /* clip LEFT, pentagon */
1331 {
1332 dely = (dlong)(c->r_xbot - points[0].p_x) * height;
1333 points[0].p_x = c->r_xbot;
1334 points[4].p_x = c->r_xbot;
1335 points[4].p_y = points[0].p_y + yround(dely);
1336 *np = 5;
1337 }
1338 }
1339 else if (c->r_xbot > points[0].p_x) /* clip LEFT, triangle */
1340 {
1341 dely = (dlong)(c->r_xbot - points[0].p_x) * height;
1342 points[0].p_x = c->r_xbot;
1343 points[3].p_x = c->r_xbot;
1344 points[3].p_y = points[0].p_y + yround(dely);
1345 *np = 4;
1346 }
1347 if (points[0].p_x > points[1].p_x || points[1].p_y > points[2].p_y)
1348 *np = 0; /* clipped out of existence */
1349 break;
1350
1351 case TT_DIAGONAL | TT_SIDE | TT_DIRECTION: /* ne */
1352 /* order: (top, right), (bottom, left) */
1353 if (c->r_xtop < r->r_xtop) /* clip RIGHT */
1354 {
1355 dely = (dlong)(points[1].p_x - c->r_xtop) * height;
1356 points[1].p_x = c->r_xtop;
1357 points[0].p_x = c->r_xtop;
1358 points[0].p_y += yround(dely);
1359 }
1360 if (c->r_ytop < r->r_ytop) /* clip TOP */
1361 {
1362 delx = (dlong)(points[2].p_y - c->r_ytop) * width;
1363 points[1].p_y = c->r_ytop;
1364 points[2].p_y = c->r_ytop;
1365 points[2].p_x += xround(delx);
1366 }
1367 if (c->r_xbot > points[2].p_x) /* clip LEFT */
1368 {
1369 dely = (dlong)(c->r_xbot - points[2].p_x) * height;
1370 points[2].p_x = c->r_xbot;
1371 points[3].p_x = c->r_xbot;
1372 points[3].p_y = points[2].p_y - yround(dely);
1373 *np = 4;
1374
1375 if (c->r_ybot >= points[3].p_y) /* clip BOTTOM, rectangle */
1376 {
1377 points[3].p_y = c->r_ybot;
1378 points[0].p_y = c->r_ybot;
1379 }
1380 else if (c->r_ybot > points[0].p_y) /* clip BOTTOM, pentagon */
1381 {
1382 delx = (dlong)(c->r_ybot - points[0].p_y) * width;
1383 points[0].p_y = c->r_ybot;
1384 points[4].p_y = c->r_ybot;
1385 points[4].p_x = points[0].p_x - xround(delx);
1386 *np = 5;
1387 }
1388 }
1389 else if (c->r_ybot > points[0].p_y) /* clip BOTTOM, quadrangle */
1390 {
1391 delx = (dlong)(c->r_ybot - points[0].p_y) * width;
1392 points[0].p_y = c->r_ybot;
1393 points[3].p_y = c->r_ybot;
1394 points[3].p_x = points[0].p_x - xround(delx);
1395 *np = 4;
1396 }
1397 if (points[1].p_y < points[0].p_y || points[2].p_x > points[1].p_x)
1398 *np = 0; /* clipped out of existence */
1399 break;
1400 }
1401 }
1402 }
1403
1404 /*---------------------------------------------------------
1405 * GrDrawTriangleEdge --
1406 * Draws the diagonal line in a triangle clipped by
1407 * grCurClip.
1408 *
1409 * Results:
1410 * None.
1411 *
1412 * Side effects:
1413 * Draws nonmanhattan layout geometry.
1414 *
1415 *---------------------------------------------------------
1416 */
1417
1418 void
GrDrawTriangleEdge(r,dinfo)1419 GrDrawTriangleEdge(r, dinfo)
1420 Rect *r; /* Bounding box of triangle, in screen coords */
1421 TileType dinfo;
1422 {
1423 Point tpoints[5];
1424 int tnum, i, j;
1425
1426 GrClipTriangle(r, &grCurClip, TRUE, dinfo, tpoints, &tnum);
1427
1428 for (i = 0; i < tnum; i++)
1429 {
1430 j = (i + 1) % tnum;
1431 if (tpoints[i].p_x != tpoints[j].p_x &&
1432 tpoints[i].p_y != tpoints[j].p_y)
1433 {
1434 GrClipLine(tpoints[i].p_x, tpoints[i].p_y,
1435 tpoints[j].p_x, tpoints[j].p_y);
1436 break;
1437 }
1438 }
1439 }
1440
1441 /*---------------------------------------------------------
1442 * GrDiagonal:
1443 * GrDiagonal will draw a triangle on the screen in the
1444 * style set by the previous call to GrSetStuff. It will also
1445 * be clipped against the rectangles passed to GrSetStuff.
1446 *
1447 * If GrDiagonal is called between GrFastBox calls then GrSetStuff
1448 * must be called to set the parameters back.
1449 *
1450 * Results:
1451 * None.
1452 *
1453 * Side Effects:
1454 * The rectangle is drawn in the style specified.
1455 * The rectangle is clipped before being drawn.
1456 *---------------------------------------------------------
1457 */
1458
1459 void
GrDiagonal(prect,dinfo)1460 GrDiagonal(prect, dinfo)
1461 Rect *prect; /* The rectangle to be drawn, given in
1462 * screen coordinates.
1463 */
1464 TileType dinfo; /* split and direction information */
1465 {
1466 Rect *r;
1467 bool needClip, needObscure;
1468 LinkedRect *ob;
1469 int cp, np;
1470 Rect clipr, fullr;
1471 Point polyp[5];
1472
1473 GR_CHECK_LOCK();
1474 if (!grDriverInformed) grInformDriver();
1475 GrNumClipBoxes++;
1476 if (grCurFill == GR_STGRID)
1477 {
1478 r = &grCurClip;
1479 grGridRect = prect;
1480 }
1481 else
1482 {
1483 r = prect;
1484 if (!GEO_TOUCH(r, &grCurClip)) return;
1485 }
1486
1487 /* Do a quick check to make the (very common) special case of
1488 * no clipping go fast.
1489 */
1490 needClip = !GEO_SURROUND(&grCurClip, r);
1491 needObscure = FALSE;
1492 for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
1493 needObscure |= GEO_TOUCH(r, &(ob->r_r));
1494
1495 /* Generate points for the triangle and do clipping if necessary */
1496
1497 clipr = fullr = *r;
1498 if (needClip)
1499 GeoClip(&clipr, &grCurClip);
1500
1501 GrClipTriangle(&fullr, &clipr, needClip, dinfo, polyp, &np);
1502
1503 /* do solid areas */
1504 if ( (grCurFill == GR_STSOLID) ||
1505 (grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
1506 {
1507 if (needObscure)
1508 grObsBox(&clipr);
1509 else if (grFillPolygonPtr)
1510 (void) (*grFillPolygonPtr)(polyp, np);
1511 }
1512
1513 /* return if rectangle is too small to see */
1514
1515 if ((r->r_xtop - r->r_xbot < GR_THRESH) &&
1516 (r->r_ytop - r->r_ybot < GR_THRESH) && (grCurFill != GR_STOUTLINE))
1517 return;
1518
1519 /* draw outlines */
1520 if ( (grCurOutline != 0) && (grCurFill != GR_STGRID) )
1521 {
1522 /* TO DO: Check for boundary with shared tile type */
1523 for (cp = 0; cp < np - 1; cp++)
1524 (*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
1525 polyp[cp + 1].p_x, polyp[cp + 1].p_y);
1526
1527 (*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
1528 polyp[0].p_x, polyp[0].p_y);
1529 }
1530 }
1531
1532 /*---------------------------------------------------------
1533 * GrFillPolygon --
1534 * This routine is simply a call to the locally-defined
1535 * grFillPolygonPtr routine.
1536 *
1537 *---------------------------------------------------------
1538 */
1539
1540 void
GrFillPolygon(polyp,np)1541 GrFillPolygon(polyp, np)
1542 Point *polyp; /* Array of points defining polygon */
1543 int np; /* number of points in array polyp */
1544 {
1545 if (grFillPolygonPtr != NULL)
1546 {
1547 (*grFillPolygonPtr)(polyp, np);
1548 }
1549 }
1550
1551
1552 /*---------------------------------------------------------
1553 * GrClipBox:
1554 * GrClipBox will draw a rectangle on the screen in one
1555 * of several possible styles, except that the rectangle will
1556 * be clipped against a list of obscuring rectangles.
1557 *
1558 * Results: None.
1559 *
1560 * Side Effects:
1561 * The rectangle is drawn in the style specified.
1562 * The rectangle is clipped before being drawn.
1563 *---------------------------------------------------------
1564 */
1565
1566 void
GrClipBox(prect,style)1567 GrClipBox(prect, style)
1568 Rect *prect; /* The rectangle to be drawn, given in
1569 * screen coordinates.
1570 */
1571 int style; /* The style to be used in drawing it. */
1572 {
1573 GrSetStuff(style);
1574 GrFastBox(prect);
1575 }
1576
1577
1578 /*
1579 * ----------------------------------------------------------------------------
1580 * GrDisjoint --
1581 *
1582 * Clip a rectanglular area against a clipping box, applying the
1583 * supplied procedure to each rectangular region in "area" which
1584 * falls outside "clipbox". This works in pixel space, where a
1585 * rectangle is contains its lower x- and y-coordinates AND ALSO
1586 * its upper coordinates. This means that if the clipping box
1587 * occupies a given pixel, the things being clipped must not occupy
1588 * that pixel. This procedure will NOT work in tile space.
1589 *
1590 * The procedure should be of the form:
1591 * bool func(box, cdarg)
1592 * Rect * box;
1593 * ClientData cdarg;
1594 *
1595 * Results:
1596 * Return TRUE unless the supplied function returns FALSE.
1597 *
1598 * Side effects:
1599 * The side effects of the invoked procedure.
1600 * ----------------------------------------------------------------------------
1601 */
1602 bool
GrDisjoint(area,clipBox,func,cdarg)1603 GrDisjoint(area, clipBox, func, cdarg)
1604 Rect * area;
1605 Rect * clipBox;
1606 bool (*func) ();
1607 ClientData cdarg;
1608 {
1609 Rect ok, rArea;
1610 bool result;
1611
1612 #define NULLBOX(R) ((R.r_xbot>R.r_xtop)||(R.r_ybot>R.r_ytop))
1613
1614 ASSERT((area!=(Rect *) NULL), "GrDisjoint");
1615 if((clipBox==(Rect *) NULL)||(!GEO_TOUCH(area, clipBox)))
1616 {
1617 /* Since there is no overlap, all of "area" may be processed. */
1618
1619 result= (*func)(area, cdarg);
1620 return(result);
1621 }
1622
1623 /* Do the disjoint operation in four steps, one for each side
1624 * of clipBox. In each step, divide the area being clipped
1625 * into one piece that is DEFINITELY outside clipBox, and one
1626 * piece left to check some more.
1627 */
1628
1629 /* Top edge of clipBox: */
1630
1631 rArea = *area;
1632 result = TRUE;
1633 if (clipBox->r_ytop < rArea.r_ytop)
1634 {
1635 ok = rArea;
1636 ok.r_ybot = clipBox->r_ytop + 1;
1637 rArea.r_ytop = clipBox->r_ytop;
1638 if (!(*func)(&ok, cdarg)) result = FALSE;
1639 }
1640
1641 /* Bottom edge of clipBox: */
1642
1643 if (clipBox->r_ybot > rArea.r_ybot)
1644 {
1645 ok = rArea;
1646 ok.r_ytop = clipBox->r_ybot - 1;
1647 rArea.r_ybot = clipBox->r_ybot;
1648 if (!(*func)(&ok, cdarg)) result = FALSE;
1649 }
1650
1651 /* Right edge of clipBox: */
1652
1653 if (clipBox->r_xtop < rArea.r_xtop)
1654 {
1655 ok = rArea;
1656 ok.r_xbot = clipBox->r_xtop + 1;
1657 rArea.r_xtop = clipBox->r_xtop;
1658 if (!(*func)(&ok, cdarg)) result = FALSE;
1659 }
1660
1661 /* Left edge of clipBox: */
1662
1663 if (clipBox->r_xbot > rArea.r_xbot)
1664 {
1665 ok = rArea;
1666 ok.r_xtop = clipBox->r_xbot - 1;
1667 rArea.r_xbot = clipBox->r_xbot;
1668 if (!(*func)(&ok, cdarg)) result = FALSE;
1669 }
1670
1671 /* Just throw away what's left of the area being clipped, since
1672 * it overlaps the clipBox.
1673 */
1674
1675 return result;
1676 } /*GrDisjoint*/
1677