comparison packages/services/gfx/mw/current/src/engine/devrgn2.c @ 208:e0c0827131d1 ecos

Merge from eCos master repository on 2002-05-20-20:11:54-BST
author jlarmour
date Mon, 20 May 2002 22:19:26 +0000
parents
children
comparison
equal deleted inserted replaced
207:74c807ddde34 208:e0c0827131d1
1 /*
2 * Portions Copyright (c) 2000 Greg Haerr <greg@censoft.com>
3 * Somewhat less shamelessly ripped from the Wine distribution
4 * and the X Window System.
5 *
6 * Device-independent Microwindows polygon regions, implemented using
7 * multiple rectangles.
8 *
9 * Shamelessly ripped out from the X11 distribution
10 * Thanks for the nice licence.
11 *
12 * Copyright 1993, 1994, 1995 Alexandre Julliard
13 * Modifications and additions: Copyright 1998 Huw Davies
14 */
15
16 /************************************************************************
17
18 Copyright (c) 1987, 1988 X Consortium
19
20 Permission is hereby granted, free of charge, to any person obtaining a copy
21 of this software and associated documentation files (the "Software"), to deal
22 in the Software without restriction, including without limitation the rights
23 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24 copies of the Software, and to permit persons to whom the Software is
25 furnished to do so, subject to the following conditions:
26
27 The above copyright notice and this permission notice shall be included in
28 all copies or substantial portions of the Software.
29
30 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
34 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
35 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36
37 Except as contained in this notice, the name of the X Consortium shall not be
38 used in advertising or otherwise to promote the sale, use or other dealings
39 in this Software without prior written authorization from the X Consortium.
40
41
42 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
43
44 All Rights Reserved
45
46 Permission to use, copy, modify, and distribute this software and its
47 documentation for any purpose and without fee is hereby granted,
48 provided that the above copyright notice appear in all copies and that
49 both that copyright notice and this permission notice appear in
50 supporting documentation, and that the name of Digital not be
51 used in advertising or publicity pertaining to distribution of the
52 software without specific, written prior permission.
53
54 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
55 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
56 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
57 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
58 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
59 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
60 SOFTWARE.
61
62 ************************************************************************/
63
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include "device.h"
67
68 #if POLYREGIONS
69
70 /*
71 * number of points to buffer before sending them off
72 * to scanlines() : Must be an even number
73 */
74 #define NUMPTSTOBUFFER 200
75
76 /*
77 * used to allocate buffers for points and link
78 * the buffers together
79 */
80
81 typedef struct _POINTBLOCK {
82 MWPOINT pts[NUMPTSTOBUFFER];
83 struct _POINTBLOCK *next;
84 } POINTBLOCK;
85
86 /*
87 * This file contains a few macros to help track
88 * the edge of a filled object. The object is assumed
89 * to be filled in scanline order, and thus the
90 * algorithm used is an extension of Bresenham's line
91 * drawing algorithm which assumes that y is always the
92 * major axis.
93 * Since these pieces of code are the same for any filled shape,
94 * it is more convenient to gather the library in one
95 * place, but since these pieces of code are also in
96 * the inner loops of output primitives, procedure call
97 * overhead is out of the question.
98 * See the author for a derivation if needed.
99 */
100
101 /*
102 * In scan converting polygons, we want to choose those pixels
103 * which are inside the polygon. Thus, we add .5 to the starting
104 * x coordinate for both left and right edges. Now we choose the
105 * first pixel which is inside the pgon for the left edge and the
106 * first pixel which is outside the pgon for the right edge.
107 * Draw the left pixel, but not the right.
108 *
109 * How to add .5 to the starting x coordinate:
110 * If the edge is moving to the right, then subtract dy from the
111 * error term from the general form of the algorithm.
112 * If the edge is moving to the left, then add dy to the error term.
113 *
114 * The reason for the difference between edges moving to the left
115 * and edges moving to the right is simple: If an edge is moving
116 * to the right, then we want the algorithm to flip immediately.
117 * If it is moving to the left, then we don't want it to flip until
118 * we traverse an entire pixel.
119 */
120
121 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
122 int dx; /* local storage */ \
123 \
124 /* \
125 * if the edge is horizontal, then it is ignored \
126 * and assumed not to be processed. Otherwise, do this stuff. \
127 */ \
128 if ((dy) != 0) { \
129 xStart = (x1); \
130 dx = (x2) - xStart; \
131 if (dx < 0) { \
132 m = dx / (dy); \
133 m1 = m - 1; \
134 incr1 = (-2) * (dx) + 2 * (dy) * (m1); \
135 incr2 = (-2) * (dx) + 2 * (dy) * (m); \
136 d = 2 * (m) * (dy) - 2 * (dx) - 2 * (dy); \
137 } else { \
138 m = dx / (dy); \
139 m1 = m + 1; \
140 incr1 = (2 * dx) - 2 * (dy) * m1; \
141 incr2 = (2 * dx) - 2 * (dy) * m; \
142 d = (-2) * m * (dy) + 2 * dx; \
143 } \
144 } \
145 }
146
147 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
148 if (m1 > 0) { \
149 if (d > 0) { \
150 minval += m1; \
151 d += incr1; \
152 } \
153 else { \
154 minval += m; \
155 d += incr2; \
156 } \
157 } else {\
158 if (d >= 0) { \
159 minval += m1; \
160 d += incr1; \
161 } \
162 else { \
163 minval += m; \
164 d += incr2; \
165 } \
166 } \
167 }
168
169
170 /*
171 * This structure contains all of the information needed
172 * to run the bresenham algorithm.
173 * The variables may be hardcoded into the declarations
174 * instead of using this structure to make use of
175 * register declarations.
176 */
177 typedef struct {
178 MWCOORD minor_axis; /* minor axis */
179 int d; /* decision variable */
180 int m, m1; /* slope and slope+1 */
181 int incr1, incr2; /* error increments */
182 } BRESINFO;
183
184 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
185 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
186 bres.m, bres.m1, bres.incr1, bres.incr2)
187
188 #define BRESINCRPGONSTRUCT(bres) \
189 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
190
191
192 /*
193 * These are the data structures needed to scan
194 * convert regions. Two different scan conversion
195 * methods are available -- the even-odd method, and
196 * the winding number method.
197 * The even-odd rule states that a point is inside
198 * the polygon if a ray drawn from that point in any
199 * direction will pass through an odd number of
200 * path segments.
201 * By the winding number rule, a point is decided
202 * to be inside the polygon if a ray drawn from that
203 * point in any direction passes through a different
204 * number of clockwise and counter-clockwise path
205 * segments.
206 *
207 * These data structures are adapted somewhat from
208 * the algorithm in (Foley/Van Dam) for scan converting
209 * polygons.
210 * The basic algorithm is to start at the top (smallest y)
211 * of the polygon, stepping down to the bottom of
212 * the polygon by incrementing the y coordinate. We
213 * keep a list of edges which the current scanline crosses,
214 * sorted by x. This list is called the Active Edge Table (AET)
215 * As we change the y-coordinate, we update each entry in
216 * in the active edge table to reflect the edges new xcoord.
217 * This list must be sorted at each scanline in case
218 * two edges intersect.
219 * We also keep a data structure known as the Edge Table (ET),
220 * which keeps track of all the edges which the current
221 * scanline has not yet reached. The ET is basically a
222 * list of ScanLineList structures containing a list of
223 * edges which are entered at a given scanline. There is one
224 * ScanLineList per scanline at which an edge is entered.
225 * When we enter a new edge, we move it from the ET to the AET.
226 *
227 * From the AET, we can implement the even-odd rule as in
228 * (Foley/Van Dam).
229 * The winding number rule is a little trickier. We also
230 * keep the EdgeTableEntries in the AET linked by the
231 * nextWETE (winding EdgeTableEntry) link. This allows
232 * the edges to be linked just as before for updating
233 * purposes, but only uses the edges linked by the nextWETE
234 * link as edges representing spans of the polygon to
235 * drawn (as with the even-odd rule).
236 */
237
238 /*
239 * for the winding number rule
240 */
241 #define CLOCKWISE 1
242 #define COUNTERCLOCKWISE -1
243
244 typedef struct _EdgeTableEntry {
245 MWCOORD ymax; /* ycoord at which we exit this edge. */
246 BRESINFO bres; /* Bresenham info to run the edge */
247 struct _EdgeTableEntry *next; /* next in the list */
248 struct _EdgeTableEntry *back; /* for insertion sort */
249 struct _EdgeTableEntry *nextWETE; /* for winding num rule */
250 int ClockWise; /* flag for winding number rule */
251 } EdgeTableEntry;
252
253
254 typedef struct _ScanLineList{
255 int scanline; /* the scanline represented */
256 EdgeTableEntry *edgelist; /* header node */
257 struct _ScanLineList *next; /* next in the list */
258 } ScanLineList;
259
260
261 typedef struct {
262 MWCOORD ymax; /* ymax for the polygon */
263 MWCOORD ymin; /* ymin for the polygon */
264 ScanLineList scanlines; /* header node */
265 } EdgeTable;
266
267
268 /*
269 * Here is a struct to help with storage allocation
270 * so we can allocate a big chunk at a time, and then take
271 * pieces from this heap when we need to.
272 */
273 #define SLLSPERBLOCK 25
274
275 typedef struct _ScanLineListBlock {
276 ScanLineList SLLs[SLLSPERBLOCK];
277 struct _ScanLineListBlock *next;
278 } ScanLineListBlock;
279
280 /*
281 *
282 * a few macros for the inner loops of the fill code where
283 * performance considerations don't allow a procedure call.
284 *
285 * Evaluate the given edge at the given scanline.
286 * If the edge has expired, then we leave it and fix up
287 * the active edge table; otherwise, we increment the
288 * x value to be ready for the next scanline.
289 * The winding number rule is in effect, so we must notify
290 * the caller when the edge has been removed so he
291 * can reorder the Winding Active Edge Table.
292 */
293 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
294 if (pAET->ymax == y) { /* leaving this edge */ \
295 pPrevAET->next = pAET->next; \
296 pAET = pPrevAET->next; \
297 fixWAET = 1; \
298 if (pAET) \
299 pAET->back = pPrevAET; \
300 } \
301 else { \
302 BRESINCRPGONSTRUCT(pAET->bres); \
303 pPrevAET = pAET; \
304 pAET = pAET->next; \
305 } \
306 }
307
308
309 /*
310 * Evaluate the given edge at the given scanline.
311 * If the edge has expired, then we leave it and fix up
312 * the active edge table; otherwise, we increment the
313 * x value to be ready for the next scanline.
314 * The even-odd rule is in effect.
315 */
316 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
317 if (pAET->ymax == y) { /* leaving this edge */ \
318 pPrevAET->next = pAET->next; \
319 pAET = pPrevAET->next; \
320 if (pAET) \
321 pAET->back = pPrevAET; \
322 } \
323 else { \
324 BRESINCRPGONSTRUCT(pAET->bres); \
325 pPrevAET = pAET; \
326 pAET = pAET->next; \
327 } \
328 }
329
330
331
332 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
333 #define SMALL_COORDINATE 0x80000000
334
335 /*
336 * REGION_InsertEdgeInET
337 *
338 * Insert the given edge into the edge table.
339 * First we must find the correct bucket in the
340 * Edge table, then find the right slot in the
341 * bucket. Finally, we can insert it.
342 *
343 */
344 static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
345 int scanline, ScanLineListBlock **SLLBlock, int *iSLLBlock)
346
347 {
348 EdgeTableEntry *start, *prev;
349 ScanLineList *pSLL, *pPrevSLL;
350 ScanLineListBlock *tmpSLLBlock;
351
352 /*
353 * find the right bucket to put the edge into
354 */
355 pPrevSLL = &ET->scanlines;
356 pSLL = pPrevSLL->next;
357 while (pSLL && (pSLL->scanline < scanline))
358 {
359 pPrevSLL = pSLL;
360 pSLL = pSLL->next;
361 }
362
363 /*
364 * reassign pSLL (pointer to ScanLineList) if necessary
365 */
366 if ((!pSLL) || (pSLL->scanline > scanline))
367 {
368 if (*iSLLBlock > SLLSPERBLOCK-1)
369 {
370 tmpSLLBlock = malloc( sizeof(ScanLineListBlock));
371 if(!tmpSLLBlock)
372 {
373 return;
374 }
375 (*SLLBlock)->next = tmpSLLBlock;
376 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
377 *SLLBlock = tmpSLLBlock;
378 *iSLLBlock = 0;
379 }
380 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
381
382 pSLL->next = pPrevSLL->next;
383 pSLL->edgelist = (EdgeTableEntry *)NULL;
384 pPrevSLL->next = pSLL;
385 }
386 pSLL->scanline = scanline;
387
388 /*
389 * now insert the edge in the right bucket
390 */
391 prev = (EdgeTableEntry *)NULL;
392 start = pSLL->edgelist;
393 while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
394 {
395 prev = start;
396 start = start->next;
397 }
398 ETE->next = start;
399
400 if (prev)
401 prev->next = ETE;
402 else
403 pSLL->edgelist = ETE;
404 }
405
406
407 /*
408 * REGION_CreateEdgeTable
409 *
410 * This routine creates the edge table for
411 * scan converting polygons.
412 * The Edge Table (ET) looks like:
413 *
414 * EdgeTable
415 * --------
416 * | ymax | ScanLineLists
417 * |scanline|-->------------>-------------->...
418 * -------- |scanline| |scanline|
419 * |edgelist| |edgelist|
420 * --------- ---------
421 * | |
422 * | |
423 * V V
424 * list of ETEs list of ETEs
425 *
426 * where ETE is an EdgeTableEntry data structure,
427 * and there is one ScanLineList per scanline at
428 * which an edge is initially entered.
429 *
430 */
431 static void REGION_CreateETandAET(int *Count, int nbpolygons,
432 MWPOINT *pts, EdgeTable *ET, EdgeTableEntry *AET,
433 EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
434 {
435 MWPOINT *top, *bottom;
436 MWPOINT *PrevPt, *CurrPt, *EndPt;
437 int poly, count;
438 int iSLLBlock = 0;
439 int dy;
440
441
442 /*
443 * initialize the Active Edge Table
444 */
445 AET->next = (EdgeTableEntry *)NULL;
446 AET->back = (EdgeTableEntry *)NULL;
447 AET->nextWETE = (EdgeTableEntry *)NULL;
448 AET->bres.minor_axis = SMALL_COORDINATE;
449
450 /*
451 * initialize the Edge Table.
452 */
453 ET->scanlines.next = (ScanLineList *)NULL;
454 ET->ymax = SMALL_COORDINATE;
455 ET->ymin = LARGE_COORDINATE;
456 pSLLBlock->next = (ScanLineListBlock *)NULL;
457
458 EndPt = pts - 1;
459 for(poly = 0; poly < nbpolygons; poly++)
460 {
461 count = Count[poly];
462 EndPt += count;
463 if(count < 2)
464 continue;
465
466 PrevPt = EndPt;
467
468 /*
469 * for each vertex in the array of points.
470 * In this loop we are dealing with two vertices at
471 * a time -- these make up one edge of the polygon.
472 */
473 while (count--)
474 {
475 CurrPt = pts++;
476 /*
477 * find out which point is above and which is below.
478 */
479 if (PrevPt->y > CurrPt->y)
480 {
481 bottom = PrevPt, top = CurrPt;
482 pETEs->ClockWise = 0;
483 }
484 else
485 {
486 bottom = CurrPt, top = PrevPt;
487 pETEs->ClockWise = 1;
488 }
489
490 /*
491 * don't add horizontal edges to the Edge table.
492 */
493 if (bottom->y != top->y)
494 {
495 pETEs->ymax = bottom->y-1;
496 /* -1 so we don't get last scanline */
497
498 /*
499 * initialize integer edge algorithm
500 */
501 dy = bottom->y - top->y;
502
503 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
504
505 REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
506 &iSLLBlock);
507
508 if (PrevPt->y > ET->ymax)
509 ET->ymax = PrevPt->y;
510 if (PrevPt->y < ET->ymin)
511 ET->ymin = PrevPt->y;
512 pETEs++;
513 }
514
515 PrevPt = CurrPt;
516 }
517 }
518 }
519
520 /*
521 * REGION_loadAET
522 *
523 * This routine moves EdgeTableEntries from the
524 * EdgeTable into the Active Edge Table,
525 * leaving them sorted by smaller x coordinate.
526 *
527 */
528 static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
529 {
530 EdgeTableEntry *pPrevAET;
531 EdgeTableEntry *tmp;
532
533 pPrevAET = AET;
534 AET = AET->next;
535 while (ETEs)
536 {
537 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
538 {
539 pPrevAET = AET;
540 AET = AET->next;
541 }
542 tmp = ETEs->next;
543 ETEs->next = AET;
544 if (AET)
545 AET->back = ETEs;
546 ETEs->back = pPrevAET;
547 pPrevAET->next = ETEs;
548 pPrevAET = ETEs;
549
550 ETEs = tmp;
551 }
552 }
553
554 /*
555 * REGION_computeWAET
556 *
557 * This routine links the AET by the
558 * nextWETE (winding EdgeTableEntry) link for
559 * use by the winding number rule. The final
560 * Active Edge Table (AET) might look something
561 * like:
562 *
563 * AET
564 * ---------- --------- ---------
565 * |ymax | |ymax | |ymax |
566 * | ... | |... | |... |
567 * |next |->|next |->|next |->...
568 * |nextWETE| |nextWETE| |nextWETE|
569 * --------- --------- ^--------
570 * | | |
571 * V-------------------> V---> ...
572 *
573 */
574 static void REGION_computeWAET(EdgeTableEntry *AET)
575 {
576 EdgeTableEntry *pWETE;
577 int inside = 1;
578 int isInside = 0;
579
580 AET->nextWETE = (EdgeTableEntry *)NULL;
581 pWETE = AET;
582 AET = AET->next;
583 while (AET)
584 {
585 if (AET->ClockWise)
586 isInside++;
587 else
588 isInside--;
589
590 if ((!inside && !isInside) ||
591 ( inside && isInside))
592 {
593 pWETE->nextWETE = AET;
594 pWETE = AET;
595 inside = !inside;
596 }
597 AET = AET->next;
598 }
599 pWETE->nextWETE = (EdgeTableEntry *)NULL;
600 }
601
602 /*
603 * REGION_InsertionSort
604 *
605 * Just a simple insertion sort using
606 * pointers and back pointers to sort the Active
607 * Edge Table.
608 *
609 */
610 static MWBOOL REGION_InsertionSort(EdgeTableEntry *AET)
611 {
612 EdgeTableEntry *pETEchase;
613 EdgeTableEntry *pETEinsert;
614 EdgeTableEntry *pETEchaseBackTMP;
615 MWBOOL changed = FALSE;
616
617 AET = AET->next;
618 while (AET)
619 {
620 pETEinsert = AET;
621 pETEchase = AET;
622 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
623 pETEchase = pETEchase->back;
624
625 AET = AET->next;
626 if (pETEchase != pETEinsert)
627 {
628 pETEchaseBackTMP = pETEchase->back;
629 pETEinsert->back->next = AET;
630 if (AET)
631 AET->back = pETEinsert->back;
632 pETEinsert->next = pETEchase;
633 pETEchase->back->next = pETEinsert;
634 pETEchase->back = pETEinsert;
635 pETEinsert->back = pETEchaseBackTMP;
636 changed = TRUE;
637 }
638 }
639 return changed;
640 }
641
642 /*
643 * REGION_FreeStorage
644 *
645 * Clean up our act.
646 */
647 static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
648 {
649 ScanLineListBlock *tmpSLLBlock;
650
651 while (pSLLBlock)
652 {
653 tmpSLLBlock = pSLLBlock->next;
654 free( pSLLBlock );
655 pSLLBlock = tmpSLLBlock;
656 }
657 }
658
659
660 /*
661 * REGION_PtsToRegion
662 *
663 * Create an array of rectangles from a list of points.
664 */
665 static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
666 POINTBLOCK *FirstPtBlock, MWCLIPREGION *reg)
667 {
668 MWRECT *rects;
669 MWPOINT *pts;
670 POINTBLOCK *CurPtBlock;
671 int i;
672 MWRECT *extents;
673 int numRects;
674
675 extents = &reg->extents;
676
677 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
678
679 if (!(reg->rects = realloc( reg->rects, sizeof(MWRECT) * numRects )))
680 return(0);
681
682 reg->size = numRects;
683 CurPtBlock = FirstPtBlock;
684 rects = reg->rects - 1;
685 numRects = 0;
686 extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
687
688 for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
689 /* the loop uses 2 points per iteration */
690 i = NUMPTSTOBUFFER >> 1;
691 if (!numFullPtBlocks)
692 i = iCurPtBlock >> 1;
693 for (pts = CurPtBlock->pts; i--; pts += 2) {
694 if (pts->x == pts[1].x)
695 continue;
696 if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
697 pts[1].x == rects->right &&
698 (numRects == 1 || rects[-1].top != rects->top) &&
699 (i && pts[2].y > pts[1].y)) {
700 rects->bottom = pts[1].y + 1;
701 continue;
702 }
703 numRects++;
704 rects++;
705 rects->left = pts->x; rects->top = pts->y;
706 rects->right = pts[1].x; rects->bottom = pts[1].y + 1;
707 if (rects->left < extents->left)
708 extents->left = rects->left;
709 if (rects->right > extents->right)
710 extents->right = rects->right;
711 }
712 CurPtBlock = CurPtBlock->next;
713 }
714
715 if (numRects) {
716 extents->top = reg->rects->top;
717 extents->bottom = rects->bottom;
718 } else {
719 extents->left = 0;
720 extents->top = 0;
721 extents->right = 0;
722 extents->bottom = 0;
723 }
724 reg->numRects = numRects;
725
726 return(TRUE);
727 }
728
729 /*
730 * GdAllocPolygonRegion
731 */
732 MWCLIPREGION *
733 GdAllocPolygonRegion(MWPOINT *points, int count, int mode)
734 {
735 return GdAllocPolyPolygonRegion(points, &count, 1, mode );
736 }
737
738 /*
739 * GdAllocPolyPolygonRegion
740 */
741 MWCLIPREGION *
742 GdAllocPolyPolygonRegion(MWPOINT *points, int *count, int nbpolygons, int mode)
743 {
744 MWCLIPREGION *rgn;
745 EdgeTableEntry *pAET; /* Active Edge Table */
746 int y; /* current scanline */
747 int iPts = 0; /* number of pts in buffer */
748 EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
749 ScanLineList *pSLL; /* current scanLineList */
750 MWPOINT *pts; /* output buffer */
751 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
752 EdgeTable ET; /* header node for ET */
753 EdgeTableEntry AET; /* header node for AET */
754 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
755 ScanLineListBlock SLLBlock; /* header for scanlinelist */
756 int fixWAET = FALSE;
757 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
758 POINTBLOCK *tmpPtBlock;
759 int numFullPtBlocks = 0;
760 int poly, total;
761
762 if(!(rgn = GdAllocRegion()))
763 return NULL;
764
765 /* special case a rectangle */
766
767 if (((nbpolygons == 1) && ((*count == 4) ||
768 ((*count == 5) && (points[4].x == points[0].x)
769 && (points[4].y == points[0].y)))) &&
770 (((points[0].y == points[1].y) &&
771 (points[1].x == points[2].x) &&
772 (points[2].y == points[3].y) &&
773 (points[3].x == points[0].x)) ||
774 ((points[0].x == points[1].x) &&
775 (points[1].y == points[2].y) &&
776 (points[2].x == points[3].x) &&
777 (points[3].y == points[0].y))))
778 {
779 GdSetRectRegion( rgn,
780 MWMIN(points[0].x, points[2].x), MWMIN(points[0].y, points[2].y),
781 MWMAX(points[0].x, points[2].x), MWMAX(points[0].y, points[2].y) );
782 return rgn;
783 }
784
785 for(poly = total = 0; poly < nbpolygons; poly++)
786 total += count[poly];
787 if (! (pETEs = malloc( sizeof(EdgeTableEntry) * total )))
788 {
789 GdDestroyRegion( rgn );
790 return 0;
791 }
792 pts = FirstPtBlock.pts;
793 REGION_CreateETandAET(count, nbpolygons, points, &ET, &AET,
794 pETEs, &SLLBlock);
795 pSLL = ET.scanlines.next;
796 curPtBlock = &FirstPtBlock;
797
798 if (mode != MWPOLY_WINDING) {
799 /*
800 * for each scanline
801 */
802 for (y = ET.ymin; y < ET.ymax; y++) {
803 /*
804 * Add a new edge to the active edge table when we
805 * get to the next edge.
806 */
807 if (pSLL != NULL && y == pSLL->scanline) {
808 REGION_loadAET(&AET, pSLL->edgelist);
809 pSLL = pSLL->next;
810 }
811 pPrevAET = &AET;
812 pAET = AET.next;
813
814 /*
815 * for each active edge
816 */
817 while (pAET) {
818 pts->x = pAET->bres.minor_axis, pts->y = y;
819 pts++, iPts++;
820
821 /*
822 * send out the buffer
823 */
824 if (iPts == NUMPTSTOBUFFER) {
825 tmpPtBlock = malloc( sizeof(POINTBLOCK));
826 if(!tmpPtBlock) {
827 return 0;
828 }
829 curPtBlock->next = tmpPtBlock;
830 curPtBlock = tmpPtBlock;
831 pts = curPtBlock->pts;
832 numFullPtBlocks++;
833 iPts = 0;
834 }
835 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
836
837 }
838 REGION_InsertionSort(&AET);
839 }
840 }
841 else {
842 /*
843 * for each scanline
844 */
845 for (y = ET.ymin; y < ET.ymax; y++) {
846 /*
847 * Add a new edge to the active edge table when we
848 * get to the next edge.
849 */
850 if (pSLL != NULL && y == pSLL->scanline) {
851 REGION_loadAET(&AET, pSLL->edgelist);
852 REGION_computeWAET(&AET);
853 pSLL = pSLL->next;
854 }
855 pPrevAET = &AET;
856 pAET = AET.next;
857 pWETE = pAET;
858
859 /*
860 * for each active edge
861 */
862 while (pAET) {
863 /*
864 * add to the buffer only those edges that
865 * are in the Winding active edge table.
866 */
867 if (pWETE == pAET) {
868 pts->x = pAET->bres.minor_axis, pts->y = y;
869 pts++, iPts++;
870
871 /*
872 * send out the buffer
873 */
874 if (iPts == NUMPTSTOBUFFER) {
875 tmpPtBlock = malloc( sizeof(POINTBLOCK) );
876 if(!tmpPtBlock) {
877 return 0;
878 }
879 curPtBlock->next = tmpPtBlock;
880 curPtBlock = tmpPtBlock;
881 pts = curPtBlock->pts;
882 numFullPtBlocks++; iPts = 0;
883 }
884 pWETE = pWETE->nextWETE;
885 }
886 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
887 }
888
889 /*
890 * recompute the winding active edge table if
891 * we just resorted or have exited an edge.
892 */
893 if (REGION_InsertionSort(&AET) || fixWAET) {
894 REGION_computeWAET(&AET);
895 fixWAET = FALSE;
896 }
897 }
898 }
899 REGION_FreeStorage(SLLBlock.next);
900 REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, rgn);
901 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
902 tmpPtBlock = curPtBlock->next;
903 free( curPtBlock );
904 curPtBlock = tmpPtBlock;
905 }
906 free( pETEs );
907 return rgn;
908 }
909
910 #endif /* POLYREGIONS*/