home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
gondwana.ecr.mu.oz.au/pub/
/
Graphics.tar
/
Graphics
/
atomart.tar.gz
/
atomart.tar
/
util.c
< prev
Wrap
C/C++ Source or Header
|
1990-06-17
|
6KB
|
357 lines
#include <stdio.h>
#include <math.h>
#include "atomart.h"
#include "macro.h"
extern attr *astackp;
extern matrix trans;
extern vector org;
/*
* utility routines for adjusting transformations, general calcs and other
* things.
*/
/*
* power
*
* raise x to the integer power e
*/
double
power(x, e)
double x;
register int e;
{
register double a, b;
b = x;
switch (e) {
case 0:
return(1.0);
case 1:
return(b);
case 2:
return(b * b);
case 3:
return(b * b * b);
case 4:
b *= b;
return(b * b);
case 5:
b *= b;
return(b * b * x);
case 6:
b *= b;
return(b * b * b);
default:
e -= 6;
a = b * b;
a = a * a * a;
for (;;) {
if (e & 1) {
a *= b;
if ((e /= 2) == 0)
return(a);
} else
e /= 2;
b *= b;
}
}
/* NOTREACHED */
}
/*
* rotate
*
* adjust the transformation matrix for a rotate - done in reverse
* as it is done to the ray.
*/
rotate(ang, axis)
float ang;
char axis;
{
matrix mat, tmp;
float sinval, cosval;
mident4(mat);
sinval = sin(-ang * M_PI / 180.0);
cosval = cos(-ang * M_PI / 180.0);
switch (axis) {
case 'x':
mat[1][1] = cosval;
mat[1][2] = sinval;
mat[2][2] = cosval;
mat[2][1] = -sinval;
break;
case 'y':
mat[0][0] = cosval;
mat[0][2] = sinval;
mat[2][0] = -sinval;
mat[2][2] = cosval;
break;
case 'z':
mat[0][0] = cosval;
mat[0][1] = sinval;
mat[1][0] = -sinval;
mat[1][1] = cosval;
break;
default:
fatal("atomart: bad axis name in rotate.\n");
}
mcpy4(tmp, astackp->m);
mmult4(astackp->m, mat, tmp);
astackp->mcopy = TRUE;
}
/*
* translate
*
* translate - done in reverse as we do this to the ray.
*/
translate(x, y, z)
float x, y, z;
{
matrix mat, tmp;
mident4(mat);
mat[3][0] = -x;
mat[3][1] = -y;
mat[3][2] = -z;
mcpy4(tmp, astackp->m);
mmult4(astackp->m, mat, tmp);
}
/*
* objtranslate
*
* translate done through the current transformation matrix.
*/
objtranslate(x, y, z)
float x, y, z;
{
matrix mat, tmp;
mident4(mat);
mat[3][0] = -x / astackp->scales.x;
mat[3][1] = -y / astackp->scales.y;
mat[3][2] = -z / astackp->scales.z;
mcpy4(tmp, astackp->m);
mmult4(astackp->m, tmp, mat);
}
/*
* scale
*
* scale routine - done in reverse as we do this to the ray.
*/
scale(x, y, z)
float x, y, z;
{
astackp->scales.x /= x;
astackp->scales.y /= y;
astackp->scales.z /= z;
if (astackp->scales.x < astackp->scales.y)
astackp->maxscale = astackp->scales.x;
else
astackp->maxscale = astackp->scales.y;
if (astackp->scales.z < astackp->maxscale)
astackp->maxscale = astackp->scales.z;
astackp->maxscale = 1.0 / astackp->maxscale;
}
/*
* qtransform
*
* set up the appropriate rotations, scaling, and translations for
* a cylinder, cone, or general quadric. This routine needs to be
* called before radii, etc... are taken into account.
*/
qtransform(cent1, cent2)
vector cent1, cent2;
{
float sinval, cosval, d1, d2, d3;
matrix m, tmp;
/*
* translate it
*/
mident4(m);
m[3][0] = -cent1.x / astackp->scales.x;
m[3][1] = -cent1.y / astackp->scales.y;
m[3][2] = -cent1.z / astackp->scales.z;
mcpy4(tmp, astackp->m);
mmult4(astackp->m, tmp, m);
/*
* fix the quadric's height
*/
scale(1.0, 1.0, sqrt(sqr(cent2.x - cent1.x) + sqr(cent2.y - cent1.y) + sqr(cent2.z - cent1.z)));
/*
* calculate the rotations to align the ray
* with the quadric's axis
*/
d1 = cent1.x - cent2.x;
d2 = cent1.y - cent2.y;
d3 = cent1.z - cent2.z;
if (d1 != 0.0 || d3 != 0.0) { /* rotate about y */
sinval = -d1 / sqrt(d1 * d1 + d3 * d3);
cosval = d3 / sqrt(d1 * d1 + d3 * d3);
if (fabs(sinval) > 1.0)
sinval = (sinval > 0.0) ? 1.0 : -1.0;
if (fabs(cosval) > 1.0)
cosval = (cosval > 0.0) ? 1.0 : -1.0;
mident4(m);
m[0][0] = cosval;
m[2][0] = sinval;
m[0][2] = -sinval;
m[2][2] = cosval;
mcpy4(tmp, astackp->m);
mmult4(astackp->m, tmp, m);
}
if (d2 != 0.0) { /* rotate about x */
sinval = d2 / sqrt(d1 * d1 + d2 * d2 + d3 * d3);
if (fabs(sinval) > 1.0)
sinval = (sinval > 0.0) ? 1.0 : -1.0;
cosval = sqrt(1.0 - sinval * sinval);
mident4(m);
m[1][1] = cosval;
m[1][2] = sinval;
m[2][2] = cosval;
m[2][1] = -sinval;
mcpy4(tmp, astackp->m);
mmult4(astackp->m, tmp, m);
}
/*
* twist around y to align with positive in z
* (the transformations above align us in negative z)
*/
mident4(m);
m[0][0] = -1.0;
m[2][2] = -1.0;
mcpy4(tmp, astackp->m);
mmult4(astackp->m, tmp, m);
astackp->mcopy = TRUE;
}
/*
* setattributes
*
* set the attributes and transformations for an object.
*/
setattributes(o)
object *o;
{
matrix tmp;
tlist *tl, *tlnxt;
o->s = astackp->s;
/*
* put textures into correct order and set some parameters
*/
o->s.txtlist = (tlist *)NULL;
for (tl = astackp->s.txtlist; tl != (tlist *)NULL; tl = tlnxt) {
tlnxt = tl->nxt;
tl->nxt = o->s.txtlist;
o->s.txtlist = tl;
o->s.txtlist->txt.c = astackp->s.c;
o->s.txtlist->txt.a = astackp->s.a;
}
}
/*
* readascmap
*
* read in an ascii texture/bump map.
*/
readascmap(txt, name)
texture *txt;
char *name;
{
FILE *f;
int c, noheader, x, y, tot;
float val1, val2, val3;
char buf[BUFSIZ];
if ((f = fopen(name, "r")) == (FILE *)NULL) {
sprintf(buf, "atomart: can't open ascii map file %s.\n", name);
fatal(buf);
}
noheader = TRUE;
while (noheader && (c = getc(f)) != EOF) {
if (c == '#') /* comment */
while ((c = getc(f)) != '\n' && c != EOF)
;
else {
ungetc(c, f);
if (fscanf(f, "%d %d ", &x, &y) != 2) {
sprintf(buf, "atomart: improper header in ascii map file %s.\n", name);
fatal(buf);
}
noheader = FALSE;
}
}
txt->pixw = x;
txt->pixh = y;
txt->map = (char *)smalloc(x * y * 3);
if (noheader) {
sprintf(buf, "atomart: no header in ascii map file %s.\n", name);
fatal(buf);
}
tot = 0;
while (tot < x * y && (c = getc(f)) != EOF) {
if (c == '#') /* comment */
while ((c = getc(f)) != '\n' && c != EOF)
;
else {
ungetc(c, f);
if (fscanf(f, "%f %f %f ", &val1, &val2, &val3) != 3) {
sprintf(buf, "atomart: improper data in ascii map file %s.\n", name);
fatal(buf);
}
txt->map[tot * 3] = val1 * 255.0;
txt->map[tot * 3 + 1] = val2 * 255.0;
txt->map[tot * 3 + 2] = val3 * 255.0;
tot++;
}
}
if (tot != x * y) {
sprintf(buf, "atomart: ascii map file %s too short.\n", name);
warning(buf);
}
fclose(f);
}