mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
my Polygon algorithm sandbox
svn path=/trunk/; revision=5594
This commit is contained in:
parent
349c41fe42
commit
58d4ce9842
3 changed files with 928 additions and 0 deletions
811
reactos/apps/tests/polytest/polytest.cpp
Normal file
811
reactos/apps/tests/polytest/polytest.cpp
Normal file
|
@ -0,0 +1,811 @@
|
||||||
|
// this is a little 'sandbox' application I put together that duplicates
|
||||||
|
// the 'guts' of the Polygon algorithm. It allows for quick turn-around
|
||||||
|
// in testing the algorithm to see what effect your changes have.
|
||||||
|
//
|
||||||
|
// Royce3
|
||||||
|
|
||||||
|
// the stuff immediately following is support so that the sandbox code
|
||||||
|
// is nearly identical to the real thing.
|
||||||
|
// search for the _tagFILL_EDGE struct to find the beginning of the
|
||||||
|
// real stuff.
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <conio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define FASTCALL
|
||||||
|
#define STDCALL
|
||||||
|
#define INT int
|
||||||
|
#define BOOL bool
|
||||||
|
#define TRUE true
|
||||||
|
#define FALSE false
|
||||||
|
#define CONST const
|
||||||
|
#define MmCopyFromCaller memmove
|
||||||
|
|
||||||
|
#define ASSERT assert
|
||||||
|
|
||||||
|
#define EngFreeMem free
|
||||||
|
|
||||||
|
#define FILL_EDGE_ALLOC_TAG 0x45465044
|
||||||
|
|
||||||
|
#define FL_ZERO_MEMORY 1
|
||||||
|
|
||||||
|
#define DPRINT1 printf("%i:",__LINE__);printf
|
||||||
|
|
||||||
|
#define SCREENX 16
|
||||||
|
#define SCREENY 16
|
||||||
|
char screen[SCREENY][SCREENX];
|
||||||
|
|
||||||
|
#define EDGE_CHAR '*'
|
||||||
|
#define FILL_CHAR 'o'
|
||||||
|
|
||||||
|
void* EngAllocMem ( int zero, unsigned long size, int tag=0 )
|
||||||
|
{
|
||||||
|
void* p = malloc ( size );
|
||||||
|
if ( zero )
|
||||||
|
memset ( p, 0, size );
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline T MIN ( T a, T b )
|
||||||
|
{
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline T MAX ( T a, T b )
|
||||||
|
{
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline T abs ( T t )
|
||||||
|
{
|
||||||
|
return t < 0 ? -t : t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void putpixel ( int x, int y, char c )
|
||||||
|
{
|
||||||
|
ASSERT( x >= 0 && x < SCREENX && y >= 0 && y < SCREENY );
|
||||||
|
if ( screen[y][x] == c )
|
||||||
|
return;
|
||||||
|
if ( screen[y][x] == ' ' )
|
||||||
|
screen[y][x] = c;
|
||||||
|
else
|
||||||
|
screen[y][x] = '#';
|
||||||
|
}
|
||||||
|
|
||||||
|
void Line ( int x1, int y1, int x2, int y2, char c )
|
||||||
|
{
|
||||||
|
int dx = x2 - x1;
|
||||||
|
int dy = y2 - y1;
|
||||||
|
int absdx = abs(dx);
|
||||||
|
int absdy = abs(dy);
|
||||||
|
int EMax = MAX(absdx,absdy);
|
||||||
|
int E = EMax/2;
|
||||||
|
int xinc = dx < 0 ? -1 : 1,
|
||||||
|
yinc = dy < 0 ? -1 : 1;
|
||||||
|
if ( !dy )
|
||||||
|
{
|
||||||
|
while ( x1 != x2 )
|
||||||
|
{
|
||||||
|
putpixel ( x1, y1, c );
|
||||||
|
x1 += xinc;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( !dx )
|
||||||
|
{
|
||||||
|
while ( y1 != y2 )
|
||||||
|
{
|
||||||
|
putpixel ( x1, y1, c );
|
||||||
|
y1 += yinc;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for ( int i = 0; i < EMax; i++ )
|
||||||
|
{
|
||||||
|
putpixel ( x1, y1, c );
|
||||||
|
if ( absdy > absdx )
|
||||||
|
{
|
||||||
|
y1 += yinc;
|
||||||
|
E += absdx;
|
||||||
|
if ( E >= EMax )
|
||||||
|
{
|
||||||
|
E -= absdy;
|
||||||
|
x1 += xinc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x1 += xinc;
|
||||||
|
E += absdy;
|
||||||
|
if ( E >= EMax )
|
||||||
|
{
|
||||||
|
E -= absdx;
|
||||||
|
y1 += yinc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct tagPOINT
|
||||||
|
{
|
||||||
|
long x, y;
|
||||||
|
} POINT, *PPOINT, *LPPOINT;
|
||||||
|
|
||||||
|
typedef struct tagRECTL
|
||||||
|
{
|
||||||
|
long left, top, right, bottom;
|
||||||
|
} RECTL, *PRECTL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This struct is used for book keeping during polygon filling routines.
|
||||||
|
*/
|
||||||
|
typedef struct _tagFILL_EDGE
|
||||||
|
{
|
||||||
|
/*Basic line information*/
|
||||||
|
int FromX;
|
||||||
|
int FromY;
|
||||||
|
int ToX;
|
||||||
|
int ToY;
|
||||||
|
int dx;
|
||||||
|
int dy;
|
||||||
|
int absdx, absdy;
|
||||||
|
int x, y;
|
||||||
|
int xmajor;
|
||||||
|
|
||||||
|
/*Active Edge List information*/
|
||||||
|
int XIntercept[2];
|
||||||
|
int Error;
|
||||||
|
int ErrorMax;
|
||||||
|
int XDirection, YDirection;
|
||||||
|
|
||||||
|
/* The next edge in the active Edge List*/
|
||||||
|
struct _tagFILL_EDGE * pNext;
|
||||||
|
} FILL_EDGE;
|
||||||
|
|
||||||
|
typedef struct _FILL_EDGE_LIST
|
||||||
|
{
|
||||||
|
int Count;
|
||||||
|
FILL_EDGE** Edges;
|
||||||
|
} FILL_EDGE_LIST;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static
|
||||||
|
void
|
||||||
|
DEBUG_PRINT_ACTIVE_EDGELIST ( FILL_EDGE* list )
|
||||||
|
{
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
FASTCALL
|
||||||
|
POLYGONFILL_DestroyEdgeList(FILL_EDGE_LIST* list)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if ( list )
|
||||||
|
{
|
||||||
|
if ( list->Edges )
|
||||||
|
{
|
||||||
|
for ( i = 0; i < list->Count; i++ )
|
||||||
|
{
|
||||||
|
if ( list->Edges[i] )
|
||||||
|
EngFreeMem ( list->Edges[i] );
|
||||||
|
}
|
||||||
|
EngFreeMem ( list->Edges );
|
||||||
|
}
|
||||||
|
EngFreeMem ( list );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This makes and initiaizes an Edge struct for a line between two points.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
FILL_EDGE*
|
||||||
|
FASTCALL
|
||||||
|
POLYGONFILL_MakeEdge(POINT From, POINT To)
|
||||||
|
{
|
||||||
|
FILL_EDGE* rc = (FILL_EDGE*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE), FILL_EDGE_ALLOC_TAG);
|
||||||
|
|
||||||
|
if (0 == rc)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//DPRINT1("Making Edge: (%d, %d) to (%d, %d)\n", From.x, From.y, To.x, To.y);
|
||||||
|
//Now Fill the struct.
|
||||||
|
if ( To.y < From.y )
|
||||||
|
{
|
||||||
|
rc->FromX = To.x;
|
||||||
|
rc->FromY = To.y;
|
||||||
|
rc->ToX = From.x;
|
||||||
|
rc->ToY = From.y;
|
||||||
|
rc->YDirection = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc->FromX = From.x;
|
||||||
|
rc->FromY = From.y;
|
||||||
|
rc->ToX = To.x;
|
||||||
|
rc->ToY = To.y;
|
||||||
|
rc->YDirection = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc->x = rc->FromX;
|
||||||
|
rc->y = rc->FromY;
|
||||||
|
rc->dx = rc->ToX - rc->FromX;
|
||||||
|
rc->dy = rc->ToY - rc->FromY;
|
||||||
|
rc->absdx = abs(rc->dx);
|
||||||
|
rc->absdy = abs(rc->dy);
|
||||||
|
|
||||||
|
rc->xmajor = rc->absdx > rc->absdy;
|
||||||
|
|
||||||
|
rc->ErrorMax = MAX(rc->absdx,rc->absdy);
|
||||||
|
|
||||||
|
rc->Error = rc->ErrorMax / 2;
|
||||||
|
|
||||||
|
rc->XDirection = (rc->dx < 0)?(-1):(1);
|
||||||
|
|
||||||
|
rc->pNext = 0;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT1("MakeEdge (%i,%i)->(%i,%i) d=(%i,%i) dir=(%i,%i) err=%i max=%i\n",
|
||||||
|
From.x, From.y, To.x, To.y, rc->dx, rc->dy, rc->XDirection, rc->YDirection, rc->Error, rc->ErrorMax );
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** My Edge comparison routine.
|
||||||
|
** This is for scan converting polygon fill.
|
||||||
|
** First sort by MinY, then Minx, then slope.
|
||||||
|
**
|
||||||
|
** This comparison will help us determine which
|
||||||
|
** lines will become active first when scanning from
|
||||||
|
** top (min y) to bottom (max y).
|
||||||
|
**
|
||||||
|
** Return Value Meaning
|
||||||
|
** Negative integer element1 < element2
|
||||||
|
** Zero element1 = element2
|
||||||
|
** Positive integer element1 > element2
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
INT
|
||||||
|
FASTCALL
|
||||||
|
FILL_EDGE_Compare(FILL_EDGE* Edge1, FILL_EDGE* Edge2)
|
||||||
|
{
|
||||||
|
int e1 = Edge1->XIntercept[0] + Edge1->XIntercept[1];
|
||||||
|
int e2 = Edge2->XIntercept[0] + Edge2->XIntercept[1];
|
||||||
|
|
||||||
|
return e1 - e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Insert an edge into a list keeping the list in order.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
FASTCALL
|
||||||
|
POLYGONFILL_ActiveListInsert(FILL_EDGE** activehead, FILL_EDGE* NewEdge )
|
||||||
|
{
|
||||||
|
FILL_EDGE *pPrev, *pThis;
|
||||||
|
//DPRINT1("In POLYGONFILL_ActiveListInsert()\n");
|
||||||
|
ASSERT ( activehead && NewEdge );
|
||||||
|
if ( !*activehead )
|
||||||
|
{
|
||||||
|
NewEdge->pNext = NULL;
|
||||||
|
*activehead = NewEdge;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** First lets check to see if we have a new smallest value.
|
||||||
|
*/
|
||||||
|
if (FILL_EDGE_Compare(NewEdge, *activehead) <= 0)
|
||||||
|
{
|
||||||
|
NewEdge->pNext = *activehead;
|
||||||
|
*activehead = NewEdge;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** Ok, now scan to the next spot to put this item.
|
||||||
|
*/
|
||||||
|
pThis = *activehead;
|
||||||
|
pPrev = NULL;
|
||||||
|
while ( pThis && FILL_EDGE_Compare(pThis, NewEdge) < 0 )
|
||||||
|
{
|
||||||
|
pPrev = pThis;
|
||||||
|
pThis = pThis->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(pPrev);
|
||||||
|
NewEdge->pNext = pPrev->pNext;
|
||||||
|
pPrev->pNext = NewEdge;
|
||||||
|
//DEBUG_PRINT_ACTIVE_EDGELIST(*activehead);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Create a list of edges for a list of points.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
FILL_EDGE_LIST*
|
||||||
|
FASTCALL
|
||||||
|
POLYGONFILL_MakeEdgeList(PPOINT Points, int Count)
|
||||||
|
{
|
||||||
|
int CurPt = 0;
|
||||||
|
FILL_EDGE_LIST* list = 0;
|
||||||
|
FILL_EDGE* e = 0;
|
||||||
|
|
||||||
|
if ( 0 == Points || 2 > Count )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
list = (FILL_EDGE_LIST*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE_LIST), FILL_EDGE_ALLOC_TAG);
|
||||||
|
if ( 0 == list )
|
||||||
|
goto fail;
|
||||||
|
list->Count = 0;
|
||||||
|
list->Edges = (FILL_EDGE**)EngAllocMem(FL_ZERO_MEMORY, Count*sizeof(FILL_EDGE*), FILL_EDGE_ALLOC_TAG);
|
||||||
|
if ( !list->Edges )
|
||||||
|
goto fail;
|
||||||
|
memset ( list->Edges, 0, Count * sizeof(FILL_EDGE*) );
|
||||||
|
|
||||||
|
for ( CurPt = 1; CurPt < Count; ++CurPt )
|
||||||
|
{
|
||||||
|
e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[CurPt] );
|
||||||
|
if ( !e )
|
||||||
|
goto fail;
|
||||||
|
// if a straight horizontal line - who cares?
|
||||||
|
if ( !e->absdy )
|
||||||
|
EngFreeMem ( e );
|
||||||
|
else
|
||||||
|
list->Edges[list->Count++] = e;
|
||||||
|
}
|
||||||
|
e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[0] );
|
||||||
|
if ( !e )
|
||||||
|
goto fail;
|
||||||
|
if ( !e->absdy )
|
||||||
|
EngFreeMem ( e );
|
||||||
|
else
|
||||||
|
list->Edges[list->Count++] = e;
|
||||||
|
return list;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
DPRINT1("Out Of MEMORY!!\n");
|
||||||
|
POLYGONFILL_DestroyEdgeList ( list );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This slow routine uses the data stored in the edge list to
|
||||||
|
** calculate the x intercepts for each line in the edge list
|
||||||
|
** for scanline Scanline.
|
||||||
|
**TODO: Get rid of this floating point arithmetic
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
FASTCALL
|
||||||
|
POLYGONFILL_UpdateScanline(FILL_EDGE* pEdge, int Scanline)
|
||||||
|
{
|
||||||
|
if ( 0 == pEdge->dy )
|
||||||
|
return;
|
||||||
|
|
||||||
|
ASSERT ( pEdge->FromY < Scanline && pEdge->ToY >= Scanline );
|
||||||
|
|
||||||
|
if ( pEdge->xmajor )
|
||||||
|
{
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
pEdge->Error -= pEdge->ErrorMax;
|
||||||
|
pEdge->x += pEdge->XDirection;
|
||||||
|
ASSERT ( pEdge->Error < pEdge->ErrorMax );
|
||||||
|
}
|
||||||
|
|
||||||
|
pEdge->XIntercept[0] = pEdge->x;
|
||||||
|
pEdge->XIntercept[1] = pEdge->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT1("Line (%d, %d) to (%d, %d) intersects scanline %d at (%d,%d)\n",
|
||||||
|
pEdge->FromX, pEdge->FromY, pEdge->ToX, pEdge->ToY, Scanline, pEdge->XIntercept[0], pEdge->XIntercept[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This method updates the Active edge collection for the scanline Scanline.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
STDCALL
|
||||||
|
POLYGONFILL_BuildActiveList ( int Scanline, FILL_EDGE_LIST* list, FILL_EDGE** ActiveHead )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ASSERT ( list && ActiveHead );
|
||||||
|
*ActiveHead = 0;
|
||||||
|
for ( i = 0; i < list->Count; i++ )
|
||||||
|
{
|
||||||
|
FILL_EDGE* pEdge = list->Edges[i];
|
||||||
|
ASSERT(pEdge);
|
||||||
|
if ( pEdge->FromY < Scanline && pEdge->ToY >= Scanline )
|
||||||
|
{
|
||||||
|
POLYGONFILL_UpdateScanline ( pEdge, Scanline );
|
||||||
|
POLYGONFILL_ActiveListInsert ( ActiveHead, pEdge );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This method fills the portion of the polygon that intersects with the scanline
|
||||||
|
** Scanline.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
STDCALL
|
||||||
|
POLYGONFILL_FillScanLineAlternate ( int ScanLine, FILL_EDGE* ActiveHead )
|
||||||
|
{
|
||||||
|
FILL_EDGE *pLeft, *pRight;
|
||||||
|
|
||||||
|
if ( !ActiveHead )
|
||||||
|
return;
|
||||||
|
|
||||||
|
pLeft = ActiveHead;
|
||||||
|
pRight = pLeft->pNext;
|
||||||
|
ASSERT(pRight);
|
||||||
|
|
||||||
|
while ( NULL != pRight )
|
||||||
|
{
|
||||||
|
int x1 = pLeft->XIntercept[1];
|
||||||
|
int x2 = pRight->XIntercept[0]+1;
|
||||||
|
if ( x2 > x1 )
|
||||||
|
{
|
||||||
|
RECTL BoundRect;
|
||||||
|
BoundRect.top = ScanLine;
|
||||||
|
BoundRect.bottom = ScanLine + 1;
|
||||||
|
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,
|
||||||
|
dc->CombinedClip,
|
||||||
|
BrushObj,
|
||||||
|
x1,
|
||||||
|
ScanLine,
|
||||||
|
x2,
|
||||||
|
ScanLine,
|
||||||
|
&BoundRect, // Bounding rectangle
|
||||||
|
RopMode);*/ // MIX
|
||||||
|
}
|
||||||
|
pLeft = pRight->pNext;
|
||||||
|
pRight = pLeft ? pLeft->pNext : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
STDCALL
|
||||||
|
POLYGONFILL_FillScanLineWinding ( int ScanLine, FILL_EDGE* ActiveHead )
|
||||||
|
{
|
||||||
|
FILL_EDGE *pLeft, *pRight;
|
||||||
|
int winding = 0;
|
||||||
|
|
||||||
|
if ( !ActiveHead )
|
||||||
|
return;
|
||||||
|
|
||||||
|
pLeft = ActiveHead;
|
||||||
|
winding = pLeft->YDirection;
|
||||||
|
pRight = pLeft->pNext;
|
||||||
|
ASSERT(pRight);
|
||||||
|
|
||||||
|
while ( NULL != pRight )
|
||||||
|
{
|
||||||
|
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 = 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,
|
||||||
|
dc->CombinedClip,
|
||||||
|
BrushObj,
|
||||||
|
x1,
|
||||||
|
ScanLine,
|
||||||
|
x2,
|
||||||
|
ScanLine,
|
||||||
|
&BoundRect, // Bounding rectangle
|
||||||
|
RopMode);*/ // MIX
|
||||||
|
}
|
||||||
|
pLeft = pRight;
|
||||||
|
pRight = pLeft->pNext;
|
||||||
|
winding += pLeft->XDirection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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.
|
||||||
|
//The direction of each edge of the polygon is important.
|
||||||
|
BOOL
|
||||||
|
STDCALL
|
||||||
|
FillPolygon_WINDING(CONST PPOINT Points, int Count, RECTL BoundRect)
|
||||||
|
{
|
||||||
|
FILL_EDGE_LIST *list = 0;
|
||||||
|
FILL_EDGE *ActiveHead = 0;
|
||||||
|
int ScanLine;
|
||||||
|
|
||||||
|
DPRINT1("FillPolygon_WINDING\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_FillScanLineWinding(ScanLine, ActiveHead);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free Edge List. If any are left. */
|
||||||
|
POLYGONFILL_DestroyEdgeList(list);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
BOOL
|
||||||
|
Polygon ( CONST PPOINT UnsafePoints, int Count )
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
RECTL DestRect;
|
||||||
|
int CurrentPoint;
|
||||||
|
PPOINT Points;
|
||||||
|
|
||||||
|
DPRINT1("In W32kPolygon()\n");
|
||||||
|
|
||||||
|
if ( NULL == UnsafePoints || Count < 2)
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR_INVALID_PARAMETER\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy points from userspace to kernelspace */
|
||||||
|
Points = (PPOINT)EngAllocMem(0, Count * sizeof(POINT));
|
||||||
|
if (NULL == Points)
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR_NOT_ENOUGH_MEMORY\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
MmCopyFromCaller(Points, UnsafePoints, Count * sizeof(POINT));
|
||||||
|
if ( memcmp ( Points, UnsafePoints, Count * sizeof(POINT) ) )
|
||||||
|
{
|
||||||
|
free(Points);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
DestRect.right = MAX(DestRect.right, Points[CurrentPoint].x);
|
||||||
|
DestRect.top = MIN(DestRect.top, Points[CurrentPoint].y);
|
||||||
|
DestRect.bottom = MAX(DestRect.bottom, Points[CurrentPoint].y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the Polygon Edges with the current pen
|
||||||
|
for (CurrentPoint = 0; CurrentPoint < Count; ++CurrentPoint)
|
||||||
|
{
|
||||||
|
POINT To, From; //, Next;
|
||||||
|
|
||||||
|
/* Let CurrentPoint be i
|
||||||
|
* if i+1 > Count, Draw a line from Points[i] to Points[0]
|
||||||
|
* Draw a line from Points[i] to Points[i+1]
|
||||||
|
*/
|
||||||
|
From = Points[CurrentPoint];
|
||||||
|
if ( CurrentPoint + 1 >= Count)
|
||||||
|
{
|
||||||
|
To = Points[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
To = Points[CurrentPoint + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
}
|
||||||
|
/* determine the fill mode to fill the polygon. */
|
||||||
|
ret = FillPolygon_ALTERNATE(Points, Count, DestRect);
|
||||||
|
free(Points);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
memset ( screen, ' ', sizeof(screen) );
|
||||||
|
POINT pts[] =
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 12, 4 },
|
||||||
|
{ 4, 8 },
|
||||||
|
#else
|
||||||
|
{ 2, 8 },
|
||||||
|
{ 6, 2 },
|
||||||
|
{ 9, 8 },
|
||||||
|
{ 2, 4 },
|
||||||
|
{ 10, 4 }
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
Polygon ( pts,sizeof(pts)/sizeof(pts[0]) );
|
||||||
|
for ( int y = 0; y < SCREENY; y++ )
|
||||||
|
{
|
||||||
|
for ( int x = 0; x < SCREENX; x++ )
|
||||||
|
{
|
||||||
|
printf("%c", screen[y][x] );
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
DPRINT1("Done!\n");
|
||||||
|
(void)getch();
|
||||||
|
}
|
||||||
|
|
88
reactos/apps/tests/polytest/polytest.dsp
Normal file
88
reactos/apps/tests/polytest/polytest.dsp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
# Microsoft Developer Studio Project File - Name="polytest" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||||
|
|
||||||
|
CFG=polytest - Win32 Debug
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "polytest.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "polytest.mak" CFG="polytest - Win32 Debug"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "polytest - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||||
|
!MESSAGE "polytest - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName ""
|
||||||
|
# PROP Scc_LocalPath ""
|
||||||
|
CPP=cl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "polytest - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "polytest - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "polytest - Win32 Release"
|
||||||
|
# Name "polytest - Win32 Debug"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\polytest.cpp
|
||||||
|
# End Source File
|
||||||
|
# End Target
|
||||||
|
# End Project
|
29
reactos/apps/tests/polytest/polytest.dsw
Normal file
29
reactos/apps/tests/polytest/polytest.dsw
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||||
|
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Project: "polytest"=".\polytest.dsp" - Package Owner=<4>
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<4>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Global:
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<3>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
Loading…
Reference in a new issue