home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
gondwana.ecr.mu.oz.au/pub/
/
Graphics.tar
/
Graphics
/
atomart.tar.gz
/
atomart.tar
/
sphere.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-28
|
4KB
|
228 lines
#include <math.h>
#include <stdio.h>
#include "atomart.h"
#include "macro.h"
#include "gram.h"
extern attr *astackp;
extern hlist *fhlist;
extern matrix trans;
/*
* spherei
*
* returns the closest hit for the ray r and sphere o.
*/
hlist *
spherei(r, o)
register ray *r;
register object *o;
{
vector c;
hlist *hp;
register float b, d;
if (o->raynumber == r->raynumber) {
if (o->lastt != 0.0) {
fetch(hp);
hp->t = o->lastt;
hp->obj = o;
hp->nxt = (hlist *)NULL;
return(hp);
} else
return((hlist *)NULL);
}
o->raynumber = r->raynumber;
o->lastt = 0.0;
vsub(c, r->org, o->u.sph->cent);
b = -dprod(c, r->dir);
d = b * b - (dprod(c, c) - o->u.sph->radsqu);
if (d < 0.0 || b < 0.0)
return((hlist *)NULL);
d = sqrt((double)d);
fetch(hp);
hp->t = b - d;
if (hp->t < TOLERANCE) {
hp->t = b + d;
if (hp->t < TOLERANCE) {
release(hp);
return((hlist *)NULL);
}
}
hp->obj = o;
hp->nxt = (hlist *)NULL;
o->lastt = hp->t;
return(hp);
}
/*
* spheren
*
* returns the normal to the sphere s
*/
void
spheren(n, l, o)
register vector *n;
register vector *l;
register object *o;
{
vsub(*n, *l, o->u.sph->cent);
normalise(*n);
}
/*
* spherec
*
* return the color of a sphere o at a the intersection point l.
*
*/
void
spherec(o, txt, l, n, pcol, type)
object *o;
texture *txt;
vector *l, *n;
pixel *pcol;
int type;
{
vector tmp, loc;
float t, u, v, theta, phi;
int w, h, indx;
totexture(txt, loc, *l);
t = -dprod(loc, txt->vref1);
if (fabs(t) > 1.0) /* precision check */
t = (t < 0.0) ? -1.0 : 1.0;
phi = acos(t);
v = phi / M_PI;
if (v != 0.0 && v != 1.0) {
t = dprod(txt->vref2, loc) / sin(phi);
if (fabs(t) > 1.0) /* precision check */
t = (t < 0.0) ? -1.0 : 1.0;
theta = acos(t) / (2 * M_PI);
xprod(tmp, txt->vref1, txt->vref2)
if (dprod(tmp, loc) > 0)
u = theta;
else
u = 1 - theta;
} else
u = 0.0;
w = u * txt->scalew;
h = v * txt->scaleh;
indx = (w % txt->pixw + (h % txt->pixh) * txt->pixw) * 3;
pcol->r = (unsigned char)txt->map[indx] / 255.0;
pcol->g = (unsigned char)txt->map[indx + 1] / 255.0;
pcol->b = (unsigned char)txt->map[indx + 2] / 255.0;
}
/*
* sphereinit
*
* initialise the function pointers and fields for a sphere object,
* returning its pointer.
*/
object *
sphereinit(d)
details *d;
{
object *o;
tlist *tl;
details *ld;
float radius;
sphere *s;
matrix tmp;
vector cent, v;
o = (object *)smalloc(sizeof(object));
o->type = SPHERE;
o->intersects = spherei;
o->normal = spheren;
o->raynumber = 0;
o->lastt = 0.0;
o->u.sph = s = (sphere *)smalloc(sizeof(sphere));
cent.x = cent.y = cent.z = 0.0;
radius = 1.0;
while (d != (details *)NULL) {
switch (d->type) {
case CENTER:
cent = d->u.v;
break;
case RADIUS:
radius = d->u.f;
break;
default:
warning("atomart: illegal field in sphere ignored.\n");
}
ld = d;
d = d->nxt;
free(ld);
}
cent.x /= astackp->scales.x;
cent.y /= astackp->scales.y;
cent.z /= astackp->scales.z;
mmult4(tmp, trans, astackp->m);
cent.x -= tmp[3][0];
cent.y -= tmp[3][1];
cent.z -= tmp[3][2];
v3x3tmult(s->cent, cent, tmp);
s->rad = radius * astackp->maxscale;
s->radsqu = s->rad * s->rad;
objtranslate(cent.x, cent.y, cent.z);
scale(radius, radius, radius);
setattributes(o);
for (tl = o->s.txtlist; tl != (tlist *)NULL; tl = tl->nxt)
if (tl->txtcol == (void (*)())NULL) {
if (!tl->txt.refset) {
tl->txt.vref1.y = 1.0;
tl->txt.vref1.x = tl->txt.vref1.z = 0.0;
tl->txt.vref2.x = 1.0;
tl->txt.vref2.y = tl->txt.vref2.z = 0.0;
}
tl->txtcol = spherec;
v3x3tmult(v, tl->txt.vref1, astackp->m);
tl->txt.vref1 = v;
v3x3tmult(v, tl->txt.vref2, astackp->m);
tl->txt.vref2 = v;
}
return(o);
}