📄 xpol5.c
字号:
double winding rule fill desired (intersection of two sets of edges,
used for arcs)
allEdgesAreLines = 1 if all edges in the GET are line edges, 0 if some
edges are not lines (quadrant arcs, for example)
***IMPORTANT NOTE***
blitCnt is modified in the passed-in blitRcd in mwSA, so this should be a
throwaway copy, not a permanent or reusable blitRcd. */
void mwScanGET(void **GETPtrPtr, blitRcd *fillRcd, int scanRcdSize, int shape,
int fillRule, int allEdgesAreLines)
{
lineEdgeV **AETEdgeLink;
lineEdgeV *AETPtr;
lineEdgeV *TempEdge;
long AETPtrPtr;
lclFillRule = fillRule; /* pick up passed parameters */
allLineEdges = allEdgesAreLines;
lclFillRcd = fillRcd;
/* now set up the fill record according to the settings in the current port */
*lclFillRcd = grafBlit; /* Init local blitRcd from grafBlit */
/* Point blitList to area after local blitRcd */
lclFillRcd->blitList = (long) lclFillRcd + sizeof(blitRcd);
/* calculate the last address at which a rect can start in the blitRcd
without being the last rect that can fit in the blitRcd */
highWater = (rect *) ((long) lclFillRcd + scanRcdSize - 2 * sizeof(rect));
rectCount = 0; /* no rects yet */
rectBase = (rect *) lclFillRcd->blitList; /* point to the first rect location */
rectPtr = rectBase;
leGETPtr = (lineEdgeV *)*GETPtrPtr;
AETEdgeLink = (lineEdgeV **) (&AETPtrPtr);
if (leGETPtr == 0) return; /* nothing to do */
*AETEdgeLink = 0; /* AETPtr = NULL */
currentY = leGETPtr->StartY; /* initial scan line */
sameAsLast = 0; /* mark that the first line can't be the same as the
preceding line */
/* Moves all edges that start at the specified Y coordinate from the GET to
the AET, placing them in the AET so as to maintain the X sorting of the AET.
The GET is Y sorted. Any edges that start at the desired 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 desired Y coordinate. Also, the GET
is X sorted within each Y coordinate, so each successive edge we add to the
AET is guaranteed to belong later in the AET than the one we just added. */
do {
while (leGETPtr != 0)
{
if (leGETPtr->StartY != currentY) break; /* done if we've found all
the edges that start on this scan line */
sameAsLast = 0; /* mark that this line isn't the same as the preceding
line (because we just added another edge) */
/* now link the new edge into the AET so that the AET is still sorted by
X coordinate */
while ((AETPtr = *AETEdgeLink) != 0)
{
if (AETPtr->CurrentX >= leGETPtr->CurrentX) break; /* add here if
new X is less than or equal to the new edge's X */
AETEdgeLink = &AETPtr->NextEdge;
}
/* we've found the link location; unlink the edge from the GET and link
it into the AET */
TempEdge = leGETPtr->NextEdge;
*AETEdgeLink = leGETPtr;
AETEdgeLink = &leGETPtr->NextEdge;
leGETPtr->NextEdge = AETPtr;
leGETPtr = TempEdge;
}
*GETPtrPtr = leGETPtr; /* update leGETPtr */
AETEdgeLink = (lineEdgeV **) (&AETPtrPtr);
if ((AETPtr = *AETEdgeLink) != 0) /* skip the remaining functions if the */
{ /* AET is empty */
ScanOutAET(AETPtr);
/* Advance each edge in the AET by one scan line. Remove edges that
have been fully scanned. */
while ((AETPtr = *AETEdgeLink) != 0) /* skip if nothing in AET */
{
AETPtr->Count--; /* decrement the y counter */
if (AETPtr->Count == 0) /* check if done with edge */
{ /* yes, remove it from the AET */
sameAsLast = 0;
*AETEdgeLink = AETPtr->NextEdge;
}
else
{ /* count off one scan line for this edge */
if (allLineEdges != 0) /* are all the edges lines? */
{ /* yes, handle directly. Note that this loop handles
sameAsLast directly */
if (AETPtr->WholePixelXMoveV != 0)
{ /* advance the edge's X coordinate by the minimum
# of pixels */
sameAsLast = 0;
AETPtr->CurrentX += (short) AETPtr->WholePixelXMoveV;
}
AETPtr->ErrorTermV += AETPtr->ErrorTermAdjUpV;
if (AETPtr->ErrorTermV > 0)
{ /* the error term turned over, so move X one more */
sameAsLast = 0;
AETPtr->CurrentX += (short) AETPtr->XDirection;
AETPtr->ErrorTermV -= AETPtr->ErrorTermAdjDownV;
}
}
else
{ /* Use the StepVector field to call each edge's stepping
routine to handle the case where not all edges are lines. */
sameAsLast &= AETPtr->StepVector(AETPtr);
}
AETEdgeLink = &AETPtr->NextEdge;
}
}
AETEdgeLink = (lineEdgeV **) (&AETPtrPtr);
XSortAET(AETEdgeLink);
}
currentY++;
/* continue while any edges remain in either the AET or the GET */
} while ((*GETPtrPtr != 0) || (*AETEdgeLink != 0));
if (rectCount != 0) /* do any rects remain? */
{ /* yes, do the remaining rects */
lclFillRcd->blitCnt = rectCount; /* set the count field in the blitRcd */
lclFillRcd->blitDmap->prFill(lclFillRcd); /* draw the rectangles */
}
return;
}
/* The following four functions are the vectored AET stepping routines. (Steps X
from current scan line to next.) They are called through the StepVector function.
Returns a 1 if this edge's X didn't change from last time, 0 if it did change. */
/* Straight edge stepper */
byte StepStraightEdge(lineEdgeV *CurrentEdge)
{
byte chngSts;
chngSts = 1; /* assume edge doesn't change from last time */
/* advance the edge's X coordinate by the minimum # of pixels */
if (CurrentEdge->WholePixelXMoveV != 0)
{ /* mark that this line isn't the same as on the preceding line */
chngSts = 0;
CurrentEdge->CurrentX += (short) CurrentEdge->WholePixelXMoveV;
}
/* determine whether it's time for X to advance one extra */
CurrentEdge->ErrorTermV += CurrentEdge->ErrorTermAdjUpV;
if (CurrentEdge->ErrorTermV > 0)
{ /* the error term turned over, so move X one more */
chngSts = 0;
CurrentEdge->CurrentX += (short) CurrentEdge->XDirection;
CurrentEdge->ErrorTermV -= CurrentEdge->ErrorTermAdjDownV;
}
return (chngSts); /* return line-change status */
}
/* Vertical edge stepper */
byte StepVertical(qarcState *CurrentEdge)
{
return (1); /* X never changes from last time */
}
/* Top-half quadrant arc stepper */
/* Steps y by 1, adjusts yadjust and error term accordingly, then steps x
as far as possible. */
#ifdef FIXPOINT
byte StepQATopNativeSize(qarcState *CurrentEdge)
{
int dFix_sub(dblFix *first, dblFix *second, dblFix *result);
int dFix_add(dblFix *first, dblFix *second, dblFix *result);
dblFix stepY, tempDF;
/* increment the y change in the error to the value for the next y */
tempDF.fUpper = (CurrentEdge->qaASqX2 >> 16);
tempDF.fLower = (CurrentEdge->qaASqX2 << 16);
dFix_sub(&CurrentEdge->qaYAdjust, &tempDF, &stepY);
if ((stepY.fLower == 0) && (stepY.fUpper == 0))
{ /* we're at the final (bottom) point on the arc; handle specially
because otherwise the maximum extent of the arc at Y==0 isn't reached */
CurrentEdge->CurrentX = (short) CurrentEdge->qaFinalX; /* use x-axis intercept */
return (0); /* we don't really know, so assume edge is not previous edge */
}
CurrentEdge->qaYAdjust = stepY; /* remember new yadjust */
dFix_sub(&CurrentEdge->qaErrTerm, &stepY, &CurrentEdge->qaErrTerm); /* error term -= yadjust */
if (CurrentEdge->qaErrTerm.fUpper >= 0) return (1); /* can't advance x at all */
/* advance x until error term >= 0 (at which point x will be as far as it
can go for this y) */
tempDF.fUpper = (CurrentEdge->qaBSqX2 >> 16);
tempDF.fLower = (CurrentEdge->qaBSqX2 << 16);
do {
CurrentEdge->CurrentX += (short) CurrentEdge->XDirection;
dFix_add(&CurrentEdge->qaXAdjust, &tempDF, &CurrentEdge->qaXAdjust);
dFix_add(&CurrentEdge->qaErrTerm, &CurrentEdge->qaXAdjust,
&CurrentEdge->qaErrTerm);
} while (CurrentEdge->qaErrTerm.fUpper < 0); /* continue until the error term
turns over */
return (0); /* edge isn't same this time as last time */
}
#else
byte StepQATopNativeSize(qarcState *CurrentEdge)
{
double stepY;
/* increment the y change in the error to the value for the next y */
stepY = CurrentEdge->qaYAdjust - CurrentEdge->qaASqX2;
if (stepY == 0)
{ /* we're at the final (bottom) point on the arc; handle specially
because otherwise the maximum extent of the arc at Y==0 isn't reached */
CurrentEdge->CurrentX = (short) CurrentEdge->qaFinalX; /* use x-axis intercept */
return (0); /* we don't really know, so assume edge is not previous edge */
}
CurrentEdge->qaYAdjust = stepY; /* remember new yadjust */
CurrentEdge->qaErrTerm -= stepY; /* error term -= yadjust */
if (CurrentEdge->qaErrTerm >= 0) return (1); /* can't advance x at all */
/* advance x until error term >= 0 (at which point x will be as far as it
can go for this y) */
do {
CurrentEdge->CurrentX += (short) CurrentEdge->XDirection;
CurrentEdge->qaXAdjust += CurrentEdge->qaBSqX2;
CurrentEdge->qaErrTerm += CurrentEdge->qaXAdjust;
} while (CurrentEdge->qaErrTerm < 0); /* continue until the error term
turns over */
return (0); /* edge isn't same this time as last time */
}
#endif
/* Bottom-half quadrant arc stepper */
/* Steps y by 1, adjusts yadjust and error term accordingly, then steps x
as far as possible. */
#ifdef FIXPOINT
byte StepQABottomNativeSize(qarcState *CurrentEdge)
{
int dFix_sub(dblFix *first, dblFix *second, dblFix *result);
int dFix_add(dblFix *first, dblFix *second, dblFix *result);
dblFix stepY, tempDF;
stepY = CurrentEdge->qaYAdjust; /* need later */
/* increment the y change in the error to the value for the next y */
tempDF.fUpper = (CurrentEdge->qaASqX2 >> 16);
tempDF.fLower = (CurrentEdge->qaASqX2 << 16);
dFix_add(&CurrentEdge->qaYAdjust, &tempDF, &CurrentEdge->qaYAdjust);
dFix_add(&CurrentEdge->qaErrTerm, &stepY, &CurrentEdge->qaErrTerm);
if ((CurrentEdge->qaErrTerm.fUpper < 0) || ((CurrentEdge->qaXAdjust.fLower == 0)
&& (CurrentEdge->qaXAdjust.fUpper == 0))) return (1); /* can't advance x any farther */
/* advance x until error term < 0 (at which point x will be as far as it
can go for this y) */
tempDF.fUpper = (CurrentEdge->qaBSqX2 >> 16);
tempDF.fLower = (CurrentEdge->qaBSqX2 << 16);
do {
CurrentEdge->CurrentX += (short) CurrentEdge->XDirection;
dFix_sub(&CurrentEdge->qaXAdjust, &tempDF, &CurrentEdge->qaXAdjust);
if ((CurrentEdge->qaXAdjust.fLower == 0) &&
(CurrentEdge->qaXAdjust.fUpper == 0)) break;
dFix_sub(&CurrentEdge->qaErrTerm, &CurrentEdge->qaXAdjust,
&CurrentEdge->qaErrTerm);
} while (!(CurrentEdge->qaErrTerm.fUpper < 0)); /* continue until the error term turns over */
return (0); /* edge isn't same this time as last time */
}
#else
byte StepQABottomNativeSize(qarcState *CurrentEdge)
{
double stepY;
stepY = CurrentEdge->qaYAdjust; /* need later */
/* increment the y change in the error to the value for the next y */
CurrentEdge->qaYAdjust += CurrentEdge->qaASqX2;
CurrentEdge->qaErrTerm += stepY; /* error term += old yadjust */
if ((CurrentEdge->qaErrTerm < 0) || (CurrentEdge->qaXAdjust == 0))
return (1); /* can't advance x any farther */
/* advance x until error term < 0 (at which point x will be as far as it
can go for this y) */
do {
CurrentEdge->CurrentX += (short) CurrentEdge->XDirection;
CurrentEdge->qaXAdjust -= CurrentEdge->qaBSqX2;
if (CurrentEdge->qaXAdjust == 0) break;
CurrentEdge->qaErrTerm -= CurrentEdge->qaXAdjust;
} while (CurrentEdge->qaErrTerm >= 0); /* continue until the error term turns over */
return (0); /* edge isn't same this time as last time */
}
#endif
/* Function mwSTQA sets up a top quadrant arc edge (a 90-degree arc edge
entity, either from 90 to 0 or from 90 to 180).
QArcEdge = pointer to qarcState to set up
QArcA = X radius of arc (>=0)
QArcB = Y radius of arc (>=0)
QArcCenterX = X center point of arc
QArcCenterY = Y center point of arc
QArcDirection = 1 if arc goes from 90 to 0, -1 if arc goes from 90 to 180
***no other values are acceptable for QArcDirection***
QArcTToB = 1 if arc is interpreted as top to bottom, -1 if bottom to top
***no other values are acceptable for QArcTToB*** */
#ifdef FIXPOINT
void mwSTQA(qarcState *QArcEdge, int QArcA, int QArcB, int QArcCenterX,
int QArcCenterY, int QArcDirection, int QArcTToB)
{
int dFix_add(dblFix *first, dblFix *second, dblFix *result);
int dFix_sub(dblFix *first, dblFix *second, dblFix *result);
int dFix_mul(dblFix *first, dblFix *second, dblFix *result);
byte StepVertical(qarcState *CurrentEdge);
dblFix dblTmp, dblTmp2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -