source: trunk/src/qt3support/other/q3polygonscanner.cpp@ 807

Last change on this file since 807 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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