improvements to Polygon algo - commiting to get help on one last detail. Winding polygons now work and floating point code is eliminated.

svn path=/trunk/; revision=5591
This commit is contained in:
Royce Mitchell III 2003-08-15 18:51:32 +00:00
parent 4f6a2a6124
commit d4deb682ee
5 changed files with 606 additions and 518 deletions

View file

@ -1,4 +1,4 @@
# $Id: makefile,v 1.1 2003/03/19 16:03:02 mtempel Exp $
# $Id: makefile,v 1.2 2003/08/15 18:51:31 royce Exp $
PATH_TO_TOP = ../../..
@ -6,10 +6,12 @@ TARGET_NORC = yes
TARGET_TYPE = program
TARGET_APPTYPE = console
TARGET_APPTYPE = windows
TARGET_NAME = shaptest
TARGET_CFLAGS = -Wall -Werror
TARGET_SDKLIBS = kernel32.a gdi32.a
TARGET_OBJECTS = $(TARGET_NAME).o

View file

@ -15,90 +15,95 @@
HFONT tf;
LRESULT WINAPI MainWndProc(HWND, UINT, WPARAM, LPARAM);
void __stdcall PolygonTest(HDC Desktop)
void PolygonTest ( HDC hdc )
{
HPEN BluePen;
HPEN OldPen;
HBRUSH RedBrush;
HBRUSH OldBrush;
POINT lpPointsAlternate[5];
POINT lpPointsWinding[5];
DWORD Mode;
HPEN BluePen, OldPen;
HBRUSH RedBrush, OldBrush;
DWORD Mode;
POINT PointsAlternate[] =
{
{ 20, 80 },
{ 60, 20 },
{ 90, 80 },
{ 20, 40 },
{ 100, 40 }
};
POINT PointsWinding[] =
{
{ 130, 80 },
{ 170, 20 },
{ 200, 80 },
{ 130, 40 },
{ 210, 40 }
};
POINT Tri1[] =
{
{ 3, 3 },
{ 5, 3 },
{ 3, 5 }
};
POINT Tri2[] =
{
{ 7, 3 },
{ 7, 7 },
{ 3, 7 },
};
//create a pen to draw the shape
BluePen = CreatePen(PS_SOLID, 3, RGB(0, 0, 0xff));
RedBrush = CreateSolidBrush(RGB(0xff, 0, 0));
//create a pen to draw the shape
BluePen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0xff));
RedBrush = CreateSolidBrush(RGB(0xff, 0, 0));
//initialize a set of points for alternate.
lpPointsAlternate[0].x = 20;
lpPointsAlternate[0].y = 80; //{20,80};
lpPointsAlternate[1].x = 60;
lpPointsAlternate[1].y = 20; //{60,20};
lpPointsAlternate[2].x = 90;
lpPointsAlternate[2].y = 80; //{90,80};
lpPointsAlternate[3].x = 20;
lpPointsAlternate[3].y = 40; //{20,40};
lpPointsAlternate[4].x = 100;
lpPointsAlternate[4].y = 40; //{100,40};
//initialize a set of points for alternate.
/*lpPointsAlternate[0].x = 20;
lpPointsAlternate[0].y = 80; //{20,80};
lpPointsAlternate[1].x = 60;
lpPointsAlternate[1].y = 20; //{60,20};
lpPointsAlternate[2].x = 90;
lpPointsAlternate[2].y = 80; //{90,80};
lpPointsAlternate[3].x = 20;
lpPointsAlternate[3].y = 40; //{20,40};
lpPointsAlternate[4].x = 100;
lpPointsAlternate[4].y = 40; //{100,40};
//initialize a set of points for winding.
lpPointsWinding[0].x = 130;
lpPointsWinding[0].y = 80; //{130,80};
lpPointsWinding[1].x = 170;
lpPointsWinding[1].y = 20; //{170,20};
lpPointsWinding[2].x = 200;
lpPointsWinding[2].y = 80; //{200,80};
lpPointsWinding[3].x = 130;
lpPointsWinding[3].y = 40; //{130,40};
lpPointsWinding[4].x = 210;
lpPointsWinding[4].y = 40; //{210,40};
//initialize a set of points for winding.
lpPointsWinding[0].x = 130;
lpPointsWinding[0].y = 80; //{130,80};
lpPointsWinding[1].x = 170;
lpPointsWinding[1].y = 20; //{170,20};
lpPointsWinding[2].x = 200;
lpPointsWinding[2].y = 80; //{200,80};
lpPointsWinding[3].x = 130;
lpPointsWinding[3].y = 40; //{130,40};
lpPointsWinding[4].x = 210;
lpPointsWinding[4].y = 40; //{210,40};
*/
OldPen = (HPEN)SelectObject(hdc, BluePen);
OldBrush = (HBRUSH)SelectObject(hdc, RedBrush);
OldPen = (HPEN)SelectObject(Desktop, BluePen);
OldBrush = (HBRUSH)SelectObject(Desktop, RedBrush);
Mode = GetPolyFillMode(hdc);
Mode = GetPolyFillMode(Desktop);
SetPolyFillMode(hdc, ALTERNATE);
Polygon(hdc,PointsAlternate,sizeof(PointsAlternate)/sizeof(PointsAlternate[0]));
SetPolyFillMode(Desktop, ALTERNATE);
Polygon(Desktop,lpPointsAlternate,5);
SetPolyFillMode(hdc, WINDING);
Polygon(hdc,PointsWinding,sizeof(PointsWinding)/sizeof(PointsWinding[0]));
SetPolyFillMode(Desktop, WINDING);
Polygon(Desktop,lpPointsWinding,5);
//cleanup
SetPolyFillMode(Desktop, Mode);
SelectObject(Desktop, OldPen);
SelectObject(Desktop, OldBrush);
DeleteObject(BluePen);
DeleteObject(RedBrush);
Polygon(hdc,Tri1,sizeof(Tri1)/sizeof(Tri1[0]));
Polygon(hdc,Tri2,sizeof(Tri2)/sizeof(Tri2[0]));
Rectangle ( hdc, 3, 15, 7, 20 );
//cleanup
SetPolyFillMode(hdc, Mode);
DeleteObject ( SelectObject(hdc, OldPen) );
DeleteObject ( SelectObject(hdc, OldBrush) );
}
void shaptest( HDC DevCtx ){
HDC Desktop, MyDC, DC24;
HPEN RedPen, GreenPen, BluePen, WhitePen;
HBITMAP MyBitmap, DIB24;
HFONT hf, tf;
BITMAPINFOHEADER BitInf;
BITMAPINFO BitPalInf;
HRGN hRgn1, hRgn2, hRgn3;
HBRUSH BlueBrush, DefBrush;
int sec,Xmod,Ymod;
char tbuf[5];
BlueBrush = CreateSolidBrush( RGB(0, 0, 0xff) );
DefBrush = SelectObject( DevCtx, BlueBrush );
SelectObject( DevCtx, DefBrush );
DeleteObject( BlueBrush );
// Create a blue pen and select it into the DC
BluePen = CreatePen(PS_SOLID, 8, RGB(0, 0, 0xff));
SelectObject(DevCtx, BluePen);
void shaptest( HDC hdc )
{
//Test the Polygon routine.
PolygonTest(DevCtx);
PolygonTest(hdc);
}
@ -116,8 +121,8 @@ WinMain(HINSTANCE hInstance,
wc.lpfnWndProc = MainWndProc;
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = (HICON)LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
wc.hCursor = (HCURSOR)LoadCursor(NULL, (LPCTSTR)IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
@ -125,7 +130,7 @@ WinMain(HINSTANCE hInstance,
if (RegisterClass(&wc) == 0)
{
fprintf(stderr, "RegisterClass failed (last error 0x%X)\n",
GetLastError());
(unsigned int)GetLastError());
return(1);
}
@ -143,7 +148,7 @@ WinMain(HINSTANCE hInstance,
if (hWnd == NULL)
{
fprintf(stderr, "CreateWindow failed (last error 0x%X)\n",
GetLastError());
(unsigned int)GetLastError());
return(1);
}
@ -166,27 +171,25 @@ WinMain(HINSTANCE hInstance,
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hDC;
RECT clr, wir;
char spr[100], sir[100];
PAINTSTRUCT ps;
HDC hDC;
switch(msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
shaptest( hDC );
EndPaint(hWnd, &ps);
break;
switch(msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
shaptest( hDC );
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}

View file

@ -3,6 +3,6 @@
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 (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);
#endif /* __WIN32K_PAINT_H */

View file

@ -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.21 2003/07/14 09:43:11 gvg Exp $ */
/* $Id: fillshap.c,v 1.22 2003/08/15 18:51:32 royce Exp $ */
#undef WIN32_LEAN_AND_MEAN
#include <windows.h>
@ -83,23 +83,24 @@ W32kPie(HDC hDC,
//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,
SURFOBJ *SurfObj,
PBRUSHOBJ BrushObj,
MIX RopMode,
CONST PPOINT Points,
int Count,
RECTL BoundRect);
SURFOBJ *SurfObj,
PBRUSHOBJ BrushObj,
MIX RopMode,
CONST PPOINT Points,
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(SURFOBJ *SurfObj,
PBRUSHOBJ BrushObj,MIX RopMode,
CONST PPOINT Points,
int Count,
RECTL BoundRect);
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
@ -122,7 +123,7 @@ W32kPolygon(HDC hDC,
DPRINT("In W32kPolygon()\n");
if (NULL == dc || NULL == Points || Count < 2)
if (NULL == dc || NULL == UnsafePoints || Count < 2)
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
@ -154,22 +155,22 @@ W32kPolygon(HDC hDC,
//ei not yet implemented ASSERT(RectBounds);
if (PATH_IsPathOpen(dc->w.path))
{
{
ret = PATH_Polygon(hDC, Points, Count);
}
else
}
else
{
/* Get the current pen. */
pen = (PENOBJ*) GDIOBJ_LockObj(dc->w.hPen, GO_PEN_MAGIC);
ASSERT(pen);
OutBrushObj = (PBRUSHOBJ) PenToBrushObj(dc, pen);
GDIOBJ_UnlockObj(dc->w.hPen, GO_PEN_MAGIC);
DestRect.left = Points[0].x;
DestRect.right = Points[0].x;
DestRect.top = Points[0].y;
DestRect.bottom = Points[0].y;
for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
{
DestRect.left = MIN(DestRect.left, Points[CurrentPoint].x);
@ -181,19 +182,20 @@ 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(SurfObj, FillBrushObj, dc->w.ROPmode, Points, Count, DestRect);
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);
}
#endif
// Draw the Polygon Edges with the current pen
for (CurrentPoint = 0; CurrentPoint < Count; ++CurrentPoint)
{
POINT To, From, Next;
{
POINT To, From; //, Next;
/* Let CurrentPoint be i
* if i+1 > Count, Draw a line from Points[i] to Points[0]
@ -209,39 +211,6 @@ W32kPolygon(HDC hDC,
To = Points[CurrentPoint + 1];
}
/* Special handling of lower right corner of a rectangle. If we
* don't treat it specially, it will end up looking like this:
*
* *
* *
* *
* *********
*/
if (3 < Count)
{
if (Count <= CurrentPoint + 2)
{
Next = Points[CurrentPoint + 2 - Count];
}
else
{
Next = Points[CurrentPoint + 2];
}
if (From.x == To.x &&
From.y <= To.y &&
To.y == Next.y &&
Next.x <= To.x)
{
To.y++;
}
else if (From.y == To.y &&
From.x <= To.x &&
To.x == Next.x &&
Next.y <= To.y)
{
To.x++;
}
}
DPRINT("Polygon Making line from (%d,%d) to (%d,%d)\n", From.x, From.y, To.x, To.y );
ret = IntEngLineTo(SurfObj,
dc->CombinedClip,
@ -254,6 +223,17 @@ W32kPolygon(HDC hDC,
dc->w.ROPmode); /* MIX */
}
#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);
}
#endif
GDIOBJ_UnlockObj(dc->w.hBrush, GO_BRUSH_MAGIC);
}
@ -297,9 +277,12 @@ W32kRectangle(HDC hDC,
RectBounds = GDIOBJ_LockObj(dc->w.hGCClipRgn, GO_REGION_MAGIC);
//ei not yet implemented ASSERT(RectBounds);
if(PATH_IsPathOpen(dc->w.path)) {
if(PATH_IsPathOpen(dc->w.path))
{
ret = PATH_Rectangle(hDC, LeftRect, TopRect, RightRect, BottomRect);
} else {
}
else
{
// Draw the rectangle with the current pen
pen = (PENOBJ*) GDIOBJ_LockObj(dc->w.hPen, GO_PEN_MAGIC);
ASSERT(pen);

View file

@ -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.6 2003/08/13 00:50:25 royce Exp $
/* $Id: polyfill.c,v 1.7 2003/08/15 18:51:32 royce Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -47,33 +47,44 @@
*/
typedef struct _tagPFILL_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;
/*Basic line information*/
int FromX;
int FromY;
int ToX;
int ToY;
int dx;
int dy;
int MinX;
int MaxX;
int MinY;
int MaxY;
/* The next edge in the Edge List*/
struct _tagPFILL_EDGE * pNext;
/*Active Edge List information*/
int XIntercept;
int Error;
int ErrorInc;
int ErrorMax;
int XPerY;
int XDirection;
int YDirection; // used for Winding
/* The next edge in the Edge List*/
struct _tagPFILL_EDGE * pNext;
} PFILL_EDGE, *PPFILL_EDGE;
typedef PPFILL_EDGE PFILL_EDGE_LIST;
typedef PPFILL_EDGE PFILL_EDGE_LIST;
/*static void DEBUG_PRINT_EDGELIST(PFILL_EDGE_LIST list)
static
inline
int
abs ( int a )
{
return a < 0 ? -a : a;
}
/*static
void
DEBUG_PRINT_EDGELIST(PFILL_EDGE_LIST list)
{
PPFILL_EDGE pThis = list;
if (0 == list)
@ -92,96 +103,101 @@ typedef PPFILL_EDGE PFILL_EDGE_LIST;
/*
** Hide memory clean up.
*/
static void FASTCALL POLYGONFILL_DestroyEdge(PPFILL_EDGE pEdge)
static
void
FASTCALL
POLYGONFILL_DestroyEdge(PPFILL_EDGE pEdge)
{
if (0 != pEdge)
EngFreeMem(pEdge);
if (0 != pEdge)
EngFreeMem(pEdge);
}
/*
** Clean up a list.
*/
static void FASTCALL POLYGONFILL_DestroyEdgeList(PFILL_EDGE_LIST list)
static
void
FASTCALL
POLYGONFILL_DestroyEdgeList(PFILL_EDGE_LIST list)
{
PPFILL_EDGE pThis = 0;
PPFILL_EDGE pNext = 0;
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;
}
pThis = list;
while (0 != pThis)
{
//DPRINT("Destroying Edge\n");
pNext = pThis->pNext;
POLYGONFILL_DestroyEdge(pThis);
pThis = pNext;
}
}
/*
** This makes and initiaizes an Edge struct for a line between two points.
*/
static PPFILL_EDGE FASTCALL POLYGONFILL_MakeEdge(POINT From, POINT To)
static
PPFILL_EDGE
FASTCALL
POLYGONFILL_MakeEdge(POINT From, POINT To)
{
PPFILL_EDGE rc = (PPFILL_EDGE)EngAllocMem(FL_ZERO_MEMORY, sizeof(PFILL_EDGE), PFILL_EDGE_ALLOC_TAG);
int absdx, absdy;
PPFILL_EDGE rc = (PPFILL_EDGE)EngAllocMem(FL_ZERO_MEMORY, sizeof(PFILL_EDGE), PFILL_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 (0 == rc)
return NULL;
if (rc->MinY == To.y)
rc->XIntercept = To.x;
else
rc->XIntercept = From.x;
//DPRINT ("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;
}
else
{
rc->FromX = From.x;
rc->FromY = From.y;
rc->ToX = To.x;
rc->ToY = To.y;
rc->YDirection = 1;
}
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;
}
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);
/*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 (rc->MinY == To.y)
rc->XIntercept = To.x;
else
rc->XIntercept = From.x;
rc->ErrorMax = absdy;
rc->ErrorInc = absdx;
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 err=%i max=%i\n",
From.x, From.y, To.x, To.y, rc->dx, rc->dy, rc->Direction, 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
@ -192,107 +208,115 @@ static PPFILL_EDGE FASTCALL POLYGONFILL_MakeEdge(POINT From, POINT To)
** Zero element1 = element2
** Positive integer element1 > element2
*/
static INT FASTCALL PFILL_EDGE_Compare(PPFILL_EDGE Edge1, PPFILL_EDGE Edge2)
static
INT
FASTCALL
PFILL_EDGE_Compare(PPFILL_EDGE Edge1, PPFILL_EDGE Edge2)
{
//DPRINT("In PFILL_EDGE_Compare()\n");
if (Edge1->MinY == Edge2->MinY)
//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)
{
//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;
}
if (0 == Edge2->dx || 0 == Edge1->dx)
{
return Edge1->dx - Edge2->dx;
}
else
{
return (Edge1->dy/Edge1->dx) - (Edge2->dy/Edge2->dx);
}
}
//DPRINT("In PFILL_EDGE_Compare() returning: %d\n",Edge1->MinY - Edge2->MinY);
return Edge1->MinY - Edge2->MinY;
else
{
return Edge1->MinX - Edge2->MinX;
}
}
//DPRINT("In PFILL_EDGE_Compare() returning: %d\n",Edge1->MinY - Edge2->MinY);
return Edge1->MinY - Edge2->MinY;
}
/*
** Insert an edge into a list keeping the list in order.
*/
static void FASTCALL POLYGONFILL_ListInsert(PFILL_EDGE_LIST *list, PPFILL_EDGE NewEdge)
static
void
FASTCALL
POLYGONFILL_ListInsert(PFILL_EDGE_LIST *list, PPFILL_EDGE NewEdge)
{
PPFILL_EDGE pThis;
if (0 != list && 0 != 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))
{
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 = 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);
}
}
/*
** Create a list of edges for a list of points.
*/
static PFILL_EDGE_LIST FASTCALL POLYGONFILL_MakeEdgeList(PPOINT Points, int Count)
static
PFILL_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;
int CurPt = 0;
int SeqNum = 0;
PPFILL_EDGE rc = 0;
PPFILL_EDGE NextEdge = 0;
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;
if ( 0 == Points || 2 > Count )
return rc;
//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
{
DPRINT1("Out Of MEMORY!! NextEdge = 0\n");
}
}
return rc;
}
@ -302,28 +326,27 @@ static PFILL_EDGE_LIST FASTCALL POLYGONFILL_MakeEdgeList(PPOINT Points, int Coun
** for scanline Scanline.
**TODO: Get rid of this floating point arithmetic
*/
static void FASTCALL POLYGONFILL_UpdateScanline(PPFILL_EDGE pEdge, int Scanline)
static
void
FASTCALL
POLYGONFILL_UpdateScanline(PPFILL_EDGE pEdge, int Scanline)
{
int Coord = 0;
float XCoord = 0;
if (0 == pEdge->dy) return;
if ( 0 == pEdge->dy )
return;
XCoord = (Scanline*pEdge->dx - pEdge->FromY*pEdge->dx)/pEdge->dy + pEdge->FromX;
Coord = XCoord + 0.5;
//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;
/*pEdge->XIntercept += pEdge->XPerY;
if ((pEdge->ErrorTerm += pEdge->ErrorTermAdjUp) > 0)
if ( pEdge->ErrorMax )
{
pEdge->Error += pEdge->ErrorInc;
if ( pEdge->Error >= pEdge->ErrorMax )
{
pEdge->XIntercept += pEdge->Direction;
pEdge->ErrorTerm -= pEdge->ErrorTermAdjDown;
}*/
int steps = pEdge->Error / pEdge->ErrorMax;
pEdge->XIntercept += steps * pEdge->XDirection;
pEdge->Error -= steps * pEdge->ErrorMax;
}
}
DPRINT ("Line (%d, %d) to (%d, %d) intersects scanline %d at %d\n",
pEdge->FromX, pEdge->FromY, pEdge->ToX, pEdge->ToY, Scanline, pEdge->XIntercept );
}
/*
@ -333,197 +356,249 @@ static void FASTCALL POLYGONFILL_UpdateScanline(PPFILL_EDGE pEdge, int Scanline)
**
** Note: once an edge is no longer active, it is deleted.
*/
static void FASTCALL POLYGONFILL_AECInsertInOrder(PFILL_EDGE_LIST *list, PPFILL_EDGE pEdge)
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)
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)
{
/*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;
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)
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;
}
PPFILL_EDGE pThis = 0;
PPFILL_EDGE pPrev = 0;
PPFILL_EDGE pTarg = 0;
pThis = *AEC;
/*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;
}
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)
static
void
STDCALL
POLYGONFILL_UpdateActiveEdges(int Scanline, PFILL_EDGE_LIST *GEC, PFILL_EDGE_LIST *AEC)
{
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*/
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)
{
//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;
while (0 != pThis && pThis->MinY <= Scanline)
}
/*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("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;
//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);
}
/*Now remove any edges in the AEC that are no longer active and Update the XIntercept in the AEC*/
pThis = *AEC;
while (0 != pThis)
else/*Otherwise, update the scanline*/
{
/*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(pThis, Scanline);
pPrev = pThis;
}
/*Last re Xintercept order the AEC*/
POLYGONFILL_AECReorder(AEC);
/*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 STDCALL POLYGONFILL_FillScanLine(PDC dc, int ScanLine, PFILL_EDGE_LIST ActiveEdges, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode)
static
void
STDCALL
POLYGONFILL_FillScanLineAlternate(PDC dc, int ScanLine, PFILL_EDGE_LIST ActiveEdges, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode)
{
BOOL OnOdd = TRUE;
RECTL BoundRect;
int XInterceptOdd,XInterceptEven,ret;
PPFILL_EDGE pThis = ActiveEdges;
while (NULL != pThis)
{
if (OnOdd)
{
XInterceptOdd = pThis->XIntercept;
OnOdd = FALSE;
}
else
{
BoundRect.top = ScanLine - 1;
BoundRect.bottom = ScanLine + 1;
BoundRect.left = XInterceptOdd - 2;
BoundRect.right = XInterceptEven;
XInterceptEven = pThis->XIntercept;
DPRINT("Fill Line (%d, %d) to (%d, %d)\n",XInterceptOdd - 1, ScanLine, XInterceptEven - 1, ScanLine);
ret = IntEngLineTo(SurfObj,
dc->CombinedClip,
BrushObj,
XInterceptOdd - 1,
ScanLine,
XInterceptEven - 1,
ScanLine,
&BoundRect, /* Bounding rectangle */
RopMode); /* MIX */
OnOdd = TRUE;
}
pThis = pThis->pNext;
while (NULL != pThis)
{
if (OnOdd)
{
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;
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;
}
pThis = pThis->pNext;
}
}
static
void
STDCALL
POLYGONFILL_FillScanLineWinding(PDC dc, int ScanLine, PFILL_EDGE_LIST ActiveEdges, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode)
{
RECTL BoundRect;
int XPrevIntercept,XIntercept,ret;
PPFILL_EDGE pThis = ActiveEdges;
int winding = 0;
XPrevIntercept = pThis->XIntercept;
winding += pThis->YDirection;
pThis = pThis->pNext;
while (NULL != pThis)
{
XIntercept = pThis->XIntercept + 1;
if ( winding && XIntercept > XPrevIntercept )
{
BoundRect.top = ScanLine;
BoundRect.bottom = ScanLine + 1;
BoundRect.left = XPrevIntercept;
BoundRect.right = XIntercept;
DPRINT ("Fill Line (%d, %d) to (%d, %d)\n",XPrevIntercept, ScanLine, XIntercept, ScanLine);
ret = IntEngLineTo( SurfObj,
dc->CombinedClip,
BrushObj,
XPrevIntercept,
ScanLine,
XIntercept,
ScanLine,
&BoundRect, // Bounding rectangle
RopMode); // MIX
}
XPrevIntercept = XIntercept - 1;
winding += pThis->YDirection;
pThis = pThis->pNext;
}
}
//ALTERNATE Selects alternate mode (fills the area between odd-numbered and even-numbered
@ -531,32 +606,32 @@ static void STDCALL POLYGONFILL_FillScanLine(PDC dc, int ScanLine, PFILL_EDGE_LI
//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)
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;
}
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(dc, ScanLine, ActiveEdges, SurfObj, BrushObj, RopMode);
}
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);
@ -567,10 +642,35 @@ BOOL STDCALL FillPolygon_ALTERNATE(PDC dc, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj,
//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(SURFOBJ *SurfObj, PBRUSHOBJ BrushObj,MIX RopMode, CONST PPOINT Points, int Count, RECTL BoundRect)
BOOL
STDCALL
FillPolygon_WINDING(PDC dc, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj,MIX RopMode, CONST PPOINT Points, int Count, RECTL BoundRect)
{
DPRINT("FillPolygon_WINDING\n");
PFILL_EDGE_LIST list = 0;
PFILL_EDGE_LIST ActiveEdges = 0;
int ScanLine;
return FALSE;
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_FillScanLineWinding(dc, ScanLine, ActiveEdges, SurfObj, BrushObj, RopMode);
}
/* Free Edge List. If any are left. */
POLYGONFILL_DestroyEdgeList(list);
return TRUE;
}
/* EOF */