#include <math.h>
#include "ogEdgeTable.h"
void ogEdgeTable::AdvanceAET(void)
{
ogEdgeState * currentEdge;
ogEdgeState ** currentEdgePtr;
currentEdgePtr = &activeEdges;
currentEdge = activeEdges;
while (currentEdge!=NULL) {
--currentEdge->count;
if (currentEdge->count == 0)
{
// this edge is finished, so remove it from the AET
*currentEdgePtr = currentEdge->nextEdge;
// I'm thinking I should dispose currentEdge here!?
}
else
{
// advance the edge's x coord by minimum move
currentEdge->x += currentEdge->wholePixelXMove;
// determine whether it's time for X to advance one extra
currentEdge->errorTerm += currentEdge->errorTermAdjUp;
if (currentEdge->errorTerm > 0)
{
currentEdge->x += currentEdge->xDirection;
currentEdge->errorTerm -= currentEdge->errorTermAdjDown;
} // if
currentEdgePtr = ¤tEdge->nextEdge;
} // else
currentEdge = *currentEdgePtr;
} // while
} // void ogEdgeTable::AdvanceAET()
void ogEdgeTable::BuildGET(uInt32 numPoints, ogPoint2d * polyPoints)
{
int32 i, x1, y1, x2, y2, deltaX, deltaY, width, tmp;
ogEdgeState * newEdgePtr;
ogEdgeState * followingEdge;
ogEdgeState ** followingEdgeLink;
/*
* Creates a GET in the buffer pointed to by NextFreeEdgeStruc from
* the vertex list. Edge endpoints are flipped, if necessary, to
* guarantee all edges go top to bottom. The GET is sorted primarily
* by ascending Y start coordinate, and secondarily by ascending X
* start coordinate within edges with common Y coordinates }
*/
// Scan through the vertex list and put all non-0-height edges into
// the GET, sorted by increasing Y start coordinate}
for (i = 0; i < (int32)numPoints; i++)
{
// calculate the edge height and width
x1 = polyPoints[i].x;
y1 = polyPoints[i].y;
if (i == 0)
{
// wrap back around to the end of the list
x2 = polyPoints[numPoints-1].x;
y2 = polyPoints[numPoints-1].y;
}
else
{
x2 = polyPoints[i-1].x;
y2 = polyPoints[i-1].y;
} // else i!=0
if (y1 > y2)
{
tmp = x1;
x1 = x2;
x2 = tmp;
tmp = y1;
y1 = y2;
y2 = tmp;
} // if y1>y2
// skip if this can't ever be an active edge (has 0 height)
deltaY = y2-y1;
if (deltaY != 0)
{
newEdgePtr = new ogEdgeState;
newEdgePtr->xDirection = ((deltaX = x2-x1) > 0) ? 1 : -1;
width = fabs(deltaX);
newEdgePtr->x = x1;
newEdgePtr->startY = y1;
newEdgePtr->count = newEdgePtr->errorTermAdjDown = deltaY;
newEdgePtr->errorTerm = (deltaX >= 0) ? 0 : 1-deltaY;
if (deltaY >= width)
{
newEdgePtr->wholePixelXMove = 0;
newEdgePtr->errorTermAdjUp = width;
}
else
{
newEdgePtr->wholePixelXMove = (width / deltaY) * newEdgePtr->xDirection;
newEdgePtr->errorTermAdjUp = width % deltaY;
} // else
followingEdgeLink = &globalEdges;
while (true) {
followingEdge = *followingEdgeLink;
if ((followingEdge == NULL) ||
(followingEdge->startY > y1) ||
((followingEdge->startY == y1) &&
(followingEdge->x>=x1)))
{
newEdgePtr->nextEdge = followingEdge;
*followingEdgeLink = newEdgePtr;
break;
} // if
followingEdgeLink = &followingEdge->nextEdge;
} // while
} // if deltaY!=0
} // for
} // void ogEdgeTable::BuildGET()
void ogEdgeTable::BuildGET_G(uInt32 numPoints, ogPoint2d * polyPoints, ogRGBA8 * colours)
{
int32 i, x1, y1, x2, y2, deltaX, deltaY, width, tmp;
ogEdgeState * newEdgePtr;
ogEdgeState * followingEdge;
ogEdgeState ** followingEdgeLink;
ogRGBA8 c1, c2, cTmp;
/*
* Creates a GET in the buffer pointed to by NextFreeEdgeStruc from
* the vertex list. Edge endpoints are flipped, if necessary, to
* guarantee all edges go top to bottom. The GET is sorted primarily
* by ascending Y start coordinate, and secondarily by ascending X
* start coordinate within edges with common Y coordinates }
*/
// Scan through the vertex list and put all non-0-height edges into
// the GET, sorted by increasing Y start coordinate}
for (i = 0; i < (int32)numPoints; i++)
{
// calculate the edge height and width
x1 = polyPoints[i].x;
y1 = polyPoints[i].y;
c1 = colours[i];
if (0 == i)
{
// wrap back around to the end of the list
x2 = polyPoints[numPoints-1].x;
y2 = polyPoints[numPoints-1].y;
c2 = colours[numPoints-1];
}
else
{
x2 = polyPoints[i-1].x;
y2 = polyPoints[i-1].y;
c2 = colours[i-1];
} // else i!=0
if (y1 > y2)
{
tmp = x1;
x1 = x2;
x2 = tmp;
tmp = y1;
y1 = y2;
y2 = tmp;
cTmp = c1;
c1 = c2;
c2 = cTmp;
} // if y1>y2
// skip if this can't ever be an active edge (has 0 height)
deltaY = y2-y1;
if (deltaY != 0)
{
newEdgePtr = new ogEdgeState;
newEdgePtr->colour = c1;
newEdgePtr->xDirection = ((deltaX = x2-x1) > 0) ? 1 : -1;
newEdgePtr -> rStepY = ((c2.red - c1.red +1) << 16) / deltaY;
newEdgePtr -> gStepY = ((c2.green - c1.green +1) << 16) / deltaY;
newEdgePtr -> bStepY = ((c2.blue - c1.blue +1) << 16) / deltaY;
newEdgePtr -> aStepY = ((c2.alpha - c1.alpha +1) << 16) / deltaY;
newEdgePtr -> rIncY = newEdgePtr -> gIncY = 0;
newEdgePtr -> bIncY = newEdgePtr -> aIncY = 0;
width = fabs(deltaX);
newEdgePtr->x = x1;
newEdgePtr->startY = y1;
newEdgePtr->count = newEdgePtr->errorTermAdjDown = deltaY;
newEdgePtr->errorTerm = (deltaX >= 0) ? 0 : 1-deltaY;
if (deltaY >= width)
{
newEdgePtr->wholePixelXMove = 0;
newEdgePtr->errorTermAdjUp = width;
}
else
{
newEdgePtr->wholePixelXMove = (width / deltaY) * newEdgePtr->xDirection;
newEdgePtr->errorTermAdjUp = width % deltaY;
} // else
followingEdgeLink = &globalEdges;
while (true) {
followingEdge = *followingEdgeLink;
if ((followingEdge == NULL) ||
(followingEdge->startY > y1) ||
((followingEdge->startY == y1) &&
(followingEdge->x >= x1)))
{
newEdgePtr->nextEdge = followingEdge;
*followingEdgeLink = newEdgePtr;
break;
} // if
followingEdgeLink = &followingEdge->nextEdge;
} // while
} // if deltaY!=0
} // for
return;
} // ogEdgeTable::BuildGET_G
void ogEdgeTable::MoveXSortedToAET(int32 yToMove)
{
ogEdgeState * AETEdge;
ogEdgeState * tempEdge;
ogEdgeState ** AETEdgePtr;
int32 currentX;
/* The GET is Y sorted. Any edges that start at the d%%esired Y
* coordinate will be first in the GET, so we'll move edges from
* the GET to AET until the first edge left in the GET is no
* longer at the d%%esired Y coordinate. Also, the GET is X sorted
* within each Y cordinate, so each successive edge we add to the
* AET is guaranteed to belong later in the AET than the one just
* added.
*/
AETEdgePtr = &activeEdges;
while ((globalEdges != NULL) && (globalEdges->startY == yToMove))
{
currentX = globalEdges->x;
// link the new edge into the AET so that the AET is still
// sorted by X coordinate
while (true) {
AETEdge = *AETEdgePtr;
if ((AETEdge == NULL) || (AETEdge->x >= currentX))
{
tempEdge = globalEdges->nextEdge;
*AETEdgePtr = globalEdges;
globalEdges->nextEdge = AETEdge;
AETEdgePtr = &globalEdges->nextEdge;
globalEdges = tempEdge;
break;
} else AETEdgePtr = &AETEdge->nextEdge;
} // while true
} // while globalEdges!=NULL and globalEdges->startY==yToMove
} // void ogEdgeTable::MoveXSortedToAET()
void ogEdgeTable::ScanOutAET(ogSurface & destObject, int32 yToScan, uInt32 colour)
{
ogEdgeState * currentEdge;
int32 leftX;
/* Scan through the AET, drawing line segments as each pair of edge
* crossings is encountered. The nearest pixel on or to the right
* of the left edges is drawn, and the nearest pixel to the left
* of but not on right edges is drawn
*/
currentEdge = activeEdges;
while (currentEdge != NULL) {
leftX = currentEdge->x;
currentEdge = currentEdge->nextEdge;
if (currentEdge != NULL)
{
if (currentEdge->x > leftX)
destObject.ogHLine(leftX, currentEdge->x-1, yToScan, colour);
currentEdge = currentEdge->nextEdge;
} // if currentEdge != NULL
} // while
return;
} // void ogEdgeTable::ScanOutAET()
void ogEdgeTable::ScanOutAET_G(ogSurface & destObject, int32 yToScan)
{
ogEdgeState * currentEdge;
int32 leftX, count;
int32 rStepX, gStepX, bStepX, aStepX;
int32 rIncX, gIncX, bIncX, aIncX;
int32 lR, lG, lB, lA;
int32 rR, rG, rB, rA;
int32 dR, dG, dB, dA;
int32 dist;
/* Scan through the AET, drawing line segments as each pair of edge
* crossings is encountered. The nearest pixel on or to the right
* of the left edges is drawn, and the nearest pixel to the left
* of but not on right edges is drawn
*/
currentEdge = activeEdges;
while (currentEdge != NULL)
{
leftX = currentEdge->x;
lR = currentEdge->colour.red;
lG = currentEdge->colour.green;
lB = currentEdge->colour.blue;
lA = currentEdge->colour.alpha;
lR += currentEdge->rIncY >> 16;
lG += currentEdge->gIncY >> 16;
lB += currentEdge->bIncY >> 16;
lA += currentEdge->aIncY >> 16;
currentEdge->rIncY += currentEdge->rStepY;
currentEdge->gIncY += currentEdge->gStepY;
currentEdge->bIncY += currentEdge->bStepY;
currentEdge->aIncY += currentEdge->aStepY;
currentEdge = currentEdge->nextEdge;
if (currentEdge != NULL)
{
if (leftX != currentEdge->x)
{
rR = currentEdge->colour.red;
rG = currentEdge->colour.green;
rB = currentEdge->colour.blue;
rA = currentEdge->colour.alpha;
rR += currentEdge->rIncY >> 16;
rG += currentEdge->gIncY >> 16;
rB += currentEdge->bIncY >> 16;
rA += currentEdge->aIncY >> 16;
currentEdge->rIncY += currentEdge->rStepY;
currentEdge->gIncY += currentEdge->gStepY;
currentEdge->bIncY += currentEdge->bStepY;
currentEdge->aIncY += currentEdge->aStepY;
dR = rR - lR;
dG = rG - lG;
dB = rB - lB;
dA = rA - lA;
dist = currentEdge->x - leftX;
rStepX = (dR << 16) / dist;
gStepX = (dG << 16) / dist;
bStepX = (dB << 16) / dist;
aStepX = (dA << 16) / dist;
rIncX = gIncX = bIncX = aIncX = 0;
for (count = leftX; count < currentEdge->x; count++)
{
destObject.ogSetPixel(count, yToScan,
static_cast<uInt8>(lR + (rIncX >> 16)),
static_cast<uInt8>(lG + (gIncX >> 16)),
static_cast<uInt8>(lB + (bIncX >> 16)),
static_cast<uInt8>(lA + (aIncX >> 16)) );
rIncX += rStepX;
gIncX += gStepX;
bIncX += bStepX;
aIncX += aStepX;
} // for
}
currentEdge = currentEdge->nextEdge;
} // if currentEdge != NULL
} // while
} // void ogEdgeTable::ScanOutAET_G()
void ogEdgeTable::XSortAET(void)
{
ogEdgeState * currentEdge;
ogEdgeState * tempEdge;
ogEdgeState ** currentEdgePtr;
bool swapOccurred;
if (activeEdges == NULL) return;
do {
swapOccurred = false;
currentEdgePtr = &activeEdges;
currentEdge = activeEdges;
while (currentEdge->nextEdge != NULL)
{
if (currentEdge->x > currentEdge->nextEdge->x)
{
// the second edge has a lower x than the first
// swap them in the AET
tempEdge = currentEdge->nextEdge->nextEdge;
*currentEdgePtr = currentEdge->nextEdge;
currentEdge->nextEdge->nextEdge = currentEdge;
currentEdge->nextEdge = tempEdge;
swapOccurred = true;
} // if
currentEdgePtr = &((*currentEdgePtr)->nextEdge);
currentEdge = *currentEdgePtr;
} // while
} while (swapOccurred);
} // void ogEdgeTable::XSortAET()
ogEdgeTable::~ogEdgeTable(void)
{
ogEdgeState * edge;
ogEdgeState * tmpEdge;
tmpEdge = globalEdges;
// first walk the global edges and delete any non-null nodes
while (tmpEdge != NULL)
{
edge = tmpEdge;
tmpEdge = edge->nextEdge;
delete edge;
} // while
tmpEdge = activeEdges;
// next walk the activeEdges and delete any non-null nodes. Note that this should
// always be null
while (tmpEdge != NULL)
{
edge = tmpEdge;
tmpEdge = edge->nextEdge;
delete edge;
} // while
return;
} // ogEdgeTable::~ogEdgeTable()