src/qt3support/other/q3polygonscanner.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "q3polygonscanner.h"
       
    43 #include "q3pointarray.h"
       
    44 #include <stdlib.h>
       
    45 
       
    46 QT_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 
       
   108 Copyright (c) 1987  X Consortium
       
   109 
       
   110 Permission is hereby granted, free of charge, to any person obtaining
       
   111 a copy of this software and associated documentation files (the
       
   112 "Software"), to deal in the Software without restriction, including
       
   113 without limitation the rights to use, copy, modify, merge, publish,
       
   114 distribute, sublicense, and/or sell copies of the Software, and to
       
   115 permit persons to whom the Software is furnished to do so, subject to
       
   116 the following conditions:
       
   117 
       
   118 The above copyright notice and this permission notice shall be included
       
   119 in all copies or substantial portions of the Software.
       
   120 
       
   121 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
       
   122 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
   123 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       
   124 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
       
   125 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
       
   126 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
       
   127 OTHER DEALINGS IN THE SOFTWARE.
       
   128 
       
   129 Except as contained in this notice, the name of the X Consortium shall
       
   130 not be used in advertising or otherwise to promote the sale, use or
       
   131 other dealings in this Software without prior written authorization
       
   132 from 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 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
       
   202     if (m1 > 0) { \
       
   203         if (d > 0) { \
       
   204             minval += m1; \
       
   205             d += incr1; \
       
   206         } \
       
   207         else { \
       
   208             minval += m; \
       
   209             d += incr2; \
       
   210         } \
       
   211     } else {\
       
   212         if (d >= 0) { \
       
   213             minval += m1; \
       
   214             d += incr1; \
       
   215         } \
       
   216         else { \
       
   217             minval += m; \
       
   218             d += incr2; \
       
   219         } \
       
   220     } \
       
   221 }
       
   222 
       
   223 
       
   224 /*
       
   225  *     This structure contains all of the information needed
       
   226  *     to run the bresenham algorithm.
       
   227  *     The variables may be hardcoded into the declarations
       
   228  *     instead of using this structure to make use of
       
   229  *     register declarations.
       
   230  */
       
   231 typedef struct {
       
   232     int minor;         /* minor axis        */
       
   233     int d;           /* decision variable */
       
   234     int m, m1;       /* slope and slope+1 */
       
   235     int incr1, incr2; /* error increments */
       
   236 } BRESINFO;
       
   237 
       
   238 
       
   239 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
       
   240         BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
       
   241                      bres.m, bres.m1, bres.incr1, bres.incr2)
       
   242 
       
   243 #define BRESINCRPGONSTRUCT(bres) \
       
   244         BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
       
   245 
       
   246 
       
   247 typedef struct _EdgeTableEntry {
       
   248      int ymax;             /* ycoord at which we exit this edge. */
       
   249      BRESINFO bres;        /* Bresenham info to run the edge     */
       
   250      struct _EdgeTableEntry *next;       /* next in the list     */
       
   251      struct _EdgeTableEntry *back;       /* for insertion sort   */
       
   252      struct _EdgeTableEntry *nextWETE;   /* for winding num rule */
       
   253      int ClockWise;        /* flag for winding number rule       */
       
   254 } EdgeTableEntry;
       
   255 
       
   256 
       
   257 typedef struct _ScanLineList{
       
   258      int scanline;              /* the scanline represented */
       
   259      EdgeTableEntry *edgelist;  /* header node              */
       
   260      struct _ScanLineList *next;  /* next in the list       */
       
   261 } ScanLineList;
       
   262 
       
   263 
       
   264 typedef struct {
       
   265      int ymax;                 /* ymax for the polygon     */
       
   266      int ymin;                 /* ymin for the polygon     */
       
   267      ScanLineList scanlines;   /* header node              */
       
   268 } EdgeTable;
       
   269 
       
   270 
       
   271 /*
       
   272  * Here is a struct to help with storage allocation
       
   273  * so we can allocate a big chunk at a time, and then take
       
   274  * pieces from this heap when we need to.
       
   275  */
       
   276 #define SLLSPERBLOCK 25
       
   277 
       
   278 typedef struct _ScanLineListBlock {
       
   279      ScanLineList SLLs[SLLSPERBLOCK];
       
   280      struct _ScanLineListBlock *next;
       
   281 } ScanLineListBlock;
       
   282 
       
   283 /*
       
   284  * number of points to buffer before sending them off
       
   285  * to scanlines() :  Must be an even number
       
   286  */
       
   287 #define NUMPTSTOBUFFER 200
       
   288 
       
   289 /*
       
   290  *
       
   291  *     a few macros for the inner loops of the fill code where
       
   292  *     performance considerations don't allow a procedure call.
       
   293  *
       
   294  *     Evaluate the given edge at the given scanline.
       
   295  *     If the edge has expired, then we leave it and fix up
       
   296  *     the active edge table; otherwise, we increment the
       
   297  *     x value to be ready for the next scanline.
       
   298  *     The winding number rule is in effect, so we must notify
       
   299  *     the caller when the edge has been removed so he
       
   300  *     can reorder the Winding Active Edge Table.
       
   301  */
       
   302 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
       
   303    if (pAET->ymax == y) {          /* leaving this edge */ \
       
   304       pPrevAET->next = pAET->next; \
       
   305       pAET = pPrevAET->next; \
       
   306       fixWAET = 1; \
       
   307       if (pAET) \
       
   308          pAET->back = pPrevAET; \
       
   309    } \
       
   310    else { \
       
   311       BRESINCRPGONSTRUCT(pAET->bres); \
       
   312       pPrevAET = pAET; \
       
   313       pAET = pAET->next; \
       
   314    } \
       
   315 }
       
   316 
       
   317 
       
   318 /*
       
   319  *     Evaluate the given edge at the given scanline.
       
   320  *     If the edge has expired, then we leave it and fix up
       
   321  *     the active edge table; otherwise, we increment the
       
   322  *     x value to be ready for the next scanline.
       
   323  *     The even-odd rule is in effect.
       
   324  */
       
   325 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
       
   326    if (pAET->ymax == y) {          /* leaving this edge */ \
       
   327       pPrevAET->next = pAET->next; \
       
   328       pAET = pPrevAET->next; \
       
   329       if (pAET) \
       
   330          pAET->back = pPrevAET; \
       
   331    } \
       
   332    else { \
       
   333       BRESINCRPGONSTRUCT(pAET->bres) \
       
   334       pPrevAET = pAET; \
       
   335       pAET = pAET->next; \
       
   336    } \
       
   337 }
       
   338 
       
   339 /***********************************************************
       
   340 
       
   341 Copyright (c) 1987  X Consortium
       
   342 
       
   343 Permission is hereby granted, free of charge, to any person obtaining a copy
       
   344 of this software and associated documentation files (the "Software"), to deal
       
   345 in the Software without restriction, including without limitation the rights
       
   346 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
   347 copies of the Software, and to permit persons to whom the Software is
       
   348 furnished to do so, subject to the following conditions:
       
   349 
       
   350 The above copyright notice and this permission notice shall be included in
       
   351 all copies or substantial portions of the Software.
       
   352 
       
   353 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
   354 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
   355 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
       
   356 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
       
   357 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
       
   358 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       
   359 
       
   360 Except as contained in this notice, the name of the X Consortium shall not be
       
   361 used in advertising or otherwise to promote the sale, use or other dealings
       
   362 in this Software without prior written authorization from the X Consortium.
       
   363 
       
   364 
       
   365 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
       
   366 
       
   367                         All Rights Reserved
       
   368 
       
   369 Permission to use, copy, modify, and distribute this software and its
       
   370 documentation for any purpose and without fee is hereby granted,
       
   371 provided that the above copyright notice appear in all copies and that
       
   372 both that copyright notice and this permission notice appear in
       
   373 supporting documentation, and that the name of Digital not be
       
   374 used in advertising or publicity pertaining to distribution of the
       
   375 software without specific, written prior permission.
       
   376 
       
   377 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
       
   378 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
       
   379 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
       
   380 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
       
   381 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
       
   382 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
       
   383 SOFTWARE.
       
   384 
       
   385 ******************************************************************/
       
   386 
       
   387 #define MAXINT 0x7fffffff
       
   388 #define MININT -MAXINT
       
   389 
       
   390 /*
       
   391  *     fillUtils.c
       
   392  *
       
   393  *     Written by Brian Kelleher;  Oct. 1985
       
   394  *
       
   395  *     This module contains all of the utility functions
       
   396  *     needed to scan convert a polygon.
       
   397  *
       
   398  */
       
   399 /*
       
   400  *     InsertEdgeInET
       
   401  *
       
   402  *     Insert the given edge into the edge table.
       
   403  *     First we must find the correct bucket in the
       
   404  *     Edge table, then find the right slot in the
       
   405  *     bucket.  Finally, we can insert it.
       
   406  *
       
   407  */
       
   408 static bool
       
   409 miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
       
   410         int scanline, ScanLineListBlock **SLLBlock, int *iSLLBlock)
       
   411 {
       
   412     register EdgeTableEntry *start, *prev;
       
   413     register ScanLineList *pSLL, *pPrevSLL;
       
   414     ScanLineListBlock *tmpSLLBlock;
       
   415 
       
   416     /*
       
   417      * find the right bucket to put the edge into
       
   418      */
       
   419     pPrevSLL = &ET->scanlines;
       
   420     pSLL = pPrevSLL->next;
       
   421     while (pSLL && (pSLL->scanline < scanline))
       
   422     {
       
   423         pPrevSLL = pSLL;
       
   424         pSLL = pSLL->next;
       
   425     }
       
   426 
       
   427     /*
       
   428      * reassign pSLL (pointer to ScanLineList) if necessary
       
   429      */
       
   430     if ((!pSLL) || (pSLL->scanline > scanline))
       
   431     {
       
   432         if (*iSLLBlock > SLLSPERBLOCK-1)
       
   433         {
       
   434             tmpSLLBlock =
       
   435                   (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
       
   436             if (!tmpSLLBlock)
       
   437                 return false;
       
   438             (*SLLBlock)->next = tmpSLLBlock;
       
   439             tmpSLLBlock->next = 0;
       
   440             *SLLBlock = tmpSLLBlock;
       
   441             *iSLLBlock = 0;
       
   442         }
       
   443         pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
       
   444 
       
   445         pSLL->next = pPrevSLL->next;
       
   446         pSLL->edgelist = 0;
       
   447         pPrevSLL->next = pSLL;
       
   448     }
       
   449     pSLL->scanline = scanline;
       
   450 
       
   451     /*
       
   452      * now insert the edge in the right bucket
       
   453      */
       
   454     prev = 0;
       
   455     start = pSLL->edgelist;
       
   456     while (start && (start->bres.minor < ETE->bres.minor))
       
   457     {
       
   458         prev = start;
       
   459         start = start->next;
       
   460     }
       
   461     ETE->next = start;
       
   462 
       
   463     if (prev)
       
   464         prev->next = ETE;
       
   465     else
       
   466         pSLL->edgelist = ETE;
       
   467     return true;
       
   468 }
       
   469 
       
   470 /*
       
   471  *     CreateEdgeTable
       
   472  *
       
   473  *     This routine creates the edge table for
       
   474  *     scan converting polygons.
       
   475  *     The Edge Table (ET) looks like:
       
   476  *
       
   477  *    EdgeTable
       
   478  *     --------
       
   479  *    |  ymax  |        ScanLineLists
       
   480  *    |scanline|-->------------>-------------->...
       
   481  *     --------   |scanline|   |scanline|
       
   482  *                |edgelist|   |edgelist|
       
   483  *                ---------    ---------
       
   484  *                    |             |
       
   485  *                    |             |
       
   486  *                    V             V
       
   487  *              list of ETEs   list of ETEs
       
   488  *
       
   489  *     where ETE is an EdgeTableEntry data structure,
       
   490  *     and there is one ScanLineList per scanline at
       
   491  *     which an edge is initially entered.
       
   492  *
       
   493  */
       
   494 
       
   495 typedef struct {
       
   496 #if defined(Q_OS_MAC)
       
   497     int y, x;
       
   498 #else
       
   499     int x, y;
       
   500 #endif
       
   501 
       
   502 } DDXPointRec, *DDXPointPtr;
       
   503 
       
   504 /*
       
   505  *     Clean up our act.
       
   506  */
       
   507 static void
       
   508 miFreeStorage(ScanLineListBlock   *pSLLBlock)
       
   509 {
       
   510     register ScanLineListBlock   *tmpSLLBlock;
       
   511 
       
   512     while (pSLLBlock)
       
   513     {
       
   514         tmpSLLBlock = pSLLBlock->next;
       
   515         free(pSLLBlock);
       
   516         pSLLBlock = tmpSLLBlock;
       
   517     }
       
   518 }
       
   519 
       
   520 static bool
       
   521 miCreateETandAET(int count, DDXPointPtr pts, EdgeTable *ET,
       
   522         EdgeTableEntry *AET, EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
       
   523 {
       
   524     register DDXPointPtr top, bottom;
       
   525     register DDXPointPtr PrevPt, CurrPt;
       
   526     int iSLLBlock = 0;
       
   527 
       
   528     int dy;
       
   529 
       
   530     if (count < 2)  return true;
       
   531 
       
   532     /*
       
   533      *  initialize the Active Edge Table
       
   534      */
       
   535     AET->next = 0;
       
   536     AET->back = 0;
       
   537     AET->nextWETE = 0;
       
   538     AET->bres.minor = MININT;
       
   539 
       
   540     /*
       
   541      *  initialize the Edge Table.
       
   542      */
       
   543     ET->scanlines.next = 0;
       
   544     ET->ymax = MININT;
       
   545     ET->ymin = MAXINT;
       
   546     pSLLBlock->next = 0;
       
   547 
       
   548     PrevPt = &pts[count-1];
       
   549 
       
   550     /*
       
   551      *  for each vertex in the array of points.
       
   552      *  In this loop we are dealing with two vertices at
       
   553      *  a time -- these make up one edge of the polygon.
       
   554      */
       
   555     while (count--)
       
   556     {
       
   557         CurrPt = pts++;
       
   558 
       
   559         /*
       
   560          *  find out which point is above and which is below.
       
   561          */
       
   562         if (PrevPt->y > CurrPt->y)
       
   563         {
       
   564             bottom = PrevPt, top = CurrPt;
       
   565             pETEs->ClockWise = 0;
       
   566         }
       
   567         else
       
   568         {
       
   569             bottom = CurrPt, top = PrevPt;
       
   570             pETEs->ClockWise = 1;
       
   571         }
       
   572 
       
   573         /*
       
   574          * don't add horizontal edges to the Edge table.
       
   575          */
       
   576         if (bottom->y != top->y)
       
   577         {
       
   578             pETEs->ymax = bottom->y-1;  /* -1 so we don't get last scanline */
       
   579 
       
   580             /*
       
   581              *  initialize integer edge algorithm
       
   582              */
       
   583             dy = bottom->y - top->y;
       
   584             BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres)
       
   585 
       
   586             if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock))
       
   587             {
       
   588                 miFreeStorage(pSLLBlock->next);
       
   589                 return false;
       
   590             }
       
   591 
       
   592             ET->ymax = qMax(ET->ymax, PrevPt->y);
       
   593             ET->ymin = qMin(ET->ymin, PrevPt->y);
       
   594             pETEs++;
       
   595         }
       
   596 
       
   597         PrevPt = CurrPt;
       
   598     }
       
   599     return true;
       
   600 }
       
   601 
       
   602 /*
       
   603  *     loadAET
       
   604  *
       
   605  *     This routine moves EdgeTableEntries from the
       
   606  *     EdgeTable into the Active Edge Table,
       
   607  *     leaving them sorted by smaller x coordinate.
       
   608  *
       
   609  */
       
   610 
       
   611 static void
       
   612 miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
       
   613 {
       
   614     register EdgeTableEntry *pPrevAET;
       
   615     register EdgeTableEntry *tmp;
       
   616 
       
   617     pPrevAET = AET;
       
   618     AET = AET->next;
       
   619     while (ETEs)
       
   620     {
       
   621         while (AET && (AET->bres.minor < ETEs->bres.minor))
       
   622         {
       
   623             pPrevAET = AET;
       
   624             AET = AET->next;
       
   625         }
       
   626         tmp = ETEs->next;
       
   627         ETEs->next = AET;
       
   628         if (AET)
       
   629             AET->back = ETEs;
       
   630         ETEs->back = pPrevAET;
       
   631         pPrevAET->next = ETEs;
       
   632         pPrevAET = ETEs;
       
   633 
       
   634         ETEs = tmp;
       
   635     }
       
   636 }
       
   637 
       
   638 /*
       
   639  *     computeWAET
       
   640  *
       
   641  *     This routine links the AET by the
       
   642  *     nextWETE (winding EdgeTableEntry) link for
       
   643  *     use by the winding number rule.  The final
       
   644  *     Active Edge Table (AET) might look something
       
   645  *     like:
       
   646  *
       
   647  *     AET
       
   648  *     ----------  ---------   ---------
       
   649  *     |ymax    |  |ymax    |  |ymax    |
       
   650  *     | ...    |  |...     |  |...     |
       
   651  *     |next    |->|next    |->|next    |->...
       
   652  *     |nextWETE|  |nextWETE|  |nextWETE|
       
   653  *     ---------   ---------   ^--------
       
   654  *         |                   |       |
       
   655  *         V------------------->       V---> ...
       
   656  *
       
   657  */
       
   658 static void
       
   659 micomputeWAET(EdgeTableEntry *AET)
       
   660 {
       
   661     register EdgeTableEntry *pWETE;
       
   662     register int inside = 1;
       
   663     register int isInside = 0;
       
   664 
       
   665     AET->nextWETE = 0;
       
   666     pWETE = AET;
       
   667     AET = AET->next;
       
   668     while (AET)
       
   669     {
       
   670         if (AET->ClockWise)
       
   671             isInside++;
       
   672         else
       
   673             isInside--;
       
   674 
       
   675         if ((!inside && !isInside) ||
       
   676             (inside &&  isInside))
       
   677         {
       
   678             pWETE->nextWETE = AET;
       
   679             pWETE = AET;
       
   680             inside = !inside;
       
   681         }
       
   682         AET = AET->next;
       
   683     }
       
   684     pWETE->nextWETE = 0;
       
   685 }
       
   686 
       
   687 /*
       
   688  *     InsertionSort
       
   689  *
       
   690  *     Just a simple insertion sort using
       
   691  *     pointers and back pointers to sort the Active
       
   692  *     Edge Table.
       
   693  *
       
   694  */
       
   695 
       
   696 static int
       
   697 miInsertionSort(EdgeTableEntry *AET)
       
   698 {
       
   699     register EdgeTableEntry *pETEchase;
       
   700     register EdgeTableEntry *pETEinsert;
       
   701     register EdgeTableEntry *pETEchaseBackTMP;
       
   702     register int changed = 0;
       
   703 
       
   704     AET = AET->next;
       
   705     while (AET)
       
   706     {
       
   707         pETEinsert = AET;
       
   708         pETEchase = AET;
       
   709         while (pETEchase->back->bres.minor > AET->bres.minor)
       
   710             pETEchase = pETEchase->back;
       
   711 
       
   712         AET = AET->next;
       
   713         if (pETEchase != pETEinsert)
       
   714         {
       
   715             pETEchaseBackTMP = pETEchase->back;
       
   716             pETEinsert->back->next = AET;
       
   717             if (AET)
       
   718                 AET->back = pETEinsert->back;
       
   719             pETEinsert->next = pETEchase;
       
   720             pETEchase->back->next = pETEinsert;
       
   721             pETEchase->back = pETEinsert;
       
   722             pETEinsert->back = pETEchaseBackTMP;
       
   723             changed = 1;
       
   724         }
       
   725     }
       
   726     return changed;
       
   727 }
       
   728 
       
   729 /*!
       
   730     \overload
       
   731 */
       
   732 void Q3PolygonScanner::scan(const Q3PointArray& pa, bool winding, int index, int npoints)
       
   733 {
       
   734     scan(pa, winding, index, npoints, true);
       
   735 }
       
   736 
       
   737 /*!
       
   738     \overload
       
   739 
       
   740     If \a stitchable is false, the right and bottom edges of the
       
   741     polygon are included. This causes adjacent polygons to overlap.
       
   742 */
       
   743 void Q3PolygonScanner::scan(const Q3PointArray& pa, bool winding, int index, int npoints, bool stitchable)
       
   744 {
       
   745     scan(pa, winding, index, npoints,
       
   746         stitchable ? Edge(Left+Top) : Edge(Left+Right+Top+Bottom));
       
   747 }
       
   748 
       
   749 /*!
       
   750     Calls processSpans() for all scanlines of the polygon defined by
       
   751     \a npoints starting at \a index in \a pa.
       
   752 
       
   753     If \a winding is true, the Winding algorithm rather than the
       
   754     Odd-Even rule is used.
       
   755 
       
   756     The \a edges is any bitwise combination of:
       
   757     \list
       
   758     \i Q3PolygonScanner::Left
       
   759     \i Q3PolygonScanner::Right
       
   760     \i Q3PolygonScanner::Top
       
   761     \i Q3PolygonScanner::Bottom
       
   762     \endlist
       
   763     \a edges determines which edges are included.
       
   764 
       
   765     \warning The edges feature does not work properly.
       
   766 
       
   767 */
       
   768 void Q3PolygonScanner::scan(const Q3PointArray& pa, bool winding, int index, int npoints, Edge edges)
       
   769 {
       
   770 
       
   771 
       
   772     DDXPointPtr ptsIn = (DDXPointPtr)pa.data();
       
   773     ptsIn += index;
       
   774     register EdgeTableEntry *pAET;  /* the Active Edge Table   */
       
   775     register int y;                 /* the current scanline    */
       
   776     register int nPts = 0;          /* number of pts in buffer */
       
   777     register EdgeTableEntry *pWETE; /* Winding Edge Table      */
       
   778     register ScanLineList *pSLL;    /* Current ScanLineList    */
       
   779     register DDXPointPtr ptsOut;      /* ptr to output buffers   */
       
   780     int *width;
       
   781     DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
       
   782     int FirstWidth[NUMPTSTOBUFFER];
       
   783     EdgeTableEntry *pPrevAET;       /* previous AET entry      */
       
   784     EdgeTable ET;                   /* Edge Table header node  */
       
   785     EdgeTableEntry AET;             /* Active ET header node   */
       
   786     EdgeTableEntry *pETEs;          /* Edge Table Entries buff */
       
   787     ScanLineListBlock SLLBlock;     /* header for ScanLineList */
       
   788     int fixWAET = 0;
       
   789     int edge_l = (edges & Left) ? 1 : 0;
       
   790     int edge_r = (edges & Right) ? 1 : 0;
       
   791     int edge_t = 1; //#### (edges & Top) ? 1 : 0;
       
   792     int edge_b = (edges & Bottom) ? 1 : 0;
       
   793 
       
   794     if (npoints == -1)
       
   795         npoints = pa.size();
       
   796 
       
   797     if (npoints < 3)
       
   798         return;
       
   799 
       
   800     if(!(pETEs = (EdgeTableEntry *)
       
   801         malloc(sizeof(EdgeTableEntry) * npoints)))
       
   802         return;
       
   803     ptsOut = FirstPoint;
       
   804     width = FirstWidth;
       
   805     if (!miCreateETandAET(npoints, ptsIn, &ET, &AET, pETEs, &SLLBlock))
       
   806     {
       
   807         free(pETEs);
       
   808         return;
       
   809     }
       
   810     pSLL = ET.scanlines.next;
       
   811 
       
   812     if (!winding)
       
   813     {
       
   814         /*
       
   815          *  for each scanline
       
   816          */
       
   817         for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++)
       
   818         {
       
   819             /*
       
   820              *  Add a new edge to the active edge table when we
       
   821              *  get to the next edge.
       
   822              */
       
   823             if (pSLL && y == pSLL->scanline)
       
   824             {
       
   825                 miloadAET(&AET, pSLL->edgelist);
       
   826                 pSLL = pSLL->next;
       
   827             }
       
   828             pPrevAET = &AET;
       
   829             pAET = AET.next;
       
   830 
       
   831             /*
       
   832              *  for each active edge
       
   833              */
       
   834             while (pAET)
       
   835             {
       
   836                 ptsOut->x = pAET->bres.minor + 1 - edge_l;
       
   837                 ptsOut++->y = y;
       
   838                 *width++ = pAET->next->bres.minor - pAET->bres.minor
       
   839                     - 1 + edge_l + edge_r;
       
   840                 nPts++;
       
   841 
       
   842                 /*
       
   843                  *  send out the buffer when its full
       
   844                  */
       
   845                 if (nPts == NUMPTSTOBUFFER)
       
   846                 {
       
   847                     processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
       
   848                     ptsOut = FirstPoint;
       
   849                     width = FirstWidth;
       
   850                     nPts = 0;
       
   851                 }
       
   852                 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
       
   853                 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
       
   854             }
       
   855             miInsertionSort(&AET);
       
   856         }
       
   857     }
       
   858     else      /* default to WindingNumber */
       
   859     {
       
   860         /*
       
   861          *  for each scanline
       
   862          */
       
   863         for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++)
       
   864         {
       
   865             /*
       
   866              *  Add a new edge to the active edge table when we
       
   867              *  get to the next edge.
       
   868              */
       
   869             if (pSLL && y == pSLL->scanline)
       
   870             {
       
   871                 miloadAET(&AET, pSLL->edgelist);
       
   872                 micomputeWAET(&AET);
       
   873                 pSLL = pSLL->next;
       
   874             }
       
   875             pPrevAET = &AET;
       
   876             pAET = AET.next;
       
   877             pWETE = pAET;
       
   878 
       
   879             /*
       
   880              *  for each active edge
       
   881              */
       
   882             while (pAET)
       
   883             {
       
   884                 /*
       
   885                  *  if the next edge in the active edge table is
       
   886                  *  also the next edge in the winding active edge
       
   887                  *  table.
       
   888                  */
       
   889                 if (pWETE == pAET)
       
   890                 {
       
   891                     ptsOut->x = pAET->bres.minor + 1 - edge_l;
       
   892                     ptsOut++->y = y;
       
   893                     *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r;
       
   894                     nPts++;
       
   895 
       
   896                     /*
       
   897                      *  send out the buffer
       
   898                      */
       
   899                     if (nPts == NUMPTSTOBUFFER)
       
   900                     {
       
   901                         processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
       
   902                         ptsOut = FirstPoint;
       
   903                         width  = FirstWidth;
       
   904                         nPts = 0;
       
   905                     }
       
   906 
       
   907                     pWETE = pWETE->nextWETE;
       
   908                     while (pWETE != pAET) {
       
   909                         EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
       
   910                     }
       
   911                     pWETE = pWETE->nextWETE;
       
   912                 }
       
   913                 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
       
   914             }
       
   915 
       
   916             /*
       
   917              *  reevaluate the Winding active edge table if we
       
   918              *  just had to resort it or if we just exited an edge.
       
   919              */
       
   920             if (miInsertionSort(&AET) || fixWAET)
       
   921             {
       
   922                 micomputeWAET(&AET);
       
   923                 fixWAET = 0;
       
   924             }
       
   925         }
       
   926     }
       
   927 
       
   928     /*
       
   929      *     Get any spans that we missed by buffering
       
   930      */
       
   931 
       
   932 
       
   933     processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
       
   934     free(pETEs);
       
   935     miFreeStorage(SLLBlock.next);
       
   936 }
       
   937 /***** END OF X11-based CODE *****/
       
   938 
       
   939 QT_END_NAMESPACE