clip.c 4.63 KB

#include "graphic.h"

/*--------------------------------------------------*/
do_bf_cull( va, vb, vc)
/* return true if backface */
struct Vertex *va, *vb, *vc;
/* XXXX makes sense to integrate this with setup to reuse pleq terms */
{
int xa, ya, xb, yb;
int sign;
	xa = va->x;
	ya = va->y;
	xb = vb->x - xa;
	yb = vb->y - ya;
	xa = vc->x - xa;
	ya = vc->y - ya;
	sign = (int)((float)xa*(float)yb-(float)xb*(float)ya);
	if (sign == 0) return( en_bf_cull);	/* no area */
	/* shift so all sign bits */
	return( ((sign >> 31) ^ bf_cull_sign) & en_bf_cull);
	}
/*--------------------------------------------------*/
do_clip( cc_clip, va, vb, vtx, vcount)
int cc_clip;		/* OR of clip codes of input vertices */
struct Vertex **va, **vb; /* vertex list and working list */
struct Vertex *vtx;	/* intput vertices, new added after vcount */
int *vcount;		/* number of vertices */
{
struct Vertex **vpi, **vpo, **vpt; /* list swap pointers */
struct Vertex *vp, *vn;		/* previous and next vertex */
struct Vertex *vins, *vout; 	/* inside and outside vertex */
int vci, vco, vc;	/* input, output, local vertex count */
int vcn;		/* new vertex index */
int plane, count, flag, index;	/* clip plane references */
int inside, last_in;	/* vertex status */
int xi, xo, wi, wo;	/* coordinates */
int wone;               /* offset to clip < w */
int num, den;		/* clip distance num/den */
	vpi = va;
	vpo = vb;
	vci = *vcount;
	vcn = vci;	/* put new vertices after the input ones */
	count = 0;	/* number of planes clipped */
for (plane=0; plane<CLIP_PLANE; plane++) {
	flag = 1 << plane;		/* clip plane to test */
	if (!(cc_clip & flag)) continue; /* nothing out this plane */
	cc_clip = 0;		/* reset for new vertices */
	count++;			/* number of planes clipped */
	index = plane >> 1;		/* coord being clipped */
	vco = 0;			/* no ouput vertices */
	vn = vpi[vci-1];		/* pointer to last vertex */
	inside = !(vn->cc & flag);	/* true if clip bit zero */
	for(vc=0; vc<vci; vc++) {
		last_in = inside;	/* save previous vertex status */
		vp = vn;
		vn = vpi[vc];		/* next vertex status */
		inside = !(vn->cc & flag);
	/* detect crossing */
		if (inside ^ last_in) { /* true if only one is zero */
	/* clip always in-to-out so shared edges have exact same vertex */
			vout = vn; vins = vp;
			if (inside) { vins = vn; vout = vp; }
			wo = vout->cw;
			xo = get_xyz( vout, index);
			wi = vins->cw;
			xi = get_xyz( vins, index);
			wone = 1;
			if (!(plane & 1)) { /* negative w plane */
				wi = -wi; wo = -wo; wone = -1; }
	/* for clipped coord equal to one less than w:
		wi + (wo - wi) * d - 1 = xi + (xo - xi) * d;
		or, d = (wi - xi - 1) / (xo - xi - wo + wi); */
			num = wi - xi - wone;
			den = xo - xi - wo + wi;
			clip_vertex( num, den, vins, vout, &vtx[vcn]);
			vpo[vco] = &vtx[vcn];	/* copy pointer */
			cc_clip |= vpo[vco]->cc; /* update clip code */
			vco++;			/* inc output count */
			vcn++;			/* inc vertex count */
			}
		if (inside) {	/* copy inside vertex */
			vpo[vco] = vpi[vc];	/* copy pointer */
			cc_clip |= vpo[vco]->cc; /* update clip code */
			vco++;			/* inc output count */
			}
		}
	vpt = vpi; vpi = vpo; vpo = vpt; /* flip input and output lists */
	vci = vco;	/* input count is previous output count */
	}
/* project the newly generated vertices (together here to possibly
	pipeline the divides). XXXX better to do only the output ones. */
for (vc=*vcount; vc<vcn; vc++) do_project( &vtx[vc]);
*vcount = vci;			/* update vertex count */
if (count & 1)	/* odd number of planes, so copy output to input */
	for (vc=0; vc<vco; vc++) va[vc] = vb[vc];
}
/*----------------------------*/
get_xyz( v, i)
/* XXXX vertex should be an array indexed by i instead of a structure */
struct Vertex *v;
int i;
{
if (i == 0) return( v->cx);
if (i == 1) return( v->cy);
return( v->cz);
}
/*----------------------------*/
clip_vertex( n, d, vi, vo, vn)
int n, d;
struct Vertex *vi, *vo, *vn;
{
/* XXXX should be vector ops */
int e, f, g;
	divide_seed( d, &e);
	divide_newt( d, e, &f);
	g = (int)((float)n*f);
	d = g;
/*
	if (d != 0) d = (int)((float)DIV_RECP_FRAC*n/d); 
*/
	clip_attr( d, vi->r, vo->r, &vn->r);
	clip_attr( d, vi->g, vo->g, &vn->g);
	clip_attr( d, vi->b, vo->b, &vn->b);
	clip_attr( d, vi->a, vo->a, &vn->a);
	clip_attr( d, vi->s, vo->s, &vn->s);
	clip_attr( d, vi->t, vo->t, &vn->t);
	clip_attr( d, vi->cx, vo->cx, &vn->cx);
	clip_attr( d, vi->cy, vo->cy, &vn->cy);
	clip_attr( d, vi->cz, vo->cz, &vn->cz);
	clip_attr( d, vi->cw, vo->cw, &vn->cw);
	do_clip_test( vn);	/* new flags for more plane tests */
	/* project later after done clipping */
}
/*----------------------------*/
clip_attr( a, i, o, n)
int a, i, o, *n;
{
*n = i + (int)((float)(o-i)*a*(float)1.0/DIV_RECP_FRAC);
}
/*----------------------------*/