home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Programming Black Book (Special Edition)
/
BlackBook.bin
/
disk1
/
source
/
chapter39
/
l39-2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-06-18
|
5KB
|
120 lines
/* Scan converts an edge from (X1,Y1) to (X2,Y2), not including the
point at (X2,Y2). If SkipFirst == 1, the point at (X1,Y1) isn't
drawn; if SkipFirst == 0, it is. For each scan line, the pixel
closest to the scanned edge without being to the left of the
scanned edge is chosen. Uses an all-integer approach for speed and
precision
Link with L21-1.C, L21-3.C, and L22-1.C in Compact model.
Tested with Borland C++ 4.02 by Jim Mischel 12/16/94.
*/
#include <math.h>
#include "polygon.h"
void ScanEdge(int X1, int Y1, int X2, int Y2, int SetXStart,
int SkipFirst, struct HLine **EdgePointPtr)
{
int Y, DeltaX, Height, Width, AdvanceAmt, ErrorTerm, i;
int ErrorTermAdvance, XMajorAdvanceAmt;
struct HLine *WorkingEdgePointPtr;
WorkingEdgePointPtr = *EdgePointPtr; /* avoid double dereference */
AdvanceAmt = ((DeltaX = X2 - X1) > 0) ? 1 : -1;
/* direction in which X moves (Y2 is
always > Y1, so Y always counts up) */
if ((Height = Y2 - Y1) <= 0) /* Y length of the edge */
return; /* guard against 0-length and horizontal edges */
/* Figure out whether the edge is vertical, diagonal, X-major
(mostly horizontal), or Y-major (mostly vertical) and handle
appropriately */
if ((Width = abs(DeltaX)) == 0) {
/* The edge is vertical; special-case by just storing the same
X coordinate for every scan line */
/* Scan the edge for each scan line in turn */
for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) {
/* Store the X coordinate in the appropriate edge list */
if (SetXStart == 1)
WorkingEdgePointPtr->XStart = X1;
else
WorkingEdgePointPtr->XEnd = X1;
}
} else if (Width == Height) {
/* The edge is diagonal; special-case by advancing the X
coordinate 1 pixel for each scan line */
if (SkipFirst) /* skip the first point if so indicated */
X1 += AdvanceAmt; /* move 1 pixel to the left or right */
/* Scan the edge for each scan line in turn */
for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) {
/* Store the X coordinate in the appropriate edge list */
if (SetXStart == 1)
WorkingEdgePointPtr->XStart = X1;
else
WorkingEdgePointPtr->XEnd = X1;
X1 += AdvanceAmt; /* move 1 pixel to the left or right */
}
} else if (Height > Width) {
/* Edge is closer to vertical than horizontal (Y-major) */
if (DeltaX >= 0)
ErrorTerm = 0; /* initial error term going left->right */
else
ErrorTerm = -Height + 1; /* going right->left */
if (SkipFirst) { /* skip the first point if so indicated */
/* Determine whether it's time for the X coord to advance */
if ((ErrorTerm += Width) > 0) {
X1 += AdvanceAmt; /* move 1 pixel to the left or right */
ErrorTerm -= Height; /* advance ErrorTerm to next point */
}
}
/* Scan the edge for each scan line in turn */
for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) {
/* Store the X coordinate in the appropriate edge list */
if (SetXStart == 1)
WorkingEdgePointPtr->XStart = X1;
else
WorkingEdgePointPtr->XEnd = X1;
/* Determine whether it's time for the X coord to advance */
if ((ErrorTerm += Width) > 0) {
X1 += AdvanceAmt; /* move 1 pixel to the left or right */
ErrorTerm -= Height; /* advance ErrorTerm to correspond */
}
}
} else {
/* Edge is closer to horizontal than vertical (X-major) */
/* Minimum distance to advance X each time */
XMajorAdvanceAmt = (Width / Height) * AdvanceAmt;
/* Error term advance for deciding when to advance X 1 extra */
ErrorTermAdvance = Width % Height;
if (DeltaX >= 0)
ErrorTerm = 0; /* initial error term going left->right */
else
ErrorTerm = -Height + 1; /* going right->left */
if (SkipFirst) { /* skip the first point if so indicated */
X1 += XMajorAdvanceAmt; /* move X minimum distance */
/* Determine whether it's time for X to advance one extra */
if ((ErrorTerm += ErrorTermAdvance) > 0) {
X1 += AdvanceAmt; /* move X one more */
ErrorTerm -= Height; /* advance ErrorTerm to correspond */
}
}
/* Scan the edge for each scan line in turn */
for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) {
/* Store the X coordinate in the appropriate edge list */
if (SetXStart == 1)
WorkingEdgePointPtr->XStart = X1;
else
WorkingEdgePointPtr->XEnd = X1;
X1 += XMajorAdvanceAmt; /* move X minimum distance */
/* Determine whether it's time for X to advance one extra */
if ((ErrorTerm += ErrorTermAdvance) > 0) {
X1 += AdvanceAmt; /* move X one more */
ErrorTerm -= Height; /* advance ErrorTerm to correspond */
}
}
}
*EdgePointPtr = WorkingEdgePointPtr; /* advance caller's ptr */
}