home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Virtual Reality Homebrewer's Handbook
/
vr.iso
/
vr386
/
intmath
/
matrix.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-19
|
7KB
|
280 lines
// Non-assembler matrix math routines
// All code by Dave Stampe, last updated 23/12/93
/*
This code is part of the VR-386 project, created by Dave Stampe.
VR-386 is a desendent of REND386, created by Dave Stampe and
Bernie Roehl. Almost all the code has been rewritten by Dave
Stampre for VR-386.
Copyright (c) 1994 by Dave Stampe:
May be freely used to write software for release into the public domain
or for educational use; all commercial endeavours MUST contact Dave Stampe
(dstampe@psych.toronto.edu) for permission to incorporate any part of
this software or source code into their products! Usually there is no
charge for under 50-100 items for low-cost or shareware products, and terms
are reasonable. Any royalties are used for development, so equipment is
often acceptable payment.
ATTRIBUTION: If you use any part of this source code or the libraries
in your projects, you must give attribution to VR-386 and Dave Stampe,
and any other authors in your documentation, source code, and at startup
of your program. Let's keep the freeware ball rolling!
DEVELOPMENT: VR-386 is a effort to develop the process started by
REND386, improving programmer access by rewriting the code and supplying
a standard API. If you write improvements, add new functions rather
than rewriting current functions. This will make it possible to
include you improved code in the next API release. YOU can help advance
VR-386. Comments on the API are welcome.
CONTACT: dstampe@psych.toronto.edu
*/
#include <mem.h> /* memcpy() */
#include "intmath.h"
/******************** MISC. VECTOR MATH ****************/
/* replaces column N of a matrix with cross of other 2 */
/* used to speed computations, repair matrix scaling */
void cross_column(MATRIX m, int col)
{
extern void cross_product(long *col1, long *col2, long *col3); // asm code
long *c1, *c2, *c3;
switch (col)
{
case 0:
c1 = &(m[0][1]);
c2 = &(m[0][2]);
c3 = &(m[0][0]);
break;
case 1:
c1 = &(m[0][2]);
c2 = &(m[0][0]);
c3 = &(m[0][1]);
break;
case 2:
c1 = &(m[0][0]);
c2 = &(m[0][1]);
c3 = &(m[0][2]);
break;
}
cross_product(c1, c2, c3);
}
/****************** MATRIX MANIPULATION ***************/
#define XFSC 536870912 /* 2**29 for shifting real to <3.29 fixed point */
void identity_matrix(MATRIX m)
{
int i, j;
m[0][0] = m[1][1] = m[2][2] = XFSC;
m[1][0] = m[2][0] = m[3][0] = 0;
m[0][1] = m[2][1] = m[3][1] = 0;
m[0][2] = m[1][2] = m[3][2] = 0;
}
/* copy 3x4 matrix */
void matrix_copy(MATRIX m, MATRIX n)
{
memcpy (n, m, sizeof(MATRIX));
}
/* copy 3x3 rotation part of matrix */
void matrix_rot_copy(MATRIX m, MATRIX n)
{
memcpy (n, m, sizeof(MATRIX));
n[3][0] = n[3][1] = n[3][2] = 0;
}
/*************** ANGLE/POSITION TO HOMOGENOUS MATRIX ************/
// assembler from matrixm.asm
extern void matrix_RXYZ(MATRIX m, long rx, long ry, long rz,
long tx, long ty, long tz);
extern void matrix_RYXZ(MATRIX m, long rx, long ry, long rz,
long tx, long ty, long tz);
extern void matrix_RXZY(MATRIX m, long rx, long ry, long rz,
long tx, long ty, long tz);
#define RXYZ 1 /* matrix rotation types */
#define RYXZ 0
#define RXZY 2
#define RZYX 5
#define RZXY 4
#define RYZX 6 /* create rotation/translation */
/* "matrix" from angle data */
void multi_matrix(MATRIX m, long rx, long ry, long rz,
long tx, long ty, long tz, int type )
{
if (rx == 0) /* tests for single-axis rotates */
{ /* much faster to directly make */
if (ry == 0)
{
identity_matrix(m);
if (rz != 0)
{
m[0][0] = m[1][1] = icosine(rz);
m[1][0] = isine(rz);
m[0][1] = -m[1][0];
}
goto shortcut;
}
else if (rz == 0)
{
identity_matrix(m);
m[0][0] = m[2][2] = icosine(ry);
m[0][2] = isine(ry);
m[2][0] = -m[0][2];
goto shortcut;
}
}
else if (ry == 0 && rz == 0)
{
identity_matrix(m);
m[1][1] = m[2][2] = icosine(rx);
m[2][1] = isine(rx);
m[1][2] = -m[2][1];
goto shortcut;
}
switch(type&7)
{
case RXYZ:
matrix_RXYZ(m,rx,ry,rz,tx,ty,tz);
break;
case RZYX:
matrix_RXYZ(m,-rx,-ry,-rz,tx,ty,tz); // reverse order: just
matrix_transpose(m,m); // negate angles, take
break; // rotational inverse
case RYXZ:
matrix_RYXZ(m,rx,ry,rz,tx,ty,tz);
break;
case RZXY:
matrix_RYXZ(m,-rx,-ry,-rz,tx,ty,tz);
matrix_transpose(m,m);
break;
case RXZY:
matrix_RXZY(m,rx,ry,rz,tx,ty,tz);
break;
case RYZX:
matrix_RXZY(m,-rx,-ry,-rz,tx,ty,tz);
matrix_transpose(m,m);
break;
}
return;
shortcut:
m[3][0] = tx;
m[3][1] = ty;
m[3][2] = tz;
}
/* the default matrix: RYXZ */
/* used for camera transform */
void std_matrix(MATRIX m, long rx, long ry, long rz,
long tx, long ty, long tz)
{
multi_matrix(m, rx, ry, rz, tx, ty, tz, RYXZ);
}
/*************** MATRIX-TO-ANGLES (RYXZ ONLY) *************/
void matrix_to_angle(MATRIX m, long *rx, long *ry, long *rz)
{
long t,p,a;
long c2;
if (m[1][2] > 536334041 || m[1][2] < -536334041)
{
c2 = magnitude32(m[0][2],m[2][2],0); /* need accuracy for this one */
if (c2 > 2000000)
{
p = arccosine(c2);
if (m[1][2] < 0) p = -p;
}
else
{
t = (m[1][2] < 0) ? 90*65536L : -90*65536L; /* works with Z-axis rule */
a = 0;
p = arccosine(m[1][0]);
if (m[1][2] > 0) p = -p;
goto assign;
}
}
else p = -arcsine(m[1][2]);
t = arctan2(m[0][2], m[2][2]);
a = arctan2(m[1][0], m[1][1]);
assign:
*ry = t;
*rx = p;
*rz = a;
}
/******************* MATRIX RENORMALIZE ***************/
#define XFLC 536870912 // fixed -> <3.29>
void renormalize_matrix(MATRIX m) /* slow but sure: do once every 1000 matrix mults */
{
set_vector_magnitude32(XFLC, &m[0][0], &m[0][1], &m[0][2]);
set_vector_magnitude32(XFLC, &m[1][0], &m[1][1], &m[1][2]);
set_vector_magnitude32(XFLC, &m[2][0], &m[2][1], &m[2][2]);
set_vector_magnitude32(XFLC, &m[0][0], &m[1][0], &m[2][0]);
set_vector_magnitude32(XFLC, &m[0][1], &m[1][1], &m[2][1]);
set_vector_magnitude32(XFLC, &m[0][2], &m[1][2], &m[2][2]);
}
/******************* MATRIX FROM VECTOR ***************/
void vector_to_matrix(MATRIX m, long x, long y, long z)
{
long ya = arctan2(x, z);
long sz = magnitude32(x,y,z);
long r = divide_29(y, sz );
long xa = -arcsine(r);
std_matrix(m, xa, ya, 0, 0, 0, 0);
}