source: vendor/trolltech/current/src/kernel/qpolygonscanner.cpp

Last change on this file was 67, checked in by dmik, 19 years ago

Imported canvas and session manager sources from the official release 3.3.1 from Trolltech.

  • Property svn:keywords set to Id
File size: 28.8 KB
Line 
1/****************************************************************************
2** $Id: qpolygonscanner.cpp 67 2006-03-18 17:30:20Z dmik $
3**
4** Implementation of QPolygonScanner class
5**
6** Created : 000120
7**
8** Copyright (C) 1999-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qpolygonscanner.h"
39#include "qpointarray.h"
40#include <stdlib.h>
41
42
43// Based on Xserver code miFillGeneralPoly...
44/*
45 *
46 * Written by Brian Kelleher; Oct. 1985
47 *
48 * Routine to fill a polygon. Two fill rules are
49 * supported: frWINDING and frEVENODD.
50 *
51 * See fillpoly.h for a complete description of the algorithm.
52 */
53
54/*
55 * These are the data structures needed to scan
56 * convert regions. Two different scan conversion
57 * methods are available -- the even-odd method, and
58 * the winding number method.
59 * The even-odd rule states that a point is inside
60 * the polygon if a ray drawn from that point in any
61 * direction will pass through an odd number of
62 * path segments.
63 * By the winding number rule, a point is decided
64 * to be inside the polygon if a ray drawn from that
65 * point in any direction passes through a different
66 * number of clockwise and counterclockwise path
67 * segments.
68 *
69 * These data structures are adapted somewhat from
70 * the algorithm in (Foley/Van Dam) for scan converting
71 * polygons.
72 * The basic algorithm is to start at the top (smallest y)
73 * of the polygon, stepping down to the bottom of
74 * the polygon by incrementing the y coordinate. We
75 * keep a list of edges which the current scanline crosses,
76 * sorted by x. This list is called the Active Edge Table (AET)
77 * As we change the y-coordinate, we update each entry in
78 * in the active edge table to reflect the edges new xcoord.
79 * This list must be sorted at each scanline in case
80 * two edges intersect.
81 * We also keep a data structure known as the Edge Table (ET),
82 * which keeps track of all the edges which the current
83 * scanline has not yet reached. The ET is basically a
84 * list of ScanLineList structures containing a list of
85 * edges which are entered at a given scanline. There is one
86 * ScanLineList per scanline at which an edge is entered.
87 * When we enter a new edge, we move it from the ET to the AET.
88 *
89 * From the AET, we can implement the even-odd rule as in
90 * (Foley/Van Dam).
91 * The winding number rule is a little trickier. We also
92 * keep the EdgeTableEntries in the AET linked by the
93 * nextWETE (winding EdgeTableEntry) link. This allows
94 * the edges to be linked just as before for updating
95 * purposes, but only uses the edges linked by the nextWETE
96 * link as edges representing spans of the polygon to
97 * drawn (as with the even-odd rule).
98 */
99
100/* $XConsortium: miscanfill.h,v 1.5 94/04/17 20:27:50 dpw Exp $ */
101/*
102
103Copyright (c) 1987 X Consortium
104
105Permission is hereby granted, free of charge, to any person obtaining
106a copy of this software and associated documentation files (the
107"Software"), to deal in the Software without restriction, including
108without limitation the rights to use, copy, modify, merge, publish,
109distribute, sublicense, and/or sell copies of the Software, and to
110permit persons to whom the Software is furnished to do so, subject to
111the following conditions:
112
113The above copyright notice and this permission notice shall be included
114in all copies or substantial portions of the Software.
115
116THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
117OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
118MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
119IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
120OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
121ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
122OTHER DEALINGS IN THE SOFTWARE.
123
124Except as contained in this notice, the name of the X Consortium shall
125not be used in advertising or otherwise to promote the sale, use or
126other dealings in this Software without prior written authorization
127from the X Consortium.
128
129*/
130
131
132/*
133 * scanfill.h
134 *
135 * Written by Brian Kelleher; Jan 1985
136 *
137 * This file contains a few macros to help track
138 * the edge of a filled object. The object is assumed
139 * to be filled in scanline order, and thus the
140 * algorithm used is an extension of Bresenham's line
141 * drawing algorithm which assumes that y is always the
142 * major axis.
143 * Since these pieces of code are the same for any filled shape,
144 * it is more convenient to gather the library in one
145 * place, but since these pieces of code are also in
146 * the inner loops of output primitives, procedure call
147 * overhead is out of the question.
148 * See the author for a derivation if needed.
149 */
150
151/*
152 * In scan converting polygons, we want to choose those pixels
153 * which are inside the polygon. Thus, we add .5 to the starting
154 * x coordinate for both left and right edges. Now we choose the
155 * first pixel which is inside the pgon for the left edge and the
156 * first pixel which is outside the pgon for the right edge.
157 * Draw the left pixel, but not the right.
158 *
159 * How to add .5 to the starting x coordinate:
160 * If the edge is moving to the right, then subtract dy from the
161 * error term from the general form of the algorithm.
162 * If the edge is moving to the left, then add dy to the error term.
163 *
164 * The reason for the difference between edges moving to the left
165 * and edges moving to the right is simple: If an edge is moving
166 * to the right, then we want the algorithm to flip immediately.
167 * If it is moving to the left, then we don't want it to flip until
168 * we traverse an entire pixel.
169 */
170#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
171 int dx; /* local storage */ \
172\
173 /* \
174 * if the edge is horizontal, then it is ignored \
175 * and assumed not to be processed. Otherwise, do this stuff. \
176 */ \
177 if ((dy) != 0) { \
178 xStart = (x1); \
179 dx = (x2) - xStart; \
180 if (dx < 0) { \
181 m = dx / (dy); \
182 m1 = m - 1; \
183 incr1 = -2 * dx + 2 * (dy) * m1; \
184 incr2 = -2 * dx + 2 * (dy) * m; \
185 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
186 } else { \
187 m = dx / (dy); \
188 m1 = m + 1; \
189 incr1 = 2 * dx - 2 * (dy) * m1; \
190 incr2 = 2 * dx - 2 * (dy) * m; \
191 d = -2 * m * (dy) + 2 * dx; \
192 } \
193 } \
194}
195
196
197#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
198 if (m1 > 0) { \
199 if (d > 0) { \
200 minval += m1; \
201 d += incr1; \
202 } \
203 else { \
204 minval += m; \
205 d += incr2; \
206 } \
207 } else {\
208 if (d >= 0) { \
209 minval += m1; \
210 d += incr1; \
211 } \
212 else { \
213 minval += m; \
214 d += incr2; \
215 } \
216 } \
217}
218
219
220
221/*
222 * This structure contains all of the information needed
223 * to run the bresenham algorithm.
224 * The variables may be hardcoded into the declarations
225 * instead of using this structure to make use of
226 * register declarations.
227 */
228typedef struct {
229 int minor; /* minor axis */
230 int d; /* decision variable */
231 int m, m1; /* slope and slope+1 */
232 int incr1, incr2; /* error increments */
233} BRESINFO;
234
235
236#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
237 BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
238 bres.m, bres.m1, bres.incr1, bres.incr2)
239
240#define BRESINCRPGONSTRUCT(bres) \
241 BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
242
243
244typedef struct _EdgeTableEntry {
245 int 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
254typedef 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
261typedef struct {
262 int ymax; /* ymax for the polygon */
263 int 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
275typedef struct _ScanLineListBlock {
276 ScanLineList SLLs[SLLSPERBLOCK];
277 struct _ScanLineListBlock *next;
278} ScanLineListBlock;
279
280/*
281 * number of points to buffer before sending them off
282 * to scanlines() : Must be an even number
283 */
284#define NUMPTSTOBUFFER 200
285
286/*
287 *
288 * a few macros for the inner loops of the fill code where
289 * performance considerations don't allow a procedure call.
290 *
291 * Evaluate the given edge at the given scanline.
292 * If the edge has expired, then we leave it and fix up
293 * the active edge table; otherwise, we increment the
294 * x value to be ready for the next scanline.
295 * The winding number rule is in effect, so we must notify
296 * the caller when the edge has been removed so he
297 * can reorder the Winding Active Edge Table.
298 */
299#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
300 if (pAET->ymax == y) { /* leaving this edge */ \
301 pPrevAET->next = pAET->next; \
302 pAET = pPrevAET->next; \
303 fixWAET = 1; \
304 if (pAET) \
305 pAET->back = pPrevAET; \
306 } \
307 else { \
308 BRESINCRPGONSTRUCT(pAET->bres); \
309 pPrevAET = pAET; \
310 pAET = pAET->next; \
311 } \
312}
313
314
315/*
316 * Evaluate the given edge at the given scanline.
317 * If the edge has expired, then we leave it and fix up
318 * the active edge table; otherwise, we increment the
319 * x value to be ready for the next scanline.
320 * The even-odd rule is in effect.
321 */
322#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
323 if (pAET->ymax == y) { /* leaving this edge */ \
324 pPrevAET->next = pAET->next; \
325 pAET = pPrevAET->next; \
326 if (pAET) \
327 pAET->back = pPrevAET; \
328 } \
329 else { \
330 BRESINCRPGONSTRUCT(pAET->bres) \
331 pPrevAET = pAET; \
332 pAET = pAET->next; \
333 } \
334}
335
336/***********************************************************
337
338Copyright (c) 1987 X Consortium
339
340Permission is hereby granted, free of charge, to any person obtaining a copy
341of this software and associated documentation files (the "Software"), to deal
342in the Software without restriction, including without limitation the rights
343to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
344copies of the Software, and to permit persons to whom the Software is
345furnished to do so, subject to the following conditions:
346
347The above copyright notice and this permission notice shall be included in
348all copies or substantial portions of the Software.
349
350THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
351IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
352FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
353X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
354AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
355CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
356
357Except as contained in this notice, the name of the X Consortium shall not be
358used in advertising or otherwise to promote the sale, use or other dealings
359in this Software without prior written authorization from the X Consortium.
360
361
362Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
363
364 All Rights Reserved
365
366Permission to use, copy, modify, and distribute this software and its
367documentation for any purpose and without fee is hereby granted,
368provided that the above copyright notice appear in all copies and that
369both that copyright notice and this permission notice appear in
370supporting documentation, and that the name of Digital not be
371used in advertising or publicity pertaining to distribution of the
372software without specific, written prior permission.
373
374DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
375ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
376DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
377ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
378WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
379ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
380SOFTWARE.
381
382******************************************************************/
383
384#define MAXINT 0x7fffffff
385#define MININT -MAXINT
386
387/*
388 * fillUtils.c
389 *
390 * Written by Brian Kelleher; Oct. 1985
391 *
392 * This module contains all of the utility functions
393 * needed to scan convert a polygon.
394 *
395 */
396/*
397 * InsertEdgeInET
398 *
399 * Insert the given edge into the edge table.
400 * First we must find the correct bucket in the
401 * Edge table, then find the right slot in the
402 * bucket. Finally, we can insert it.
403 *
404 */
405bool
406miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
407 int scanline, ScanLineListBlock **SLLBlock, int *iSLLBlock)
408{
409 register EdgeTableEntry *start, *prev;
410 register ScanLineList *pSLL, *pPrevSLL;
411 ScanLineListBlock *tmpSLLBlock;
412
413 /*
414 * find the right bucket to put the edge into
415 */
416 pPrevSLL = &ET->scanlines;
417 pSLL = pPrevSLL->next;
418 while (pSLL && (pSLL->scanline < scanline))
419 {
420 pPrevSLL = pSLL;
421 pSLL = pSLL->next;
422 }
423
424 /*
425 * reassign pSLL (pointer to ScanLineList) if necessary
426 */
427 if ((!pSLL) || (pSLL->scanline > scanline))
428 {
429 if (*iSLLBlock > SLLSPERBLOCK-1)
430 {
431 tmpSLLBlock =
432 (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
433 if (!tmpSLLBlock)
434 return FALSE;
435 (*SLLBlock)->next = tmpSLLBlock;
436 tmpSLLBlock->next = 0;
437 *SLLBlock = tmpSLLBlock;
438 *iSLLBlock = 0;
439 }
440 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
441
442 pSLL->next = pPrevSLL->next;
443 pSLL->edgelist = 0;
444 pPrevSLL->next = pSLL;
445 }
446 pSLL->scanline = scanline;
447
448 /*
449 * now insert the edge in the right bucket
450 */
451 prev = 0;
452 start = pSLL->edgelist;
453 while (start && (start->bres.minor < ETE->bres.minor))
454 {
455 prev = start;
456 start = start->next;
457 }
458 ETE->next = start;
459
460 if (prev)
461 prev->next = ETE;
462 else
463 pSLL->edgelist = ETE;
464 return TRUE;
465}
466
467
468/*
469 * CreateEdgeTable
470 *
471 * This routine creates the edge table for
472 * scan converting polygons.
473 * The Edge Table (ET) looks like:
474 *
475 * EdgeTable
476 * --------
477 * | ymax | ScanLineLists
478 * |scanline|-->------------>-------------->...
479 * -------- |scanline| |scanline|
480 * |edgelist| |edgelist|
481 * --------- ---------
482 * | |
483 * | |
484 * V V
485 * list of ETEs list of ETEs
486 *
487 * where ETE is an EdgeTableEntry data structure,
488 * and there is one ScanLineList per scanline at
489 * which an edge is initially entered.
490 *
491 */
492
493typedef struct {
494#if defined(Q_OS_MAC)
495 int y, x;
496#else
497 int x, y;
498#endif
499
500} DDXPointRec, *DDXPointPtr;
501
502/*
503 * Clean up our act.
504 */
505void
506miFreeStorage(ScanLineListBlock *pSLLBlock)
507{
508 register ScanLineListBlock *tmpSLLBlock;
509
510 while (pSLLBlock)
511 {
512 tmpSLLBlock = pSLLBlock->next;
513 free(pSLLBlock);
514 pSLLBlock = tmpSLLBlock;
515 }
516}
517
518bool
519miCreateETandAET(int count, DDXPointPtr pts, EdgeTable *ET,
520 EdgeTableEntry *AET, EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
521{
522 register DDXPointPtr top, bottom;
523 register DDXPointPtr PrevPt, CurrPt;
524 int iSLLBlock = 0;
525
526 int dy;
527
528 if (count < 2) return TRUE;
529
530 /*
531 * initialize the Active Edge Table
532 */
533 AET->next = 0;
534 AET->back = 0;
535 AET->nextWETE = 0;
536 AET->bres.minor = MININT;
537
538 /*
539 * initialize the Edge Table.
540 */
541 ET->scanlines.next = 0;
542 ET->ymax = MININT;
543 ET->ymin = MAXINT;
544 pSLLBlock->next = 0;
545
546 PrevPt = &pts[count-1];
547
548 /*
549 * for each vertex in the array of points.
550 * In this loop we are dealing with two vertices at
551 * a time -- these make up one edge of the polygon.
552 */
553 while (count--)
554 {
555 CurrPt = pts++;
556
557 /*
558 * find out which point is above and which is below.
559 */
560 if (PrevPt->y > CurrPt->y)
561 {
562 bottom = PrevPt, top = CurrPt;
563 pETEs->ClockWise = 0;
564 }
565 else
566 {
567 bottom = CurrPt, top = PrevPt;
568 pETEs->ClockWise = 1;
569 }
570
571 /*
572 * don't add horizontal edges to the Edge table.
573 */
574 if (bottom->y != top->y)
575 {
576 pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */
577
578 /*
579 * initialize integer edge algorithm
580 */
581 dy = bottom->y - top->y;
582 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres)
583
584 if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock))
585 {
586 miFreeStorage(pSLLBlock->next);
587 return FALSE;
588 }
589
590 ET->ymax = QMAX(ET->ymax, PrevPt->y);
591 ET->ymin = QMIN(ET->ymin, PrevPt->y);
592 pETEs++;
593 }
594
595 PrevPt = CurrPt;
596 }
597 return TRUE;
598}
599
600
601/*
602 * loadAET
603 *
604 * This routine moves EdgeTableEntries from the
605 * EdgeTable into the Active Edge Table,
606 * leaving them sorted by smaller x coordinate.
607 *
608 */
609
610void
611miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
612{
613 register EdgeTableEntry *pPrevAET;
614 register EdgeTableEntry *tmp;
615
616 pPrevAET = AET;
617 AET = AET->next;
618 while (ETEs)
619 {
620 while (AET && (AET->bres.minor < ETEs->bres.minor))
621 {
622 pPrevAET = AET;
623 AET = AET->next;
624 }
625 tmp = ETEs->next;
626 ETEs->next = AET;
627 if (AET)
628 AET->back = ETEs;
629 ETEs->back = pPrevAET;
630 pPrevAET->next = ETEs;
631 pPrevAET = ETEs;
632
633 ETEs = tmp;
634 }
635}
636
637
638/*
639 * computeWAET
640 *
641 * This routine links the AET by the
642 * nextWETE (winding EdgeTableEntry) link for
643 * use by the winding number rule. The final
644 * Active Edge Table (AET) might look something
645 * like:
646 *
647 * AET
648 * ---------- --------- ---------
649 * |ymax | |ymax | |ymax |
650 * | ... | |... | |... |
651 * |next |->|next |->|next |->...
652 * |nextWETE| |nextWETE| |nextWETE|
653 * --------- --------- ^--------
654 * | | |
655 * V-------------------> V---> ...
656 *
657 */
658void
659micomputeWAET(EdgeTableEntry *AET)
660{
661 register EdgeTableEntry *pWETE;
662 register int inside = 1;
663 register int isInside = 0;
664
665 AET->nextWETE = 0;
666 pWETE = AET;
667 AET = AET->next;
668 while (AET)
669 {
670 if (AET->ClockWise)
671 isInside++;
672 else
673 isInside--;
674
675 if ((!inside && !isInside) ||
676 ( inside && isInside))
677 {
678 pWETE->nextWETE = AET;
679 pWETE = AET;
680 inside = !inside;
681 }
682 AET = AET->next;
683 }
684 pWETE->nextWETE = 0;
685}
686
687
688/*
689 * InsertionSort
690 *
691 * Just a simple insertion sort using
692 * pointers and back pointers to sort the Active
693 * Edge Table.
694 *
695 */
696
697int
698miInsertionSort(EdgeTableEntry *AET)
699{
700 register EdgeTableEntry *pETEchase;
701 register EdgeTableEntry *pETEinsert;
702 register EdgeTableEntry *pETEchaseBackTMP;
703 register int changed = 0;
704
705 AET = AET->next;
706 while (AET)
707 {
708 pETEinsert = AET;
709 pETEchase = AET;
710 while (pETEchase->back->bres.minor > AET->bres.minor)
711 pETEchase = pETEchase->back;
712
713 AET = AET->next;
714 if (pETEchase != pETEinsert)
715 {
716 pETEchaseBackTMP = pETEchase->back;
717 pETEinsert->back->next = AET;
718 if (AET)
719 AET->back = pETEinsert->back;
720 pETEinsert->next = pETEchase;
721 pETEchase->back->next = pETEinsert;
722 pETEchase->back = pETEinsert;
723 pETEinsert->back = pETEchaseBackTMP;
724 changed = 1;
725 }
726 }
727 return(changed);
728}
729
730/*!
731 \overload
732*/
733void QPolygonScanner::scan(const QPointArray& pa, bool winding, int index, int npoints)
734{
735 scan( pa, winding, index, npoints, TRUE );
736}
737
738/*!
739 \overload
740
741 If \a stitchable is FALSE, the right and bottom edges of the
742 polygon are included. This causes adjacent polygons to overlap.
743*/
744void QPolygonScanner::scan(const QPointArray& pa, bool winding, int index, int npoints, bool stitchable)
745{
746 scan( pa, winding, index, npoints,
747 stitchable ? Edge(Left+Top) : Edge(Left+Right+Top+Bottom) );
748}
749
750/*!
751 Calls processSpans() for all scanlines of the polygon defined by
752 \a npoints starting at \a index in \a pa.
753
754 If \a winding is TRUE, the Winding algorithm rather than the
755 Odd-Even rule is used.
756
757 The \a edges is any bitwise combination of:
758 \list
759 \i \c QPolygonScanner::Left
760 \i \c QPolygonScanner::Right
761 \i \c QPolygonScanner::Top
762 \i \c QPolygonScanner::Bottom
763 \endlist
764 \a edges determines which edges are included.
765
766 \warning The edges feature does not work properly.
767
768*/
769void QPolygonScanner::scan( const QPointArray& pa, bool winding, int index, int npoints, Edge edges )
770{
771
772
773 DDXPointPtr ptsIn = (DDXPointPtr)pa.data();
774 ptsIn += index;
775 register EdgeTableEntry *pAET; /* the Active Edge Table */
776 register int y; /* the current scanline */
777 register int nPts = 0; /* number of pts in buffer */
778 register EdgeTableEntry *pWETE; /* Winding Edge Table */
779 register ScanLineList *pSLL; /* Current ScanLineList */
780 register DDXPointPtr ptsOut; /* ptr to output buffers */
781 int *width;
782 DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
783 int FirstWidth[NUMPTSTOBUFFER];
784 EdgeTableEntry *pPrevAET; /* previous AET entry */
785 EdgeTable ET; /* Edge Table header node */
786 EdgeTableEntry AET; /* Active ET header node */
787 EdgeTableEntry *pETEs; /* Edge Table Entries buff */
788 ScanLineListBlock SLLBlock; /* header for ScanLineList */
789 int fixWAET = 0;
790 int edge_l = (edges & Left) ? 1 : 0;
791 int edge_r = (edges & Right) ? 1 : 0;
792 int edge_t = 1; //#### (edges & Top) ? 1 : 0;
793 int edge_b = (edges & Bottom) ? 1 : 0;
794
795 if (npoints == -1)
796 npoints = pa.size();
797
798 if (npoints < 3)
799 return;
800
801 if(!(pETEs = (EdgeTableEntry *)
802 malloc(sizeof(EdgeTableEntry) * npoints)))
803 return;
804 ptsOut = FirstPoint;
805 width = FirstWidth;
806 if (!miCreateETandAET(npoints, ptsIn, &ET, &AET, pETEs, &SLLBlock))
807 {
808 free(pETEs);
809 return;
810 }
811 pSLL = ET.scanlines.next;
812
813 if (!winding)
814 {
815 /*
816 * for each scanline
817 */
818 for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++)
819 {
820 /*
821 * Add a new edge to the active edge table when we
822 * get to the next edge.
823 */
824 if (pSLL && y == pSLL->scanline)
825 {
826 miloadAET(&AET, pSLL->edgelist);
827 pSLL = pSLL->next;
828 }
829 pPrevAET = &AET;
830 pAET = AET.next;
831
832 /*
833 * for each active edge
834 */
835 while (pAET)
836 {
837 ptsOut->x = pAET->bres.minor + 1 - edge_l;
838 ptsOut++->y = y;
839 *width++ = pAET->next->bres.minor - pAET->bres.minor
840 - 1 + edge_l + edge_r;
841 nPts++;
842
843 /*
844 * send out the buffer when its full
845 */
846 if (nPts == NUMPTSTOBUFFER)
847 {
848 processSpans( nPts, (QPoint*)FirstPoint, FirstWidth );
849 ptsOut = FirstPoint;
850 width = FirstWidth;
851 nPts = 0;
852 }
853 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
854 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
855 }
856 miInsertionSort(&AET);
857 }
858 }
859 else /* default to WindingNumber */
860 {
861 /*
862 * for each scanline
863 */
864 for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++)
865 {
866 /*
867 * Add a new edge to the active edge table when we
868 * get to the next edge.
869 */
870 if (pSLL && y == pSLL->scanline)
871 {
872 miloadAET(&AET, pSLL->edgelist);
873 micomputeWAET(&AET);
874 pSLL = pSLL->next;
875 }
876 pPrevAET = &AET;
877 pAET = AET.next;
878 pWETE = pAET;
879
880 /*
881 * for each active edge
882 */
883 while (pAET)
884 {
885 /*
886 * if the next edge in the active edge table is
887 * also the next edge in the winding active edge
888 * table.
889 */
890 if (pWETE == pAET)
891 {
892 ptsOut->x = pAET->bres.minor + 1 - edge_l;
893 ptsOut++->y = y;
894 *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r;
895 nPts++;
896
897 /*
898 * send out the buffer
899 */
900 if (nPts == NUMPTSTOBUFFER)
901 {
902 processSpans( nPts, (QPoint*)FirstPoint, FirstWidth );
903 ptsOut = FirstPoint;
904 width = FirstWidth;
905 nPts = 0;
906 }
907
908 pWETE = pWETE->nextWETE;
909 while (pWETE != pAET) {
910 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
911 }
912 pWETE = pWETE->nextWETE;
913 }
914 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
915 }
916
917 /*
918 * reevaluate the Winding active edge table if we
919 * just had to resort it or if we just exited an edge.
920 */
921 if (miInsertionSort(&AET) || fixWAET)
922 {
923 micomputeWAET(&AET);
924 fixWAET = 0;
925 }
926 }
927 }
928
929 /*
930 * Get any spans that we missed by buffering
931 */
932
933
934 processSpans( nPts, (QPoint*)FirstPoint, FirstWidth );
935 free(pETEs);
936 miFreeStorage(SLLBlock.next);
937}
938/***** END OF X11-based CODE *****/
939
940
Note: See TracBrowser for help on using the repository browser.