home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
RISC DISC 3
/
RISC_DISC_3.iso
/
resources
/
etexts
/
gems
/
gemsiii
/
edgecalc.c
< prev
next >
Wrap
Text File
|
1992-03-17
|
16KB
|
408 lines
/******************************************************************************
EDGE AND BIT-MASK CALCULATIONS FOR ANTI-ALIASING
Russell C.H. Cheng, University of Wales, Cardiff, 21 Jan 1992.
This routine calculates the geometry of the overlap of the edges of a polygon
with square pixels, using a fast alternating Bresenham error-update technique.
Entry:
Pointer to a structure (defined below) giving details of the polygon.
Pointers to precalculated bitmasks.
Exit:
The routine outputs the overlap information pixel by pixel via resultproc().
The arguments are: the pixel position, position of the endpoints of the
overlapping edge, the pixeltype, and the edgetype.
In this implementation resultproc() uses this information to calculate the
positions of the leftmost and rightmost pixels on each scanline, and the
bitmasks of overlap of the polygon with each pixel.
Implementation Details:
(i) The procedure resultproc() accesses external pointers: int * xl,
int * xr, aabufftype * aabuffptr, short int * fragptr. These are
described in resultproc(). These should be globally defined.
(ii) edge_calculate() accesses polygonal information via a pointer
to the structure:
typedef struct SCRNPOLYGON
{
int numvert; number of vertices
float xcoord[10]; coordinates of each vertex
float ycoord[10]; in clockwise order
int imax; subscript of vertex with largest y-coord
int imin; subscript of vertex with smallest y-coord
} SCRNPOLYGON;
******************************************************************************/
#define LARGE 10000000.0
#define TRUE 1
#define FALSE 0
/*== The following two structures are included here to enable compilation,
they should normally be defined earlier for access by the main routine ==*/
typedef struct {
unsigned short mask[4][5][5][5][5];
} aabufftype;
typedef struct {
int numvert; /* number of vertices */
float xcoord[10]; /* coordinates of each vertex */
float ycoord[10]; /* in clockwise order */
int imax; /* subscript of vertex with largest y-coord */
int imin; /* subscript of vertex with smallest y-coord */
} SCRNPOLYGON;
#define NN 0 /* The different types of overlap possible in a pixel. */
#define LX 1 /* See Fig.2 in the main text. */
#define LY 2
#define RX 3
#define RY 4
#define MX 5
#define MY 6
#define SX 7
#define SY 8
#define TX 9
#define TY 10
#define HRES 768 /* horizontal resolution */
int rl[11][5] = { /* Array used to select pixeltype/edgetype combinations */
0, 0, 0, 1, -1, /* at which an xl or xr value should be set. */
-1, 0, 1, 1, -1, /* 1 indicates where xr is set */
0, 0, 0, 0, -1, /* -1 indicates where xl is set */
1, -1, 0, 1, -1,
0, 0, 0, 1, 0,
0, -1, 1, 1, -1,
0, 0, 0, 0, 0,
0, 0, 0, 1, 0,
0, -1, 0, 0, 0,
0, 0, 0, 0, -1,
0, 0, 1, 0, 0,
};
void edge_calculator(scrnfaceptr)
SCRNPOLYGON * scrnfaceptr;
{
void resultproc();
float delx,dely,delymp,dx_by_dy,dy_by_dx;
int edgetype;
float ex; /* Bresenham x-error variables */
float exend, exstt, ex0; /* '' */
float ey; /* Bresenham y-error variables */
float eyend, eystt, ey0; /* '' */
int firstleftedgetype; /* edgetype of first left edge encountered*/
int firstrightedge; /* flag showing when 1st right-edge is reached */
float hpix = 1.0; /* Pixel edgelength */
int iv, ivm1, ivp1; /* work variables holding array subscripts */
float largemp; /* work variable used in slope calculation */
int lastleftedgetype; /* edgetype of the last left-edge */
int toggle; /* switch-flag, 1=odd, 2=even edgetypes */
float xstt,xend; /* x-positions of start and end points of edge */
int xpix, xpend, xpstt; /* current, edge-start & edge-end pixel x-coords */
float ystt,yend; /* y-positions of start and end points of edge */
int ypix, ypend, ypstt; /* current, edge-start & edge-end pixel y-coords */
/*==== Process each edge of the left-hand side of polygon ====*/
iv = scrnfaceptr->imin; /* Find subscripts of first */
ivp1 = (iv+1) % scrnfaceptr->numvert; /* left edge and the */
xend=scrnfaceptr->xcoord[iv]; yend=scrnfaceptr->ycoord[iv]; /* coords */
xpend = (int)xend; ypend = (int)yend; /* of its starting point. */
firstleftedgetype = 0;
while(iv!=scrnfaceptr->imax) {
xpix = xpend; ypix = ypend; /* Get the coords of the */
xstt= xend; ystt= yend; /* starting pixel of edge */
xpstt = xpend; ypstt = ypend; /* and the coords of the */
xpend=(int)(xend= scrnfaceptr->xcoord[ivp1]); /* end */
ypend=(int)(yend= scrnfaceptr->ycoord[ivp1]); /* pixel. */
exend= xend-xpend; eyend= yend-ypend; /* Bresenham errors at end pixel.*/
if(xstt<xend) { /*-- Left: Edgetype 1 --*/
if(firstleftedgetype==0) { /* If at first edge, */
firstleftedgetype = 1; /* make a note of its type. */
resultproc(xpix,ypix, 0.0,0.0,0.0,0.0, LX,0);
/* Special call equivalent to xl[ypix] = xpix */
}
edgetype=1; toggle = 1; /* Set edgetype and */
goto gamma; /* go to main edge-processor.*/
}
else { /*-- Left: Edgetype 4 --*/
if(firstleftedgetype==0) /* If at first edge, make */
firstleftedgetype = 4; /* a note of its type. */
edgetype=4; toggle = 2; /* Set edgetype and */
goto gamma; /* go to main edge-processor.*/
}
edge_end_l: /* The main edge-processor returns here when the edge is done*/
iv = ivp1; /* Set subscripts for the next left edge. */
ivp1= (iv+1) % scrnfaceptr->numvert; /* '' */
}
/*=== Make a note of the edgetype of the last edge on the left. ====*/
lastleftedgetype = edgetype;
/*==== Process each edge of the right-hand side of polygon. ====*/
iv = scrnfaceptr->imin; /* Find subscripts of first */
ivm1= (iv+scrnfaceptr->numvert-1) % scrnfaceptr->numvert; /* right edge & */
xend=scrnfaceptr->xcoord[iv]; yend=scrnfaceptr->ycoord[iv]; /* the coords */
xpend = (int)xend; ypend = (int)yend; /* of its starting point.*/
firstrightedge = TRUE;
while(iv!=scrnfaceptr->imax) {
xpix = xpend; ypix = ypend; /* get coords of the */
xstt = xend; ystt = yend; /* starting pixel of edge */
xpstt = xpend; ypstt = ypend; /* and */
xpend=(int)(xend= scrnfaceptr->xcoord[ivm1]); /* the coords of */
ypend=(int)(yend= scrnfaceptr->ycoord[ivm1]); /* the end pixel. */
exend= xend-xpend; eyend= yend-ypend; /* Bresenham errors at end pixel. */
if(xstt<xend) { /*--- Right: Edgetype 3 ---*/
/*-- Correct for bottom-most pixel bitmask, if necessary. --*/
if(firstrightedge == TRUE) {
firstrightedge = FALSE;
if(firstleftedgetype==1) {
exstt=(xstt-xpstt); eystt=(ystt-ypstt);
resultproc( xpix,ypix, exstt, eystt, exstt, eystt, MY, 4);
}
}
edgetype=3; toggle = 1; /* Set the current edgetype and */
goto gamma; /* go to the main edge-processor. */
}
else { /*--- Right: Edgetype 2 ---*/
/*-- Correct for bottom-most pixel bitmask, if necessary. --*/
if(firstrightedge==TRUE) {
firstrightedge = FALSE;
if(firstleftedgetype==4) {
exstt=(xstt-xpstt); eystt=(ystt-ypstt);
resultproc(xpix,ypix, exstt, eystt, exstt, eystt, MY, 3);
}
resultproc(xpix,ypix, 0.0,0.0,0.0,0.0, RX,0);
/* Special call equivalent to xr[ypix] = xpix. */
}
edgetype=2; toggle = 2; /* Set the current edgetype. */
goto gamma; /* Go to main edge-processor.*/
}
edge_end_r: /* The main edge-processor returns here once edge is done */
iv = ivm1; /* set subscripts for next right-edge */
ivm1= (iv+scrnfaceptr->numvert-1) % scrnfaceptr->numvert;
}
/*=== do the final vertex bitmask correction, if necessary ===*/
if(lastleftedgetype==4 && edgetype==2)
resultproc(xpend,ypend, exend, eyend, exend, eyend, MY, 1);
else if(lastleftedgetype==1 && edgetype==3)
resultproc(xpend,ypend, exend, eyend, exend, eyend, MY, 2);
return;
/*=== Routine ends here, extracted code follows ======================
The following segment is the main edge-processor. It identifies the
coords xpix,ypix of each pixel intersected by the edge, and the type
of intersection (see Fig. 2 in the main text). All four edgetypes
are handled using the switches 'edgetype' and 'toggle'
Two Bresenham 'error' quantities are used to identify the pixels:
ex: the x-distance from the left boundary of the pixel to the
intercept of the edge with the upper boundary of the pixel.
ey: the y-distance from the right boundary of the pixel to the
intercept of the edge with the right boundary of the pixel.
Each pixel is found from the previous one by updating either ex or
ey and then testing its value to identify the type of intersection.
ex0, ey0 are initially the values of ex, ey at the starting pixel of
the edge, but subsequently hold the previous values as ex,ey are
updated.
=====================================================================*/
gamma:
/*=== If the edge lies entirely in one pixel, record this and finish. ===*/
if( (xpix==xpend) && (ypix==ypend) ) {
resultproc(xpix,ypix, xstt-xpstt,ystt-ypstt, exend,eyend, NN, edgetype);
switch(edgetype) {
case 3: case 2: goto edge_end_r;
case 4: case 1: goto edge_end_l;
}
}
/*=== If not, calculate the slope of the edge. ===*/
delx = xend-xstt; dely = yend-ystt;
if(toggle==1) { /* edgetype 1 or 3 */
delymp = dely; largemp = LARGE;
}
else { /* edgetype 2 or 4 */
delymp = -dely; largemp = -LARGE;
}
if(delx!=0) dy_by_dx=delymp/delx;
else {
dx_by_dy = 0; dy_by_dx = LARGE;
}
if(dely!=0) dx_by_dy=delx/dely;
else {
dy_by_dx = 0; dx_by_dy = largemp;
}
/*=== Look at first pixel. ===*/
ex0= xstt-xpstt; ey0= ystt-ypstt; /* Set Bresenham error variables */
ex = ex0 + dx_by_dy*(hpix-ey0);
if(toggle==1) { /* edgetype 1 or 3 */
ey = ey0 + dy_by_dx*(hpix-ex0);
if(ex < hpix) { /* Depending on the size of ex, the pixel is of type LX */
resultproc(xpix, ypix, ex0, ey0, ex, hpix, LX, edgetype); goto alpha;
}
else { /* or of type LY. */
resultproc(xpix, ypix, ex0, ey0, hpix, ey, LY, edgetype); goto beta;
}
}
else { /* edgetype 2 or 4 */
ey = ey0 + dy_by_dx*ex0;
if(ex > 0) { /* Depending on the sign of ex, the pixel is of type RX */
resultproc(xpix, ypix, ex0, ey0, ex, hpix, RX, edgetype); goto alpha;
}
else { /* or of type RY. */
resultproc(xpix, ypix, ex0, ey0, 0.0, ey, RY, edgetype); goto beta;
}
}
alpha: /*== The upper boundary just crossed; now at new y-level ==*/
ypix++;
ey -= hpix;
if(toggle==1) { /* edgetype 1 or 3 */
/* If at last pixel of edge, finish off edge. */
if( (ypix >= ypend) && (xpix >= xpend) ) {
resultproc(xpend,ypend, ex, 0.0, exend, eyend, RX, edgetype);
if(edgetype==1) goto edge_end_l;
else goto edge_end_r;
}
}
else { /* edgetype 2 or 4 */
/* If at last pixel of edge, finish off edge. */
if( (ypix >= ypend) && (xpix <= xpend) ) {
resultproc(xpend, ypend, ex, 0.0, exend, eyend, LX, edgetype);
if(edgetype==4) goto edge_end_l;
else goto edge_end_r;
}
}
/*=== Not yet at end of edge. Update ex and carry on. ===*/
ex0 = ex; ex += dx_by_dy;
if(toggle==1) { /* edgetype 1 or 3 */
if(ex < hpix) { /* Depending on the size of ex, pixel is of type MX */
resultproc(xpix, ypix, ex0, 0.0, ex, hpix, MX, edgetype); goto alpha;
}
else { /* or of type SY. */
resultproc(xpix, ypix, ex0, 0.0, hpix, ey, SY, edgetype); goto beta;
}
}
else { /* edgetype 2 or 4 */
if(ex > 0) { /* Depending on the sign of ex, pixel is of type MX */
resultproc(xpix, ypix, ex0, 0.0, ex, hpix, MX, edgetype); goto alpha;
}
else { /* or of type TY. */
resultproc(xpix, ypix, ex0, 0.0, 0.0, ey, TY, edgetype); goto beta;
}
}
beta: /*== Just crossed a vertical pixel boundary; now at new x-level ==*/
if(toggle==1) { /* edgetype 1 or 3 */
xpix++;
ex -= hpix;
/* If at last pixel of edge, finish off edge. */
if( (ypix>=ypend) && (xpix>=xpend) ) {
resultproc(xpend, ypend, 0.0, ey, exend, eyend, RY, edgetype);
if(edgetype==3) goto edge_end_r;
else goto edge_end_l;
}
}
else { /* edgetype 2 or 4 */
xpix--;
ex += hpix;
/* If at last pixel of edge, finish off edge. */
if( (xpix <= xpend) && (ypix >= ypend) ) {
resultproc(xpend, ypend, hpix, ey, exend, eyend, LY, edgetype);
if(edgetype==4) goto edge_end_l;
else goto edge_end_r;
}
}
/*=== Not yet at end of edge. Update ey, and carry on. ===*/
ey0 = ey; ey += dy_by_dx;
if(toggle==1) { /* edgetype 1 or 3 */
if(ey < hpix) { /* Depending on size of ey, pixel is of type MY */
resultproc(xpix, ypix, 0.0, ey0, hpix, ey, MY, edgetype); goto beta;
}
else { /* or of type SX. */
resultproc(xpix, ypix, 0.0, ey0, ex, hpix, SX, edgetype); goto alpha;
}
}
else { /* edgetype 2 or 4 */
if(ey < hpix) { /* Depending on size of ey, pixel is of type MY */
resultproc(xpix, ypix, hpix, ey0, 0.0, ey, MY, edgetype); goto beta;
}
else { /* or of type TX. */
resultproc(xpix, ypix, hpix, ey0, ex, hpix, TX, edgetype); goto alpha;
}
}
}
/*===========================================================================
This illustrates how the output from the edge calculator can be used
The routine modifies externally defined arrays fragptr[], xl[] and xr[] (which
are accessed via global pointers).
It uses a global pointer to recognize precalculated bitmasks held in a
structure.
===========================================================================*/
void resultproc(xpix,ypix,x1,y1,x2,y2,pixtype,edgetype)
int xpix,ypix; /* position of pixel to which information applies */
float x1,y1,x2,y2; /* position of the two endpoints of edge intersecting
the polygon */
int pixtype; /* type of overlap in this pixel (NN,LX,LY,...) */
int edgetype; /* type of edge (1,2,3 or 4) */
{
extern aabufftype * aabuffptr; /* pointer to a structure in which the
precomputed bitmasks are held. Their format is given in the text.*/
extern unsigned short * fragptr; /* pointer to linear array holding bitmasks
of the overlaps of the polygon with pixels, assuming HRES
pixels per scanline. On entry each entry should be set to 0xffff */
extern int * xl, * xr; /* pointers to arrays storing positions of the
left and right edges of the polygon: xl[y] and xr[y] give the
x-position of the leftmost and rightmost pixels of the polygon on
scanline y */
static float scale = 3.999; /* this should be set to just less than the ratio
of pixel to subpixel widths. The value 3.999 is for the case where
each pixel is 4x4 subpixels */
int ij,ix1,ix2,iy1,iy2;
ij = xpix + HRES*ypix;
ix1 = x1*scale; iy1 = y1*scale;
ix2 = x2*scale; iy2 = y2*scale;
/*-- adjust current bitmask by bitwise ANDing it with computed bitmask --*/
if(edgetype>0)
fragptr[ij] &= aabuffptr->mask[edgetype] [ix1] [iy1] [ix2] [iy2];
/*-- record the leftmost and rightmost pixel positions, xl[y] and xr[y]
of the polygon on each scanline y --*/
if (rl[pixtype][edgetype]== 1) xr[ypix]=xpix;
else if (rl[pixtype][edgetype]==-1) xl[ypix]=xpix;
return ;
}