File:  [Research Unix] / researchv10no / cmd / view2d / term / 3d.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:35 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

/*% 3cc -c %
 * Fixed-point 3d coordinate transform routines for machines with
 * 16 bit shorts and 32 bit longs.
 */
#include	<CC/jerq.h>
#include	<CC/3d.h>
#include	<CC/font.h>
static Hcoordl cur;
static Point cen;
Point Ap, Bp;
static int wid;
/*
 * angles are scaled so that PI=>32768
 * Since unsigned shorts are 16 bits, 2*PI overflows and yields
 * 0, which seems appropriate.
 */
angle cvtangle[361]={
0,	182,	364,	546,	728,	910,	1092,	1274,
1456,	1638,	1820,	2002,	2184,	2366,	2548,	2730,
2912,	3094,	3276,	3458,	3640,	3822,	4004,	4187,
4369,	4551,	4733,	4915,	5097,	5279,	5461,	5643,
5825,	6007,	6189,	6371,	6553,	6735,	6917,	7099,
7281,	7463,	7645,	7827,	8009,	8192,	8374,	8556,
8738,	8920,	9102,	9284,	9466,	9648,	9830,	10012,
10194,	10376,	10558,	10740,	10922,	11104,	11286,	11468,
11650,	11832,	12014,	12196,	12379,	12561,	12743,	12925,
13107,	13289,	13471,	13653,	13835,	14017,	14199,	14381,
14563,	14745,	14927,	15109,	15291,	15473,	15655,	15837,
16019,	16201,	16384,	16566,	16748,	16930,	17112,	17294,
17476,	17658,	17840,	18022,	18204,	18386,	18568,	18750,
18932,	19114,	19296,	19478,	19660,	19842,	20024,	20206,
20388,	20571,	20753,	20935,	21117,	21299,	21481,	21663,
21845,	22027,	22209,	22391,	22573,	22755,	22937,	23119,
23301,	23483,	23665,	23847,	24029,	24211,	24393,	24576,
24758,	24940,	25122,	25304,	25486,	25668,	25850,	26032,
26214,	26396,	26578,	26760,	26942,	27124,	27306,	27488,
27670,	27852,	28034,	28216,	28398,	28580,	28763,	28945,
29127,	29309,	29491,	29673,	29855,	30037,	30219,	30401,
30583,	30765,	30947,	31129,	31311,	31493,	31675,	31857,
32039,	32221,	32403,	32585,	32768,	32950,	33132,	33314,
33496,	33678,	33860,	34042,	34224,	34406,	34588,	34770,
34952,	35134,	35316,	35498,	35680,	35862,	36044,	36226,
36408,	36590,	36772,	36955,	37137,	37319,	37501,	37683,
37865,	38047,	38229,	38411,	38593,	38775,	38957,	39139,
39321,	39503,	39685,	39867,	40049,	40231,	40413,	40595,
40777,	40960,	41142,	41324,	41506,	41688,	41870,	42052,
42234,	42416,	42598,	42780,	42962,	43144,	43326,	43508,
43690,	43872,	44054,	44236,	44418,	44600,	44782,	44964,
45147,	45329,	45511,	45693,	45875,	46057,	46239,	46421,
46603,	46785,	46967,	47149,	47331,	47513,	47695,	47877,
48059,	48241,	48423,	48605,	48787,	48969,	49152,	49334,
49516,	49698,	49880,	50062,	50244,	50426,	50608,	50790,
50972,	51154,	51336,	51518,	51700,	51882,	52064,	52246,
52428,	52610,	52792,	52974,	53156,	53339,	53521,	53703,
53885,	54067,	54249,	54431,	54613,	54795,	54977,	55159,
55341,	55523,	55705,	55887,	56069,	56251,	56433,	56615,
56797,	56979,	57161,	57344,	57526,	57708,	57890,	58072,
58254,	58436,	58618,	58800,	58982,	59164,	59346,	59528,
59710,	59892,	60074,	60256,	60438,	60620,	60802,	60984,
61166,	61348,	61531,	61713,	61895,	62077,	62259,	62441,
62623,	62805,	62987,	63169,	63351,	63533,	63715,	63897,
64079,	64261,	64443,	64625,	64807,	64989,	65171,	65353,
65536,	
};
static fract sintab[128+2]={
0,	201,	402,	603,	803,	1004,	1205,	1405,
1605,	1805,	2005,	2204,	2404,	2602,	2801,	2998,
3196,	3393,	3589,	3785,	3980,	4175,	4369,	4563,
4756,	4948,	5139,	5329,	5519,	5708,	5896,	6083,
6269,	6455,	6639,	6822,	7005,	7186,	7366,	7545,
7723,	7900,	8075,	8249,	8423,	8594,	8765,	8934,
9102,	9268,	9434,	9597,	9759,	9920,	10079,	10237,
10393,	10548,	10701,	10853,	11002,	11150,	11297,	11442,
11585,	11726,	11866,	12003,	12139,	12273,	12406,	12536,
12665,	12791,	12916,	13038,	13159,	13278,	13395,	13510,
13622,	13733,	13842,	13948,	14053,	14155,	14255,	14353,
14449,	14543,	14634,	14723,	14810,	14895,	14978,	15058,
15136,	15212,	15286,	15357,	15426,	15492,	15557,	15618,
15678,	15735,	15790,	15842,	15892,	15940,	15985,	16028,
16069,	16107,	16142,	16175,	16206,	16234,	16260,	16284,
16305,	16323,	16339,	16353,	16364,	16372,	16379,	16382,
16384,	16382,	
};
fract isin(x)
register angle x;
{
	register fract a, b;
	register i, f=0;
	if(x>=PI){
		x-=PI;
		f=1;
	}
	if(x>PI/2)
		x=PI-x;
	i=x>>7;
	a=sintab[i];
	b=sintab[i+1]-a;
	i=x&0177;
	a+=(b*i+64)/128;
	return(f?-a:a);
}
fract icos(x)
register angle x;
{
	return(isin(x+PI/2));
}
long isqrt(a)
register long a;
{
	register long x, y;
	if(a<=0)return(0);
	for(y=a,x=1;y!=0;y>>=2,x<<=1);
	while((y=(a/x+x)>>1)<x)x=y;
	return(x);
}
#define	NSTACK	32
Hcoord hcoord(x, y, z, w)
fract x, y, z, w;
{
	Hcoord r;
	r.x=x;
	r.y=y;
	r.z=z;
	r.w=w;
	return(r);
}
matrix stack3[NSTACK]={
	ONE,0,0,0,
	0,ONE,0,0,
	0,0,ONE,0,
	0,0,0,ONE,
};
matrix *sp3=stack3;		/* matrix stack pointer */
/*
 * Initialize the matrix stack.
 * v is the viewport into which to map the image.  (d/s) is the distance to the
 * screen, whose half-width is 1. (equivalently, d is the distance to a screen of
 * half-size s.)
 */
Bitmap *viewport;
init3(v, d, s)
Bitmap *v;
{
	sp3=stack3;
	ident(*sp3);
	(*sp3)[0][0]=(*sp3)[2][2]=d;
	(*sp3)[1][1]=s;
	(*sp3)[3][3]=s;
	viewport=v;
	cen=div(add(v->rect.origin, v->rect.corner), 2);
	wid=min(v->rect.corner.x-v->rect.origin.x,
		v->rect.corner.y-v->rect.origin.y)/2;
}
/*
 * Push a copy of the top of the matrix stack onto the stack
 */
push3(){
	register i, j;
	;if(sp3==stack3+NSTACK-1)
		return(-1);
	for(i=0;i!=4;i++) for(j=0;j!=4;j++)
		sp3[1][i][j]=sp3[0][i][j];
	sp3++;
	return(0);
}
/*
 * pop the top matrix off the stack
 */
pop3(){
	if(sp3==stack3)
		return(-1);
	--sp3;
	return(0);
}
/*
 * Multiply the top matrix on the stack by rotation of angle theta about
 * the given axis.
 */
rot3(theta, axis)
angle theta;
{
	rotsc3(isin(theta), icos(theta), axis);
}
/*
 * rotate, given the sin and cosine of the rotation angle.
 */
rotsc3(s, c, axis)
short s, c;
{
	matrix m;
	register i=(axis+1)%3, j=(axis+2)%3;
	ident(m);
	m[i][i] = c;
	m[i][j] = -s;
	m[j][i] = s;
	m[j][j] = c;
	xform3(m);
}
/*
 * Scale by a factor of [xyz]/w about axis [xyz]
 */
scale3(p)
Hcoord p;
{
	matrix m;
	ident(m);
	m[0][0]=p.x;
	m[1][1]=p.y;
	m[2][2]=p.z;
	m[3][3]=p.w;
	xform3(m);
}
/*
 * translate by (dx/dw, dy/dw, dz/dw)
 */
tran3(p)
Hcoord p;
{
	matrix m;
	ident(m);
	m[0][0]=p.w;
	m[1][1]=p.w;
	m[2][2]=p.w;
	m[3][3]=p.w;
	m[0][3]=p.x;
	m[1][3]=p.y;
	m[2][3]=p.z;
	xform3(m);
}
/*
 * Store an identity matrix in m
 */
ident(m)
matrix m;
{
	register fract *s = &m[0][0];
	*s++=ONE;*s++=0;*s++=0;*s++=0;
	*s++=0;*s++=ONE;*s++=0;*s++=0;
	*s++=0;*s++=0;*s++=ONE;*s++=0;
	*s++=0;*s++=0;*s++=0;*s++=ONE;
}
/*
 * Multiply the top of the matrix stack by m
 */
xform3(m)
matrix m;
{
	register i, j, k;
	long sum, max=0;
	long tmp[4][4];
	char buf[128];

	for(i=0;i!=4;i++) for(j=0;j!=4;j++){
		sum=0;
		for(k=0;k!=4;k++)
			sum+=(long)(*sp3)[i][k]*m[k][j];
		tmp[i][j]=sum;
		if(sum<0)
			sum = -sum;
		if(sum>max)
			max=sum;
	}
	if((k = max/(ONE-1)) == 0) k = 1;
	for(i=0;i!=4;i++) for(j=0;j!=4;j++)
		(*sp3)[i][j]=tmp[i][j]/k;
}
long dot(a, b)
Hcoord a, b;
{
	return((long)a.x*b.x+(long)a.y*b.y+(long)a.z*b.z);
}
Hcoord unitize(a)
Hcoord a;
{
	short l=isqrt(dot(a, a));
	Hcoord v;
	if(l==0){
		v=a;
		v.w=0;
	}
	else{
		if(a.w<0) l = -l;
		v.x=muldiv(a.x, ONE, l);
		v.y=muldiv(a.y, ONE, l);
		v.z=muldiv(a.z, ONE, l);
		v.w=ONE;
	}
	return(v);
}
Hcoord cross(a, b)
Hcoord a, b;
{
	Hcoord r;
	r.x=((long)a.y*b.z-(long)a.z*b.y)/ONE;
	r.y=((long)a.z*b.x-(long)a.x*b.z)/ONE;
	r.z=((long)a.x*b.y-(long)a.y*b.x)/ONE;
	r.w=ONE;
	return(r);
}
/*
 * multiply the top of the maxrix stack by a view-pointing transformation
 * with the eyepoint at e, looking in direction (lx, ly, lz),
 * with up direction (ux, uy, uz)
 */
look3(e, l, u)
Hcoord e, l, u;
{
	matrix m;
	fract len;
	Hcoord r;

	/*printf("look3(e=(%d,%d,%d,%d), l=(%d,%d,%d,%d), u=(%d,%d,%d,%d))\n",
		e.x,e.y,e.z,e.w,l.x,l.y,l.z,l.w,u.x,u.y,u.z,u.w);*/
	l=unitize(l);
	if(l.w==0){
		l.y=ONE;
		l.w=ONE;
	}
	/* Adjust u to be perpendicular to l */
	u=unitize(u);
	len=dot(u, l)/ONE;
	u.x-=muldiv(len, l.x, ONE);
	u.y-=muldiv(len, l.y, ONE);
	u.z-=muldiv(len, l.z, ONE);
	u=unitize(u);
	if(u.w==0){
		u.z=ONE;
		u.w=ONE;
	}
	r=cross(l, u);
	/*printf("r=(%d,%d,%d,%d), l=(%d,%d,%d,%d), u=(%d,%d,%d,%d))\n",
		r.x,r.y,r.z,r.w,l.x,l.y,l.z,l.w,u.x,u.y,u.z,u.w);*/
	/* make the matrix to transform from (rlu) space to (xyz) space */
	ident(m);
	m[0][0]=r.x; m[0][1]=r.y; m[0][2]=r.z;
	m[1][0]=l.x; m[1][1]=l.y; m[1][2]=l.z;
	m[2][0]=u.x; m[2][1]=u.y; m[2][2]=u.z;
	xform3(m);
	tran3(hcoord(e.x, e.y, e.z, -e.w));
}
Hcoordl xformp(p)
Hcoord p;
{
	Hcoordl r;
	r.x=(long)(*sp3)[0][0]*p.x+(long)(*sp3)[0][1]*p.y
		+(long)(*sp3)[0][2]*p.z+(long)(*sp3)[0][3]*p.w;
	r.y=(long)(*sp3)[1][0]*p.x+(long)(*sp3)[1][1]*p.y
		+(long)(*sp3)[1][2]*p.z+(long)(*sp3)[1][3]*p.w;
	r.z=(long)(*sp3)[2][0]*p.x+(long)(*sp3)[2][1]*p.y
		+(long)(*sp3)[2][2]*p.z+(long)(*sp3)[2][3]*p.w;
	r.w=(long)(*sp3)[3][0]*p.x+(long)(*sp3)[3][1]*p.y
		+(long)(*sp3)[3][2]*p.z+(long)(*sp3)[3][3]*p.w;
	return(r);
}
move3(p)
Hcoord p;
{
	cur=xformp(p);
	/*printf("move3(%d,%d,%d,%d)\n", p.x, p.y, p.z, p.w);*/
}
line3(p)
Hcoord p;
{
	Hcoordl new;
	/*printf("line3(%d,%d,%d,%d)\n", p.x, p.y, p.z, p.w);*/
	new=xformp(p);
	clipanddraw(cur, new);
	cur=new;
}
/*
 * clip points to the viewing volume, then do perspective division
 * and mapping to screen coordinates and draw lines.  We only clip against the
 * eye plane, trusting segment to clip in x and z.  There probably should
 * be some overflow precaution taken in the multiplication by n/d.
 */
int clip3scale = 0;

static clipanddraw(a, b)
Hcoordl a, b;
{
	Point A, B;
	Hcoordl t;
	int clip=0;
	long n, d;
	long m;
	long as, bs;
#define		OV	(32767)		/* 2**(15.5) */
	/*
	 * we clip against the plane p=(0,1,0,-1)  [this corresponds
	 * to the euclidean plane y=1.  This is picked rather than y=0
	 * to avoid a divide check in the perspective divide]
	 * First we check to see if one endpoint is on each side of the plane.
	 * and if necessary switch them so that a is behind and b is in front.
	 * then we replace a by a+(b-a)*n/d, where p.(a+(b-a)*n/d)=0
	 * i.e.	a.y+(b.y-a.y)*n/d-a.w-(b.w-a.w)*n/d=0
	 *	(b.y-a.y-b.w+a.w)*n/d=a.w-a.y
	 *	n/d=(a.w-a.y)/(b.y-a.y-b.w+a.w)
	 */
	/*printf("clipanddraw(a=(%d,%d,%d,%d), b=(%d,%d,%d,%d)\n",
		a.x,a.y,a.z,a.w,b.x,b.y,b.z,b.w);*/
	if(a.w>0?a.y<a.w:a.y>a.w)	/* eqv. a.y/a.w<1, but avoids divide */
		clip++;
	if(b.w>0?b.y<b.w:b.y>b.w){
		if(clip)		/* both points behind y=1 plane */
		{
			/*printf("clipped out of existence\n");*/
			return;
		}
		t=a;
		a=b;
		b=t;
		clip++;
	}
	/* check for overflow */
	m = max(max(abs(a.x), abs(a.y)), max(abs(a.z), abs(b.x)));
	m = max(m, max(max(abs(b.y), abs(b.z)), max(abs(a.w), abs(b.w))));
	if(m > OV)
	{
		m = (m+OV-1)/OV;
		a.x /= m;
		a.y /= m;
		a.z /= m;
		a.w /= m;
		b.x /= m;
		b.y /= m;
		b.z /= m;
		b.w /= m;
	}
	if(clip){
		n=a.w-a.y;
		d=b.y-a.y-b.w+a.w;
		if(d==0)			/* never happens? */
			return;
		a.x+=(b.x-a.x)*n/d;
		a.y+=(b.y-a.y)*n/d;
		a.z+=(b.z-a.z)*n/d;
		a.w+=(b.w-a.w)*n/d;	/* don't use w below */
		/*printf("clipped to a=(%d,%d,%d,%d), b=(%d,%d,%d,%d)\n",
			a.x,a.y,a.z,a.w,b.x,b.y,b.z,b.w);*/
	}
	if(clip3scale)
	{
		as = a.w*clip3scale;
		bs = b.w*clip3scale;
	}
	else
	{
		as = a.y;
		bs = b.y;
	}
	A=add(Pt((short)muldiv(a.x, wid, as), (short)muldiv(-a.z, wid, as)), cen);
	B=add(Pt((short)muldiv(b.x, wid, bs), (short)muldiv(-b.z, wid, bs)), cen);
#define	safe(P)	if(P.x<-16000)P.x= -16000;if(P.x>16000)P.x=16000;if(P.y<-16000)P.y= -16000;if(P.y>16000)P.y=16000
	safe(A);
	safe(B);
	Ap = A;
	Bp = B;
	segment(viewport, A, B, F_OR);
	/*printf("---->drew points (%d,%d) - (%d,%d)\n", A.x, A.y, B.x, B.y);*/
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.