⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xpol5.c

📁 与Nucleus Plus配套的图形库
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -