📄 path.c
字号:
// !TODO!
Enter(L"InitializeEdgeList");
EdgeList->Array = (PERM3_EDGE *)SystemAlloc(NumEdges * sizeof(PERM3_EDGE));
if (EdgeList->Array != NULL) {
EdgeList->Size = NumEdges;
EdgeList->Count = 0;
EdgeList->MinY = 0;
EdgeList->MaxY = 0;
EdgeList->FirstTop = NULL;
EdgeList->FirstBottom = NULL;
EdgeList->FirstActive = NULL;
}
else {
Error(L"System memory allocation failure.\n");
}
Exit(L"InitializeEdgeList");
}
BOOL
AddEdge(
PERM3_EDGE_LIST * EdgeList,
FIX x1,
FIX y1,
FIX x2,
FIX y2
)
{
// AddEdge
// This function adds an edge to the given edge list. The edge is defined
// by two points, given in 28:4 fixed point.
// Local variables.
BOOL FnRetVal = FALSE;
BOOL SpaceAvailable = FALSE;
PERM3_EDGE * NewEdge;
LONG dX, dY;
LONG IntegralAdvance;
LONG FractionalAdvance;
LONG FractionalTotal;
// Check parameters.
// !TODO!
Enter(L"AddEdge");
if (EdgeList->Count < EdgeList->Size) {
SpaceAvailable = TRUE;
}
else {
// We have run out of space. We need more.
EdgeList->Array = SystemReAlloc(EdgeList->Array,
(EdgeList->Size + EDGE_ARRAY_GROW) * sizeof(PERM3_EDGE));
if (EdgeList->Array != NULL) {
EdgeList->Size += EDGE_ARRAY_GROW;
SpaceAvailable = TRUE;
}
}
if (SpaceAvailable) {
NewEdge = &EdgeList->Array[EdgeList->Count];
if (y1 < y2) {
NewEdge->Direction = 1;
}
else {
NewEdge->Direction = -1;
Swap(y1,y2);
Swap(x1,x2);
}
// Discard edges with dY == 0.
if (((y1 + 15) & ~15) < ((y2 + 15) & ~15)) {
EdgeList->Count++;
dX = x2 - x1;
dY = y2 - y1;
IntegralAdvance = dX / dY;
FractionalAdvance = dX % dY;
FractionalTotal = 0;
while (y1 & 15) {
y1++;
x1 += IntegralAdvance;
FractionalTotal += FractionalAdvance;
if (FractionalAdvance >= 0) {
if (FractionalTotal > 0) {
FractionalTotal -= dY;
x1++;
}
}
else {
if (FractionalTotal <= -dY) {
FractionalTotal += dY;
x1--;
}
}
}
// Now, (x1,y1) are the 16:16 coordinates where the edge intersects a row.
NewEdge->TopY = y1 >> 4;
NewEdge->BottomY = (y2 + 15) >> 4;
NewEdge->TopX = x1;
NewEdge->NextTop = NULL;
NewEdge->NextBottom = NULL;
NewEdge->XIntegralAdvance = (dX * 16) / dY;
NewEdge->XFractionalAdvance = (dX * 16) % dY;
NewEdge->Height = dY;
NewEdge->FractionalTotalStart = FractionalTotal;
// This insures that we resort the edgelist next time we draw it.
EdgeList->FirstTop = NULL;
}
FnRetVal = TRUE;
}
else {
Error(L"No space available to grow edge list!\n");
}
Exit(L"AddEdge");
return FnRetVal;
}
BOOL
FillEdge(
PERM3_EDGE_LIST * EdgeList,
PERM3_BLT_PARAM * Parameters
)
{
// FillEdge
// This method, given a closed path as defined by the given edge list,
// will rasterize that list. It uses a given blit structure, assuming that
// by simply modifying the destination rectangle and repeatedly calling
// TryBothBlt will have the desired effect.
// Local variables.
BOOL FnRetVal = FALSE;
LONG NewEdgeNum;
PERM3_EDGE * Edge;
PERM3_EDGE ** IndirectEdge;
ULONG EdgeCount;
ULONG ClipRectCount;
const RECT * ClipRect;
RECT ScreenRect;
RECT * DestRect;
LONG y;
LONG LastRow;
PERM3_EDGE * TopList;
PERM3_EDGE * BottomList;
BOOL Swapped;
LONG LeftX;
LONG RightX;
// Check parameters.
// !TODO!
Enter(L"FillEdge");
DestRect = (RECT *)Parameters->DestRect;
if (EdgeList->Count >= 1) {
if (EdgeList->FirstTop == NULL) {
// Resort the list by TopY and BottomY.
for (Edge = EdgeList->Array, NewEdgeNum = 0;
NewEdgeNum < EdgeList->Count;
NewEdgeNum++, Edge++) {
// Insert into the list sorted by TopY.
for (IndirectEdge = &EdgeList->FirstTop;
(*IndirectEdge != NULL) && (Edge->TopY > (*IndirectEdge)->TopY);
IndirectEdge = &((*IndirectEdge)->NextTop));
Edge->NextTop = *IndirectEdge;
*IndirectEdge = Edge;
// Insert into the list sorted by BottomY.
for (IndirectEdge = &EdgeList->FirstBottom;
(*IndirectEdge != NULL) && (Edge->BottomY > (*IndirectEdge)->BottomY);
IndirectEdge = &((*IndirectEdge)->NextBottom));
if (*IndirectEdge == NULL) {
EdgeList->MaxY = Edge->BottomY;
}
Edge->NextBottom = *IndirectEdge;
*IndirectEdge = Edge;
}
EdgeList->MinY = EdgeList->FirstTop->TopY;
}
// Now, we iterate over the clipping rectangles.
// If we have no clipping rectangles, we clip to the screen.
if (Parameters->ClipRectCount == 0) {
ScreenRect.left = 0;
ScreenRect.top = 0;
ScreenRect.right = GetDisplayModeWidth(GetCurrentMode());
ScreenRect.bottom = GetDisplayModeHeight(GetCurrentMode());
Parameters->ClipRectCount = 1;
Parameters->ClipRect = &ScreenRect;
}
for (ClipRectCount = 0;
ClipRectCount < Parameters->ClipRectCount;
ClipRectCount++) {
ClipRect = &(Parameters->ClipRect[ClipRectCount]);
if (EdgeList->MinY >= ClipRect->bottom ||
EdgeList->MaxY < ClipRect->top) {
// We have completely clipped the edge, vertically.
continue;
}
// Loop over all of the rows spanned by this edge list.
TopList = EdgeList->FirstTop;
BottomList = EdgeList->FirstBottom;
EdgeList->FirstActive = NULL;
LastRow = min(EdgeList->MaxY, ClipRect->bottom);
for (y = EdgeList->MinY;
y < LastRow;
y++) {
DestRect->top = y;
DestRect->bottom = y + 1;
// Add new edges to the active list.
for (;
(TopList != NULL) && (TopList->TopY <= y);
TopList = TopList->NextTop) {
// Reset x and error accumulator for line.
TopList->FractionalTotal = TopList->FractionalTotalStart;
TopList->X = TopList->TopX;
// Insert into list sorted by X.
for (IndirectEdge = &(EdgeList->FirstActive);
(*IndirectEdge != NULL) && (TopList->X > (*IndirectEdge)->X);
IndirectEdge = &((*IndirectEdge)->NextActive));
TopList->NextActive = *IndirectEdge;
*IndirectEdge = TopList;
}
// Remove edges from active list that do not intersect with our
// scanline.
for (;
(BottomList != NULL) && (BottomList->BottomY <= y);
BottomList = BottomList->NextBottom) {
for (IndirectEdge = &(EdgeList->FirstActive);
(*IndirectEdge != NULL) && (*IndirectEdge != BottomList);
IndirectEdge = &((*IndirectEdge)->NextActive));
if (*IndirectEdge != NULL) {
*IndirectEdge = (*IndirectEdge)->NextActive;
}
}
// Now, sort the active edge list by x.
do {
Swapped = FALSE;
for (IndirectEdge = &(EdgeList->FirstActive);
(*IndirectEdge != NULL) && ((*IndirectEdge)->NextActive != NULL);
IndirectEdge = &((*IndirectEdge)->NextActive)) {
Edge = *IndirectEdge;
if (Edge->X > Edge->NextActive->X) {
Swapped = TRUE;
*IndirectEdge = Edge->NextActive;
Edge->NextActive = Edge->NextActive->NextActive;
(*IndirectEdge)->NextActive = Edge;
}
}
} while (Swapped);
EdgeCount = 0;
// Draw each span for the current scanline.
if (y >= ClipRect->top) {
for (Edge = EdgeList->FirstActive;
Edge != NULL;
Edge = Edge->NextActive) {
LeftX = (Edge->X + 15) >> 4;
for (EdgeCount = Edge->Direction;
EdgeCount != 0;
) {
Edge = Edge->NextActive;
if (Edge == NULL) {
break;
}
EdgeCount += Edge->Direction;
}
if (Edge != NULL) {
RightX = (Edge->X + 15) >> 4;
if (LeftX < ClipRect->left) LeftX = ClipRect->left;
if (RightX > ClipRect->right) RightX = ClipRect->right;
if (LeftX < RightX) {
DestRect->left = LeftX;
DestRect->right = RightX;
FnRetVal = TryBothBlt(Parameters);
if (!FnRetVal) {
return FnRetVal;
}
}
}
else {
Error(L"Unmatched line segment in polygon fill.\n");
return FALSE;
}
}
}
// Now, increment edges.
for (Edge = EdgeList->FirstActive;
Edge != NULL;
Edge = Edge->NextActive) {
Edge->X += Edge->XIntegralAdvance;
Edge->FractionalTotal += Edge->XFractionalAdvance;
if (Edge->XFractionalAdvance >= 0) {
if (Edge->FractionalTotal > 0) {
Edge->FractionalTotal -= Edge->Height;
Edge->X++;
}
}
else {
if (Edge->FractionalTotal <= -Edge->Height) {
Edge->FractionalTotal += Edge->Height;
Edge->X--;
}
}
}
}
}
}
else {
// Can't do anything with a NULL polygon. Draw nothing and call it
// success.
FnRetVal = TRUE;
}
Exit(L"FillEdge");
return FnRetVal;
}
void
DestroyEdgeList(
PERM3_EDGE_LIST * EdgeList
)
{
// DestroyEdgeList
// This function frees any resources allocated in the course of using the
// given PERM3_EDGE_LIST.
// Check parameters.
// !TODO!
Enter(L"DestroyEdgeList");
if (EdgeList->Array != NULL) {
SystemFree(EdgeList->Array);
EdgeList->Array = NULL;
}
Exit(L"DestroyEdgeList");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -