mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +00:00
Polygon now works flawlessly ( with possible exception to the issue mentioned on the list earlier this evening ). Scrollbar arrows are now perfect.
svn path=/trunk/; revision=5595
This commit is contained in:
parent
58d4ce9842
commit
321a71f1dd
4 changed files with 439 additions and 551 deletions
|
@ -19,24 +19,50 @@
|
|||
#define FASTCALL
|
||||
#define STDCALL
|
||||
#define INT int
|
||||
#define CLIPOBJ int
|
||||
#define SURFOBJ int
|
||||
#define PBRUSHOBJ int
|
||||
#define MIX char
|
||||
#define BOOL bool
|
||||
#define TRUE true
|
||||
#define FALSE false
|
||||
#define CONST const
|
||||
#define MmCopyFromCaller memmove
|
||||
#define ALTERNATE 0
|
||||
#define WINDING 1
|
||||
|
||||
#define ASSERT assert
|
||||
|
||||
#define EngFreeMem free
|
||||
typedef struct W
|
||||
{
|
||||
int polyFillMode;
|
||||
} W;
|
||||
|
||||
#define FILL_EDGE_ALLOC_TAG 0x45465044
|
||||
typedef struct DC
|
||||
{
|
||||
CLIPOBJ CombinedClip;
|
||||
W w;
|
||||
} DC, *PDC;
|
||||
|
||||
typedef struct tagPOINT
|
||||
{
|
||||
long x, y;
|
||||
} POINT, *PPOINT, *LPPOINT;
|
||||
|
||||
typedef struct RECTL
|
||||
{
|
||||
long left, top, right, bottom;
|
||||
} RECTL, *PRECTL;
|
||||
|
||||
#define EngFreeMem free
|
||||
|
||||
#define FL_ZERO_MEMORY 1
|
||||
|
||||
#define DPRINT1 printf("%i:",__LINE__);printf
|
||||
inline void DPRINT(...){}
|
||||
|
||||
#define SCREENX 16
|
||||
#define SCREENY 16
|
||||
#define SCREENX 25
|
||||
#define SCREENY 25
|
||||
char screen[SCREENY][SCREENX];
|
||||
|
||||
#define EDGE_CHAR '*'
|
||||
|
@ -79,7 +105,13 @@ void putpixel ( int x, int y, char c )
|
|||
screen[y][x] = '#';
|
||||
}
|
||||
|
||||
void Line ( int x1, int y1, int x2, int y2, char c )
|
||||
void IntEngLineTo (
|
||||
SURFOBJ*,
|
||||
CLIPOBJ,
|
||||
PBRUSHOBJ,
|
||||
int x1, int y1, int x2, int y2,
|
||||
RECTL*,
|
||||
MIX mix )
|
||||
{
|
||||
int dx = x2 - x1;
|
||||
int dy = y2 - y1;
|
||||
|
@ -93,7 +125,7 @@ void Line ( int x1, int y1, int x2, int y2, char c )
|
|||
{
|
||||
while ( x1 != x2 )
|
||||
{
|
||||
putpixel ( x1, y1, c );
|
||||
putpixel ( x1, y1, mix );
|
||||
x1 += xinc;
|
||||
}
|
||||
return;
|
||||
|
@ -102,14 +134,14 @@ void Line ( int x1, int y1, int x2, int y2, char c )
|
|||
{
|
||||
while ( y1 != y2 )
|
||||
{
|
||||
putpixel ( x1, y1, c );
|
||||
putpixel ( x1, y1, mix );
|
||||
y1 += yinc;
|
||||
}
|
||||
return;
|
||||
}
|
||||
for ( int i = 0; i < EMax; i++ )
|
||||
{
|
||||
putpixel ( x1, y1, c );
|
||||
putpixel ( x1, y1, mix );
|
||||
if ( absdy > absdx )
|
||||
{
|
||||
y1 += yinc;
|
||||
|
@ -133,15 +165,7 @@ void Line ( int x1, int y1, int x2, int y2, char c )
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct tagPOINT
|
||||
{
|
||||
long x, y;
|
||||
} POINT, *PPOINT, *LPPOINT;
|
||||
|
||||
typedef struct tagRECTL
|
||||
{
|
||||
long left, top, right, bottom;
|
||||
} RECTL, *PRECTL;
|
||||
#define FILL_EDGE_ALLOC_TAG 0x45465044
|
||||
|
||||
/*
|
||||
** This struct is used for book keeping during polygon filling routines.
|
||||
|
@ -288,7 +312,7 @@ POLYGONFILL_MakeEdge(POINT From, POINT To)
|
|||
}
|
||||
}
|
||||
|
||||
DPRINT1("MakeEdge (%i,%i)->(%i,%i) d=(%i,%i) dir=(%i,%i) err=%i max=%i\n",
|
||||
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;
|
||||
|
@ -478,7 +502,7 @@ POLYGONFILL_UpdateScanline(FILL_EDGE* pEdge, int Scanline)
|
|||
pEdge->XIntercept[1] = pEdge->x;
|
||||
}
|
||||
|
||||
DPRINT1("Line (%d, %d) to (%d, %d) intersects scanline %d at (%d,%d)\n",
|
||||
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] );
|
||||
}
|
||||
|
||||
|
@ -513,7 +537,13 @@ POLYGONFILL_BuildActiveList ( int Scanline, FILL_EDGE_LIST* list, FILL_EDGE** Ac
|
|||
static
|
||||
void
|
||||
STDCALL
|
||||
POLYGONFILL_FillScanLineAlternate ( int ScanLine, FILL_EDGE* ActiveHead )
|
||||
POLYGONFILL_FillScanLineAlternate(
|
||||
PDC dc,
|
||||
int ScanLine,
|
||||
FILL_EDGE* ActiveHead,
|
||||
SURFOBJ *SurfObj,
|
||||
PBRUSHOBJ BrushObj,
|
||||
MIX RopMode )
|
||||
{
|
||||
FILL_EDGE *pLeft, *pRight;
|
||||
|
||||
|
@ -536,17 +566,16 @@ POLYGONFILL_FillScanLineAlternate ( int ScanLine, FILL_EDGE* ActiveHead )
|
|||
BoundRect.left = x1;
|
||||
BoundRect.right = x2;
|
||||
|
||||
DPRINT1("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
|
||||
Line ( x1, ScanLine, x2, ScanLine, FILL_CHAR );
|
||||
/*ret = IntEngLineTo( SurfObj,
|
||||
DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
|
||||
IntEngLineTo( SurfObj,
|
||||
dc->CombinedClip,
|
||||
BrushObj,
|
||||
x1,
|
||||
ScanLine,
|
||||
ScanLine,
|
||||
x2,
|
||||
ScanLine,
|
||||
&BoundRect, // Bounding rectangle
|
||||
RopMode);*/ // MIX
|
||||
RopMode); // MIX
|
||||
}
|
||||
pLeft = pRight->pNext;
|
||||
pRight = pLeft ? pLeft->pNext : NULL;
|
||||
|
@ -556,7 +585,13 @@ POLYGONFILL_FillScanLineAlternate ( int ScanLine, FILL_EDGE* ActiveHead )
|
|||
static
|
||||
void
|
||||
STDCALL
|
||||
POLYGONFILL_FillScanLineWinding ( int ScanLine, FILL_EDGE* ActiveHead )
|
||||
POLYGONFILL_FillScanLineWinding(
|
||||
PDC dc,
|
||||
int ScanLine,
|
||||
FILL_EDGE* ActiveHead,
|
||||
SURFOBJ *SurfObj,
|
||||
PBRUSHOBJ BrushObj,
|
||||
MIX RopMode )
|
||||
{
|
||||
FILL_EDGE *pLeft, *pRight;
|
||||
int winding = 0;
|
||||
|
@ -581,74 +616,58 @@ POLYGONFILL_FillScanLineWinding ( int ScanLine, FILL_EDGE* ActiveHead )
|
|||
BoundRect.left = x1;
|
||||
BoundRect.right = x2;
|
||||
|
||||
DPRINT1("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
|
||||
Line ( x1, ScanLine, x2, ScanLine, FILL_CHAR );
|
||||
/*ret = IntEngLineTo( SurfObj,
|
||||
DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
|
||||
IntEngLineTo( SurfObj,
|
||||
dc->CombinedClip,
|
||||
BrushObj,
|
||||
x1,
|
||||
ScanLine,
|
||||
ScanLine,
|
||||
x2,
|
||||
ScanLine,
|
||||
&BoundRect, // Bounding rectangle
|
||||
RopMode);*/ // MIX
|
||||
RopMode); // MIX
|
||||
}
|
||||
pLeft = pRight;
|
||||
pRight = pLeft->pNext;
|
||||
winding += pLeft->XDirection;
|
||||
winding += pLeft->YDirection;
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
STDCALL
|
||||
FillPolygon_ALTERNATE(CONST PPOINT Points, int Count, RECTL BoundRect)
|
||||
{
|
||||
FILL_EDGE_LIST *list = 0;
|
||||
FILL_EDGE *ActiveHead = 0;
|
||||
int ScanLine;
|
||||
|
||||
DPRINT1("FillPolygon_ALTERNATE\n");
|
||||
|
||||
/* Create Edge List. */
|
||||
list = POLYGONFILL_MakeEdgeList(Points, Count);
|
||||
/* DEBUG_PRINT_EDGELIST(list); */
|
||||
if (NULL == 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_BuildActiveList(ScanLine, list, &ActiveHead);
|
||||
//DEBUG_PRINT_ACTIVE_EDGELIST(ActiveHead);
|
||||
POLYGONFILL_FillScanLineAlternate(ScanLine, ActiveHead);
|
||||
}
|
||||
|
||||
/* 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
|
||||
STDCALL
|
||||
FillPolygon_WINDING(CONST PPOINT Points, int Count, RECTL BoundRect)
|
||||
FillPolygon(
|
||||
PDC dc,
|
||||
SURFOBJ *SurfObj,
|
||||
PBRUSHOBJ BrushObj,
|
||||
MIX RopMode,
|
||||
CONST PPOINT Points,
|
||||
int Count,
|
||||
RECTL BoundRect )
|
||||
{
|
||||
FILL_EDGE_LIST *list = 0;
|
||||
FILL_EDGE *ActiveHead = 0;
|
||||
int ScanLine;
|
||||
|
||||
DPRINT1("FillPolygon_WINDING\n");
|
||||
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);
|
||||
|
@ -656,6 +675,11 @@ FillPolygon_WINDING(CONST PPOINT Points, int Count, RECTL BoundRect)
|
|||
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
|
||||
*/
|
||||
|
@ -663,7 +687,7 @@ FillPolygon_WINDING(CONST PPOINT Points, int Count, RECTL BoundRect)
|
|||
{
|
||||
POLYGONFILL_BuildActiveList(ScanLine, list, &ActiveHead);
|
||||
//DEBUG_PRINT_ACTIVE_EDGELIST(ActiveHead);
|
||||
POLYGONFILL_FillScanLineWinding(ScanLine, ActiveHead);
|
||||
FillScanLine ( dc, ScanLine, ActiveHead, SurfObj, BrushObj, RopMode );
|
||||
}
|
||||
|
||||
/* Free Edge List. If any are left. */
|
||||
|
@ -674,35 +698,22 @@ FillPolygon_WINDING(CONST PPOINT Points, int Count, RECTL BoundRect)
|
|||
|
||||
|
||||
|
||||
/*
|
||||
* 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: polytest.cpp,v 1.1 2003/08/16 01:34:29 royce Exp $ */
|
||||
|
||||
|
||||
//This implementation is blatantly ripped off from W32kRectangle
|
||||
// this is highly hacked from W32kPolygon...
|
||||
BOOL
|
||||
Polygon ( CONST PPOINT UnsafePoints, int Count )
|
||||
Polygon ( CONST PPOINT UnsafePoints, int Count, int polyFillMode )
|
||||
{
|
||||
BOOL ret;
|
||||
RECTL DestRect;
|
||||
int CurrentPoint;
|
||||
PPOINT Points;
|
||||
SURFOBJ* SurfObj = 0;
|
||||
DC dc;
|
||||
PBRUSHOBJ OutBrushObj = 0;
|
||||
|
||||
dc.CombinedClip = 0;
|
||||
dc.w.polyFillMode = polyFillMode;
|
||||
|
||||
DPRINT1("In W32kPolygon()\n");
|
||||
|
||||
|
@ -759,20 +770,18 @@ Polygon ( CONST PPOINT UnsafePoints, int Count )
|
|||
}
|
||||
|
||||
DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n", From.x, From.y, To.x, To.y );
|
||||
Line ( From.x, From.y, To.x, To.y, EDGE_CHAR );
|
||||
/*ret = IntEngLineTo(SurfObj,
|
||||
dc->CombinedClip,
|
||||
OutBrushObj,
|
||||
From.x,
|
||||
From.y,
|
||||
To.x,
|
||||
To.y,
|
||||
&DestRect,
|
||||
dc->w.ROPmode);*/ /* MIX */
|
||||
|
||||
IntEngLineTo(SurfObj,
|
||||
dc.CombinedClip,
|
||||
OutBrushObj,
|
||||
From.x,
|
||||
From.y,
|
||||
To.x,
|
||||
To.y,
|
||||
&DestRect,
|
||||
EDGE_CHAR); /* MIX */
|
||||
}
|
||||
/* determine the fill mode to fill the polygon. */
|
||||
ret = FillPolygon_ALTERNATE(Points, Count, DestRect);
|
||||
ret = FillPolygon(&dc, SurfObj, OutBrushObj, FILL_CHAR, Points, Count, DestRect );
|
||||
free(Points);
|
||||
|
||||
return ret;
|
||||
|
@ -789,14 +798,19 @@ void main()
|
|||
{ 12, 4 },
|
||||
{ 4, 8 },
|
||||
#else
|
||||
{ 2, 8 },
|
||||
{ 6, 2 },
|
||||
{ 9, 8 },
|
||||
{ 2, 4 },
|
||||
{ 10, 4 }
|
||||
{ 4, 16 },
|
||||
{ 12, 4 },
|
||||
{ 18, 16 },
|
||||
{ 4, 8 },
|
||||
{ 20, 8 }
|
||||
#endif
|
||||
};
|
||||
Polygon ( pts,sizeof(pts)/sizeof(pts[0]) );
|
||||
const int pts_count = sizeof(pts)/sizeof(pts[0]);
|
||||
|
||||
// use ALTERNATE or WINDING for 3rd param
|
||||
Polygon ( pts, pts_count, ALTERNATE );
|
||||
|
||||
// print out our "screen"
|
||||
for ( int y = 0; y < SCREENY; y++ )
|
||||
{
|
||||
for ( int x = 0; x < SCREENX; x++ )
|
||||
|
@ -808,4 +822,4 @@ void main()
|
|||
DPRINT1("Done!\n");
|
||||
(void)getch();
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define __WIN32K_PAINT_H
|
||||
|
||||
BOOL STDCALL FillSolid (PSURFOBJ Surface, PRECTL Dimensions, ULONG iColor);
|
||||
BOOL STDCALL FillPolygon_ALTERNATE (PDC dc, PSURFOBJ SurfObj, PBRUSHOBJ BrushObj, MIX RopMode, CONST PPOINT Points, INT Count, RECTL BoundRect);
|
||||
BOOL STDCALL FillPolygon_WINDING (PDC dc, PSURFOBJ SurfObj, PBRUSHOBJ BrushObj, MIX RopMode, CONST PPOINT Points, INT Count, RECTL BoundRect);
|
||||
BOOL STDCALL FillPolygon ( PDC dc, PSURFOBJ SurfObj, PBRUSHOBJ BrushObj, MIX RopMode, CONST PPOINT Points, INT Count, RECTL BoundRect );
|
||||
|
||||
#endif /* __WIN32K_PAINT_H */
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* $Id: fillshap.c,v 1.22 2003/08/15 18:51:32 royce Exp $ */
|
||||
/* $Id: fillshap.c,v 1.23 2003/08/16 04:47:41 royce Exp $ */
|
||||
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
@ -77,12 +77,16 @@ W32kPie(HDC hDC,
|
|||
|
||||
#if 0
|
||||
|
||||
//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.
|
||||
extern BOOL FillPolygon_ALTERNATE(PDC dc,
|
||||
|
||||
//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.
|
||||
//The direction of each edge of the polygon is important.
|
||||
|
||||
extern BOOL FillPolygon(PDC dc,
|
||||
SURFOBJ *SurfObj,
|
||||
PBRUSHOBJ BrushObj,
|
||||
MIX RopMode,
|
||||
|
@ -90,17 +94,6 @@ extern BOOL FillPolygon_ALTERNATE(PDC dc,
|
|||
int Count,
|
||||
RECTL BoundRect);
|
||||
|
||||
|
||||
//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.
|
||||
//The direction of each edge of the polygon is important.
|
||||
extern BOOL FillPolygon_WINDING(PDC dc,
|
||||
SURFOBJ *SurfObj,
|
||||
PBRUSHOBJ BrushObj,MIX RopMode,
|
||||
CONST PPOINT Points,
|
||||
int Count,
|
||||
RECTL BoundRect);
|
||||
#endif
|
||||
|
||||
//This implementation is blatantly ripped off from W32kRectangle
|
||||
|
@ -181,16 +174,9 @@ W32kPolygon(HDC hDC,
|
|||
|
||||
/* Now fill the polygon with the current brush. */
|
||||
FillBrushObj = (BRUSHOBJ*) GDIOBJ_LockObj(dc->w.hBrush, GO_BRUSH_MAGIC);
|
||||
/* determine the fill mode to fill the polygon. */
|
||||
|
||||
#if 1
|
||||
if (WINDING == dc->w.polyFillMode)
|
||||
{
|
||||
ret = FillPolygon_WINDING(dc, SurfObj, FillBrushObj, dc->w.ROPmode, Points, Count, DestRect);
|
||||
}
|
||||
else /* default */
|
||||
{
|
||||
ret = FillPolygon_ALTERNATE(dc, SurfObj, FillBrushObj, dc->w.ROPmode, Points, Count, DestRect);
|
||||
}
|
||||
ret = FillPolygon ( dc, SurfObj, FillBrushObj, dc->w.ROPmode, Points, Count, DestRect);
|
||||
#endif
|
||||
// Draw the Polygon Edges with the current pen
|
||||
for (CurrentPoint = 0; CurrentPoint < Count; ++CurrentPoint)
|
||||
|
@ -224,15 +210,7 @@ W32kPolygon(HDC hDC,
|
|||
|
||||
}
|
||||
#if 0
|
||||
/* determine the fill mode to fill the polygon. */
|
||||
if (WINDING == dc->w.polyFillMode)
|
||||
{
|
||||
ret = FillPolygon_WINDING(dc, SurfObj, FillBrushObj, dc->w.ROPmode, Points, Count, DestRect);
|
||||
}
|
||||
else /* default */
|
||||
{
|
||||
ret = FillPolygon_ALTERNATE(dc, SurfObj, FillBrushObj, dc->w.ROPmode, Points, Count, DestRect);
|
||||
}
|
||||
ret = FillPolygon ( dc, SurfObj, FillBrushObj, dc->w.ROPmode, Points, Count, DestRect);
|
||||
#endif
|
||||
GDIOBJ_UnlockObj(dc->w.hBrush, GO_BRUSH_MAGIC);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* $Id: polyfill.c,v 1.7 2003/08/15 18:51:32 royce Exp $
|
||||
/* $Id: polyfill.c,v 1.8 2003/08/16 04:47:41 royce Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -40,12 +40,12 @@
|
|||
#define NDEBUG
|
||||
#include <win32k/debug1.h>
|
||||
|
||||
#define PFILL_EDGE_ALLOC_TAG 0x45465044
|
||||
#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;
|
||||
|
@ -54,51 +54,48 @@ typedef struct _tagPFILL_EDGE
|
|||
int ToY;
|
||||
int dx;
|
||||
int dy;
|
||||
int MinX;
|
||||
int MaxX;
|
||||
int MinY;
|
||||
int MaxY;
|
||||
int absdx, absdy;
|
||||
int x, y;
|
||||
int xmajor;
|
||||
|
||||
/*Active Edge List information*/
|
||||
int XIntercept;
|
||||
int XIntercept[2];
|
||||
int Error;
|
||||
int ErrorInc;
|
||||
int ErrorMax;
|
||||
int XPerY;
|
||||
int XDirection;
|
||||
int YDirection; // used for Winding
|
||||
int XDirection, YDirection;
|
||||
|
||||
/* The next edge in the Edge List*/
|
||||
struct _tagPFILL_EDGE * pNext;
|
||||
} PFILL_EDGE, *PPFILL_EDGE;
|
||||
/* The next edge in the active Edge List*/
|
||||
struct _tagFILL_EDGE * pNext;
|
||||
} FILL_EDGE;
|
||||
|
||||
typedef PPFILL_EDGE PFILL_EDGE_LIST;
|
||||
typedef struct _FILL_EDGE_LIST
|
||||
{
|
||||
int Count;
|
||||
FILL_EDGE** Edges;
|
||||
} FILL_EDGE_LIST;
|
||||
|
||||
#if 0
|
||||
static
|
||||
inline
|
||||
int
|
||||
abs ( int a )
|
||||
{
|
||||
return a < 0 ? -a : a;
|
||||
}
|
||||
|
||||
/*static
|
||||
void
|
||||
DEBUG_PRINT_EDGELIST(PFILL_EDGE_LIST list)
|
||||
DEBUG_PRINT_ACTIVE_EDGELIST ( 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;
|
||||
}
|
||||
}*/
|
||||
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
|
||||
|
||||
/*
|
||||
** Hide memory clean up.
|
||||
|
@ -106,30 +103,21 @@ DEBUG_PRINT_EDGELIST(PFILL_EDGE_LIST list)
|
|||
static
|
||||
void
|
||||
FASTCALL
|
||||
POLYGONFILL_DestroyEdge(PPFILL_EDGE pEdge)
|
||||
POLYGONFILL_DestroyEdgeList(FILL_EDGE_LIST* list)
|
||||
{
|
||||
if (0 != pEdge)
|
||||
EngFreeMem(pEdge);
|
||||
}
|
||||
|
||||
/*
|
||||
** Clean up a list.
|
||||
*/
|
||||
static
|
||||
void
|
||||
FASTCALL
|
||||
POLYGONFILL_DestroyEdgeList(PFILL_EDGE_LIST list)
|
||||
{
|
||||
PPFILL_EDGE pThis = 0;
|
||||
PPFILL_EDGE pNext = 0;
|
||||
|
||||
pThis = list;
|
||||
while (0 != pThis)
|
||||
int i;
|
||||
if ( list )
|
||||
{
|
||||
//DPRINT("Destroying Edge\n");
|
||||
pNext = pThis->pNext;
|
||||
POLYGONFILL_DestroyEdge(pThis);
|
||||
pThis = pNext;
|
||||
if ( list->Edges )
|
||||
{
|
||||
for ( i = 0; i < list->Count; i++ )
|
||||
{
|
||||
if ( list->Edges[i] )
|
||||
EngFreeMem ( list->Edges[i] );
|
||||
}
|
||||
EngFreeMem ( list->Edges );
|
||||
}
|
||||
EngFreeMem ( list );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,17 +125,16 @@ POLYGONFILL_DestroyEdgeList(PFILL_EDGE_LIST list)
|
|||
** This makes and initiaizes an Edge struct for a line between two points.
|
||||
*/
|
||||
static
|
||||
PPFILL_EDGE
|
||||
FILL_EDGE*
|
||||
FASTCALL
|
||||
POLYGONFILL_MakeEdge(POINT From, POINT To)
|
||||
{
|
||||
int absdx, absdy;
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
//DPRINT ("Making Edge: (%d, %d) to (%d, %d)\n", From.x, From.y, To.x, To.y);
|
||||
//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 )
|
||||
{
|
||||
|
@ -166,22 +153,16 @@ POLYGONFILL_MakeEdge(POINT From, POINT To)
|
|||
rc->YDirection = 1;
|
||||
}
|
||||
|
||||
rc->x = rc->FromX;
|
||||
rc->y = rc->FromY;
|
||||
rc->dx = rc->ToX - rc->FromX;
|
||||
rc->dy = rc->ToY - rc->FromY;
|
||||
absdx = abs(rc->dx);
|
||||
absdy = abs(rc->dy);
|
||||
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);
|
||||
rc->absdx = abs(rc->dx);
|
||||
rc->absdy = abs(rc->dy);
|
||||
|
||||
if (rc->MinY == To.y)
|
||||
rc->XIntercept = To.x;
|
||||
else
|
||||
rc->XIntercept = From.x;
|
||||
rc->xmajor = rc->absdx > rc->absdy;
|
||||
|
||||
rc->ErrorMax = absdy;
|
||||
rc->ErrorInc = absdx;
|
||||
rc->ErrorMax = MAX(rc->absdx,rc->absdy);
|
||||
|
||||
rc->Error = rc->ErrorMax / 2;
|
||||
|
||||
|
@ -189,8 +170,25 @@ POLYGONFILL_MakeEdge(POINT From, POINT To)
|
|||
|
||||
rc->pNext = 0;
|
||||
|
||||
DPRINT ("MakeEdge (%i,%i)->(%i,%i) d=(%i,%i) dir=%i err=%i max=%i\n",
|
||||
From.x, From.y, To.x, To.y, rc->dx, rc->dy, rc->Direction, rc->Error, rc->ErrorMax );
|
||||
rc->XIntercept[0] = rc->x;
|
||||
rc->XIntercept[1] = rc->x;
|
||||
|
||||
if ( rc->xmajor && rc->absdy )
|
||||
{
|
||||
int x1 = rc->x;
|
||||
int steps = (rc->ErrorMax-rc->Error-1) / rc->absdy;
|
||||
if ( steps )
|
||||
{
|
||||
rc->x += steps * rc->XDirection;
|
||||
rc->Error += steps * rc->absdy;
|
||||
ASSERT ( rc->Error < rc->ErrorMax );
|
||||
rc->XIntercept[0] = MIN(x1,rc->x);
|
||||
rc->XIntercept[1] = MAX(x1,rc->x);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -211,30 +209,12 @@ POLYGONFILL_MakeEdge(POINT From, POINT To)
|
|||
static
|
||||
INT
|
||||
FASTCALL
|
||||
PFILL_EDGE_Compare(PPFILL_EDGE Edge1, PPFILL_EDGE Edge2)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -244,79 +224,91 @@ PFILL_EDGE_Compare(PPFILL_EDGE Edge1, PPFILL_EDGE Edge2)
|
|||
static
|
||||
void
|
||||
FASTCALL
|
||||
POLYGONFILL_ListInsert(PFILL_EDGE_LIST *list, PPFILL_EDGE NewEdge)
|
||||
POLYGONFILL_ActiveListInsert(FILL_EDGE** activehead, FILL_EDGE* NewEdge )
|
||||
{
|
||||
PPFILL_EDGE pThis;
|
||||
if (0 != list && 0 != NewEdge)
|
||||
FILL_EDGE *pPrev, *pThis;
|
||||
//DPRINT1("In POLYGONFILL_ActiveListInsert()\n");
|
||||
ASSERT ( activehead && NewEdge );
|
||||
if ( !*activehead )
|
||||
{
|
||||
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);
|
||||
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
|
||||
FILL_EDGE_LIST*
|
||||
FASTCALL
|
||||
POLYGONFILL_MakeEdgeList(PPOINT Points, int Count)
|
||||
{
|
||||
int CurPt = 0;
|
||||
int SeqNum = 0;
|
||||
PPFILL_EDGE rc = 0;
|
||||
PPFILL_EDGE NextEdge = 0;
|
||||
FILL_EDGE_LIST* list = 0;
|
||||
FILL_EDGE* e = 0;
|
||||
|
||||
if ( 0 == Points || 2 > Count )
|
||||
return rc;
|
||||
return 0;
|
||||
|
||||
//Establish the list with the first two points.
|
||||
rc = POLYGONFILL_MakeEdge ( Points[0], Points[1] );
|
||||
if (0 == rc) return rc;
|
||||
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,++SeqNum )
|
||||
for ( CurPt = 1; CurPt < Count; ++CurPt )
|
||||
{
|
||||
if (CurPt == Count - 1 )
|
||||
{
|
||||
NextEdge = POLYGONFILL_MakeEdge(Points[CurPt],Points[0]);
|
||||
}
|
||||
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
|
||||
{
|
||||
NextEdge = POLYGONFILL_MakeEdge(Points[CurPt],Points[CurPt + 1]);
|
||||
}
|
||||
if (0 != NextEdge)
|
||||
{
|
||||
POLYGONFILL_ListInsert(&rc, NextEdge);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("Out Of MEMORY!! NextEdge = 0\n");
|
||||
}
|
||||
list->Edges[list->Count++] = e;
|
||||
}
|
||||
return rc;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -329,187 +321,88 @@ POLYGONFILL_MakeEdgeList(PPOINT Points, int Count)
|
|||
static
|
||||
void
|
||||
FASTCALL
|
||||
POLYGONFILL_UpdateScanline(PPFILL_EDGE pEdge, int Scanline)
|
||||
POLYGONFILL_UpdateScanline(FILL_EDGE* pEdge, int Scanline)
|
||||
{
|
||||
if ( 0 == pEdge->dy )
|
||||
return;
|
||||
|
||||
if ( pEdge->ErrorMax )
|
||||
ASSERT ( pEdge->FromY < Scanline && pEdge->ToY >= Scanline );
|
||||
|
||||
if ( pEdge->xmajor )
|
||||
{
|
||||
pEdge->Error += pEdge->ErrorInc;
|
||||
int steps;
|
||||
// we should require exactly 1 step to step onto current 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 current scanline...
|
||||
pEdge->Error -= pEdge->absdx;
|
||||
pEdge->y++;
|
||||
|
||||
ASSERT ( pEdge->y == Scanline );
|
||||
|
||||
// now shoot to end of scanline collision
|
||||
steps = (pEdge->ErrorMax-pEdge->Error-1)/pEdge->absdy;
|
||||
if ( steps )
|
||||
{
|
||||
// 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->XIntercept[0] = pEdge->x;
|
||||
pEdge->XIntercept[1] = pEdge->x;
|
||||
}
|
||||
}
|
||||
else // then this is a y-major line
|
||||
{
|
||||
pEdge->Error += pEdge->absdx;
|
||||
pEdge->y++;
|
||||
|
||||
if ( pEdge->Error >= pEdge->ErrorMax )
|
||||
{
|
||||
int steps = pEdge->Error / pEdge->ErrorMax;
|
||||
pEdge->XIntercept += steps * pEdge->XDirection;
|
||||
pEdge->Error -= steps * pEdge->ErrorMax;
|
||||
pEdge->Error -= pEdge->ErrorMax;
|
||||
pEdge->x += pEdge->XDirection;
|
||||
ASSERT ( pEdge->Error < pEdge->ErrorMax );
|
||||
}
|
||||
|
||||
pEdge->XIntercept[0] = pEdge->x;
|
||||
pEdge->XIntercept[1] = pEdge->x;
|
||||
}
|
||||
|
||||
DPRINT ("Line (%d, %d) to (%d, %d) intersects scanline %d at %d\n",
|
||||
pEdge->FromX, pEdge->FromY, pEdge->ToX, pEdge->ToY, Scanline, pEdge->XIntercept );
|
||||
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 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
|
||||
FASTCALL
|
||||
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)
|
||||
{
|
||||
/*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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine reorders the Active Edge collection (list) after all
|
||||
** the now inactive edges have been removed.
|
||||
*/
|
||||
static
|
||||
void
|
||||
FASTCALL
|
||||
POLYGONFILL_AECReorder(PFILL_EDGE_LIST *AEC)
|
||||
{
|
||||
PPFILL_EDGE pThis = 0;
|
||||
PPFILL_EDGE pPrev = 0;
|
||||
PPFILL_EDGE pTarg = 0;
|
||||
pThis = *AEC;
|
||||
|
||||
while (0 != pThis)
|
||||
{
|
||||
/*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;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
** This method updates the Active edge collection for the scanline Scanline.
|
||||
*/
|
||||
static
|
||||
void
|
||||
STDCALL
|
||||
POLYGONFILL_UpdateActiveEdges(int Scanline, PFILL_EDGE_LIST *GEC, PFILL_EDGE_LIST *AEC)
|
||||
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++ )
|
||||
{
|
||||
//DPRINT("Moving Edge to AEC\n");
|
||||
/*Remove the edge from GEC and put it into AEC*/
|
||||
if (pThis->MinY <= Scanline)
|
||||
FILL_EDGE* pEdge = list->Edges[i];
|
||||
ASSERT(pEdge);
|
||||
if ( pEdge->FromY < Scanline && pEdge->ToY >= 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;
|
||||
}
|
||||
/*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;
|
||||
POLYGONFILL_UpdateScanline ( pEdge, Scanline );
|
||||
POLYGONFILL_ActiveListInsert ( ActiveHead, pEdge );
|
||||
}
|
||||
}
|
||||
/*Last re Xintercept order the AEC*/
|
||||
POLYGONFILL_AECReorder(AEC);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -519,138 +412,137 @@ POLYGONFILL_UpdateActiveEdges(int Scanline, PFILL_EDGE_LIST *GEC, PFILL_EDGE_LIS
|
|||
static
|
||||
void
|
||||
STDCALL
|
||||
POLYGONFILL_FillScanLineAlternate(PDC dc, int ScanLine, PFILL_EDGE_LIST ActiveEdges, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode)
|
||||
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;
|
||||
FILL_EDGE *pLeft, *pRight;
|
||||
|
||||
while (NULL != pThis)
|
||||
if ( !ActiveHead )
|
||||
return;
|
||||
|
||||
pLeft = ActiveHead;
|
||||
pRight = pLeft->pNext;
|
||||
ASSERT(pRight);
|
||||
|
||||
while ( NULL != pRight )
|
||||
{
|
||||
if (OnOdd)
|
||||
int x1 = pLeft->XIntercept[1];
|
||||
int x2 = pRight->XIntercept[0]+1;
|
||||
if ( x2 > x1 )
|
||||
{
|
||||
XInterceptOdd = pThis->XIntercept;
|
||||
OnOdd = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
XInterceptEven = pThis->XIntercept+1;
|
||||
if ( XInterceptEven > XInterceptOdd )
|
||||
{
|
||||
BoundRect.top = ScanLine;
|
||||
BoundRect.bottom = ScanLine + 1;
|
||||
BoundRect.left = XInterceptOdd;
|
||||
BoundRect.right = XInterceptEven;
|
||||
RECTL BoundRect;
|
||||
BoundRect.top = ScanLine;
|
||||
BoundRect.bottom = ScanLine + 1;
|
||||
BoundRect.left = x1;
|
||||
BoundRect.right = x2;
|
||||
|
||||
DPRINT ("Fill Line (%d, %d) to (%d, %d)\n",XInterceptOdd, ScanLine, XInterceptEven, ScanLine);
|
||||
ret = IntEngLineTo( SurfObj,
|
||||
dc->CombinedClip,
|
||||
BrushObj,
|
||||
XInterceptOdd,
|
||||
ScanLine,
|
||||
XInterceptEven,
|
||||
ScanLine,
|
||||
&BoundRect, /* Bounding rectangle */
|
||||
RopMode); /* MIX */
|
||||
}
|
||||
OnOdd = TRUE;
|
||||
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
|
||||
}
|
||||
pThis = pThis->pNext;
|
||||
pLeft = pRight->pNext;
|
||||
pRight = pLeft ? pLeft->pNext : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
STDCALL
|
||||
POLYGONFILL_FillScanLineWinding(PDC dc, int ScanLine, PFILL_EDGE_LIST ActiveEdges, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode)
|
||||
POLYGONFILL_FillScanLineWinding(
|
||||
PDC dc,
|
||||
int ScanLine,
|
||||
FILL_EDGE* ActiveHead,
|
||||
SURFOBJ *SurfObj,
|
||||
PBRUSHOBJ BrushObj,
|
||||
MIX RopMode )
|
||||
{
|
||||
RECTL BoundRect;
|
||||
int XPrevIntercept,XIntercept,ret;
|
||||
PPFILL_EDGE pThis = ActiveEdges;
|
||||
FILL_EDGE *pLeft, *pRight;
|
||||
int winding = 0;
|
||||
|
||||
XPrevIntercept = pThis->XIntercept;
|
||||
winding += pThis->YDirection;
|
||||
pThis = pThis->pNext;
|
||||
if ( !ActiveHead )
|
||||
return;
|
||||
|
||||
while (NULL != pThis)
|
||||
pLeft = ActiveHead;
|
||||
winding = pLeft->YDirection;
|
||||
pRight = pLeft->pNext;
|
||||
ASSERT(pRight);
|
||||
|
||||
while ( NULL != pRight )
|
||||
{
|
||||
XIntercept = pThis->XIntercept + 1;
|
||||
if ( winding && XIntercept > XPrevIntercept )
|
||||
int x1 = pLeft->XIntercept[1];
|
||||
int x2 = pRight->XIntercept[0]+1;
|
||||
if ( winding && x2 > x1 )
|
||||
{
|
||||
RECTL BoundRect;
|
||||
BoundRect.top = ScanLine;
|
||||
BoundRect.bottom = ScanLine + 1;
|
||||
BoundRect.left = XPrevIntercept;
|
||||
BoundRect.right = XIntercept;
|
||||
BoundRect.left = x1;
|
||||
BoundRect.right = x2;
|
||||
|
||||
DPRINT ("Fill Line (%d, %d) to (%d, %d)\n",XPrevIntercept, ScanLine, XIntercept, ScanLine);
|
||||
ret = IntEngLineTo( SurfObj,
|
||||
DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
|
||||
IntEngLineTo( SurfObj,
|
||||
dc->CombinedClip,
|
||||
BrushObj,
|
||||
XPrevIntercept,
|
||||
ScanLine,
|
||||
XIntercept,
|
||||
x1,
|
||||
ScanLine,
|
||||
x2,
|
||||
ScanLine,
|
||||
&BoundRect, // Bounding rectangle
|
||||
RopMode); // MIX
|
||||
}
|
||||
XPrevIntercept = XIntercept - 1;
|
||||
winding += pThis->YDirection;
|
||||
pThis = pThis->pNext;
|
||||
pLeft = pRight;
|
||||
pRight = pLeft->pNext;
|
||||
winding += pLeft->YDirection;
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
STDCALL
|
||||
FillPolygon_ALTERNATE(PDC dc, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode, CONST PPOINT Points, int Count, RECTL BoundRect)
|
||||
{
|
||||
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 (NULL == 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_FillScanLineAlternate(dc, ScanLine, ActiveEdges, SurfObj, BrushObj, RopMode);
|
||||
}
|
||||
|
||||
/* 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
|
||||
STDCALL
|
||||
FillPolygon_WINDING(PDC dc, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj,MIX RopMode, CONST PPOINT Points, int Count, RECTL BoundRect)
|
||||
FillPolygon(
|
||||
PDC dc,
|
||||
SURFOBJ *SurfObj,
|
||||
PBRUSHOBJ BrushObj,
|
||||
MIX RopMode,
|
||||
CONST PPOINT Points,
|
||||
int Count,
|
||||
RECTL BoundRect )
|
||||
{
|
||||
PFILL_EDGE_LIST list = 0;
|
||||
PFILL_EDGE_LIST ActiveEdges = 0;
|
||||
FILL_EDGE_LIST *list = 0;
|
||||
FILL_EDGE *ActiveHead = 0;
|
||||
int ScanLine;
|
||||
|
||||
DPRINT("FillPolygon_ALTERNATE\n");
|
||||
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);
|
||||
|
@ -658,14 +550,19 @@ FillPolygon_WINDING(PDC dc, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj,MIX RopMode, CO
|
|||
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 + 1; ScanLine < BoundRect.bottom; ++ScanLine )
|
||||
{
|
||||
POLYGONFILL_UpdateActiveEdges(ScanLine, &list, &ActiveEdges);
|
||||
/* DEBUG_PRINT_EDGELIST(ActiveEdges); */
|
||||
POLYGONFILL_FillScanLineWinding(dc, ScanLine, ActiveEdges, SurfObj, BrushObj, RopMode);
|
||||
POLYGONFILL_BuildActiveList(ScanLine, list, &ActiveHead);
|
||||
//DEBUG_PRINT_ACTIVE_EDGELIST(ActiveHead);
|
||||
FillScanLine ( dc, ScanLine, ActiveHead, SurfObj, BrushObj, RopMode );
|
||||
}
|
||||
|
||||
/* Free Edge List. If any are left. */
|
||||
|
|
Loading…
Reference in a new issue