edge_walk.c 8.66 KB

#include "graphic.h"

#define EW_X_SUBPIX_ROUND (EW_X_FRAC_MASK>>SU_XY_FRAC_SHFT)

/* minor edge state transitions */
#define EW_MINOR_BEG	1	/* in upper minor edge */
#define EW_MINOR_MID	2	/* exit upper minor edge */
#define EW_MINOR_LOW	3	/* enter lower minor edge */
#define EW_MINOR_END	4	/* in lower minor edge */

/*------------------------------------------*/
do_edge_walk()
{
struct EW_major_edge *ewh;
struct EW_minor_edge *ewm, *ewl;
struct EW_span_edge *ews;
struct MS_span_data *ms;
struct MS_subpixel *msh, *msm;
struct CZ_step *czs;
struct TC_step *tcs;
int minor_state;			/* status of minor edge */
int hx_index, mx_index, lx_index;	/* subpixel to bound span */
int hx_carry;				/* attribute dx step control */
int sp_mask;				/* subpixel enable mask */
int hu_mask, mu_mask;			/* update subpixel mask */
int hy_mask, my_mask;			/* valid subpixel mask */
int beg_mask, end_mask, mid_mask, low_mask;	/* y edge masks */
int xl, xr;				/* span x bounds */
int sy;					/* y subpixel values */
int i, j;

/* set edge pointers */
	ewh = &ew_high[0];
	ewm = &ew_mid[0];
	ewl = &ew_low[0];
	ews = &ew_span[0];
/* initialize mem_span and sort outputs */
	ms = &mem_span_data[0];
	ms->left = ewh->left;
if (ewh->left) {
	msh = &ms->s_left;
	msm = &ms->s_right;
} else {
	msh = &ms->s_right;
	msm = &ms->s_left;
	}
/* initialize cz_step and tc_step */
        tcs = &tc_step[0];
        czs = &cz_step[0];
if (ewh->left) {
	czs->del.r = ews->del.r;
	czs->del.g = ews->del.g;
	czs->del.b = ews->del.b;
	czs->del.a = ews->del.a;
	czs->del.z = ews->del.z;
	tcs->del.s = ews->del.s;
	tcs->del.t = ews->del.t;
	tcs->del.w = ews->del.w;
	tcs->del.l = ews->del.l;
} else {
	czs->del.r = -ews->del.r;
	czs->del.g = -ews->del.g;
	czs->del.b = -ews->del.b;
	czs->del.a = -ews->del.a;
	czs->del.z = -ews->del.z;
	tcs->del.s = -ews->del.s;
	tcs->del.t = -ews->del.t;
	tcs->del.w = -ews->del.w;
	tcs->del.l = -ews->del.l;
	}
/* convert attribute dx to dy+dx on x carry */
	ews->del.r += ewh->del.r;
	ews->del.g += ewh->del.g;
	ews->del.b += ewh->del.b;
	ews->del.a += ewh->del.a;
	ews->del.z += ewh->del.z;
	ews->del.s += ewh->del.s;
	ews->del.t += ewh->del.t;
	ews->del.w += ewh->del.w;
	ews->del.l += ewh->del.l;
/* if not antialiasing, draw only if integer scanline covered */
/* XXXX this an only optimization to skip spans */
	if (en_antialias) sp_mask = AA_SP_MASK;
		else sp_mask = 1 << (AA_SP_COUNT-1);

/* select x subpixel to use */
	hx_index = 0;
	mx_index = 0;
	lx_index = 0;
/* if left dx negative, use last x subpixel */
/* if right dx positive, use last x subpixel */
if ((ewh->left && ewh->xy.xdi < 0)||(!ewh->left && ewh->xy.xdi >= 0))
		hx_index = (AA_SP_COUNT-1);
if ((ewh->left && ewm->xy.xdi >= 0)||(!ewh->left && ewm->xy.xdi < 0))
		mx_index = (AA_SP_COUNT-1);
if ((ewh->left && ewl->xy.xdi >= 0)||(!ewh->left && ewl->xy.xdi < 0))
		lx_index = (AA_SP_COUNT-1);


/* generate y edge masks */
	sy = (ewh->xy.ypf) >> (EW_X_FRAC_SHFT - AA_SP_BITS);
	beg_mask = sp_decode_b[ sy];
	sy = (ewl->xy.ypf) >> (EW_X_FRAC_SHFT - AA_SP_BITS);
	end_mask = sp_decode_e[ sy];
	sy = (ewm->xy.ypf) >> (EW_X_FRAC_SHFT - AA_SP_BITS);
	mid_mask = sp_decode_e[ sy];
	low_mask = ~mid_mask & AA_SP_MASK; /* complement mid mask */

/* on first span, using begin mask on both edges, update all subpixels */
	hy_mask = beg_mask;
	my_mask = beg_mask;
	hu_mask = AA_SP_MASK;
	mu_mask = AA_SP_MASK;

/* EDGE_LOOP */
minor_state = EW_MINOR_BEG;
while (ewh->xy.yp <= ewl->xy.yp) { /* until major edge expires */

/* last line of first minor edge */
if (ewh->xy.yp == ewm->xy.yp && minor_state == EW_MINOR_BEG) {
	my_mask &= mid_mask; /* don't & mu_mask, update all subpixels */
/* if second minor edge is not zero, skip drawing span and advance edge */
	if ((ewm->xy.yp != ewl->xy.yp)||(ewm->xy.ypf != ewl->xy.ypf))
		minor_state = EW_MINOR_MID;
/* XXXX note, unfortunately need to special case zero height lower
edges in this way because the xl/xr subpixel selection gets bogus
values (because of infinite slope). maybe could simplify  that by
not updating the edge */
	else minor_state = EW_MINOR_END; /* finish, no lower minor edge */
	}

/* first line of next minor edge */
if (minor_state == EW_MINOR_LOW) {
	minor_state = EW_MINOR_END;
	mx_index = lx_index;
	mu_mask = low_mask;	/* update following subpixels */
	my_mask |= low_mask;	/* enable following subpixels */
	ewm = ewl;		/* new edge */
	}
/* last line of major edge */
if (ewh->xy.yp == ewl->xy.yp) {
	my_mask &= end_mask;	/* enable preceeding subpixels */
	hy_mask &= end_mask;
	}

/* set subpixel valid bits */
	msh->xv = hy_mask;
	msm->xv = my_mask;
/* load x subpixels */
	j = 1 << (AA_SP_COUNT-1);
for (i=0; i<AA_SP_COUNT; i++) {
	if (hu_mask & j) {
		msh->xi[i] = ewh->xy.xpi[i];
/*
		msh->xf[i] = ewh->xy.xpf[i] & EW_X_SUBPIX_MASK;
*/
		msh->xf[i] = ewh->xy.xpf[i] + EW_X_SUBPIX_ROUND;
		if (msh->xf[i] & ~EW_X_FRAC_MASK) msh->xi[i]++;
		msh->xf[i] &= EW_X_SUBPIX_MASK;
		}
	if (mu_mask & j) {
		msm->xi[i] = ewm->xy.xpi[i];
/*
		msm->xf[i] = ewm->xy.xpf[i] & EW_X_SUBPIX_MASK;
*/
		msm->xf[i] = ewm->xy.xpf[i] + EW_X_SUBPIX_ROUND;
		if (msm->xf[i] & ~EW_X_FRAC_MASK) msm->xi[i]++;
		msm->xf[i] &= EW_X_SUBPIX_MASK;
		}
	j = j >> 1;
	}
/* scissor subpixel X */
{
int sl = sc_xmin << (EW_X_FRAC_SHFT-SU_XY_FRAC_SHFT);
int sr = sc_xmax << (EW_X_FRAC_SHFT-SU_XY_FRAC_SHFT);
for (i=0; i<AA_SP_COUNT; i++) {
	if (ewh->left) {
		if (((msh->xi[i]<<EW_X_FRAC_SHFT)|msh->xf[i]) < sl) {
			msh->xi[i] = sl >> EW_X_FRAC_SHFT;
			msh->xf[i] = sl & EW_X_FRAC_MASK;
			}
		if (((msm->xi[i]<<EW_X_FRAC_SHFT)|msm->xf[i]) > sr) {
			msm->xi[i] = sr >> EW_X_FRAC_SHFT;
			msm->xf[i] = sr & EW_X_FRAC_MASK;
			}
	} else {
		if (((msm->xi[i]<<EW_X_FRAC_SHFT)|msm->xf[i]) < sl) {
			msm->xi[i] = sl >> EW_X_FRAC_SHFT;
			msm->xf[i] = sl & EW_X_FRAC_MASK;
			}
		if (((msh->xi[i]<<EW_X_FRAC_SHFT)|msh->xf[i]) > sr) {
			msh->xi[i] = sr >> EW_X_FRAC_SHFT;
			msh->xf[i] = sr & EW_X_FRAC_MASK;
			}
		}
	}
}

/* if last span of upper minor edge, skip draw until lower next edge */
if (minor_state == EW_MINOR_MID) {
	minor_state = EW_MINOR_LOW;
	continue;
	}

/* DRAW_SPAN */
if (hy_mask & my_mask & sp_mask) {/* draw if something valid */

/* get left and right x coordinates of span */
/* XXXX note that index works only for convex edge chains.
   if concave, a sort on subpixel x coordinates is required */
if (ewh->left) {
	xl = ewh->xy.xpi[hx_index];
	xr = ewm->xy.xpi[mx_index];
} else {
	xr = ewh->xy.xpi[hx_index];
	xl = ewm->xy.xpi[mx_index];
	}

/* scissor y */
	if (ewh->xy.yp > (sc_ymax>>SU_XY_FRAC_SHFT)) return;
	if (ewh->xy.yp < (sc_ymin>>SU_XY_FRAC_SHFT)) goto UPDATE_EDGES;

/* scissor x */
{
int sl, sr;
	sl = sc_xmin >> SU_XY_FRAC_SHFT;
	sr = sc_xmax >> SU_XY_FRAC_SHFT;
	if (xr < sl) goto UPDATE_EDGES;
	if (xl > sr) goto UPDATE_EDGES;
	if (ewh->left && xr > sr) xr = sr;
	if (!ewh->left && xl < sl) xl = sl;
}
	/* 
	if multiplier, attributes += (min_x - hx) * dx_attributes;
	else mem_span needs to disable pixels < min_x
	*/

/* write to cz_step */
	czs->pnt.r = ewh->pnt.r;
	czs->pnt.g = ewh->pnt.g;
	czs->pnt.b = ewh->pnt.b;
	czs->pnt.a = ewh->pnt.a;
	czs->pnt.z = ewh->pnt.z;

/* write to tc_step */
	tcs->first = TRUE;
	tcs->pnt.s = ewh->pnt.s;
	tcs->pnt.t = ewh->pnt.t;
	tcs->pnt.w = ewh->pnt.w;
	tcs->pnt.l = ewh->pnt.l;

/* write to mem_span */
/* XXX should use a scanline address not y, and update depth.base */
	ms->color.base = ewh->xy.yp;
	ms->x_left  = xl;
	ms->x_right  = xr;
	do_mem_span();
UPDATE_EDGES: ;
} /* end DRAW_SPAN */

/* step edges edges in y */
	ewh->xy.yp++;

/* step left edge x */
	hx_carry = FALSE;
	for (i=0; i<AA_SP_COUNT; i++) {
		ewh->xy.xpi[i] += ewh->xy.xdi;
		ewh->xy.xpf[i] += ewh->xy.xdf;
/* if fraction carries, bump x and remember the carry */
		if (ewh->xy.xpf[i] & ~EW_X_FRAC_MASK) {
			ewh->xy.xpf[i] &= EW_X_FRAC_MASK;
			ewh->xy.xpi[i]++;
/* remember only the indexed x carry */
			if (i == hx_index) hx_carry = TRUE;
			}
		}

/* step right edge x */
	for (i=0; i<AA_SP_COUNT; i++) {
		ewm->xy.xpi[i] += ewm->xy.xdi;
		ewm->xy.xpf[i] += ewm->xy.xdf;
		if (ewm->xy.xpf[i] & ~EW_X_FRAC_MASK) {
			ewm->xy.xpf[i] &= EW_X_FRAC_MASK;
			ewm->xy.xpi[i]++;
			}
		}
/* step left edge attributes */
if (!hx_carry) {
	ewh->pnt.r += ewh->del.r;
	ewh->pnt.g += ewh->del.g;
	ewh->pnt.b += ewh->del.b;
	ewh->pnt.a += ewh->del.a;
	ewh->pnt.z += ewh->del.z;
	ewh->pnt.s += ewh->del.s;
	ewh->pnt.t += ewh->del.t;
	ewh->pnt.w += ewh->del.w;
	ewh->pnt.l += ewh->del.l;
/* step left attributes by dx */
} else {
	ewh->pnt.r += ews->del.r;
	ewh->pnt.g += ews->del.g;
	ewh->pnt.b += ews->del.b;
	ewh->pnt.a += ews->del.a;
	ewh->pnt.z += ews->del.z;
	ewh->pnt.s += ews->del.s;
	ewh->pnt.t += ews->del.t;
	ewh->pnt.w += ews->del.w;
	ewh->pnt.l += ews->del.l;
	}
/* initialize masks for next span */
	hy_mask = hu_mask = AA_SP_MASK;
	my_mask = mu_mask = AA_SP_MASK;
	} /* end EDGE_LOOP */
}