update for HEAD-2003091401
[reactos.git] / subsys / win32k / objects / polyfill.c
index e57b5d2..1d91db9 100644 (file)
@@ -1,4 +1,23 @@
 /*
+ *  ReactOS W32 Subsystem
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id$
+ *
  * COPYRIGHT:         See COPYING in the top level directory
  * PROJECT:           ReactOS kernel
  * PURPOSE:           Various Polygon Filling routines for Polygon()
 #include <win32k/fillshap.h>
 #include <win32k/dc.h>
 #include <win32k/pen.h>
+#include <include/inteng.h>
 #include <include/object.h>
+#include <include/paint.h>
 
-#define NDEBUG
+#undef NDEBUG
 #include <win32k/debug1.h>
 
-#define PFILL_EDGE_ALLOC_TAG 0x45465044
+INT abs(INT nm);
+
+#define FILL_EDGE_ALLOC_TAG 0x45465044
 
 /*
 ** This struct is used for book keeping during polygon filling routines.
 */
-typedef struct _tagPFILL_EDGE
+typedef struct _tagFILL_EDGE
 {
-    /*Basic line information*/
-       int FromX;
-       int FromY;
-       int ToX;
-       int ToY;
-       int dx;
-       int dy;
-       int MinX;
-       int MaxX;
-       int MinY;
-       int MaxY;
-    
-    /*Active Edge List information*/
-    int XIntercept;
-    int ErrorTerm;
-    int ErrorTermAdjUp;
-    int ErrorTermAdjDown;
-    int XPerY;
-    int Direction;
-
-    /* The next edge in the Edge List*/
-       struct _tagPFILL_EDGE * pNext;
-} PFILL_EDGE, *PPFILL_EDGE;
-
-typedef PPFILL_EDGE    PFILL_EDGE_LIST;
-
-static void DEBUG_PRINT_EDGELIST(PFILL_EDGE_LIST list)
+  /*Basic line information*/
+  int FromX;
+  int FromY;
+  int ToX;
+  int ToY;
+  int dx;
+  int dy;
+  int absdx, absdy;
+  int x, y;
+  int xmajor;
+
+  /*Active Edge List information*/
+  int XIntercept[2];
+  int Error;
+  int ErrorMax;
+  int XDirection, YDirection;
+
+  /* The next edge in the active Edge List*/
+  struct _tagFILL_EDGE * pNext;
+} FILL_EDGE;
+
+typedef struct _FILL_EDGE_LIST
 {
-    PPFILL_EDGE pThis = list;
-    if (0 == list)
-    {
-        DPRINT("List is NULL\n");
-        return;
-    }
-    
-    while(0 != pThis)
-    {
-        DPRINT("EDGE: (%d, %d) to (%d, %d)\n", pThis->FromX, pThis->FromY, pThis->ToX, pThis->ToY);
-        pThis = pThis->pNext;
-    }
-}
-
-/*
-**  Hide memory clean up.
-*/
-static void POLYGONFILL_DestroyEdge(PPFILL_EDGE pEdge)
+  int Count;
+  FILL_EDGE** Edges;
+} FILL_EDGE_LIST;
+
+#if 0
+static
+void
+DEBUG_PRINT_ACTIVE_EDGELIST ( FILL_EDGE* list )
 {
-    if (0 != pEdge)
-        EngFreeMem(pEdge);
+  FILL_EDGE* pThis = list;
+  if (0 == list)
+  {
+    DPRINT1("List is NULL\n");
+    return;
+  }
+
+  while(0 != pThis)
+  {
+    //DPRINT1("EDGE: (%d, %d) to (%d, %d)\n", pThis->FromX, pThis->FromY, pThis->ToX, pThis->ToY);
+    DPRINT1("EDGE: [%d,%d]\n", pThis->XIntercept[0], pThis->XIntercept[1] );
+    pThis = pThis->pNext;
+  }
 }
+#else
+#define DEBUG_PRINT_ACTIVE_EDGELIST(x)
+#endif
 
 /*
-** Clean up a list.
+**  Hide memory clean up.
 */
-static void POLYGONFILL_DestroyEdgeList(PFILL_EDGE_LIST list)
+static
+void
+FASTCALL
+POLYGONFILL_DestroyEdgeList(FILL_EDGE_LIST* list)
 {
-    PPFILL_EDGE pThis = 0;
-    PPFILL_EDGE pNext = 0;
-
-    pThis = list;
-    while (0 != pThis)
-    {  
-        //DPRINT("Destroying Edge\n");
-        pNext = pThis->pNext;
-        POLYGONFILL_DestroyEdge(pThis);
-        pThis = pNext;
-    } 
-    
+  int i;
+  if ( list )
+  {
+    if ( list->Edges )
+    {
+      for ( i = 0; i < list->Count; i++ )
+      {
+       if ( list->Edges[i] )
+         EngFreeMem ( list->Edges[i] );
+      }
+      EngFreeMem ( list->Edges );
+    }
+    EngFreeMem ( list );
+  }
 }
 
 /*
 ** This makes and initiaizes an Edge struct for a line between two points.
 */
-static PPFILL_EDGE POLYGONFILL_MakeEdge(POINT From, POINT To)
+static
+FILL_EDGE*
+FASTCALL
+POLYGONFILL_MakeEdge(POINT From, POINT To)
 {
-    PPFILL_EDGE rc = (PPFILL_EDGE)EngAllocMem(FL_ZERO_MEMORY, sizeof(PFILL_EDGE), PFILL_EDGE_ALLOC_TAG);
+  FILL_EDGE* rc = (FILL_EDGE*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE), FILL_EDGE_ALLOC_TAG);
 
-    if (0 != rc)
-    {
-        //DPRINT("Making Edge: (%d, %d) to (%d, %d)\n", From.x, From.y, To.x, To.y);
-        //Now Fill the struct.
-           rc->FromX = From.x;
-           rc->FromY = From.y;
-           rc->ToX = To.x;
-           rc->ToY = To.y;
-           
-           rc->dx   = To.x - From.x;
-           rc->dy   = To.y - From.y;
-       rc->MinX = MIN(To.x, From.x);
-           rc->MaxX = MAX(To.x, From.x);
-           rc->MinY = MIN(To.y, From.y);
-           rc->MaxY = MAX(To.y, From.y);
-
-        if (rc->MinY == To.y)
-            rc->XIntercept = To.x;
-        else
-            rc->XIntercept = From.x;
-
-        rc->ErrorTermAdjDown = rc->dy;
-        rc->Direction   = (rc->dx < 0)?(-1):(1);
-        
-        if (rc->dx >= 0) /*edge goes l to r*/
-        {
-            rc->ErrorTerm   = 0;
-        }
-        else/*edge goes r to l*/
-        {
-            rc->ErrorTerm = -rc->dy +1;
-        }
-
-        /*Now which part of the slope is greater?*/
-        if (rc->dy == 0)
-        {
-            rc->XPerY = 0;
-            rc->ErrorTermAdjUp = 0;
-        }
-        else if (rc->dy >= rc->dx)
-        {
-            rc->XPerY = 0;
-            rc->ErrorTermAdjUp = rc->dx;
-        }
-        else 
-        {
-            rc->XPerY = rc->dx / rc->dy;
-            rc->ErrorTermAdjUp = rc->dx % rc->dy;
-        }
-        
-        rc->pNext = 0;
-    }
-    return rc;
+  if (0 == rc)
+    return NULL;
+
+  //DPRINT1("Making Edge: (%d, %d) to (%d, %d)\n", From.x, From.y, To.x, To.y);
+  //Now Fill the struct.
+  if ( To.y < From.y )
+  {
+    rc->FromX = To.x;
+    rc->FromY = To.y;
+    rc->ToX = From.x;
+    rc->ToY = From.y;
+    rc->YDirection = -1;
+
+    // lines that go up get walked backwards, so need to be offset
+    // by -1 in order to make the walk identically on a pixel-level
+    rc->Error = -1;
+  }
+  else
+  {
+    rc->FromX = From.x;
+    rc->FromY = From.y;
+    rc->ToX = To.x;
+    rc->ToY = To.y;
+    rc->YDirection = 1;
+
+    rc->Error = 0;
+  }
+
+  rc->x = rc->FromX;
+  rc->y = rc->FromY;
+  rc->dx   = rc->ToX - rc->FromX;
+  rc->dy   = rc->ToY - rc->FromY;
+  rc->absdx = abs(rc->dx);
+  rc->absdy = abs(rc->dy);
+
+  rc->xmajor = rc->absdx > rc->absdy;
+
+  rc->ErrorMax = MAX(rc->absdx,rc->absdy);
+
+  rc->Error += rc->ErrorMax / 2;
+
+  rc->XDirection = (rc->dx < 0)?(-1):(1);
+
+  rc->pNext = 0;
+
+  //DPRINT("MakeEdge (%i,%i)->(%i,%i) d=(%i,%i) dir=(%i,%i) err=%i max=%i\n",
+  //  From.x, From.y, To.x, To.y, rc->dx, rc->dy, rc->XDirection, rc->YDirection, rc->Error, rc->ErrorMax );
+
+  return rc;
 }
 /*
 ** My Edge comparison routine.
 ** This is for scan converting polygon fill.
-** Fist sort by MinY, then Minx, then slope.
+** First sort by MinY, then Minx, then slope.
 **
 ** This comparison will help us determine which
 ** lines will become active first when scanning from
@@ -171,107 +197,109 @@ static PPFILL_EDGE POLYGONFILL_MakeEdge(POINT From, POINT To)
 ** Zero element1 = element2 
 ** Positive integer element1 > element2 
 */
-static INT PFILL_EDGE_Compare(PPFILL_EDGE Edge1, PPFILL_EDGE Edge2)
+static
+INT
+FASTCALL
+FILL_EDGE_Compare(FILL_EDGE* Edge1, FILL_EDGE* Edge2)
 {
-    //DPRINT("In PFILL_EDGE_Compare()\n");
-       if (Edge1->MinY == Edge2->MinY)
-    {
-        //DPRINT("In PFILL_EDGE_Compare() MinYs are equal\n");
-        if (Edge1->MinX == Edge2->MinX)
-        {
-            if (0 == Edge2->dx || 0 == Edge1->dx)
-            {
-                return Edge1->dx - Edge2->dx;
-            }
-            else
-            {
-                return (Edge1->dy/Edge1->dx) - (Edge2->dy/Edge2->dx);
-            }
-        }
-        else
-        {
-            return Edge1->MinX - Edge2->MinX;
-        }
-    }
-    //DPRINT("In PFILL_EDGE_Compare() returning: %d\n",Edge1->MinY - Edge2->MinY);
-    return Edge1->MinY - Edge2->MinY;
-    
+  int e1 = Edge1->XIntercept[0] + Edge1->XIntercept[1];
+  int e2 = Edge2->XIntercept[0] + Edge2->XIntercept[1];
+
+  return e1 - e2;
 }
 
 
 /*
 ** Insert an edge into a list keeping the list in order.
 */
-static void POLYGONFILL_ListInsert(PFILL_EDGE_LIST *list, PPFILL_EDGE NewEdge)
+static
+void
+FASTCALL
+POLYGONFILL_ActiveListInsert(FILL_EDGE** activehead, FILL_EDGE* NewEdge )
 {
-    PPFILL_EDGE pThis;
-    if (0 != list && 0 != NewEdge)
-    {
-        pThis = *list;
-        //DPRINT("In POLYGONFILL_ListInsert()\n");
-        /*
-        ** First lets check to see if we have a new smallest value.
-        */
-        if (0 < PFILL_EDGE_Compare(pThis, NewEdge))
-        {
-            NewEdge->pNext = pThis;
-            *list = NewEdge;
-            return;
-        }
-        /*
-        ** Ok, now scan to the next spot to put this item.
-        */
-        while (0 > PFILL_EDGE_Compare(pThis, NewEdge))
-        {   
-            if (0 == pThis->pNext)
-                break;
-
-            pThis = pThis->pNext;
-        }
-        
-        NewEdge->pNext = pThis->pNext;
-        pThis->pNext = NewEdge;
-        //DEBUG_PRINT_EDGELIST(*list);
-    }
+  FILL_EDGE *pPrev, *pThis;
+  //DPRINT1("In POLYGONFILL_ActiveListInsert()\n");
+  ASSERT ( activehead && NewEdge );
+  if ( !*activehead )
+  {
+    NewEdge->pNext = NULL;
+    *activehead = NewEdge;
+    return;
+  }
+  /*
+  ** First lets check to see if we have a new smallest value.
+  */
+  if (FILL_EDGE_Compare(NewEdge, *activehead) <= 0)
+  {
+    NewEdge->pNext = *activehead;
+    *activehead = NewEdge;
+    return;
+  }
+  /*
+  ** Ok, now scan to the next spot to put this item.
+  */
+  pThis = *activehead;
+  pPrev = NULL;
+  while ( pThis && FILL_EDGE_Compare(pThis, NewEdge) < 0 )
+  {
+    pPrev = pThis;
+    pThis = pThis->pNext;
+  }
+
+  ASSERT(pPrev);
+  NewEdge->pNext = pPrev->pNext;
+  pPrev->pNext = NewEdge;
+  //DEBUG_PRINT_ACTIVE_EDGELIST(*activehead);
 }
 
 /*
 ** Create a list of edges for a list of points.
 */
-static PFILL_EDGE_LIST POLYGONFILL_MakeEdgeList(PPOINT Points, int Count)
+static
+FILL_EDGE_LIST*
+FASTCALL
+POLYGONFILL_MakeEdgeList(PPOINT Points, int Count)
 {
-       int CurPt = 0;
-       int SeqNum = 0;
-    PPFILL_EDGE rc = 0;
-    PPFILL_EDGE NextEdge = 0;
-       
-       if (0 != Points && 2 <= Count)
-       {
-        //Establish the list with the first two points.
-               rc = POLYGONFILL_MakeEdge(Points[0],Points[1]); 
-               if (0 == rc) return rc;
-
-               for (CurPt = 1; CurPt < Count; ++CurPt,++SeqNum)
-               {               
-                   if (CurPt == Count - 1)
-            {
-                NextEdge = POLYGONFILL_MakeEdge(Points[CurPt],Points[0]);
-            }
-            else
-            {
-                NextEdge = POLYGONFILL_MakeEdge(Points[CurPt],Points[CurPt + 1]);
-            }
-            if (0 != NextEdge)
-            {
-                POLYGONFILL_ListInsert(&rc, NextEdge);
-            }
-            else
-            {
-                DPRINT("Out Of MEMORY!! NextEdge = 0\n");
-            }
-               }
-       }
-       return rc;
+  int CurPt = 0;
+  FILL_EDGE_LIST* list = 0;
+  FILL_EDGE* e = 0;
+
+  if ( 0 == Points || 2 > Count )
+    return 0;
+
+  list = (FILL_EDGE_LIST*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE_LIST), FILL_EDGE_ALLOC_TAG);
+  if ( 0 == list )
+    goto fail;
+  list->Count = 0;
+  list->Edges = (FILL_EDGE**)EngAllocMem(FL_ZERO_MEMORY, Count*sizeof(FILL_EDGE*), FILL_EDGE_ALLOC_TAG);
+  if ( !list->Edges )
+    goto fail;
+  memset ( list->Edges, 0, Count * sizeof(FILL_EDGE*) );
+
+  for ( CurPt = 1; CurPt < Count; ++CurPt )
+  {
+    e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[CurPt] );
+    if ( !e )
+      goto fail;
+    // if a straight horizontal line - who cares?
+    if ( !e->absdy )
+      EngFreeMem ( e );
+    else
+      list->Edges[list->Count++] = e;
+  }
+  e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[0] );
+  if ( !e )
+    goto fail;
+  if ( !e->absdy )
+    EngFreeMem ( e );
+  else
+    list->Edges[list->Count++] = e;
+  return list;
+
+fail:
+  DPRINT1("Out Of MEMORY!!\n");
+  POLYGONFILL_DestroyEdgeList ( list );
+  return 0;
 }
 
 
@@ -281,268 +309,298 @@ static PFILL_EDGE_LIST  POLYGONFILL_MakeEdgeList(PPOINT Points, int Count)
 ** for scanline Scanline.
 **TODO: Get rid of this floating point arithmetic
 */
-static void POLYGONFILL_UpdateScanline(PPFILL_EDGE pEdge, int Scanline)
+static
+void
+FASTCALL
+POLYGONFILL_UpdateScanline(FILL_EDGE* pEdge, int Scanline)
 {
-    
-    int Coord = 0;
-    float XCoord = 0;
-    if (0 == pEdge->dy) return;
-
-    XCoord = (Scanline*pEdge->dx - pEdge->FromY*pEdge->dx)/pEdge->dy + pEdge->FromX;
-    Coord = XCoord + 0.5;
+  if ( 0 == pEdge->dy )
+    return;
 
-    //DPRINT("Line (%d, %d) to (%d, %d) intersects scanline %d at %d\n",
-    //        pEdge->FromX, pEdge->FromY, pEdge->ToX, pEdge->ToY, Scanline, Coord);
-    pEdge->XIntercept = Coord;
+  ASSERT ( pEdge->FromY <= Scanline && pEdge->ToY > Scanline );
 
+  if ( pEdge->xmajor )
+  {
+    int steps;
 
-    /*pEdge->XIntercept += pEdge->XPerY;
+    ASSERT ( pEdge->y == Scanline );
 
-    if ((pEdge->ErrorTerm += pEdge->ErrorTermAdjUp) > 0)
+    // now shoot to end of scanline collision
+    steps = (pEdge->ErrorMax-pEdge->Error-1)/pEdge->absdy;
+    if ( steps )
     {
-        pEdge->XIntercept += pEdge->Direction;
-        pEdge->ErrorTerm -= pEdge->ErrorTermAdjDown;
-    }*/
-}
-
-/*
-** This routine removes an edge from the global edge list and inserts it into
-** the active edge list (preserving the order).
-** An edge is considered Active if the current scanline intersects it.
-**
-** Note: once an edge is no longer active, it is deleted.
-*/
-static void POLYGONFILL_AECInsertInOrder(PFILL_EDGE_LIST *list, PPFILL_EDGE pEdge)
-{
-    BOOL Done = FALSE;
-    PPFILL_EDGE pThis = 0;
-    PPFILL_EDGE pPrev = 0;
-    pThis = *list;
-    while(0 != pThis && !Done)
+      // record first collision with scanline
+      int x1 = pEdge->x;
+      pEdge->x += steps * pEdge->XDirection;
+      pEdge->Error += steps * pEdge->absdy;
+      ASSERT ( pEdge->Error < pEdge->ErrorMax );
+      pEdge->XIntercept[0] = MIN(x1,pEdge->x);
+      pEdge->XIntercept[1] = MAX(x1,pEdge->x);
+    }
+    else
     {
-        /*pEdge goes before pThis*/
-        if (pThis->XIntercept > pEdge->XIntercept)
-        {
-            if (*list == pThis)
-            {
-                *list = pEdge;
-            }
-            else
-            {
-                pPrev->pNext = pEdge;
-            }
-            pEdge->pNext = pThis;
-            Done = TRUE;
-        }
-        pPrev = pThis;
-        pThis = pThis->pNext;
+      pEdge->XIntercept[0] = pEdge->x;
+      pEdge->XIntercept[1] = pEdge->x;
     }
-}
 
-/*
-** This routine reorders the Active Edge collection (list) after all
-** the now inactive edges have been removed.
-*/
-static void POLYGONFILL_AECReorder(PFILL_EDGE_LIST *AEC)
-{
-    PPFILL_EDGE pThis = 0;
-    PPFILL_EDGE pPrev = 0;
-    PPFILL_EDGE pTarg = 0; 
-    pThis = *AEC;
-    
-    while (0 != pThis)
+    // we should require exactly 1 step to step onto next scanline...
+    ASSERT ( (pEdge->ErrorMax-pEdge->Error-1) / pEdge->absdy == 0 );
+    pEdge->x += pEdge->XDirection;
+    pEdge->Error += pEdge->absdy;
+    ASSERT ( pEdge->Error >= pEdge->ErrorMax );
+
+    // now step onto next scanline...
+    pEdge->Error -= pEdge->absdx;
+    pEdge->y++;
+  }
+  else // then this is a y-major line
+  {
+    pEdge->XIntercept[0] = pEdge->x;
+    pEdge->XIntercept[1] = pEdge->x;
+
+    pEdge->Error += pEdge->absdx;
+    pEdge->y++;
+
+    if ( pEdge->Error >= pEdge->ErrorMax )
     {
-        /*We are at the end of the list*/
-        if (0 == pThis->pNext)
-        {
-            return;
-        }
-
-        /*If the next item is out of order, pull it from the list and
-        re-insert it, and don't advance pThis.*/
-        if (pThis->XIntercept > pThis->pNext->XIntercept)
-        {
-            pTarg = pThis->pNext;
-            pThis->pNext = pTarg->pNext;
-            pTarg->pNext = 0;
-            POLYGONFILL_AECInsertInOrder(AEC, pTarg);
-        }
-        else/*In order, advance pThis*/
-        {
-            pPrev = pThis;
-            pThis = pThis->pNext;
-        }
+      pEdge->Error -= pEdge->ErrorMax;
+      pEdge->x += pEdge->XDirection;
+      ASSERT ( pEdge->Error < pEdge->ErrorMax );
     }
-    
+  }
+
+  //DPRINT("Line (%d, %d) to (%d, %d) intersects scanline %d at (%d,%d)\n",
+  //        pEdge->FromX, pEdge->FromY, pEdge->ToX, pEdge->ToY, Scanline, pEdge->XIntercept[0], pEdge->XIntercept[1] );
 }
+
 /*
 ** This method updates the Active edge collection for the scanline Scanline.
 */
-static void POLYGONFILL_UpdateActiveEdges(int Scanline, PFILL_EDGE_LIST *GEC, PFILL_EDGE_LIST *AEC)
+static
+void
+STDCALL
+POLYGONFILL_BuildActiveList ( int Scanline, FILL_EDGE_LIST* list, FILL_EDGE** ActiveHead )
 {
-    PPFILL_EDGE pThis = 0;
-    PPFILL_EDGE pAECLast = 0;
-    PPFILL_EDGE pPrev = 0;
-    DPRINT("In POLYGONFILL_UpdateActiveEdges() Scanline: %d\n", Scanline);
-    /*First scan through GEC and look for any edges that have become active*/
-    pThis = *GEC;
-    while (0 != pThis && pThis->MinY <= Scanline)
+  int i;
+
+  ASSERT ( list && ActiveHead );
+  *ActiveHead = 0;
+  for ( i = 0; i < list->Count; i++ )
+  {
+    FILL_EDGE* pEdge = list->Edges[i];
+    ASSERT(pEdge);
+    if ( pEdge->FromY <= Scanline && pEdge->ToY > Scanline )
     {
-        //DPRINT("Moving Edge to AEC\n");
-        /*Remove the edge from GEC and put it into AEC*/
-        if (pThis->MinY <= Scanline)
-        {
-            /*Always peel off the front of the GEC*/
-            *GEC = pThis->pNext;
-            
-            /*Now put this edge at the end of AEC*/
-            if (0 == *AEC)
-            {
-                *AEC = pThis;
-                pThis->pNext = 0;
-                pAECLast = pThis;
-            }
-            else if(0 == pAECLast)
-            {
-                pAECLast = *AEC;
-                while(0 != pAECLast->pNext)
-                {
-                    pAECLast = pAECLast->pNext;
-                }
-             
-                pAECLast->pNext = pThis;             
-                pThis->pNext = 0;
-                pAECLast = pThis;
-            }
-            else
-            {
-                pAECLast->pNext = pThis;
-                pThis->pNext = 0;
-                pAECLast = pThis;
-
-            }
-        }
-        
-        pThis = *GEC;
+      POLYGONFILL_UpdateScanline ( pEdge, Scanline );
+      POLYGONFILL_ActiveListInsert ( ActiveHead, pEdge );
     }
-    /*Now remove any edges in the AEC that are no longer active and Update the XIntercept in the AEC*/
-    pThis = *AEC;
-    while (0 != pThis)
-    {
-        /*First check to see if this item is deleted*/
-        if (pThis->MaxY <= Scanline)
-        {
-            //DPRINT("Removing Edge from AEC\n");
-            if (0 == pPrev)/*First element in the list*/
-            {
-                *AEC = pThis->pNext;
-            }
-            else
-            {
-                pPrev->pNext = pThis->pNext;
-            }
-            POLYGONFILL_DestroyEdge(pThis);
-        }
-        else/*Otherwise, update the scanline*/
-        {
-            POLYGONFILL_UpdateScanline(pThis, Scanline);
-            pPrev = pThis; 
-        }
-        /*List Upkeep*/
-        if (0 == pPrev)/*First element in the list*/
-        {
-            pThis = *AEC;
-        }
-        else
-        {
-            pThis = pPrev->pNext;
-        }
-    }
-    /*Last re Xintercept order the AEC*/
-    POLYGONFILL_AECReorder(AEC);
-
+  }
 }
 
 /*
 ** This method fills the portion of the polygon that intersects with the scanline
 ** Scanline.
 */
-static void POLYGONFILL_FillScanLine(int ScanLine, PFILL_EDGE_LIST ActiveEdges, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode, int OrigX, int OrigY)
+static
+void
+STDCALL
+POLYGONFILL_FillScanLineAlternate(
+  PDC dc,
+  int ScanLine,
+  FILL_EDGE* ActiveHead,
+  SURFOBJ *SurfObj,
+  PBRUSHOBJ BrushObj,
+  MIX RopMode )
 {
-    BOOL OnOdd = TRUE;
-    RECTL BoundRect;
-    int XInterceptOdd,XInterceptEven,ret;
-    PPFILL_EDGE pThis = ActiveEdges;
-    
-    while (0 != pThis)
+  FILL_EDGE *pLeft, *pRight;
+
+  if ( !ActiveHead )
+    return;
+
+  pLeft = ActiveHead;
+  pRight = pLeft->pNext;
+  ASSERT(pRight);
+
+  while ( NULL != pRight )
+  {
+    int x1 = pLeft->XIntercept[0];
+    int x2 = pRight->XIntercept[1];
+    if ( x2 > x1 )
     {
-        if (OnOdd)
-        {
-            XInterceptOdd = pThis->XIntercept;
-            OnOdd = FALSE;
-        }
-        else
-        {
-            BoundRect.top = ScanLine + OrigY - 1;
-            BoundRect.bottom = ScanLine + OrigY + 1;
-            BoundRect.left = XInterceptOdd + OrigX - 2;
-            BoundRect.right = XInterceptEven + OrigX;
-
-            XInterceptEven = pThis->XIntercept;
-            DPRINT("Fill Line (%d, %d) to (%d, %d)\n",XInterceptOdd - 1,ScanLine ,XInterceptEven - 1,ScanLine );
-            ret = EngLineTo(SurfObj,
-                                               NULL, // ClipObj,
-                                               BrushObj,
-                                               XInterceptOdd + OrigX - 1, 
-                                               ScanLine + OrigY, 
-                                               XInterceptEven + OrigX - 1, 
-                                               ScanLine + OrigY,
-                                               &BoundRect, // Bounding rectangle
-                                               RopMode); // MIX
-            OnOdd = TRUE;
-        }
-        pThis = pThis->pNext;
+      RECTL BoundRect;
+      BoundRect.top = ScanLine;
+      BoundRect.bottom = ScanLine + 1;
+      BoundRect.left = x1;
+      BoundRect.right = x2;
+
+      //DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
+      IntEngLineTo( SurfObj,
+                         dc->CombinedClip,
+                         BrushObj,
+                         x1,
+                         ScanLine,
+                         x2,
+                         ScanLine,
+                         &BoundRect, // Bounding rectangle
+                         RopMode); // MIX
     }
+    pLeft = pRight->pNext;
+    pRight = pLeft ? pLeft->pNext : NULL;
+  }
+}
+
+static
+void
+STDCALL
+POLYGONFILL_FillScanLineWinding(
+  PDC dc,
+  int ScanLine,
+  FILL_EDGE* ActiveHead,
+  SURFOBJ *SurfObj,
+  PBRUSHOBJ BrushObj,
+  MIX RopMode )
+{
+  FILL_EDGE *pLeft, *pRight;
+  int x1, x2, winding = 0;
+  RECTL BoundRect;
+
+  if ( !ActiveHead )
+    return;
+
+  BoundRect.top = ScanLine;
+  BoundRect.bottom = ScanLine + 1;
+
+  pLeft = ActiveHead;
+  winding = pLeft->YDirection;
+  pRight = pLeft->pNext;
+  ASSERT(pRight);
+
+  // setup first line...
+  x1 = pLeft->XIntercept[0];
+  x2 = pRight->XIntercept[1];
+
+  pLeft = pRight;
+  pRight = pLeft->pNext;
+  winding += pLeft->YDirection;
+
+  while ( NULL != pRight )
+  {
+    int newx1 = pLeft->XIntercept[0];
+    int newx2 = pRight->XIntercept[1];
+    if ( winding )
+    {
+      // check and see if this new line touches the previous...
+      if ( (newx1 >= x1 && newx1 <= x2)
+       || (newx2 >= x1 && newx2 <= x2)
+       || (x1 >= newx1 && x1 <= newx2)
+       || (x2 >= newx2 && x2 <= newx2)
+       )
+      {
+       // yup, just tack it on to our existing line
+       x1 = MIN(x1,newx1);
+       x2 = MAX(x2,newx2);
+      }
+      else
+      {
+       // nope - render the old line..
+       BoundRect.left = x1;
+       BoundRect.right = x2;
+
+       //DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
+       IntEngLineTo( SurfObj,
+                     dc->CombinedClip,
+                     BrushObj,
+                     x1,
+                     ScanLine,
+                     x2,
+                     ScanLine,
+                     &BoundRect, // Bounding rectangle
+                     RopMode); // MIX
+
+       x1 = newx1;
+       x2 = newx2;
+      }
+    }
+    pLeft = pRight;
+    pRight = pLeft->pNext;
+    winding += pLeft->YDirection;
+  }
+  // there will always be a line left-over, render it now...
+  BoundRect.left = x1;
+  BoundRect.right = x2;
+
+  //DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
+  IntEngLineTo( SurfObj,
+               dc->CombinedClip,
+               BrushObj,
+               x1,
+               ScanLine,
+               x2,
+               ScanLine,
+               &BoundRect, // Bounding rectangle
+               RopMode); // MIX
 }
 
-//ALTERNATE Selects alternate mode (fills the area between odd-numbered and even-numbered 
-//polygon sides on each scan line). 
 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and 
 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the 
 //first and second side, between the third and fourth side, and so on. 
-BOOL FillPolygon_ALTERNATE(SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode, CONST PPOINT Points, int Count, RECTL BoundRect, int OrigX, int OrigY)
-{
-       PFILL_EDGE_LIST list = 0;
-    PFILL_EDGE_LIST ActiveEdges = 0;
-    int ScanLine;
-       DPRINT("FillPolygon_ALTERNATE\n");
-       
-       //Create Edge List.
-       list = POLYGONFILL_MakeEdgeList(Points, Count);
-       //DEBUG_PRINT_EDGELIST(list);
-    if (0 == list) return FALSE;
-
-       //For each Scanline from BoundRect.bottom to BoundRect.top, 
-       //determine line segments to draw
-       for (ScanLine = BoundRect.top + 1; ScanLine < BoundRect.bottom ; ++ScanLine)
-       {
-        POLYGONFILL_UpdateActiveEdges(ScanLine, &list, &ActiveEdges);
-        //DEBUG_PRINT_EDGELIST(ActiveEdges);
-        POLYGONFILL_FillScanLine(ScanLine, ActiveEdges, SurfObj, BrushObj, RopMode, OrigX, OrigY);
-       }
-    
-       //Free Edge List. If any are left.
-       POLYGONFILL_DestroyEdgeList(list);
-
-       return TRUE;
-}
 
 //WINDING Selects winding mode (fills any region with a nonzero winding value). 
-//When the fill mode is WINDING, GDI fills any region that has a nonzero winding value. 
-//This value is defined as the number of times a pen used to draw the polygon would go around the region. 
+//When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
+//This value is defined as the number of times a pen used to draw the polygon would go around the region.
 //The direction of each edge of the polygon is important. 
-BOOL FillPolygon_WINDING(SURFOBJ *SurfObj, PBRUSHOBJ BrushObj,MIX RopMode, CONST PPOINT Points, int Count, RECTL BoundRect, int OrigX, int OrigY)
+
+BOOL
+STDCALL
+FillPolygon(
+  PDC dc,
+  SURFOBJ *SurfObj,
+  PBRUSHOBJ BrushObj,
+  MIX RopMode,
+  CONST PPOINT Points,
+  int Count,
+  RECTL BoundRect )
 {
-       DPRINT("FillPolygon_WINDING\n");
-       return FALSE;
-}
\ No newline at end of file
+  FILL_EDGE_LIST *list = 0;
+  FILL_EDGE *ActiveHead = 0;
+  int ScanLine;
+
+  void
+  STDCALL
+  (*FillScanLine)(
+    PDC dc,
+    int ScanLine,
+    FILL_EDGE* ActiveHead,
+    SURFOBJ *SurfObj,
+    PBRUSHOBJ BrushObj,
+    MIX RopMode );
+
+  //DPRINT("FillPolygon\n");
+
+  /* Create Edge List. */
+  list = POLYGONFILL_MakeEdgeList(Points, Count);
+  /* DEBUG_PRINT_EDGELIST(list); */
+  if (NULL == list)
+    return FALSE;
+
+  if ( WINDING == dc->w.polyFillMode )
+    FillScanLine = POLYGONFILL_FillScanLineWinding;
+  else /* default */
+    FillScanLine = POLYGONFILL_FillScanLineAlternate;
+
+  /* For each Scanline from BoundRect.bottom to BoundRect.top, 
+   * determine line segments to draw
+   */
+  for ( ScanLine = BoundRect.top; ScanLine < BoundRect.bottom; ++ScanLine )
+  {
+    POLYGONFILL_BuildActiveList(ScanLine, list, &ActiveHead);
+    //DEBUG_PRINT_ACTIVE_EDGELIST(ActiveHead);
+    FillScanLine ( dc, ScanLine, ActiveHead, SurfObj, BrushObj, RopMode );
+  }
+
+  /* Free Edge List. If any are left. */
+  POLYGONFILL_DestroyEdgeList(list);
+
+  return TRUE;
+}
+/* EOF */