transform.c 5 KB

#include "graphic.h"
#include <stdio.h>

/*----------------------------------------------*/
do_clip_test( v)
struct Vertex *v;
{
	VU_REG(0, Vvtxci) = v->cx;
	VU_REG(1, Vvtxci) = v->cy;
	VU_REG(2, Vvtxci) = v->cz;
	VU_REG(3, Vvtxci) = v->cw;
	cmp_cl(Vvtxci, Vvtxci, 3);
	v->cc = VU_VCC;
}
/*----------------------------------------------*/
do_project( v)
struct Vertex *v;
{
	VU_REG(0, Vvtxci) = v->cx;
	VU_REG(1, Vvtxci) = v->cy;
	VU_REG(2, Vvtxci) = v->cz;
	VU_REG(3, Vvtxci) = v->cw;
	/* project */
	divh(Vnull, Vzero, 3, Vrwh);
	divl(Vnull, Vvtxci, 3, Vrwl);
	mudhs(Vvtxci, Vrwh, 3, Vnull);
	madms(Vvtxci, Vrwl, 3, Vvtxs);
	/* image */
	mudh(Vone, Vdct, Vnull);
	maci(Vvtxs, Vdcs, Vvtxs);

	v->x = VU_REG(0, Vvtxs);
	v->y = VU_REG(1, Vvtxs);
	v->z = v->cz;		/* VU_REG(2, Vvtxs); */
}
/*----------------------------------------------*/
do_transform( ma, is, vi, vo)
struct Matrix *ma;
struct Image_space *is;
struct Vertex *vi, *vo;
{
float xa, ya, za, wa;
float xb, yb, zb, wb;
float rw;
unsigned long clipcode = 0;

	*vo = *vi;	/* copy attributes */
	xa = vi->x;
	ya = vi->y;
	za = vi->z;
	wa = vi->w = (float)1.0;

#ifdef VU_SIM
	/*
	 * XXX right now, 1/W is a double precision divide. later we
	 * might figure out how to generate a W whose reciprocal is
	 * sufficiently accurate in 16 bits. 
	 */

	VU_REG(0, Vvtxo) = vi->x;
	VU_REG(1, Vvtxo) = vi->y;
	VU_REG(2, Vvtxo) = vi->z;

	/* xform */
	mudhs(Vmtxi0, Vvtxo, 0, Vnull);
	madms(Vmtxf0, Vvtxo, 0, Vnull);
	madhs(Vmtxi1, Vvtxo, 1, Vnull);
	madms(Vmtxf1, Vvtxo, 1, Vnull);
	madhs(Vmtxi2, Vvtxo, 2, Vnull);
	madms(Vmtxf2, Vvtxo, 2, Vnull);
	madhs(Vmtxi3, Vone, 0, Vnull);
	madms(Vmtxf3, Vone, 0, Vvtxci);

	/* clip test */
	cmp_cl(Vvtxci, Vvtxci, 3);

	/* save vcc, actually a cpmov to su */
	vo->cc = VU_VCC;

	/* save clip coordinates for clipping,
		and w for texture coords (actually will need 1/w too) */
	vo->cx = VU_REG(0, Vvtxci);
	vo->cy = VU_REG(1, Vvtxci);
	vo->cz = VU_REG(2, Vvtxci);
	vo->cw = VU_REG(3, Vvtxci);

	/* project */
	divh(Vnull, Vzero, 3, Vrwh);
	divl(Vnull, Vvtxci, 3, Vrwl);
	mudhs(Vvtxci, Vrwh, 3, Vnull);
	madms(Vvtxci, Vrwl, 3, Vvtxs);

	/* image */
	mudh(Vone, Vdct, Vnull);
	maci(Vvtxs, Vdcs, Vvtxs);

	vo->x = VU_REG(0, Vvtxs);
	vo->y = VU_REG(1, Vvtxs);
	vo->z = VU_REG(2, Vvtxs);

        vo->z = vo->cz;	/* use this for z-buffer tests */

#ifdef 0
printf("y %d y/w %d w %d 1/w(h) %d 1/w(l) %d\n", vu.vregs[1][Vvtxci], vu.vregs[1][Vvtxs], vu.vregs[3][Vvtxci], vu.vregs[3][Vrwh], vu.vregs[3][Vrwl]);
#endif

	return(VU_VCC);
#else

	/* transform */
	xb = 	xa * ma->m[0][0] + ya * ma->m[1][0] + 
		za * ma->m[2][0] + wa * ma->m[3][0];
	yb = 	xa * ma->m[0][1] + ya * ma->m[1][1] + 
		za * ma->m[2][1] + wa * ma->m[3][1];
	zb = 	xa * ma->m[0][2] + ya * ma->m[1][2] + 
		za * ma->m[2][2] + wa * ma->m[3][2];
	wb = 	xa * ma->m[0][3] + ya * ma->m[1][3] + 
		za * ma->m[2][3] + wa * ma->m[3][3];

	/* save w for texture coords (actually will need 1/w too) */
	vo->w = wb;

	/* clip test */
	if (yb < -wb) clipcode |= CLIP_BOTTOM;
	if (yb > wb) clipcode |= CLIP_TOP;
	if (xb < -wb) clipcode |= CLIP_LEFT;
	if (xb > wb) clipcode |= CLIP_RIGHT;
	if (zb < -wb) clipcode |= CLIP_NEAR;
	if (zb > wb) clipcode |= CLIP_FAR;

	/* project */
	rw = 1/wb;
	xb *= rw;
	yb *= rw;
	zb *= rw;

	/* image */
	vo->x = (int)(xb * is->sx + is->tx);
	vo->y = (int)(yb * is->sy + is->ty);
        vo->z = (int)(zb * is->sz + is->tz);

/*
printf("cc: %02x\n", clipcode);
*/
	return (clipcode);
#endif
}
/*----------------------------------------------*/
do_tc_transform( im, nw, vi, vo)
struct Image *im;
int nw;
struct Vertex *vi, *vo;
{
int s, t, w;
/* convert s, t to image coordinates */
        s = tc_image( vi->s, (im->xsize-1));
        t = tc_image( vi->t, (im->ysize-1));
	w = TC_PERSP_ONE-1;	/* maximum 1/w */
if (en_tc_persp) {
/* 	wn is the nearest w of the primitive. each w is normalized to w/nw.
	since perspective correction needs 1/w, s/w, and t/w, the
	reciprocal of w is combined with normalization to be nw/w,
	which is between 0 and 1, scaled by TC_PERSP_ONE to be a large
	integer (and not overflow at vertex wn where w/wn is 1.0).
	1/w should be retained from vertex projection.
*/
	w = (int)((TC_PERSP_ONE)*(float)nw/(float)vi->cw);
	s = (int)((float)s*w) >> TC_PERSP_SHFT;
	t = (int)((float)t*w) >> TC_PERSP_SHFT;
  	} 
	vo->s = s;
	vo->t = t;
	vo->w = w;
}
/*----------------------------------------------*/
do_normal_transform( m, v)
struct Matrix *m;
struct Vertex *v;
{
	float	x, y, z;

	x = 	v->nx * m->m[0][0] + v->ny * m->m[1][0] + 
		v->nz * m->m[2][0];
	y = 	v->nx * m->m[0][1] + v->ny * m->m[1][1] + 
		v->nz * m->m[2][1];
	z = 	v->nx * m->m[0][2] + v->ny * m->m[1][2] + 
		v->nz * m->m[2][2];

	v->nx = x;
	v->ny = y;
	v->nz = z;
}
/*----------------------------------------------*/
do_light_transform( m, l)
struct Matrix *m;
struct Light *l;
{
	float	x, y, z;

	x = 	l->nx * m->m[0][0] + l->ny * m->m[1][0] + 
		l->nz * m->m[2][0];
	y = 	l->nx * m->m[0][1] + l->ny * m->m[1][1] + 
		l->nz * m->m[2][1];
	z = 	l->nx * m->m[0][2] + l->ny * m->m[1][2] + 
		l->nz * m->m[2][2];

	l->nx = x;
	l->ny = y;
	l->nz = z;
}