1*4882a593Smuzhiyun /***********************************************************
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun Copyright 1987, 1998 The Open Group
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun Permission to use, copy, modify, distribute, and sell this software and its
6*4882a593Smuzhiyun documentation for any purpose is hereby granted without fee, provided that
7*4882a593Smuzhiyun the above copyright notice appear in all copies and that both that
8*4882a593Smuzhiyun copyright notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation.
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun all copies or substantial portions of the Software.
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17*4882a593Smuzhiyun OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18*4882a593Smuzhiyun AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19*4882a593Smuzhiyun CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun Except as contained in this notice, the name of The Open Group shall not be
22*4882a593Smuzhiyun used in advertising or otherwise to promote the sale, use or other dealings
23*4882a593Smuzhiyun in this Software without prior written authorization from The Open Group.
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun All Rights Reserved
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun Permission to use, copy, modify, and distribute this software and its
30*4882a593Smuzhiyun documentation for any purpose and without fee is hereby granted,
31*4882a593Smuzhiyun provided that the above copyright notice appear in all copies and that
32*4882a593Smuzhiyun both that copyright notice and this permission notice appear in
33*4882a593Smuzhiyun supporting documentation, and that the name of Digital not be
34*4882a593Smuzhiyun used in advertising or publicity pertaining to distribution of the
35*4882a593Smuzhiyun software without specific, written prior permission.
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38*4882a593Smuzhiyun ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39*4882a593Smuzhiyun DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40*4882a593Smuzhiyun ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41*4882a593Smuzhiyun WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42*4882a593Smuzhiyun ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43*4882a593Smuzhiyun SOFTWARE.
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun ******************************************************************/
46*4882a593Smuzhiyun /*
47*4882a593Smuzhiyun * mipoly.c
48*4882a593Smuzhiyun *
49*4882a593Smuzhiyun * Written by Brian Kelleher; June 1986
50*4882a593Smuzhiyun */
51*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
52*4882a593Smuzhiyun #include <dix-config.h>
53*4882a593Smuzhiyun #endif
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun #include <X11/X.h>
56*4882a593Smuzhiyun #include "windowstr.h"
57*4882a593Smuzhiyun #include "gcstruct.h"
58*4882a593Smuzhiyun #include "pixmapstr.h"
59*4882a593Smuzhiyun #include "mi.h"
60*4882a593Smuzhiyun #include "miscanfill.h"
61*4882a593Smuzhiyun #include "mipoly.h"
62*4882a593Smuzhiyun #include "regionstr.h"
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /*
65*4882a593Smuzhiyun * Insert the given edge into the edge table. First we must find the correct
66*4882a593Smuzhiyun * bucket in the Edge table, then find the right slot in the bucket. Finally,
67*4882a593Smuzhiyun * we can insert it.
68*4882a593Smuzhiyun */
69*4882a593Smuzhiyun static Bool
miInsertEdgeInET(EdgeTable * ET,EdgeTableEntry * ETE,int scanline,ScanLineListBlock ** SLLBlock,int * iSLLBlock)70*4882a593Smuzhiyun miInsertEdgeInET(EdgeTable * ET, EdgeTableEntry * ETE, int scanline,
71*4882a593Smuzhiyun ScanLineListBlock ** SLLBlock, int *iSLLBlock)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun EdgeTableEntry *start, *prev;
74*4882a593Smuzhiyun ScanLineList *pSLL, *pPrevSLL;
75*4882a593Smuzhiyun ScanLineListBlock *tmpSLLBlock;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /*
78*4882a593Smuzhiyun * find the right bucket to put the edge into
79*4882a593Smuzhiyun */
80*4882a593Smuzhiyun pPrevSLL = &ET->scanlines;
81*4882a593Smuzhiyun pSLL = pPrevSLL->next;
82*4882a593Smuzhiyun while (pSLL && (pSLL->scanline < scanline)) {
83*4882a593Smuzhiyun pPrevSLL = pSLL;
84*4882a593Smuzhiyun pSLL = pSLL->next;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun /*
88*4882a593Smuzhiyun * reassign pSLL (pointer to ScanLineList) if necessary
89*4882a593Smuzhiyun */
90*4882a593Smuzhiyun if ((!pSLL) || (pSLL->scanline > scanline)) {
91*4882a593Smuzhiyun if (*iSLLBlock > SLLSPERBLOCK - 1) {
92*4882a593Smuzhiyun tmpSLLBlock = malloc(sizeof(ScanLineListBlock));
93*4882a593Smuzhiyun if (!tmpSLLBlock)
94*4882a593Smuzhiyun return FALSE;
95*4882a593Smuzhiyun (*SLLBlock)->next = tmpSLLBlock;
96*4882a593Smuzhiyun tmpSLLBlock->next = NULL;
97*4882a593Smuzhiyun *SLLBlock = tmpSLLBlock;
98*4882a593Smuzhiyun *iSLLBlock = 0;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun pSLL->next = pPrevSLL->next;
103*4882a593Smuzhiyun pSLL->edgelist = NULL;
104*4882a593Smuzhiyun pPrevSLL->next = pSLL;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun pSLL->scanline = scanline;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun * now insert the edge in the right bucket
110*4882a593Smuzhiyun */
111*4882a593Smuzhiyun prev = NULL;
112*4882a593Smuzhiyun start = pSLL->edgelist;
113*4882a593Smuzhiyun while (start && (start->bres.minor < ETE->bres.minor)) {
114*4882a593Smuzhiyun prev = start;
115*4882a593Smuzhiyun start = start->next;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun ETE->next = start;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun if (prev)
120*4882a593Smuzhiyun prev->next = ETE;
121*4882a593Smuzhiyun else
122*4882a593Smuzhiyun pSLL->edgelist = ETE;
123*4882a593Smuzhiyun return TRUE;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun static void
miFreeStorage(ScanLineListBlock * pSLLBlock)127*4882a593Smuzhiyun miFreeStorage(ScanLineListBlock * pSLLBlock)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun ScanLineListBlock *tmpSLLBlock;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun while (pSLLBlock) {
132*4882a593Smuzhiyun tmpSLLBlock = pSLLBlock->next;
133*4882a593Smuzhiyun free(pSLLBlock);
134*4882a593Smuzhiyun pSLLBlock = tmpSLLBlock;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /*
139*4882a593Smuzhiyun * CreateEdgeTable
140*4882a593Smuzhiyun *
141*4882a593Smuzhiyun * This routine creates the edge table for scan converting polygons.
142*4882a593Smuzhiyun * The Edge Table (ET) looks like:
143*4882a593Smuzhiyun *
144*4882a593Smuzhiyun * EdgeTable
145*4882a593Smuzhiyun * --------
146*4882a593Smuzhiyun * | ymax | ScanLineLists
147*4882a593Smuzhiyun * |scanline|-->------------>-------------->...
148*4882a593Smuzhiyun * -------- |scanline| |scanline|
149*4882a593Smuzhiyun * |edgelist| |edgelist|
150*4882a593Smuzhiyun * --------- ---------
151*4882a593Smuzhiyun * | |
152*4882a593Smuzhiyun * | |
153*4882a593Smuzhiyun * V V
154*4882a593Smuzhiyun * list of ETEs list of ETEs
155*4882a593Smuzhiyun *
156*4882a593Smuzhiyun * where ETE is an EdgeTableEntry data structure, and there is one ScanLineList
157*4882a593Smuzhiyun * per scanline at which an edge is initially entered.
158*4882a593Smuzhiyun */
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun static Bool
miCreateETandAET(int count,DDXPointPtr pts,EdgeTable * ET,EdgeTableEntry * AET,EdgeTableEntry * pETEs,ScanLineListBlock * pSLLBlock)161*4882a593Smuzhiyun miCreateETandAET(int count, DDXPointPtr pts, EdgeTable * ET,
162*4882a593Smuzhiyun EdgeTableEntry * AET, EdgeTableEntry * pETEs,
163*4882a593Smuzhiyun ScanLineListBlock * pSLLBlock)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun DDXPointPtr top, bottom;
166*4882a593Smuzhiyun DDXPointPtr PrevPt, CurrPt;
167*4882a593Smuzhiyun int iSLLBlock = 0;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun int dy;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun if (count < 2)
172*4882a593Smuzhiyun return TRUE;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /*
175*4882a593Smuzhiyun * initialize the Active Edge Table
176*4882a593Smuzhiyun */
177*4882a593Smuzhiyun AET->next = NULL;
178*4882a593Smuzhiyun AET->back = NULL;
179*4882a593Smuzhiyun AET->nextWETE = NULL;
180*4882a593Smuzhiyun AET->bres.minor = MININT;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /*
183*4882a593Smuzhiyun * initialize the Edge Table.
184*4882a593Smuzhiyun */
185*4882a593Smuzhiyun ET->scanlines.next = NULL;
186*4882a593Smuzhiyun ET->ymax = MININT;
187*4882a593Smuzhiyun ET->ymin = MAXINT;
188*4882a593Smuzhiyun pSLLBlock->next = NULL;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun PrevPt = &pts[count - 1];
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /*
193*4882a593Smuzhiyun * for each vertex in the array of points.
194*4882a593Smuzhiyun * In this loop we are dealing with two vertices at
195*4882a593Smuzhiyun * a time -- these make up one edge of the polygon.
196*4882a593Smuzhiyun */
197*4882a593Smuzhiyun while (count--) {
198*4882a593Smuzhiyun CurrPt = pts++;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /*
201*4882a593Smuzhiyun * find out which point is above and which is below.
202*4882a593Smuzhiyun */
203*4882a593Smuzhiyun if (PrevPt->y > CurrPt->y) {
204*4882a593Smuzhiyun bottom = PrevPt, top = CurrPt;
205*4882a593Smuzhiyun pETEs->ClockWise = 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun else {
208*4882a593Smuzhiyun bottom = CurrPt, top = PrevPt;
209*4882a593Smuzhiyun pETEs->ClockWise = 1;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /*
213*4882a593Smuzhiyun * don't add horizontal edges to the Edge table.
214*4882a593Smuzhiyun */
215*4882a593Smuzhiyun if (bottom->y != top->y) {
216*4882a593Smuzhiyun pETEs->ymax = bottom->y - 1; /* -1 so we don't get last scanline */
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /*
219*4882a593Smuzhiyun * initialize integer edge algorithm
220*4882a593Smuzhiyun */
221*4882a593Smuzhiyun dy = bottom->y - top->y;
222*4882a593Smuzhiyun BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock)) {
225*4882a593Smuzhiyun miFreeStorage(pSLLBlock->next);
226*4882a593Smuzhiyun return FALSE;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun ET->ymax = max(ET->ymax, PrevPt->y);
230*4882a593Smuzhiyun ET->ymin = min(ET->ymin, PrevPt->y);
231*4882a593Smuzhiyun pETEs++;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun PrevPt = CurrPt;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun return TRUE;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /*
240*4882a593Smuzhiyun * This routine moves EdgeTableEntries from the EdgeTable into the Active Edge
241*4882a593Smuzhiyun * Table, leaving them sorted by smaller x coordinate.
242*4882a593Smuzhiyun */
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun static void
miloadAET(EdgeTableEntry * AET,EdgeTableEntry * ETEs)245*4882a593Smuzhiyun miloadAET(EdgeTableEntry * AET, EdgeTableEntry * ETEs)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun EdgeTableEntry *pPrevAET;
248*4882a593Smuzhiyun EdgeTableEntry *tmp;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun pPrevAET = AET;
251*4882a593Smuzhiyun AET = AET->next;
252*4882a593Smuzhiyun while (ETEs) {
253*4882a593Smuzhiyun while (AET && (AET->bres.minor < ETEs->bres.minor)) {
254*4882a593Smuzhiyun pPrevAET = AET;
255*4882a593Smuzhiyun AET = AET->next;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun tmp = ETEs->next;
258*4882a593Smuzhiyun ETEs->next = AET;
259*4882a593Smuzhiyun if (AET)
260*4882a593Smuzhiyun AET->back = ETEs;
261*4882a593Smuzhiyun ETEs->back = pPrevAET;
262*4882a593Smuzhiyun pPrevAET->next = ETEs;
263*4882a593Smuzhiyun pPrevAET = ETEs;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun ETEs = tmp;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /*
270*4882a593Smuzhiyun * computeWAET
271*4882a593Smuzhiyun *
272*4882a593Smuzhiyun * This routine links the AET by the nextWETE (winding EdgeTableEntry) link for
273*4882a593Smuzhiyun * use by the winding number rule. The final Active Edge Table (AET) might
274*4882a593Smuzhiyun * look something like:
275*4882a593Smuzhiyun *
276*4882a593Smuzhiyun * AET
277*4882a593Smuzhiyun * ---------- --------- ---------
278*4882a593Smuzhiyun * |ymax | |ymax | |ymax |
279*4882a593Smuzhiyun * | ... | |... | |... |
280*4882a593Smuzhiyun * |next |->|next |->|next |->...
281*4882a593Smuzhiyun * |nextWETE| |nextWETE| |nextWETE|
282*4882a593Smuzhiyun * --------- --------- ^--------
283*4882a593Smuzhiyun * | | |
284*4882a593Smuzhiyun * V-------------------> V---> ...
285*4882a593Smuzhiyun *
286*4882a593Smuzhiyun */
287*4882a593Smuzhiyun static void
micomputeWAET(EdgeTableEntry * AET)288*4882a593Smuzhiyun micomputeWAET(EdgeTableEntry * AET)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun EdgeTableEntry *pWETE;
291*4882a593Smuzhiyun int inside = 1;
292*4882a593Smuzhiyun int isInside = 0;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun AET->nextWETE = NULL;
295*4882a593Smuzhiyun pWETE = AET;
296*4882a593Smuzhiyun AET = AET->next;
297*4882a593Smuzhiyun while (AET) {
298*4882a593Smuzhiyun if (AET->ClockWise)
299*4882a593Smuzhiyun isInside++;
300*4882a593Smuzhiyun else
301*4882a593Smuzhiyun isInside--;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun if ((!inside && !isInside) || (inside && isInside)) {
304*4882a593Smuzhiyun pWETE->nextWETE = AET;
305*4882a593Smuzhiyun pWETE = AET;
306*4882a593Smuzhiyun inside = !inside;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun AET = AET->next;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun pWETE->nextWETE = NULL;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /*
314*4882a593Smuzhiyun * Just a simple insertion sort using pointers and back pointers to sort the
315*4882a593Smuzhiyun * Active Edge Table.
316*4882a593Smuzhiyun */
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun static int
miInsertionSort(EdgeTableEntry * AET)319*4882a593Smuzhiyun miInsertionSort(EdgeTableEntry * AET)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun EdgeTableEntry *pETEchase;
322*4882a593Smuzhiyun EdgeTableEntry *pETEinsert;
323*4882a593Smuzhiyun EdgeTableEntry *pETEchaseBackTMP;
324*4882a593Smuzhiyun int changed = 0;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun AET = AET->next;
327*4882a593Smuzhiyun while (AET) {
328*4882a593Smuzhiyun pETEinsert = AET;
329*4882a593Smuzhiyun pETEchase = AET;
330*4882a593Smuzhiyun while (pETEchase->back->bres.minor > AET->bres.minor)
331*4882a593Smuzhiyun pETEchase = pETEchase->back;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun AET = AET->next;
334*4882a593Smuzhiyun if (pETEchase != pETEinsert) {
335*4882a593Smuzhiyun pETEchaseBackTMP = pETEchase->back;
336*4882a593Smuzhiyun pETEinsert->back->next = AET;
337*4882a593Smuzhiyun if (AET)
338*4882a593Smuzhiyun AET->back = pETEinsert->back;
339*4882a593Smuzhiyun pETEinsert->next = pETEchase;
340*4882a593Smuzhiyun pETEchase->back->next = pETEinsert;
341*4882a593Smuzhiyun pETEchase->back = pETEinsert;
342*4882a593Smuzhiyun pETEinsert->back = pETEchaseBackTMP;
343*4882a593Smuzhiyun changed = 1;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun return changed;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /* Find the index of the point with the smallest y */
350*4882a593Smuzhiyun static int
getPolyYBounds(DDXPointPtr pts,int n,int * by,int * ty)351*4882a593Smuzhiyun getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun DDXPointPtr ptMin;
354*4882a593Smuzhiyun int ymin, ymax;
355*4882a593Smuzhiyun DDXPointPtr ptsStart = pts;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun ptMin = pts;
358*4882a593Smuzhiyun ymin = ymax = (pts++)->y;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun while (--n > 0) {
361*4882a593Smuzhiyun if (pts->y < ymin) {
362*4882a593Smuzhiyun ptMin = pts;
363*4882a593Smuzhiyun ymin = pts->y;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun if (pts->y > ymax)
366*4882a593Smuzhiyun ymax = pts->y;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun pts++;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun *by = ymin;
372*4882a593Smuzhiyun *ty = ymax;
373*4882a593Smuzhiyun return ptMin - ptsStart;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun /*
377*4882a593Smuzhiyun * Written by Brian Kelleher; Dec. 1985.
378*4882a593Smuzhiyun *
379*4882a593Smuzhiyun * Fill a convex polygon. If the given polygon is not convex, then the result
380*4882a593Smuzhiyun * is undefined. The algorithm is to order the edges from smallest y to
381*4882a593Smuzhiyun * largest by partitioning the array into a left edge list and a right edge
382*4882a593Smuzhiyun * list. The algorithm used to traverse each edge is an extension of
383*4882a593Smuzhiyun * Bresenham's line algorithm with y as the major axis. For a derivation of
384*4882a593Smuzhiyun * the algorithm, see the author of this code.
385*4882a593Smuzhiyun */
386*4882a593Smuzhiyun static Bool
miFillConvexPoly(DrawablePtr dst,GCPtr pgc,int count,DDXPointPtr ptsIn)387*4882a593Smuzhiyun miFillConvexPoly(DrawablePtr dst, GCPtr pgc, int count, DDXPointPtr ptsIn)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun int xl = 0, xr = 0; /* x vals of left and right edges */
390*4882a593Smuzhiyun int dl = 0, dr = 0; /* decision variables */
391*4882a593Smuzhiyun int ml = 0, m1l = 0; /* left edge slope and slope+1 */
392*4882a593Smuzhiyun int mr = 0, m1r = 0; /* right edge slope and slope+1 */
393*4882a593Smuzhiyun int incr1l = 0, incr2l = 0; /* left edge error increments */
394*4882a593Smuzhiyun int incr1r = 0, incr2r = 0; /* right edge error increments */
395*4882a593Smuzhiyun int dy; /* delta y */
396*4882a593Smuzhiyun int y; /* current scanline */
397*4882a593Smuzhiyun int left, right; /* indices to first endpoints */
398*4882a593Smuzhiyun int i; /* loop counter */
399*4882a593Smuzhiyun int nextleft, nextright; /* indices to second endpoints */
400*4882a593Smuzhiyun DDXPointPtr ptsOut, FirstPoint; /* output buffer */
401*4882a593Smuzhiyun int *width, *FirstWidth; /* output buffer */
402*4882a593Smuzhiyun int imin; /* index of smallest vertex (in y) */
403*4882a593Smuzhiyun int ymin; /* y-extents of polygon */
404*4882a593Smuzhiyun int ymax;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun /*
407*4882a593Smuzhiyun * find leftx, bottomy, rightx, topy, and the index
408*4882a593Smuzhiyun * of bottomy. Also translate the points.
409*4882a593Smuzhiyun */
410*4882a593Smuzhiyun imin = getPolyYBounds(ptsIn, count, &ymin, &ymax);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun dy = ymax - ymin + 1;
413*4882a593Smuzhiyun if ((count < 3) || (dy < 0))
414*4882a593Smuzhiyun return TRUE;
415*4882a593Smuzhiyun ptsOut = FirstPoint = xallocarray(dy, sizeof(DDXPointRec));
416*4882a593Smuzhiyun width = FirstWidth = xallocarray(dy, sizeof(int));
417*4882a593Smuzhiyun if (!FirstPoint || !FirstWidth) {
418*4882a593Smuzhiyun free(FirstWidth);
419*4882a593Smuzhiyun free(FirstPoint);
420*4882a593Smuzhiyun return FALSE;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun nextleft = nextright = imin;
424*4882a593Smuzhiyun y = ptsIn[nextleft].y;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /*
427*4882a593Smuzhiyun * loop through all edges of the polygon
428*4882a593Smuzhiyun */
429*4882a593Smuzhiyun do {
430*4882a593Smuzhiyun /*
431*4882a593Smuzhiyun * add a left edge if we need to
432*4882a593Smuzhiyun */
433*4882a593Smuzhiyun if (ptsIn[nextleft].y == y) {
434*4882a593Smuzhiyun left = nextleft;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun /*
437*4882a593Smuzhiyun * find the next edge, considering the end
438*4882a593Smuzhiyun * conditions of the array.
439*4882a593Smuzhiyun */
440*4882a593Smuzhiyun nextleft++;
441*4882a593Smuzhiyun if (nextleft >= count)
442*4882a593Smuzhiyun nextleft = 0;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun /*
445*4882a593Smuzhiyun * now compute all of the random information
446*4882a593Smuzhiyun * needed to run the iterative algorithm.
447*4882a593Smuzhiyun */
448*4882a593Smuzhiyun BRESINITPGON(ptsIn[nextleft].y - ptsIn[left].y,
449*4882a593Smuzhiyun ptsIn[left].x, ptsIn[nextleft].x,
450*4882a593Smuzhiyun xl, dl, ml, m1l, incr1l, incr2l);
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun /*
454*4882a593Smuzhiyun * add a right edge if we need to
455*4882a593Smuzhiyun */
456*4882a593Smuzhiyun if (ptsIn[nextright].y == y) {
457*4882a593Smuzhiyun right = nextright;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /*
460*4882a593Smuzhiyun * find the next edge, considering the end
461*4882a593Smuzhiyun * conditions of the array.
462*4882a593Smuzhiyun */
463*4882a593Smuzhiyun nextright--;
464*4882a593Smuzhiyun if (nextright < 0)
465*4882a593Smuzhiyun nextright = count - 1;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /*
468*4882a593Smuzhiyun * now compute all of the random information
469*4882a593Smuzhiyun * needed to run the iterative algorithm.
470*4882a593Smuzhiyun */
471*4882a593Smuzhiyun BRESINITPGON(ptsIn[nextright].y - ptsIn[right].y,
472*4882a593Smuzhiyun ptsIn[right].x, ptsIn[nextright].x,
473*4882a593Smuzhiyun xr, dr, mr, m1r, incr1r, incr2r);
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /*
477*4882a593Smuzhiyun * generate scans to fill while we still have
478*4882a593Smuzhiyun * a right edge as well as a left edge.
479*4882a593Smuzhiyun */
480*4882a593Smuzhiyun i = min(ptsIn[nextleft].y, ptsIn[nextright].y) - y;
481*4882a593Smuzhiyun /* in case we're called with non-convex polygon */
482*4882a593Smuzhiyun if (i < 0) {
483*4882a593Smuzhiyun free(FirstWidth);
484*4882a593Smuzhiyun free(FirstPoint);
485*4882a593Smuzhiyun return TRUE;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun while (i-- > 0) {
488*4882a593Smuzhiyun ptsOut->y = y;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun /*
491*4882a593Smuzhiyun * reverse the edges if necessary
492*4882a593Smuzhiyun */
493*4882a593Smuzhiyun if (xl < xr) {
494*4882a593Smuzhiyun *(width++) = xr - xl;
495*4882a593Smuzhiyun (ptsOut++)->x = xl;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun else {
498*4882a593Smuzhiyun *(width++) = xl - xr;
499*4882a593Smuzhiyun (ptsOut++)->x = xr;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun y++;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun /* increment down the edges */
504*4882a593Smuzhiyun BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l);
505*4882a593Smuzhiyun BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r);
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun } while (y != ymax);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun /*
510*4882a593Smuzhiyun * Finally, fill the <remaining> spans
511*4882a593Smuzhiyun */
512*4882a593Smuzhiyun (*pgc->ops->FillSpans) (dst, pgc,
513*4882a593Smuzhiyun ptsOut - FirstPoint, FirstPoint, FirstWidth, 1);
514*4882a593Smuzhiyun free(FirstWidth);
515*4882a593Smuzhiyun free(FirstPoint);
516*4882a593Smuzhiyun return TRUE;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun /*
520*4882a593Smuzhiyun * Written by Brian Kelleher; Oct. 1985
521*4882a593Smuzhiyun *
522*4882a593Smuzhiyun * Routine to fill a polygon. Two fill rules are supported: frWINDING and
523*4882a593Smuzhiyun * frEVENODD.
524*4882a593Smuzhiyun */
525*4882a593Smuzhiyun static Bool
miFillGeneralPoly(DrawablePtr dst,GCPtr pgc,int count,DDXPointPtr ptsIn)526*4882a593Smuzhiyun miFillGeneralPoly(DrawablePtr dst, GCPtr pgc, int count, DDXPointPtr ptsIn)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun EdgeTableEntry *pAET; /* the Active Edge Table */
529*4882a593Smuzhiyun int y; /* the current scanline */
530*4882a593Smuzhiyun int nPts = 0; /* number of pts in buffer */
531*4882a593Smuzhiyun EdgeTableEntry *pWETE; /* Winding Edge Table */
532*4882a593Smuzhiyun ScanLineList *pSLL; /* Current ScanLineList */
533*4882a593Smuzhiyun DDXPointPtr ptsOut; /* ptr to output buffers */
534*4882a593Smuzhiyun int *width;
535*4882a593Smuzhiyun DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
536*4882a593Smuzhiyun int FirstWidth[NUMPTSTOBUFFER];
537*4882a593Smuzhiyun EdgeTableEntry *pPrevAET; /* previous AET entry */
538*4882a593Smuzhiyun EdgeTable ET; /* Edge Table header node */
539*4882a593Smuzhiyun EdgeTableEntry AET; /* Active ET header node */
540*4882a593Smuzhiyun EdgeTableEntry *pETEs; /* Edge Table Entries buff */
541*4882a593Smuzhiyun ScanLineListBlock SLLBlock; /* header for ScanLineList */
542*4882a593Smuzhiyun int fixWAET = 0;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun if (count < 3)
545*4882a593Smuzhiyun return TRUE;
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun if (!(pETEs = malloc(sizeof(EdgeTableEntry) * count)))
548*4882a593Smuzhiyun return FALSE;
549*4882a593Smuzhiyun ptsOut = FirstPoint;
550*4882a593Smuzhiyun width = FirstWidth;
551*4882a593Smuzhiyun if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) {
552*4882a593Smuzhiyun free(pETEs);
553*4882a593Smuzhiyun return FALSE;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun pSLL = ET.scanlines.next;
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun if (pgc->fillRule == EvenOddRule) {
558*4882a593Smuzhiyun /*
559*4882a593Smuzhiyun * for each scanline
560*4882a593Smuzhiyun */
561*4882a593Smuzhiyun for (y = ET.ymin; y < ET.ymax; y++) {
562*4882a593Smuzhiyun /*
563*4882a593Smuzhiyun * Add a new edge to the active edge table when we
564*4882a593Smuzhiyun * get to the next edge.
565*4882a593Smuzhiyun */
566*4882a593Smuzhiyun if (pSLL && y == pSLL->scanline) {
567*4882a593Smuzhiyun miloadAET(&AET, pSLL->edgelist);
568*4882a593Smuzhiyun pSLL = pSLL->next;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun pPrevAET = &AET;
571*4882a593Smuzhiyun pAET = AET.next;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun /*
574*4882a593Smuzhiyun * for each active edge
575*4882a593Smuzhiyun */
576*4882a593Smuzhiyun while (pAET) {
577*4882a593Smuzhiyun ptsOut->x = pAET->bres.minor;
578*4882a593Smuzhiyun ptsOut++->y = y;
579*4882a593Smuzhiyun *width++ = pAET->next->bres.minor - pAET->bres.minor;
580*4882a593Smuzhiyun nPts++;
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /*
583*4882a593Smuzhiyun * send out the buffer when its full
584*4882a593Smuzhiyun */
585*4882a593Smuzhiyun if (nPts == NUMPTSTOBUFFER) {
586*4882a593Smuzhiyun (*pgc->ops->FillSpans) (dst, pgc,
587*4882a593Smuzhiyun nPts, FirstPoint, FirstWidth, 1);
588*4882a593Smuzhiyun ptsOut = FirstPoint;
589*4882a593Smuzhiyun width = FirstWidth;
590*4882a593Smuzhiyun nPts = 0;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
593*4882a593Smuzhiyun EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun miInsertionSort(&AET);
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun else { /* default to WindingNumber */
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun /*
601*4882a593Smuzhiyun * for each scanline
602*4882a593Smuzhiyun */
603*4882a593Smuzhiyun for (y = ET.ymin; y < ET.ymax; y++) {
604*4882a593Smuzhiyun /*
605*4882a593Smuzhiyun * Add a new edge to the active edge table when we
606*4882a593Smuzhiyun * get to the next edge.
607*4882a593Smuzhiyun */
608*4882a593Smuzhiyun if (pSLL && y == pSLL->scanline) {
609*4882a593Smuzhiyun miloadAET(&AET, pSLL->edgelist);
610*4882a593Smuzhiyun micomputeWAET(&AET);
611*4882a593Smuzhiyun pSLL = pSLL->next;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun pPrevAET = &AET;
614*4882a593Smuzhiyun pAET = AET.next;
615*4882a593Smuzhiyun pWETE = pAET;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /*
618*4882a593Smuzhiyun * for each active edge
619*4882a593Smuzhiyun */
620*4882a593Smuzhiyun while (pAET) {
621*4882a593Smuzhiyun /*
622*4882a593Smuzhiyun * if the next edge in the active edge table is
623*4882a593Smuzhiyun * also the next edge in the winding active edge
624*4882a593Smuzhiyun * table.
625*4882a593Smuzhiyun */
626*4882a593Smuzhiyun if (pWETE == pAET) {
627*4882a593Smuzhiyun ptsOut->x = pAET->bres.minor;
628*4882a593Smuzhiyun ptsOut++->y = y;
629*4882a593Smuzhiyun *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor;
630*4882a593Smuzhiyun nPts++;
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun /*
633*4882a593Smuzhiyun * send out the buffer
634*4882a593Smuzhiyun */
635*4882a593Smuzhiyun if (nPts == NUMPTSTOBUFFER) {
636*4882a593Smuzhiyun (*pgc->ops->FillSpans) (dst, pgc, nPts, FirstPoint,
637*4882a593Smuzhiyun FirstWidth, 1);
638*4882a593Smuzhiyun ptsOut = FirstPoint;
639*4882a593Smuzhiyun width = FirstWidth;
640*4882a593Smuzhiyun nPts = 0;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun pWETE = pWETE->nextWETE;
644*4882a593Smuzhiyun while (pWETE != pAET)
645*4882a593Smuzhiyun EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
646*4882a593Smuzhiyun pWETE = pWETE->nextWETE;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun /*
652*4882a593Smuzhiyun * reevaluate the Winding active edge table if we
653*4882a593Smuzhiyun * just had to resort it or if we just exited an edge.
654*4882a593Smuzhiyun */
655*4882a593Smuzhiyun if (miInsertionSort(&AET) || fixWAET) {
656*4882a593Smuzhiyun micomputeWAET(&AET);
657*4882a593Smuzhiyun fixWAET = 0;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun /*
663*4882a593Smuzhiyun * Get any spans that we missed by buffering
664*4882a593Smuzhiyun */
665*4882a593Smuzhiyun (*pgc->ops->FillSpans) (dst, pgc, nPts, FirstPoint, FirstWidth, 1);
666*4882a593Smuzhiyun free(pETEs);
667*4882a593Smuzhiyun miFreeStorage(SLLBlock.next);
668*4882a593Smuzhiyun return TRUE;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun /*
672*4882a593Smuzhiyun * Draw polygons. This routine translates the point by the origin if
673*4882a593Smuzhiyun * pGC->miTranslate is non-zero, and calls to the appropriate routine to
674*4882a593Smuzhiyun * actually scan convert the polygon.
675*4882a593Smuzhiyun */
676*4882a593Smuzhiyun void
miFillPolygon(DrawablePtr dst,GCPtr pgc,int shape,int mode,int count,DDXPointPtr pPts)677*4882a593Smuzhiyun miFillPolygon(DrawablePtr dst, GCPtr pgc,
678*4882a593Smuzhiyun int shape, int mode, int count, DDXPointPtr pPts)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun int i;
681*4882a593Smuzhiyun int xorg, yorg;
682*4882a593Smuzhiyun DDXPointPtr ppt;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun if (count == 0)
685*4882a593Smuzhiyun return;
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun ppt = pPts;
688*4882a593Smuzhiyun if (pgc->miTranslate) {
689*4882a593Smuzhiyun xorg = dst->x;
690*4882a593Smuzhiyun yorg = dst->y;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun if (mode == CoordModeOrigin) {
693*4882a593Smuzhiyun for (i = 0; i < count; i++) {
694*4882a593Smuzhiyun ppt->x += xorg;
695*4882a593Smuzhiyun ppt++->y += yorg;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun else {
699*4882a593Smuzhiyun ppt->x += xorg;
700*4882a593Smuzhiyun ppt++->y += yorg;
701*4882a593Smuzhiyun for (i = 1; i < count; i++) {
702*4882a593Smuzhiyun ppt->x += (ppt - 1)->x;
703*4882a593Smuzhiyun ppt->y += (ppt - 1)->y;
704*4882a593Smuzhiyun ppt++;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun else {
709*4882a593Smuzhiyun if (mode == CoordModePrevious) {
710*4882a593Smuzhiyun ppt++;
711*4882a593Smuzhiyun for (i = 1; i < count; i++) {
712*4882a593Smuzhiyun ppt->x += (ppt - 1)->x;
713*4882a593Smuzhiyun ppt->y += (ppt - 1)->y;
714*4882a593Smuzhiyun ppt++;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun if (shape == Convex)
719*4882a593Smuzhiyun miFillConvexPoly(dst, pgc, count, pPts);
720*4882a593Smuzhiyun else
721*4882a593Smuzhiyun miFillGeneralPoly(dst, pgc, count, pPts);
722*4882a593Smuzhiyun }
723