2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Various Polygon Filling routines for Polygon()
24 * FILE: subsys/win32k/objects/polyfill.c
25 * PROGRAMER: Mark Tempel
30 #undef WIN32_LEAN_AND_MEAN
32 #include <ddk/ntddk.h>
33 #include <win32k/fillshap.h>
34 #include <win32k/dc.h>
35 #include <win32k/pen.h>
36 #include <include/inteng.h>
37 #include <include/object.h>
38 #include <include/paint.h>
41 #include <win32k/debug1.h>
45 #define FILL_EDGE_ALLOC_TAG 0x45465044
48 ** This struct is used for book keeping during polygon filling routines.
50 typedef struct _tagFILL_EDGE
52 /*Basic line information*/
63 /*Active Edge List information*/
67 int XDirection, YDirection;
69 /* The next edge in the active Edge List*/
70 struct _tagFILL_EDGE * pNext;
73 typedef struct _FILL_EDGE_LIST
82 DEBUG_PRINT_ACTIVE_EDGELIST ( FILL_EDGE* list )
84 FILL_EDGE* pThis = list;
87 DPRINT1("List is NULL\n");
93 //DPRINT1("EDGE: (%d, %d) to (%d, %d)\n", pThis->FromX, pThis->FromY, pThis->ToX, pThis->ToY);
94 DPRINT1("EDGE: [%d,%d]\n", pThis->XIntercept[0], pThis->XIntercept[1] );
99 #define DEBUG_PRINT_ACTIVE_EDGELIST(x)
103 ** Hide memory clean up.
108 POLYGONFILL_DestroyEdgeList(FILL_EDGE_LIST* list)
115 for ( i = 0; i < list->Count; i++ )
117 if ( list->Edges[i] )
118 EngFreeMem ( list->Edges[i] );
120 EngFreeMem ( list->Edges );
127 ** This makes and initiaizes an Edge struct for a line between two points.
132 POLYGONFILL_MakeEdge(POINT From, POINT To)
134 FILL_EDGE* rc = (FILL_EDGE*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE), FILL_EDGE_ALLOC_TAG);
139 //DPRINT1("Making Edge: (%d, %d) to (%d, %d)\n", From.x, From.y, To.x, To.y);
140 //Now Fill the struct.
149 // lines that go up get walked backwards, so need to be offset
150 // by -1 in order to make the walk identically on a pixel-level
166 rc->dx = rc->ToX - rc->FromX;
167 rc->dy = rc->ToY - rc->FromY;
168 rc->absdx = abs(rc->dx);
169 rc->absdy = abs(rc->dy);
171 rc->xmajor = rc->absdx > rc->absdy;
173 rc->ErrorMax = MAX(rc->absdx,rc->absdy);
175 rc->Error += rc->ErrorMax / 2;
177 rc->XDirection = (rc->dx < 0)?(-1):(1);
181 //DPRINT("MakeEdge (%i,%i)->(%i,%i) d=(%i,%i) dir=(%i,%i) err=%i max=%i\n",
182 // From.x, From.y, To.x, To.y, rc->dx, rc->dy, rc->XDirection, rc->YDirection, rc->Error, rc->ErrorMax );
187 ** My Edge comparison routine.
188 ** This is for scan converting polygon fill.
189 ** First sort by MinY, then Minx, then slope.
191 ** This comparison will help us determine which
192 ** lines will become active first when scanning from
193 ** top (min y) to bottom (max y).
195 ** Return Value Meaning
196 ** Negative integer element1 < element2
197 ** Zero element1 = element2
198 ** Positive integer element1 > element2
203 FILL_EDGE_Compare(FILL_EDGE* Edge1, FILL_EDGE* Edge2)
205 int e1 = Edge1->XIntercept[0] + Edge1->XIntercept[1];
206 int e2 = Edge2->XIntercept[0] + Edge2->XIntercept[1];
213 ** Insert an edge into a list keeping the list in order.
218 POLYGONFILL_ActiveListInsert(FILL_EDGE** activehead, FILL_EDGE* NewEdge )
220 FILL_EDGE *pPrev, *pThis;
221 //DPRINT1("In POLYGONFILL_ActiveListInsert()\n");
222 ASSERT ( activehead && NewEdge );
225 NewEdge->pNext = NULL;
226 *activehead = NewEdge;
230 ** First lets check to see if we have a new smallest value.
232 if (FILL_EDGE_Compare(NewEdge, *activehead) <= 0)
234 NewEdge->pNext = *activehead;
235 *activehead = NewEdge;
239 ** Ok, now scan to the next spot to put this item.
243 while ( pThis && FILL_EDGE_Compare(pThis, NewEdge) < 0 )
246 pThis = pThis->pNext;
250 NewEdge->pNext = pPrev->pNext;
251 pPrev->pNext = NewEdge;
252 //DEBUG_PRINT_ACTIVE_EDGELIST(*activehead);
256 ** Create a list of edges for a list of points.
261 POLYGONFILL_MakeEdgeList(PPOINT Points, int Count)
264 FILL_EDGE_LIST* list = 0;
267 if ( 0 == Points || 2 > Count )
270 list = (FILL_EDGE_LIST*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE_LIST), FILL_EDGE_ALLOC_TAG);
274 list->Edges = (FILL_EDGE**)EngAllocMem(FL_ZERO_MEMORY, Count*sizeof(FILL_EDGE*), FILL_EDGE_ALLOC_TAG);
277 memset ( list->Edges, 0, Count * sizeof(FILL_EDGE*) );
279 for ( CurPt = 1; CurPt < Count; ++CurPt )
281 e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[CurPt] );
284 // if a straight horizontal line - who cares?
288 list->Edges[list->Count++] = e;
290 e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[0] );
296 list->Edges[list->Count++] = e;
300 DPRINT1("Out Of MEMORY!!\n");
301 POLYGONFILL_DestroyEdgeList ( list );
307 ** This slow routine uses the data stored in the edge list to
308 ** calculate the x intercepts for each line in the edge list
309 ** for scanline Scanline.
310 **TODO: Get rid of this floating point arithmetic
315 POLYGONFILL_UpdateScanline(FILL_EDGE* pEdge, int Scanline)
317 if ( 0 == pEdge->dy )
320 ASSERT ( pEdge->FromY <= Scanline && pEdge->ToY > Scanline );
326 ASSERT ( pEdge->y == Scanline );
328 // now shoot to end of scanline collision
329 steps = (pEdge->ErrorMax-pEdge->Error-1)/pEdge->absdy;
332 // record first collision with scanline
334 pEdge->x += steps * pEdge->XDirection;
335 pEdge->Error += steps * pEdge->absdy;
336 ASSERT ( pEdge->Error < pEdge->ErrorMax );
337 pEdge->XIntercept[0] = MIN(x1,pEdge->x);
338 pEdge->XIntercept[1] = MAX(x1,pEdge->x);
342 pEdge->XIntercept[0] = pEdge->x;
343 pEdge->XIntercept[1] = pEdge->x;
346 // we should require exactly 1 step to step onto next scanline...
347 ASSERT ( (pEdge->ErrorMax-pEdge->Error-1) / pEdge->absdy == 0 );
348 pEdge->x += pEdge->XDirection;
349 pEdge->Error += pEdge->absdy;
350 ASSERT ( pEdge->Error >= pEdge->ErrorMax );
352 // now step onto next scanline...
353 pEdge->Error -= pEdge->absdx;
356 else // then this is a y-major line
358 pEdge->XIntercept[0] = pEdge->x;
359 pEdge->XIntercept[1] = pEdge->x;
361 pEdge->Error += pEdge->absdx;
364 if ( pEdge->Error >= pEdge->ErrorMax )
366 pEdge->Error -= pEdge->ErrorMax;
367 pEdge->x += pEdge->XDirection;
368 ASSERT ( pEdge->Error < pEdge->ErrorMax );
372 //DPRINT("Line (%d, %d) to (%d, %d) intersects scanline %d at (%d,%d)\n",
373 // pEdge->FromX, pEdge->FromY, pEdge->ToX, pEdge->ToY, Scanline, pEdge->XIntercept[0], pEdge->XIntercept[1] );
377 ** This method updates the Active edge collection for the scanline Scanline.
382 POLYGONFILL_BuildActiveList ( int Scanline, FILL_EDGE_LIST* list, FILL_EDGE** ActiveHead )
386 ASSERT ( list && ActiveHead );
388 for ( i = 0; i < list->Count; i++ )
390 FILL_EDGE* pEdge = list->Edges[i];
392 if ( pEdge->FromY <= Scanline && pEdge->ToY > Scanline )
394 POLYGONFILL_UpdateScanline ( pEdge, Scanline );
395 POLYGONFILL_ActiveListInsert ( ActiveHead, pEdge );
401 ** This method fills the portion of the polygon that intersects with the scanline
407 POLYGONFILL_FillScanLineAlternate(
410 FILL_EDGE* ActiveHead,
415 FILL_EDGE *pLeft, *pRight;
421 pRight = pLeft->pNext;
424 while ( NULL != pRight )
426 int x1 = pLeft->XIntercept[0];
427 int x2 = pRight->XIntercept[1];
431 BoundRect.top = ScanLine;
432 BoundRect.bottom = ScanLine + 1;
434 BoundRect.right = x2;
436 //DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
437 IntEngLineTo( SurfObj,
444 &BoundRect, // Bounding rectangle
447 pLeft = pRight->pNext;
448 pRight = pLeft ? pLeft->pNext : NULL;
455 POLYGONFILL_FillScanLineWinding(
458 FILL_EDGE* ActiveHead,
463 FILL_EDGE *pLeft, *pRight;
464 int x1, x2, winding = 0;
470 BoundRect.top = ScanLine;
471 BoundRect.bottom = ScanLine + 1;
474 winding = pLeft->YDirection;
475 pRight = pLeft->pNext;
478 // setup first line...
479 x1 = pLeft->XIntercept[0];
480 x2 = pRight->XIntercept[1];
483 pRight = pLeft->pNext;
484 winding += pLeft->YDirection;
486 while ( NULL != pRight )
488 int newx1 = pLeft->XIntercept[0];
489 int newx2 = pRight->XIntercept[1];
492 // check and see if this new line touches the previous...
493 if ( (newx1 >= x1 && newx1 <= x2)
494 || (newx2 >= x1 && newx2 <= x2)
495 || (x1 >= newx1 && x1 <= newx2)
496 || (x2 >= newx2 && x2 <= newx2)
499 // yup, just tack it on to our existing line
505 // nope - render the old line..
507 BoundRect.right = x2;
509 //DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
510 IntEngLineTo( SurfObj,
517 &BoundRect, // Bounding rectangle
525 pRight = pLeft->pNext;
526 winding += pLeft->YDirection;
528 // there will always be a line left-over, render it now...
530 BoundRect.right = x2;
532 //DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
533 IntEngLineTo( SurfObj,
540 &BoundRect, // Bounding rectangle
544 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
545 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
546 //first and second side, between the third and fourth side, and so on.
548 //WINDING Selects winding mode (fills any region with a nonzero winding value).
549 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
550 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
551 //The direction of each edge of the polygon is important.
564 FILL_EDGE_LIST *list = 0;
565 FILL_EDGE *ActiveHead = 0;
573 FILL_EDGE* ActiveHead,
578 //DPRINT("FillPolygon\n");
580 /* Create Edge List. */
581 list = POLYGONFILL_MakeEdgeList(Points, Count);
582 /* DEBUG_PRINT_EDGELIST(list); */
586 if ( WINDING == dc->w.polyFillMode )
587 FillScanLine = POLYGONFILL_FillScanLineWinding;
589 FillScanLine = POLYGONFILL_FillScanLineAlternate;
591 /* For each Scanline from BoundRect.bottom to BoundRect.top,
592 * determine line segments to draw
594 for ( ScanLine = BoundRect.top; ScanLine < BoundRect.bottom; ++ScanLine )
596 POLYGONFILL_BuildActiveList(ScanLine, list, &ActiveHead);
597 //DEBUG_PRINT_ACTIVE_EDGELIST(ActiveHead);
598 FillScanLine ( dc, ScanLine, ActiveHead, SurfObj, BrushObj, RopMode );
601 /* Free Edge List. If any are left. */
602 POLYGONFILL_DestroyEdgeList(list);