1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the Qt 3 compatibility classes of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include "q3polygonscanner.h"
30
#include "q3pointarray.h"
34
// Based on Xserver code miFillGeneralPoly...
37
* Written by Brian Kelleher; Oct. 1985
39
* Routine to fill a polygon. Two fill rules are
40
* supported: frWINDING and frEVENODD.
42
* See fillpoly.h for a complete description of the algorithm.
46
* These are the data structures needed to scan
47
* convert regions. Two different scan conversion
48
* methods are available -- the even-odd method, and
49
* the winding number method.
50
* The even-odd rule states that a point is inside
51
* the polygon if a ray drawn from that point in any
52
* direction will pass through an odd number of
54
* By the winding number rule, a point is decided
55
* to be inside the polygon if a ray drawn from that
56
* point in any direction passes through a different
57
* number of clockwise and counterclockwise path
60
* These data structures are adapted somewhat from
61
* the algorithm in (Foley/Van Dam) for scan converting
63
* The basic algorithm is to start at the top (smallest y)
64
* of the polygon, stepping down to the bottom of
65
* the polygon by incrementing the y coordinate. We
66
* keep a list of edges which the current scanline crosses,
67
* sorted by x. This list is called the Active Edge Table (AET)
68
* As we change the y-coordinate, we update each entry in
69
* in the active edge table to reflect the edges new xcoord.
70
* This list must be sorted at each scanline in case
71
* two edges intersect.
72
* We also keep a data structure known as the Edge Table (ET),
73
* which keeps track of all the edges which the current
74
* scanline has not yet reached. The ET is basically a
75
* list of ScanLineList structures containing a list of
76
* edges which are entered at a given scanline. There is one
77
* ScanLineList per scanline at which an edge is entered.
78
* When we enter a new edge, we move it from the ET to the AET.
80
* From the AET, we can implement the even-odd rule as in
82
* The winding number rule is a little trickier. We also
83
* keep the EdgeTableEntries in the AET linked by the
84
* nextWETE (winding EdgeTableEntry) link. This allows
85
* the edges to be linked just as before for updating
86
* purposes, but only uses the edges linked by the nextWETE
87
* link as edges representing spans of the polygon to
88
* drawn (as with the even-odd rule).
91
/* $XConsortium: miscanfill.h,v 1.5 94/04/17 20:27:50 dpw Exp $ */
94
Copyright (c) 1987 X Consortium
96
Permission is hereby granted, free of charge, to any person obtaining
97
a copy of this software and associated documentation files (the
98
"Software"), to deal in the Software without restriction, including
99
without limitation the rights to use, copy, modify, merge, publish,
100
distribute, sublicense, and/or sell copies of the Software, and to
101
permit persons to whom the Software is furnished to do so, subject to
102
the following conditions:
104
The above copyright notice and this permission notice shall be included
105
in all copies or substantial portions of the Software.
107
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
108
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
109
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
110
IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
111
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
112
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
113
OTHER DEALINGS IN THE SOFTWARE.
115
Except as contained in this notice, the name of the X Consortium shall
116
not be used in advertising or otherwise to promote the sale, use or
117
other dealings in this Software without prior written authorization
118
from the X Consortium.
126
* Written by Brian Kelleher; Jan 1985
128
* This file contains a few macros to help track
129
* the edge of a filled object. The object is assumed
130
* to be filled in scanline order, and thus the
131
* algorithm used is an extension of Bresenham's line
132
* drawing algorithm which assumes that y is always the
134
* Since these pieces of code are the same for any filled shape,
135
* it is more convenient to gather the library in one
136
* place, but since these pieces of code are also in
137
* the inner loops of output primitives, procedure call
138
* overhead is out of the question.
139
* See the author for a derivation if needed.
143
* In scan converting polygons, we want to choose those pixels
144
* which are inside the polygon. Thus, we add .5 to the starting
145
* x coordinate for both left and right edges. Now we choose the
146
* first pixel which is inside the pgon for the left edge and the
147
* first pixel which is outside the pgon for the right edge.
148
* Draw the left pixel, but not the right.
150
* How to add .5 to the starting x coordinate:
151
* If the edge is moving to the right, then subtract dy from the
152
* error term from the general form of the algorithm.
153
* If the edge is moving to the left, then add dy to the error term.
155
* The reason for the difference between edges moving to the left
156
* and edges moving to the right is simple: If an edge is moving
157
* to the right, then we want the algorithm to flip immediately.
158
* If it is moving to the left, then we don't want it to flip until
159
* we traverse an entire pixel.
161
#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
162
int dx; /* local storage */ \
165
* if the edge is horizontal, then it is ignored \
166
* and assumed not to be processed. Otherwise, do this stuff. \
170
dx = (x2) - xStart; \
174
incr1 = -2 * dx + 2 * (dy) * m1; \
175
incr2 = -2 * dx + 2 * (dy) * m; \
176
d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
180
incr1 = 2 * dx - 2 * (dy) * m1; \
181
incr2 = 2 * dx - 2 * (dy) * m; \
182
d = -2 * m * (dy) + 2 * dx; \
187
#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
211
* This structure contains all of the information needed
212
* to run the bresenham algorithm.
213
* The variables may be hardcoded into the declarations
214
* instead of using this structure to make use of
215
* register declarations.
218
int minor; /* minor axis */
219
int d; /* decision variable */
220
int m, m1; /* slope and slope+1 */
221
int incr1, incr2; /* error increments */
225
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
226
BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
227
bres.m, bres.m1, bres.incr1, bres.incr2)
229
#define BRESINCRPGONSTRUCT(bres) \
230
BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
233
typedef struct _EdgeTableEntry {
234
int ymax; /* ycoord at which we exit this edge. */
235
BRESINFO bres; /* Bresenham info to run the edge */
236
struct _EdgeTableEntry *next; /* next in the list */
237
struct _EdgeTableEntry *back; /* for insertion sort */
238
struct _EdgeTableEntry *nextWETE; /* for winding num rule */
239
int ClockWise; /* flag for winding number rule */
243
typedef struct _ScanLineList{
244
int scanline; /* the scanline represented */
245
EdgeTableEntry *edgelist; /* header node */
246
struct _ScanLineList *next; /* next in the list */
251
int ymax; /* ymax for the polygon */
252
int ymin; /* ymin for the polygon */
253
ScanLineList scanlines; /* header node */
258
* Here is a struct to help with storage allocation
259
* so we can allocate a big chunk at a time, and then take
260
* pieces from this heap when we need to.
262
#define SLLSPERBLOCK 25
264
typedef struct _ScanLineListBlock {
265
ScanLineList SLLs[SLLSPERBLOCK];
266
struct _ScanLineListBlock *next;
270
* number of points to buffer before sending them off
271
* to scanlines() : Must be an even number
273
#define NUMPTSTOBUFFER 200
277
* a few macros for the inner loops of the fill code where
278
* performance considerations don't allow a procedure call.
280
* Evaluate the given edge at the given scanline.
281
* If the edge has expired, then we leave it and fix up
282
* the active edge table; otherwise, we increment the
283
* x value to be ready for the next scanline.
284
* The winding number rule is in effect, so we must notify
285
* the caller when the edge has been removed so he
286
* can reorder the Winding Active Edge Table.
288
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
289
if (pAET->ymax == y) { /* leaving this edge */ \
290
pPrevAET->next = pAET->next; \
291
pAET = pPrevAET->next; \
294
pAET->back = pPrevAET; \
297
BRESINCRPGONSTRUCT(pAET->bres); \
305
* Evaluate the given edge at the given scanline.
306
* If the edge has expired, then we leave it and fix up
307
* the active edge table; otherwise, we increment the
308
* x value to be ready for the next scanline.
309
* The even-odd rule is in effect.
311
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
312
if (pAET->ymax == y) { /* leaving this edge */ \
313
pPrevAET->next = pAET->next; \
314
pAET = pPrevAET->next; \
316
pAET->back = pPrevAET; \
319
BRESINCRPGONSTRUCT(pAET->bres) \
325
/***********************************************************
327
Copyright (c) 1987 X Consortium
329
Permission is hereby granted, free of charge, to any person obtaining a copy
330
of this software and associated documentation files (the "Software"), to deal
331
in the Software without restriction, including without limitation the rights
332
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
333
copies of the Software, and to permit persons to whom the Software is
334
furnished to do so, subject to the following conditions:
336
The above copyright notice and this permission notice shall be included in
337
all copies or substantial portions of the Software.
339
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
340
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
341
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
342
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
343
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
344
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
346
Except as contained in this notice, the name of the X Consortium shall not be
347
used in advertising or otherwise to promote the sale, use or other dealings
348
in this Software without prior written authorization from the X Consortium.
351
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
355
Permission to use, copy, modify, and distribute this software and its
356
documentation for any purpose and without fee is hereby granted,
357
provided that the above copyright notice appear in all copies and that
358
both that copyright notice and this permission notice appear in
359
supporting documentation, and that the name of Digital not be
360
used in advertising or publicity pertaining to distribution of the
361
software without specific, written prior permission.
363
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
364
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
365
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
366
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
367
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
368
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
371
******************************************************************/
373
#define MAXINT 0x7fffffff
374
#define MININT -MAXINT
379
* Written by Brian Kelleher; Oct. 1985
381
* This module contains all of the utility functions
382
* needed to scan convert a polygon.
388
* Insert the given edge into the edge table.
389
* First we must find the correct bucket in the
390
* Edge table, then find the right slot in the
391
* bucket. Finally, we can insert it.
395
miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
396
int scanline, ScanLineListBlock **SLLBlock, int *iSLLBlock)
398
register EdgeTableEntry *start, *prev;
399
register ScanLineList *pSLL, *pPrevSLL;
400
ScanLineListBlock *tmpSLLBlock;
403
* find the right bucket to put the edge into
405
pPrevSLL = &ET->scanlines;
406
pSLL = pPrevSLL->next;
407
while (pSLL && (pSLL->scanline < scanline))
414
* reassign pSLL (pointer to ScanLineList) if necessary
416
if ((!pSLL) || (pSLL->scanline > scanline))
418
if (*iSLLBlock > SLLSPERBLOCK-1)
421
(ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
424
(*SLLBlock)->next = tmpSLLBlock;
425
tmpSLLBlock->next = 0;
426
*SLLBlock = tmpSLLBlock;
429
pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
431
pSLL->next = pPrevSLL->next;
433
pPrevSLL->next = pSLL;
435
pSLL->scanline = scanline;
438
* now insert the edge in the right bucket
441
start = pSLL->edgelist;
442
while (start && (start->bres.minor < ETE->bres.minor))
452
pSLL->edgelist = ETE;
459
* This routine creates the edge table for
460
* scan converting polygons.
461
* The Edge Table (ET) looks like:
465
* | ymax | ScanLineLists
466
* |scanline|-->------------>-------------->...
467
* -------- |scanline| |scanline|
468
* |edgelist| |edgelist|
469
* --------- ---------
473
* list of ETEs list of ETEs
475
* where ETE is an EdgeTableEntry data structure,
476
* and there is one ScanLineList per scanline at
477
* which an edge is initially entered.
482
#if defined(Q_OS_MAC)
488
} DDXPointRec, *DDXPointPtr;
494
miFreeStorage(ScanLineListBlock *pSLLBlock)
496
register ScanLineListBlock *tmpSLLBlock;
500
tmpSLLBlock = pSLLBlock->next;
502
pSLLBlock = tmpSLLBlock;
507
miCreateETandAET(int count, DDXPointPtr pts, EdgeTable *ET,
508
EdgeTableEntry *AET, EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
510
register DDXPointPtr top, bottom;
511
register DDXPointPtr PrevPt, CurrPt;
516
if (count < 2) return true;
519
* initialize the Active Edge Table
524
AET->bres.minor = MININT;
527
* initialize the Edge Table.
529
ET->scanlines.next = 0;
534
PrevPt = &pts[count-1];
537
* for each vertex in the array of points.
538
* In this loop we are dealing with two vertices at
539
* a time -- these make up one edge of the polygon.
546
* find out which point is above and which is below.
548
if (PrevPt->y > CurrPt->y)
550
bottom = PrevPt, top = CurrPt;
551
pETEs->ClockWise = 0;
555
bottom = CurrPt, top = PrevPt;
556
pETEs->ClockWise = 1;
560
* don't add horizontal edges to the Edge table.
562
if (bottom->y != top->y)
564
pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */
567
* initialize integer edge algorithm
569
dy = bottom->y - top->y;
570
BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres)
572
if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock))
574
miFreeStorage(pSLLBlock->next);
578
ET->ymax = qMax(ET->ymax, PrevPt->y);
579
ET->ymin = qMin(ET->ymin, PrevPt->y);
591
* This routine moves EdgeTableEntries from the
592
* EdgeTable into the Active Edge Table,
593
* leaving them sorted by smaller x coordinate.
598
miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
600
register EdgeTableEntry *pPrevAET;
601
register EdgeTableEntry *tmp;
607
while (AET && (AET->bres.minor < ETEs->bres.minor))
616
ETEs->back = pPrevAET;
617
pPrevAET->next = ETEs;
627
* This routine links the AET by the
628
* nextWETE (winding EdgeTableEntry) link for
629
* use by the winding number rule. The final
630
* Active Edge Table (AET) might look something
634
* ---------- --------- ---------
635
* |ymax | |ymax | |ymax |
636
* | ... | |... | |... |
637
* |next |->|next |->|next |->...
638
* |nextWETE| |nextWETE| |nextWETE|
639
* --------- --------- ^--------
641
* V-------------------> V---> ...
645
micomputeWAET(EdgeTableEntry *AET)
647
register EdgeTableEntry *pWETE;
648
register int inside = 1;
649
register int isInside = 0;
661
if ((!inside && !isInside) ||
662
(inside && isInside))
664
pWETE->nextWETE = AET;
676
* Just a simple insertion sort using
677
* pointers and back pointers to sort the Active
683
miInsertionSort(EdgeTableEntry *AET)
685
register EdgeTableEntry *pETEchase;
686
register EdgeTableEntry *pETEinsert;
687
register EdgeTableEntry *pETEchaseBackTMP;
688
register int changed = 0;
695
while (pETEchase->back->bres.minor > AET->bres.minor)
696
pETEchase = pETEchase->back;
699
if (pETEchase != pETEinsert)
701
pETEchaseBackTMP = pETEchase->back;
702
pETEinsert->back->next = AET;
704
AET->back = pETEinsert->back;
705
pETEinsert->next = pETEchase;
706
pETEchase->back->next = pETEinsert;
707
pETEchase->back = pETEinsert;
708
pETEinsert->back = pETEchaseBackTMP;
718
void Q3PolygonScanner::scan(const Q3PointArray& pa, bool winding, int index, int npoints)
720
scan(pa, winding, index, npoints, true);
726
If \a stitchable is false, the right and bottom edges of the
727
polygon are included. This causes adjacent polygons to overlap.
729
void Q3PolygonScanner::scan(const Q3PointArray& pa, bool winding, int index, int npoints, bool stitchable)
731
scan(pa, winding, index, npoints,
732
stitchable ? Edge(Left+Top) : Edge(Left+Right+Top+Bottom));
736
Calls processSpans() for all scanlines of the polygon defined by
737
\a npoints starting at \a index in \a pa.
739
If \a winding is true, the Winding algorithm rather than the
740
Odd-Even rule is used.
742
The \a edges is any bitwise combination of:
744
\i \c Q3PolygonScanner::Left
745
\i \c Q3PolygonScanner::Right
746
\i \c Q3PolygonScanner::Top
747
\i \c Q3PolygonScanner::Bottom
749
\a edges determines which edges are included.
751
\warning The edges feature does not work properly.
754
void Q3PolygonScanner::scan(const Q3PointArray& pa, bool winding, int index, int npoints, Edge edges)
758
DDXPointPtr ptsIn = (DDXPointPtr)pa.data();
760
register EdgeTableEntry *pAET; /* the Active Edge Table */
761
register int y; /* the current scanline */
762
register int nPts = 0; /* number of pts in buffer */
763
register EdgeTableEntry *pWETE; /* Winding Edge Table */
764
register ScanLineList *pSLL; /* Current ScanLineList */
765
register DDXPointPtr ptsOut; /* ptr to output buffers */
767
DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
768
int FirstWidth[NUMPTSTOBUFFER];
769
EdgeTableEntry *pPrevAET; /* previous AET entry */
770
EdgeTable ET; /* Edge Table header node */
771
EdgeTableEntry AET; /* Active ET header node */
772
EdgeTableEntry *pETEs; /* Edge Table Entries buff */
773
ScanLineListBlock SLLBlock; /* header for ScanLineList */
775
int edge_l = (edges & Left) ? 1 : 0;
776
int edge_r = (edges & Right) ? 1 : 0;
777
int edge_t = 1; //#### (edges & Top) ? 1 : 0;
778
int edge_b = (edges & Bottom) ? 1 : 0;
786
if(!(pETEs = (EdgeTableEntry *)
787
malloc(sizeof(EdgeTableEntry) * npoints)))
791
if (!miCreateETandAET(npoints, ptsIn, &ET, &AET, pETEs, &SLLBlock))
796
pSLL = ET.scanlines.next;
803
for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++)
806
* Add a new edge to the active edge table when we
807
* get to the next edge.
809
if (pSLL && y == pSLL->scanline)
811
miloadAET(&AET, pSLL->edgelist);
818
* for each active edge
822
ptsOut->x = pAET->bres.minor + 1 - edge_l;
824
*width++ = pAET->next->bres.minor - pAET->bres.minor
825
- 1 + edge_l + edge_r;
829
* send out the buffer when its full
831
if (nPts == NUMPTSTOBUFFER)
833
processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
838
EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
839
EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
841
miInsertionSort(&AET);
844
else /* default to WindingNumber */
849
for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++)
852
* Add a new edge to the active edge table when we
853
* get to the next edge.
855
if (pSLL && y == pSLL->scanline)
857
miloadAET(&AET, pSLL->edgelist);
866
* for each active edge
871
* if the next edge in the active edge table is
872
* also the next edge in the winding active edge
877
ptsOut->x = pAET->bres.minor + 1 - edge_l;
879
*width++ = pAET->nextWETE->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r;
883
* send out the buffer
885
if (nPts == NUMPTSTOBUFFER)
887
processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
893
pWETE = pWETE->nextWETE;
894
while (pWETE != pAET) {
895
EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
897
pWETE = pWETE->nextWETE;
899
EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
903
* reevaluate the Winding active edge table if we
904
* just had to resort it or if we just exited an edge.
906
if (miInsertionSort(&AET) || fixWAET)
915
* Get any spans that we missed by buffering
919
processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
921
miFreeStorage(SLLBlock.next);
923
/***** END OF X11-based CODE *****/