xref: /OK3568_Linux_fs/external/xserver/mi/mipoly.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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