mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +00:00
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:
parent
4f6a2a6124
commit
d4deb682ee
5 changed files with 606 additions and 518 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue