home *** CD-ROM | disk | FTP | other *** search
- /*
- A word about the 3D library. Even though this library supports
- three dimensions, the matrices are 4x4 for the following reason.
- With normal 3 dimensional vectors, translation is an ADDITION,
- and rotation is a MULTIPLICATION. A vector {x,y,z} is represented
- as a 4-tuple {x,y,z,1}. It is then possible to define a 4x4
- matrix such that multiplying the vector by the matrix translates
- the vector. This allows combinations of translation and rotation
- to be obtained in a single matrix by multiplying a translation
- matrix and a rotation matrix together. Note that in the code,
- vectors have three components; since the fourth component is
- always 1, that value is not included in the vector variable to
- save space, but the routines make use of the fourth component
- (see vec_mult()). Similarly, the fourth column of EVERY matrix is
- always
- 0
- 0
- 0
- 1
- but currently the C version of a matrix includes this even though
- it could be left out of the data structure and assumed in the
- routines. Vectors are ROW vectors, and are always multiplied with
- matrices FROM THE LEFT (e.g. vector*matrix). Also note the order
- of indices of a matrix is matrix[row][column], and in usual C
- fashion, numbering starts with 0.
-
- TRANSLATION MATRIX = 1 0 0 0
- 0 1 0 0
- 0 0 1 0
- Tx Ty Tz 1
-
- SCALE MATRIX = Sx 0 0 0
- 0 Sy 0 0
- 0 0 Sz 0
- 0 0 0 1
-
- Rotation about x axis i degrees:
- ROTX(i) = 1 0 0 0
- 0 cosi sini 0
- 0 -sini cosi 0
- 0 0 0 1
-
- Rotation about y axis i degrees:
- ROTY(i) = cosi 0 -sini 0
- 0 1 0 0
- sini 0 cosi 0
- 0 0 0 1
-
- Rotation about z axis i degrees:
- ROTZ(i) = cosi sini 0 0
- -sini cosi 0 0
- 0 0 1 0
- 0 0 0 1
-
- -- Tim Wegner April 22, 1989
- */
-
- #include <stdio.h>
- #include <string.h>
- #include "prototyp.h"
-
- /* initialize a matrix and set to identity matrix
- (all 0's, 1's on diagonal) */
- void identity(MATRIX m)
- {
- int i,j;
- for(i=0;i<CMAX;i++)
- for(j=0;j<RMAX;j++)
- if(i==j)
- m[j][i] = 1.0;
- else
- m[j][i] = 0.0;
- }
-
- /* Multiply two matrices */
- void mat_mul(MATRIX mat1, MATRIX mat2, MATRIX mat3)
- {
- /* result stored in MATRIX new to avoid problems
- in case parameter mat3 == mat2 or mat 1 */
- MATRIX new;
- int i,j;
- for(i=0;i<4;i++)
- for(j=0;j<4;j++)
- new[j][i] = mat1[j][0]*mat2[0][i]+
- mat1[j][1]*mat2[1][i]+
- mat1[j][2]*mat2[2][i]+
- mat1[j][3]*mat2[3][i];
- memcpy(mat3,new,sizeof(new));
- }
-
- /* multiply a matrix by a scalar */
- void scale (double sx, double sy, double sz, MATRIX m)
- {
- MATRIX scale;
- identity(scale);
- scale[0][0] = sx;
- scale[1][1] = sy;
- scale[2][2] = sz;
- mat_mul(m,scale,m);
- }
-
- /* rotate about X axis */
- void xrot (double theta, MATRIX m)
- {
- MATRIX rot;
- double sintheta,costheta;
- sintheta = sin(theta);
- costheta = cos(theta);
- identity(rot);
- rot[1][1] = costheta;
- rot[1][2] = -sintheta;
- rot[2][1] = sintheta;
- rot[2][2] = costheta;
- mat_mul(m,rot,m);
- }
-
- /* rotate about Y axis */
- void yrot (double theta, MATRIX m)
- {
- MATRIX rot;
- double sintheta,costheta;
- sintheta = sin(theta);
- costheta = cos(theta);
- identity(rot);
- rot[0][0] = costheta;
- rot[0][2] = sintheta;
- rot[2][0] = -sintheta;
- rot[2][2] = costheta;
- mat_mul(m,rot,m);
- }
-
- /* rotate about Z axis */
- void zrot (double theta, MATRIX m)
- {
- MATRIX rot;
- double sintheta,costheta;
- sintheta = sin(theta);
- costheta = cos(theta);
- identity(rot);
- rot[0][0] = costheta;
- rot[0][1] = -sintheta;
- rot[1][0] = sintheta;
- rot[1][1] = costheta;
- mat_mul(m,rot,m);
- }
-
- /* translate */
- void trans (double tx, double ty, double tz, MATRIX m)
- {
- MATRIX trans;
- identity(trans);
- trans[3][0] = tx;
- trans[3][1] = ty;
- trans[3][2] = tz;
- mat_mul(m,trans,m);
- }
-
- /* cross product - useful because cross is perpendicular to v and w */
- int cross_product (VECTOR v, VECTOR w, VECTOR cross)
- {
- VECTOR tmp;
- tmp[0] = v[1]*w[2] - w[1]*v[2];
- tmp[1] = w[0]*v[2] - v[0]*w[2];
- tmp[2] = v[0]*w[1] - w[0]*v[1];
- cross[0] = tmp[0];
- cross[1] = tmp[1];
- cross[2] = tmp[2];
- return(0);
- }
-
- /* cross product integer arguments (not fudged) */
- /*** pb, unused
- int icross_product (IVECTOR v, IVECTOR w, IVECTOR cross)
- {
- IVECTOR tmp;
- tmp[0] = v[1]*w[2] - w[1]*v[2];
- tmp[1] = w[0]*v[2] - v[0]*w[2];
- tmp[2] = v[0]*w[1] - w[0]*v[1];
- cross[0] = tmp[0];
- cross[1] = tmp[1];
- cross[2] = tmp[2];
- return(0);
- }
- ***/
-
- /* normalize a vector to length 1 */
- normalize_vector(VECTOR v)
- {
- double vlength;
- vlength = dot_product(v,v);
-
- /* bailout if zero vlength */
- if(vlength < FLT_MIN || vlength > FLT_MAX)
- return(-1);
- vlength = sqrt(vlength);
- if(vlength < FLT_MIN)
- return(-1);
-
- v[0] /= vlength;
- v[1] /= vlength;
- v[2] /= vlength;
- return(0);
- }
-
- /* multiply source vector s by matrix m, result in target t */
- /* used to apply transformations to a vector */
- int vmult(VECTOR s, MATRIX m, VECTOR t)
- {
- VECTOR tmp;
- int i,j;
- for(j=0;j<CMAX-1;j++)
- {
- tmp[j] = 0.0;
- for(i=0;i<RMAX-1;i++)
- tmp[j] += s[i]*m[i][j];
- /* vector is really four dimensional with last component always 1 */
- tmp[j] += m[3][j];
- }
- /* set target = tmp. Necessary to use tmp in case source = target */
- memcpy(t,tmp,sizeof(tmp));
- return(0);
- }
-
- /* multiply vector s by matrix m, result in s */
- /* use with a function pointer in line3d.c */
- /* must coordinate calling conventions with */
- /* mult_vec_iit in general.asm */
- void mult_vec_c(VECTOR s)
- {
- VECTOR tmp;
- int i,j;
- for(j=0;j<CMAX-1;j++)
- {
- tmp[j] = 0.0;
- for(i=0;i<RMAX-1;i++)
- tmp[j] += s[i]*m[i][j];
- /* vector is really four dimensional with last component always 1 */
- tmp[j] += m[3][j];
- }
- /* set target = tmp. Necessary to use tmp in case source = target */
- memcpy(s,tmp,sizeof(tmp));
- }
-
- /* perspective projection of vector v with respect to viewpont vector view */
- perspective(VECTOR v)
- {
- double denom;
- denom = view[2] - v[2];
-
- if(denom >= 0.0)
- {
- v[0] = bad_value; /* clipping will catch these values */
- v[1] = bad_value; /* so they won't plot values BEHIND viewer */
- v[2] = bad_value;
- return(-1);
- }
- v[0] = (v[0]*view[2] - view[0]*v[2])/denom;
- v[1] = (v[1]*view[2] - view[1]*v[2])/denom;
-
- /* calculation of z if needed later */
- /* v[2] = v[2]/denom;*/
- return(0);
- }
-
- /* long version of vmult and perspective combined for speed */
- longvmultpersp(LVECTOR s, LMATRIX m, LVECTOR t0, LVECTOR t, LVECTOR lview,
- int bitshift)
- {
- /* s: source vector */
- /* m: transformation matrix */
- /* t0: after transformation, before persp */
- /* t: target vector */
- /* lview: perspective viewer coordinates */
- /* bitshift: fixed point conversion bitshift */
- LVECTOR tmp;
- int i,j, k;
- overflow = 0;
- k = CMAX-1; /* shorten the math if non-perspective and non-illum */
- if (lview[2] == 0 && t0[0] == 0) k--;
-
- for(j=0;j<k;j++)
- {
- tmp[j] = 0;
- for(i=0;i<RMAX-1;i++)
- tmp[j] += multiply(s[i],m[i][j],bitshift);
- /* vector is really four dimensional with last component always 1 */
- tmp[j] += m[3][j];
- }
- if(t0[0]) /* first component of t0 used as flag */
- {
- /* faster than for loop, if less general */
- t0[0] = tmp[0];
- t0[1] = tmp[1];
- t0[2] = tmp[2];
- }
- if (lview[2] != 0) /* perspective 3D */
- {
-
- LVECTOR tmpview;
- long denom;
-
- denom = lview[2] - tmp[2];
- if (denom >= 0) /* bail out if point is "behind" us */
- {
- t[0] = bad_value;
- t[0] = t[0]<<bitshift;
- t[1] = t[0];
- t[2] = t[0];
- return(-1);
- }
-
- /* doing math in this order helps prevent overflow */
- tmpview[0] = divide(lview[0],denom,bitshift);
- tmpview[1] = divide(lview[1],denom,bitshift);
- tmpview[2] = divide(lview[2],denom,bitshift);
-
- tmp[0] = multiply(tmp[0], tmpview[2], bitshift) -
- multiply(tmpview[0], tmp[2], bitshift);
-
- tmp[1] = multiply(tmp[1], tmpview[2], bitshift) -
- multiply(tmpview[1], tmp[2], bitshift);
-
- /* z coordinate if needed */
- /* tmp[2] = divide(lview[2],denom); */
- }
-
- /* set target = tmp. Necessary to use tmp in case source = target */
- /* faster than for loop, if less general */
- t[0] = tmp[0];
- t[1] = tmp[1];
- t[2] = tmp[2];
- return(overflow);
- }
-
- /* Long version of perspective. Because of use of fixed point math, there
- is danger of overflow and underflow */
- longpersp(LVECTOR lv, LVECTOR lview, int bitshift)
- {
- LVECTOR tmpview;
- long denom;
- overflow = 0;
- denom = lview[2] - lv[2];
- if (denom >= 0) /* bail out if point is "behind" us */
- {
- lv[0] = bad_value;
- lv[0] = lv[0]<<bitshift;
- lv[1] = lv[0];
- lv[2] = lv[0];
- return(-1);
- }
-
- /* doing math in this order helps prevent overflow */
- tmpview[0] = divide(lview[0],denom,bitshift);
- tmpview[1] = divide(lview[1],denom,bitshift);
- tmpview[2] = divide(lview[2],denom,bitshift);
-
- lv[0] = multiply(lv[0], tmpview[2], bitshift) -
- multiply(tmpview[0], lv[2], bitshift);
-
- lv[1] = multiply(lv[1], tmpview[2], bitshift) -
- multiply(tmpview[1], lv[2], bitshift);
-
- /* z coordinate if needed */
- /* lv[2] = divide(lview[2],denom); */
- return(overflow);
- }
-
- int longvmult(LVECTOR s,LMATRIX m,LVECTOR t,int bitshift)
- {
- LVECTOR tmp;
- int i,j, k;
- overflow = 0;
- k = CMAX-1;
-
- for(j=0;j<k;j++)
- {
- tmp[j] = 0;
- for(i=0;i<RMAX-1;i++)
- tmp[j] += multiply(s[i],m[i][j],bitshift);
- /* vector is really four dimensional with last component always 1 */
- tmp[j] += m[3][j];
- }
-
- /* set target = tmp. Necessary to use tmp in case source = target */
- /* faster than for loop, if less general */
- t[0] = tmp[0];
- t[1] = tmp[1];
- t[2] = tmp[2];
- return(overflow);
- }
-