home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
gondwana.ecr.mu.oz.au/pub/
/
Graphics.tar
/
Graphics
/
atomart.tar.gz
/
atomart.tar
/
stree.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-21
|
12KB
|
551 lines
#include <stdio.h>
#include <math.h>
#include "atomart.h"
#include "gram.h"
#include "macro.h"
extern object *oblist;
extern light *lights;
extern hlist *fhlist;
extern int maxhitlevel;
extern pixel backcol;
extern colour ambient;
extern double power();
extern float tolerance;
#define U 0
#define V 1
extern object *oblist;
extern light *lights;
extern hlist *fhlist;
extern int maxhitlevel;
extern pixel backcol;
extern colour ambient;
extern double power();
extern float tolerance;
/*
* shrinkbbox
*
* reduce the size of the bounding box for the leaf (if possible).
*/
shrinkbbox(leaf)
stree *leaf;
{
olist *ol;
sphere *s;
float val;
float minx, miny, minz;
float maxx, maxy, maxz;
if (leaf->u.leaf.oblist == (olist *)NULL)
return;
s = leaf->u.leaf.oblist->obj->u.sph;
minx = s->cent.x - s->rad;
miny = s->cent.y - s->rad;
minz = s->cent.z - s->rad;
maxx = s->cent.x + s->rad;
maxy = s->cent.y + s->rad;
maxz = s->cent.z + s->rad;
for (ol = leaf->u.leaf.oblist->nxt; ol != (olist *)NULL; ol = ol->nxt) {
s = ol->obj->u.sph;
val = s->cent.x - s->rad;
if (val < minx)
minx = val;
val = s->cent.x + s->rad;
if (val > maxx)
maxx = val;
val = s->cent.y - s->rad;
if (val < miny)
miny = val;
val = s->cent.y + s->rad;
if (val > maxy)
maxy = val;
val = s->cent.z - s->rad;
if (val < minz)
minz = val;
val = s->cent.z + s->rad;
if (val > maxz)
maxz = val;
}
if (minx > leaf->bb.min[X])
leaf->bb.min[X] = minx;
if (miny > leaf->bb.min[Y])
leaf->bb.min[Y] = miny;
if (minz > leaf->bb.min[Z])
leaf->bb.min[Z] = minz;
if (maxx < leaf->bb.max[X])
leaf->bb.max[X] = maxx;
if (maxy < leaf->bb.max[Y])
leaf->bb.max[Y] = maxy;
if (maxz < leaf->bb.max[Z])
leaf->bb.max[Z] = maxz;
}
/*
* splitleaf
*
* split a leaf along the middle of an axis.
*/
splitleaf(axis, leaf, val)
int axis;
stree *leaf;
float val;
{
olist *objs, *nxtobj, *tmpobj;
stree *left, *right;
int leftcount, rightcount;
float min, max;
sphere *s;
if (leaf->type != SPLITABLELEAF)
return;
left = (stree *)smalloc(sizeof(stree));
right = (stree *)smalloc(sizeof(stree));
leftcount = rightcount = 0;
left->u.leaf.oblist = right->u.leaf.oblist = (olist *)NULL;
left->bb = right->bb = leaf->bb;
left->bb.max[axis] = val;
right->bb.min[axis] = val;
for (objs = leaf->u.leaf.oblist; objs != (olist *)NULL; objs = nxtobj) {
nxtobj = objs->nxt;
s = objs->obj->u.sph;
switch (axis) {
case X:
min = s->cent.x - s->rad;
max = s->cent.x + s->rad;
break;
case Y:
min = s->cent.y - s->rad;
max = s->cent.y + s->rad;
break;
case Z:
min = s->cent.z - s->rad;
max = s->cent.z + s->rad;
break;
default:
fatal("atomart: bad axis in splitleaf.\n");
}
if (max < val) { /* to the left */
leftcount++;
objs->nxt = left->u.leaf.oblist;
left->u.leaf.oblist = objs;
} else if (min > val) { /* to the right */
rightcount++;
objs->nxt = right->u.leaf.oblist;
right->u.leaf.oblist = objs;
} else { /* in both (sigh) */
tmpobj = (olist *)smalloc(sizeof(olist));
tmpobj->obj = objs->obj;
leftcount++;
tmpobj->nxt = left->u.leaf.oblist;
left->u.leaf.oblist = tmpobj;
rightcount++;
objs->nxt = right->u.leaf.oblist;
right->u.leaf.oblist = objs;
}
}
shrinkbbox(left);
shrinkbbox(right);
left->u.leaf.depth = right->u.leaf.depth = leaf->u.leaf.depth + 1;
left->type = (leftcount < MAXOBJS || leaf->u.leaf.depth == 13) ? LEAF : SPLITABLELEAF;
right->type = (rightcount < MAXOBJS || leaf->u.leaf.depth == 13) ? LEAF : SPLITABLELEAF;
leaf->type = axis;
leaf->splitval = val;
leaf->u.branch.left = left;
leaf->u.branch.right = right;
/*
printf("%f %f %f %f %f\n", leaf->bb.min[X], leaf->bb.max[X], leaf->bb.min[Y], leaf->bb.max[Y], leaf->bb.min[Z], leaf->bb.max[Z]);
printf("%d %d\n", leftcount, rightcount);
printf("%f %f %f %f %f\n", left->bb.min[X], left->bb.max[X], left->bb.min[Y], left->bb.max[Y], left->bb.min[Z], left->bb.max[Z]);
printf("%f %f %f %f %f\n", right->bb.min[X], right->bb.max[X], right->bb.min[Y], right->bb.max[Y], right->bb.min[Z], right->bb.max[Z]);
*/
}
/*
* split
*
* split a splittable leaf into two nodes.
*/
void
split(root)
stree *root;
{
int total, left[3], right[3];
float vals[3], min, max;
olist *ol;
sphere *s;
total = 0;
vals[X] = (root->bb.max[X] + root->bb.min[X]) / 2;
vals[Y] = (root->bb.max[Y] + root->bb.min[Y]) / 2;
vals[Z] = (root->bb.max[Z] + root->bb.min[Z]) / 2;
left[X] = right[X] = 0;
left[Y] = right[Y] = 0;
left[Z] = right[Z] = 0;
for (ol = root->u.leaf.oblist; ol != (olist *)NULL; ol = ol->nxt) {
s = ol->obj->u.sph;
total++;
min = s->cent.x - s->rad; /* check for x */
max = s->cent.x + s->rad;
if (max < vals[X]) /* to the left */
left[X]++;
else if (min > vals[X]) /* to the right */
right[X]++;
else { /* in both (sigh) */
left[X]++;
right[X]++;
}
min = s->cent.y - s->rad; /* check for y */
max = s->cent.y + s->rad;
if (max < vals[Y]) /* to the left */
left[Y]++;
else if (min > vals[Y]) /* to the right */
right[Y]++;
else { /* in both (sigh) */
left[Y]++;
right[Y]++;
}
min = s->cent.z - s->rad; /* check for z */
max = s->cent.z + s->rad;
if (max < vals[Z]) /* to the left */
left[Z]++;
else if (min > vals[Z]) /* to the right */
right[Z]++;
else { /* in both (sigh) */
left[Z]++;
right[Z]++;
}
}
total += total / 3;
if ((left[X] + right[X]) < (left[Y] + right[Y]))
if ((left[X] + right[X]) < (left[Z] + right[Z])) {
if (left[X] + right[X] <= total)
splitleaf(X, root, vals[X]);
else
root->type = LEAF;
} else {
if (left[Z] + right[Z] <= total)
splitleaf(Z, root, vals[Z]);
else
root->type = LEAF;
}
else
if ((left[Y] + right[Y]) < (left[Z] + right[Z])) {
if (left[Y] + right[Y] <= total)
splitleaf(Y, root, vals[Y]);
else
root->type = LEAF;
} else {
if (left[Z] + right[Z] <= total)
splitleaf(Z, root, vals[Z]);
else
root->type = LEAF;
}
}
/*
* treei
*
* returns the first hit on the bsp tree tr.
*/
hlist *
treei(r, root)
register ray *r;
stree *root;
{
register olist *ol;
register hlist *hit, *prevhits, *lp, *hp;
object *o;
stree *nxtbranch;
register int p, u, v;
register float val, t1, t2, othert1, othert2;
float orgs[DIMS], dirs[DIMS];
prevhits = (hlist *)NULL;
hit = (hlist *)NULL;
if (root->type == SPLITABLELEAF) {
split(root);
hit = treei(r, root);
} else if (root->type == LEAF) {
for (ol = root->u.leaf.oblist; ol != (olist *)NULL; ol = ol->nxt) {
o = ol->obj;
if ((hit = o->intersects(r, o)) != (hlist *)NULL) {
if (prevhits == (hlist *)NULL) {
prevhits = hit;
} else {
if (prevhits->t > hit->t) {
for (hp = prevhits; hp != (hlist *)NULL; hp = lp) {
lp = hp->nxt;
release(hp);
}
prevhits = hit;
} else {
for (hp = hit; hp != (hlist *)NULL; hp = lp) {
lp = hp->nxt;
release(hp);
}
}
}
}
}
if (prevhits != (hlist *)NULL) {
val = r->org.x + r->dir.x * prevhits->t;
if (val > root->bb.max[X] || val < root->bb.min[X]) {
for (hp = prevhits; hp != (hlist *)NULL; hp = lp) {
lp = hp->nxt;
release(hp);
}
return((hlist *)NULL);
}
val = r->org.y + r->dir.y * prevhits->t;
if (val > root->bb.max[Y] || val < root->bb.min[Y]) {
for (hp = prevhits; hp != (hlist *)NULL; hp = lp) {
lp = hp->nxt;
release(hp);
}
return((hlist *)NULL);
}
val = r->org.z + r->dir.z * prevhits->t;
if (val > root->bb.max[Z] || val < root->bb.min[Z]) {
for (hp = prevhits; hp != (hlist *)NULL; hp = lp) {
lp = hp->nxt;
release(hp);
}
return((hlist *)NULL);
}
}
return(prevhits);
} else {
orgs[X] = r->org.x;
orgs[Y] = r->org.y;
orgs[Z] = r->org.z;
dirs[X] = r->dir.x;
dirs[Y] = r->dir.y;
dirs[Z] = r->dir.z;
p = root->type;
if (orgs[p] < root->splitval) {
if (orgs[p] < root->bb.min[p] && dirs[p] < 0.0)
return((hlist *)NULL);
hit = treei(r, root->u.branch.left);
if (hit != (hlist *)NULL) {
return(hit);
} else if (dirs[p] <= 0.0)
return((hlist *)NULL);
nxtbranch = root->u.branch.right;
t1 = (nxtbranch->bb.min[p] - orgs[p]) / dirs[p];
t2 = (nxtbranch->bb.max[p] - orgs[p]) / dirs[p];
} else {
if (orgs[p] > root->bb.max[p] && dirs[p] > 0.0)
return((hlist *)NULL);
hit = treei(r, root->u.branch.right);
if (hit != (hlist *)NULL) {
return(hit);
} else if (dirs[p] >= 0.0)
return((hlist *)NULL);
nxtbranch = root->u.branch.left;
t1 = (nxtbranch->bb.max[p] - orgs[p]) / dirs[p];
t2 = (nxtbranch->bb.min[p] - orgs[p]) / dirs[p];
}
if (p == X) {
u = Y;
v = Z;
} else if (p == Y) {
u = Z;
v = X;
} else {
u = X;
v = Y;
}
if (dirs[u] != 0.0) {
othert1 = (nxtbranch->bb.min[u] - orgs[u]) / dirs[u];
othert2 = (nxtbranch->bb.max[u] - orgs[u]) / dirs[u];
if (othert1 > othert2) {
if (othert1 < t1 || othert2 > t2)
return((hlist *)NULL);
} else {
if (othert2 < t1 || othert1 > t2)
return((hlist *)NULL);
}
} else {
if (nxtbranch->bb.min[u] > orgs[u])
return((hlist *)NULL);
if (nxtbranch->bb.max[u] < orgs[u])
return((hlist *)NULL);
}
if (dirs[v] != 0.0) {
othert1 = (nxtbranch->bb.min[v] - orgs[v]) / dirs[v];
othert2 = (nxtbranch->bb.max[v] - orgs[v]) / dirs[v];
if (othert1 > othert2) {
if (othert1 < t1 || othert2 > t2)
return((hlist *)NULL);
} else {
if (othert2 < t1 || othert1 > t2)
return((hlist *)NULL);
}
} else {
if (nxtbranch->bb.min[v] > orgs[v])
return((hlist *)NULL);
if (nxtbranch->bb.max[v] < orgs[v])
return((hlist *)NULL);
}
hit = treei(r, nxtbranch);
}
return(hit);
}
/*
* streei
*
* returns the first hit on the bsp tree in o
*/
hlist *
streei(r, o)
ray *r;
object *o;
{
return(treei(r, o->u.tree));
}
/*
* adjustbbox
*
* adjust the bounding box for a tree for the object o
*/
adjustbbox(tree, o)
stree *tree;
object *o;
{
register float val;
val = o->u.sph->cent.x - o->u.sph->rad;
if (val < tree->bb.min[X])
tree->bb.min[X] = val;
val = o->u.sph->cent.x + o->u.sph->rad;
if (val > tree->bb.max[X])
tree->bb.max[X] = val;
val = o->u.sph->cent.y - o->u.sph->rad;
if (val < tree->bb.min[Y])
tree->bb.min[Y] = val;
val = o->u.sph->cent.y + o->u.sph->rad;
if (val > tree->bb.max[Y])
tree->bb.max[Y] = val;
val = o->u.sph->cent.z - o->u.sph->rad;
if (val < tree->bb.min[Z])
tree->bb.min[Z] = val;
val = o->u.sph->cent.z + o->u.sph->rad;
if (val > tree->bb.max[Z])
tree->bb.max[Z] = val;
}
/*
* treeinit
*
* set up a bsp tree
*/
object *
treeinit(obs)
object *obs;
{
object *obj, *o;
olist *ol;
stree *tree;
obj = (object *)smalloc(sizeof(object));
obj->type = STREE;
obj->intersects = streei;
obj->u.tree = tree = (stree *)smalloc(sizeof(stree));
tree->type = SPLITABLELEAF;
tree->u.leaf.oblist = (olist *)NULL;
tree->u.leaf.depth = 0;
tree->bb.min[X] = obs->u.sph->cent.x - obs->u.sph->rad;
tree->bb.max[X] = obs->u.sph->cent.x + obs->u.sph->rad;
tree->bb.min[Y] = obs->u.sph->cent.y - obs->u.sph->rad;
tree->bb.max[Y] = obs->u.sph->cent.y + obs->u.sph->rad;
tree->bb.min[Z] = obs->u.sph->cent.z - obs->u.sph->rad;
tree->bb.max[Z] = obs->u.sph->cent.z + obs->u.sph->rad;
for (o = obs; o != (object *)NULL; o = o->nxt) {
ol = (olist *)smalloc(sizeof(olist));
ol->nxt = tree->u.leaf.oblist;
ol->obj = o;
adjustbbox(tree, o);
tree->u.leaf.oblist = ol;
}
return(obj);
}