line.c 4.34 KB

#include "graphic.h"

/*----------------------------------*/
mix_add( a, af, b, c, cf)
int a, af, b, *c, *cf;
{
int i;
	i = fix_ewa(a)+af+b;
	*c = i >> EW_X_FRAC_SHFT;
	*cf = i & EW_X_FRAC_MASK;
	}
/*----------------------------------*/
do_line( vh, vl)
struct Vertex *vh, *vl;
{
int width = (int)(line_width*EW_X_FRAC_ONE/2);
struct Vertex *vt;
int hy, ly, hx, lx, mx;
int hyf, lyf, hxf, lxf, mxf;
int dy, adx, dx, dxf;
int yoff, xoff, yadj;
int smin, smax;
int left = TRUE;

int hz, dz, dxz, dez, dyz;
int rx;

/* sort in y */
	if (vl->y < vh->y) { vt = vh; vh = vl; vl = vt; }
/* get points and deltas */	
	hy = vh->y;
	ly = vl->y;
	hx = vh->x;
	lx = vl->x;
	dy = ly - hy;
	dx = lx - hx;
	rx = dx;	/* save for attributes */
/* defaults */
	yoff = 0;
	smin = hx; smax = lx;
	adx = dx;
	xoff = EW_X_FRAC_ONE;
/* determine handedness */
	if (dx < 0) {
		left = FALSE; 
		smin = lx; smax = hx;
		adx = -dx;
		xoff = -xoff;
		}
/* special case horizontal lines */
	if (!dy) {
		dx = dxf = 0;
	} else {
		xy_divide( dy, &dx, &dxf);
		lx = hx;
		}

/* convert coords to int and frac */
	xy_scale( hy, &hy, &hyf);
	xy_scale( ly, &ly, &lyf);
	xy_scale( hx, &hx, &hxf);
	xy_scale( lx, &lx, &lxf);

	yadj = (hy<<EW_X_FRAC_SHFT) | hyf;
/* determine orientation */
	if (adx > dy) {	/* x major */
/*	y offset = 1 */
		yoff = EW_X_FRAC_ONE;
/* 	x offset = dx */
		xoff = (dx<<EW_X_FRAC_SHFT)+dxf;
/*	scissor to x vertices */
		set_scissor_x( smin, smax);
		}

/* scale offset by width/2 */
	xoff = (int)((float)xoff*(float)width*(float)1/EW_X_FRAC_ONE);
	yoff = (int)((float)yoff*(float)width*(float)1/EW_X_FRAC_ONE);
/* stretch height by width */
	mix_add( hy, hyf, -yoff, &hy, &hyf);
	mix_add( ly, lyf, yoff, &ly, &lyf);
	yadj = (hy<<EW_X_FRAC_SHFT) - yadj;
/* adjust to scanline */
	xy_adjust( yadj, hx, hxf, dx, dxf, &hx, &hxf);
	xy_adjust( yadj, lx, lxf, dx, dxf, &lx, &lxf);
/* offset starting x */
	mix_add( hx, hxf, -xoff, &hx, &hxf);
	mix_add( lx, lxf, xoff, &lx, &lxf);

/* attribute setup */
	hz = vh->z;
	dz = vl->z - hz;
/* dxa step in x is da/dx */
	if (adx > dy) {	/* x major */
		dxz = (int)((float)dz/(float)rx*
			(float)(EW_X_FRAC_ONE<<SU_XY_FRAC_SHFT));
/*	dea step on edge is dxa * (int)dyx */
		dez = (int)((float)dx * (float)dxz);
		dyz = 0;
	} else {
		dyz = (int)((float)dz/(float)dy*
			(float)(EW_X_FRAC_ONE<<SU_XY_FRAC_SHFT));
		dez = dyz;
		dxz = 0;
		}
/* adjust to pixel center of first scanline */
	xoff = (hx<<EW_X_FRAC_SHFT)-
		(vh->x<<(EW_X_FRAC_SHFT-SU_XY_FRAC_SHFT));
	attr_adjust( hz, dyz, yadj, dxz, xoff, &hz);
dzdx = dxz;
dzdy = dyz;

/*
printf("line z %.2f dxz %.2f dyz %.2f,\n", 
	float_ewa( hz), float_ewa( dxz), float_ewa( dyz));
*/

/*------------------------------------------- write to edge walker */
{
struct EW_xy_edge *ewh, *ewm, *ewl;
struct EW_at_edge *ews, *ewd, *ewp;

/* set orientation */
        ew_high[0].left  = left;
/* set attribute edge pointers */
        ewp = &ew_high[0].pnt;
        ewd = &ew_high[0].del;
        ews = &ew_span[0].del;
/* xy edge pointers for high, medium, low */
        ewh = &ew_high[0].xy;
        ewm = &ew_mid[0].xy;
        ewl = &ew_low[0].xy;
/* load x, y for three edges */
/* high edge */
        ewh->yp = hy;
        ewh->ypf = hyf;
        x_subpixel( hx, hxf, dx, dxf, ewh->xpi, ewh->xpf, 0);
        ewh->xdi = dx;
        ewh->xdf = dxf;
/* mid edge */
        ewm->yp = ly;
        ewm->ypf = lyf;
        x_subpixel( lx, lxf, dx, dxf, ewm->xpi, ewm->xpf, 0);
        ewm->xdi = dx;
        ewm->xdf = dxf;
/* lower edge duplicates mid edge */
        ewl->yp = ly;
        ewl->ypf = lyf;
        x_subpixel( lx, lxf, dx, dxf, ewl->xpi, ewl->xpf, 0);
        ewl->xdi = dx;
        ewl->xdf = dxf;
/* initialize attributes */
	ews->r = 0;
        ews->g = 0;
        ews->b = 0;
        ews->a = 0;
        ews->s = 0;
        ews->t = 0;
        ews->w = 0;
        ews->l = 0;
        ews->z = dxz;
/* load major edge attribute point and delta */
        ewp->r = fix_ewa( 255);
        ewp->g = fix_ewa( 255);
        ewp->b = fix_ewa( 255);
        ewp->a = fix_ewa( vh->a);
        ewp->s = 0;
        ewp->t = 0;
        ewp->w = 0;
        ewp->l = 0;
        ewp->z = hz;
        ewd->r = 0;
        ewd->g = 0;
        ewd->b = 0;
        ewd->a = 0;
        ewd->s = 0;
        ewd->t = 0;
        ewd->w = 0;
        ewd->l = 0;
        ewd->z = dez;
/* draw the line */
        do_edge_walk();
} /* end load edges */
set_scissor_screen();
}