home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************/
- /* hbvol.c */
- /* */
- /* Hierarchical bounding volume code. */
- /* Use of algorithm by [Goldsmith and Salmon87] for automatic */
- /* create of the hierarchy. Note: no shuffling or sorting has been */
- /* done on the input data. Also assume that only axis-aligned */
- /* bounding boxes are in the tree. */
- /* */
- /* Also code for receiver object list creation wrt a given source. */
- /* */
- /* Copyright (C) 1992, Bernard Kwok */
- /* All rights reserved. */
- /* Revision 1.0 */
- /* May, 1992 */
- /**********************************************************************/
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
- #include "misc.h"
- #include "geo.h"
- #include "struct.h"
- #include "io.h"
- #include "bvol.h"
- #include "scull.h"
-
- extern OptionType Option;
- extern void BoundsPrint();
- extern BoundingBoxType BoxPoly();
- extern Scene RadScene; /* Scene enclosed by hiearchy */
- HBBox Scene_BVH; /* Scene bounding volume hierarchy */
- HBBox_OptionType HBoxOption /* Hierarchy building options */
- = { UNCHANGED, ALL_BOX };
-
- Object_List *objlist; /* List of objects seen by source patch*/
- Object_List *objlist_tail; /* End of list */
- int objlist_size = 0; /* Size of list */
- int objlist_receivers = 0; /* Number of object that are receivers */
- HBBox root_BVH;
-
- /**********************************************************************/
- /* Print a box node */
- /**********************************************************************/
- void BVH_PrintBox(BVtree)
- HBBox *BVtree;
- {
- printf("\tHBox {\n");
- printf("\tarea: %g; ", BVtree->area);
- if (BVtree->object != NULL) {
- printf("object: %s%d ", BVtree->object->name, BVtree->object->id);
- if (BVtree->poly != NULL)
- printf("polygon: %s%d\n", BVtree->poly->name, BVtree->poly->id);
- else
- printf("\n");
- } else
- printf("object: None\n");
-
-
- printf("\tlevel %d; ", BVtree->level);
- if (BVtree->father != NULL)
- printf("father level: %d; ", BVtree->father->level);
- else
- printf("This is the root !; ");
- printf("%d children\n", BVtree->num_children);
-
- BoundsPrint(*BVtree->box, stdout, "");
- printf("\t}\n");
- }
-
- /**********************************************************************/
- /* Print BV tree */
- /**********************************************************************/
- void BVH_PrintHier(BVtree)
- HBBox *BVtree;
- {
- int i;
-
- if (BVtree != NULL)
- for (i=0;i<BVtree->num_children;i++) {
- BVH_PrintBox(BVtree->child[i]);
- BVH_PrintHier(BVtree->child[i]);
- }
- }
-
- /**********************************************************************/
- /* Cost of bounding box is proportional to area of box */
- /**********************************************************************/
- double BVH_Cost_Box(bbox)
- BoundingBoxType *bbox;
- {
- double dx,dy,dz;
-
- dx = bbox->max.x - bbox->min.x;
- dy = bbox->max.y - bbox->min.y;
- dz = bbox->max.z - bbox->min.z;
-
- if (HBoxOption.boxtype == ALL_BOX)
- return((dx + dy)*dz + dx*dy);
- else
- return(2.0*dx*dy + 2.0*dx*dz + 2.0*dy*dz);
- }
-
- /**********************************************************************/
- /* Cost of bounding sphere is proportional to area of sphere */
- /**********************************************************************/
- double BVH_Cost_Sphere(bsph)
- BoundingSphereType *bsph;
- {
- if (HBoxOption.boxtype == ALL_SPHERE)
- return(bsph->r * bsph->r);
- else
- return(4.0 * PI * bsph->r * bsph->r);
- }
-
- /**********************************************************************/
- /* Is node a leaf */
- /**********************************************************************/
- int IsLeafBox(hbox)
- HBBox *hbox;
- { return (hbox->num_children == 0); }
-
- /**********************************************************************/
- /* Maximum number of children reached */
- /**********************************************************************/
- int IsFullBox(hbox)
- HBBox *hbox;
- { return (hbox->num_children == MAX_BV_CHILDREN); }
-
- /**********************************************************************/
- /* Incremental area as a result of insertion of new bounding volume */
- /* into an existing one */
- /**********************************************************************/
- double BVH_IncrementalCost_Box(hbox, newbox)
- HBBox *hbox;
- BoundingBoxType *newbox;
- {
- double old_area, new_area;
- BoundingBoxType incrbox;
- double delta_area;
-
- /* Find increase in area if new box where put into hier. box */
- old_area = hbox->area;
- Bounds_Union(*hbox->box, *newbox, &incrbox);
- new_area = BVH_Cost_Box(&incrbox);
- delta_area = new_area - old_area;
-
- if (Option.debug)
- if (delta_area == 0.0) {
- printf("\tHey no change in area if you added this box in !\n");
- } else {
- printf("\tChange in area = %g\n", delta_area);
- }
- return delta_area;
- }
-
- /**********************************************************************/
- /* Create a new box in heriarchical BV tree */
- /**********************************************************************/
- HBBox *HBBox_Create(box, poly, obj, hb_father, level)
- BoundingBoxType *box;
- Polygon *poly;
- Objectt *obj;
- HBBox *hb_father;
- int level;
- {
- int i;
- HBBox *newhbox;
-
- newhbox = (HBBox *) malloc(sizeof(HBBox));
- newhbox->box = box;
- newhbox->area = BVH_Cost_Box(box);
- newhbox->poly = poly;
- newhbox->object = obj;
- if (hb_father != 0) {
- newhbox->father = hb_father;
- } else { /* Is the root of the tree */
- newhbox->father = (HBBox *)NULL;
- }
- newhbox->level = level;
- newhbox->num_children = 0; /* No children */
- for (i=0;i<MAX_BV_CHILDREN;i++)
- newhbox->child[i] = (HBBox *)NULL;
-
- return newhbox;
- }
-
- /**********************************************************************/
- /* Find cost to add to box to each of children. Return minimum cost */
- /* found and path of minimum cost. */
- /**********************************************************************/
- int BVH_MinCost_Child(BVtree, box, min_incr)
- HBBox *BVtree;
- BoundingBoxType *box;
- double *min_incr;
- {
- int i;
- double incr_cost;
- HBBox *childbox;
- int min_path;
-
- if (Option.debug) printf("\tStart finding min cost child[0]\n");
- childbox = BVtree->child[0];
- *min_incr = BVH_IncrementalCost_Box(childbox, box);
- min_path = 0;
-
- for(i=1;i<BVtree->num_children;i++) {
- if (Option.debug) printf("\tStart finding min cost child[%d]\n", i);
- childbox = BVtree->child[i];
- incr_cost = BVH_IncrementalCost_Box(childbox, box);
- if (incr_cost < *min_incr) { /* Find a new min path */
- *min_incr = incr_cost;
- min_path = i;
- }
- }
-
- if (Option.debug) printf("\tEnd finding min cost child\n");
- return min_path;
- }
-
- /**********************************************************************/
- /* Make a duplicate of BV node */
- /**********************************************************************/
- HBBox *BVH_DuplicateBox(hbox)
- HBBox *hbox;
- {
- int i;
- HBBox *nhbox;
-
- nhbox = (HBBox *) malloc(sizeof(HBBox));
- nhbox->area = hbox->area;
- nhbox->box = hbox->box;
- nhbox->poly = hbox->poly;
- nhbox->object = hbox->object;
- nhbox->father = hbox->father;
- nhbox->num_children = hbox->num_children;
- for (i=0;i<MAX_BV_CHILDREN;i++)
- nhbox->child[i] = hbox->child[i];
- nhbox->level = hbox->level;
-
- return nhbox;
- }
-
- /**********************************************************************/
- /* Quick hack to fix poly root box update problem */
- /**********************************************************************/
- void Enlarge_Root()
- {
- int i;
- BoundingBoxType *newroot_box;
-
- newroot_box = (BoundingBoxType *) malloc(sizeof(BoundingBoxType));
- *newroot_box = *Scene_BVH.box;
-
- for (i=0;i<Scene_BVH.num_children;i++) {
- Bounds_Union(*Scene_BVH.child[i]->box, *newroot_box, newroot_box);
- }
- Scene_BVH.box = newroot_box;
- Scene_BVH.area = BVH_Cost_Box(Scene_BVH.box);
- }
-
- /**********************************************************************/
- /* Enlarge boxes along a path from a current node up to the root by */
- /* amount of addition of a new box at the current node */
- /**********************************************************************/
- void Enlarge_Ancestors(BVtree, box)
- HBBox *BVtree;
- BoundingBoxType *box;
- {
- BoundingBoxType *newfather_box;
-
- if (BVtree != 0) {
- /* printf("At level %d:\n", BVtree->level); */
-
- newfather_box = (BoundingBoxType *) malloc(sizeof(BoundingBoxType));
- Bounds_Union(*box, *BVtree->box, newfather_box);
- free(BVtree->box);
- BVtree->box = newfather_box;
- BVtree->area = BVH_Cost_Box(newfather_box);
- Enlarge_Ancestors(BVtree->father, box);
- }
- }
-
- /**********************************************************************/
- /* Add box as sibling of cuurent BV, create new father */
- /**********************************************************************/
- void BVH_AddBox_Sibling(BVtree, box, pptr, optr, child_index)
- HBBox *BVtree;
- BoundingBoxType *box;
- Polygon *pptr;
- Objectt *optr;
- int child_index;
- {
- HBBox *newhbox, *new_father, *BVtree_sib;
- HBBox *old_father;
- BoundingBoxType *newfather_box;
-
- if (Option.debug) printf("\tAdding as sibling\n");
-
- /* Make duplicate of current node (for pointer updating) */
- BVtree_sib = BVH_DuplicateBox(BVtree);
- BVtree_sib->level++; /* Push down 1 level ! */
- old_father = BVtree->father;
-
- /* Create new node for object box to insert (one level down) */
- newhbox = HBBox_Create(box, pptr, optr,
- (HBBox *)NULL, BVtree->level+1);
-
- /* New node needs a new parent = union(new BV node, current node) */
- newfather_box = (BoundingBoxType *) malloc(sizeof(BoundingBoxType));
- Bounds_Union(*box, *BVtree->box, newfather_box);
- new_father = HBBox_Create(newfather_box, (Polygon *)NULL,
- (Objectt *)NULL, old_father, BVtree->level);
- new_father->num_children = 2;
- new_father->child[0] = BVtree_sib;
- new_father->child[1] = newhbox;
-
- /* Link old nodes father to old nodes new father */
- if (old_father == NULL) {
- root_BVH = *new_father;
- /* root_BVH->box = newfather_box; */
- BVtree_sib->father = &root_BVH;
- newhbox->father = &root_BVH;
- } else if (old_father != NULL) {
- old_father->child[child_index] = new_father;
- BVtree_sib->father = new_father;
- newhbox->father = new_father;
- }
-
- /* Traverse up the tree and increase size of ancestor boxes
- starting with old-father of current box */
- if (old_father != NULL)
- Enlarge_Ancestors(old_father, box);
- }
-
- /**********************************************************************/
- /* Add box as child of BV tree node with children */
- /**********************************************************************/
- void BVH_AddBox_Child(BVtree, pptr, optr, box)
- HBBox *BVtree;
- BoundingBoxType *box;
- Polygon *pptr;
- Objectt *optr;
- {
- HBBox *newhbox;
- BoundingBoxType *newcurrent_box;
-
- if (Option.debug) printf("\tAdding as child\n");
-
- /* Create new box for current node
- = union(old+box to insert), discard old */
- newcurrent_box = (BoundingBoxType *) malloc(sizeof(BoundingBoxType));
- Bounds_Union(*box, *BVtree->box, newcurrent_box);
- free(BVtree->box);
- BVtree->box = newcurrent_box;
-
- /* Create new node for box to insert, and link father to it */
- newhbox = HBBox_Create(box, pptr, optr, BVtree, BVtree->level+1);
- BVtree->child[BVtree->num_children] = newhbox;
- BVtree->num_children++;
-
- /* Traverse up the tree and increase size of ancestor boxes
- starting with father of current box */
- if (BVtree != NULL)
- Enlarge_Ancestors(BVtree, box);
- }
-
- HBBox *addition_pos; /* Current node position to add to */
- /**********************************************************************/
- /* Place box in the current BV tree */
- /**********************************************************************/
- void BVH_AddBox_To_Hier(BVtree, pptr, optr, box, level, child_index,
- min_child_index, global_min_incr)
- HBBox *BVtree; /* Current node to check */
- Polygon *pptr; /* Polygon's BV to add */
- Objectt *optr; /* Object's BV to add */
- BoundingBoxType *box; /* Box to add */
- int *child_index; /* Index of father to current node */
- int *min_child_index; /* Link to node to insert box under */
- double *global_min_incr; /* Current minimum increase cost */
- {
- double child_min_incr; /* Local increase */
- int min_path; /* Local path to follow */
-
- if (IsLeafBox(BVtree)) { /* Is a leaf check for addition to leaf */
- child_min_incr = BVH_IncrementalCost_Box(BVtree, box);
- if (child_min_incr <= *global_min_incr) {
- *min_child_index = *child_index;
- *global_min_incr = child_min_incr;
- addition_pos = BVtree;
- if (Option.debug) {
- printf("\t+ Adding under box:\n");
- BoundsPrint(*BVtree->box, stdout, "");
- }
- }
- } else {
- /* Continue to traverse down tree and find place to put the box */
- /* Find path whose incr. area will be minimized if you add this
- object's box to it. */
- min_path = BVH_MinCost_Child(BVtree, box, &child_min_incr);
-
- /* Update minimum incremental cost, and position to add
- if necessary */
- if (child_min_incr <= *global_min_incr) {
- *min_child_index = min_path;
- *global_min_incr = child_min_incr;
- addition_pos = BVtree->child[min_path];
- if (Option.debug) {
- printf("\t+ Adding under box:\n");
- BoundsPrint(*BVtree->child[min_path]->box, stdout, "");
- }
- }
-
- if (Option.debug) {
- printf("\n\tAt level %d\n", level);
- printf("\tFollowing min path %d, global incr. cost = %g\n",
- min_path, *global_min_incr);
- }
-
- /* Follow the path that provides the minimum incremental cost */
- level++;
- *child_index = min_path;
- BVH_AddBox_To_Hier(BVtree->child[min_path], pptr, optr, box,
- level, child_index, min_child_index,
- global_min_incr);
- }
- }
-
- /**********************************************************************/
- /* Create bounding volume hierarchy from the bounding volumes in the */
- /* scene */
- /**********************************************************************/
- void BVH_Create_Hierarchy(theScene, scene_BVH)
- Scene *theScene;
- HBBox *scene_BVH;
- {
- int i;
- int child_index;
- int min_child_index;
- int level = 0;
- Scene *sptr;
- Objectt *optr;
- double min_insert_cost;
- int temp;
-
- printf("\n\t*** Building Hierarchical BV's from scene ***\n");
- temp = Option.debug; Option.debug = 0;
-
- sptr = theScene;
- optr=sptr->objects;
-
- /* First object is the root */
- root_BVH = *HBBox_Create(optr->box, (Polygon *)NULL, optr,
- (HBBox *)NULL, level);
- optr++;
-
- /* Scan rest of objects in the scene and add to global BV tree */
- for(i=1;i<sptr->num_objects;i++, optr++) {
- min_insert_cost = DAMN_LARGE; /* Initialize minimum position, cost */
- addition_pos = NULL;
- min_child_index = -1;
-
- /* Check the rest of the tree for a smaller minimum cost */
- BVH_AddBox_To_Hier(&root_BVH, (Polygon *)0, optr,
- optr->box, level, &child_index,
- &min_child_index, &min_insert_cost);
-
- /* Insert new node into correct position, enlarge ancestor's boxes */
- if (!IsLeafBox(addition_pos) && !IsFullBox(addition_pos))
- BVH_AddBox_Child(addition_pos, (Polygon *)0, optr, optr->box);
- else
- BVH_AddBox_Sibling(addition_pos, optr->box, (Polygon *)0, optr,
- min_child_index);
-
- if (Option.debug) printf("\tCost to insert %s%d's box = %g\n",
- optr->name, optr->id, min_insert_cost);
- }
- *scene_BVH = root_BVH;
- Option.debug = temp;
- }
-
- int p_count = 0;
- /**********************************************************************/
- /* Create polygon hierarchical bounding volumes */
- /**********************************************************************/
- void BVH_Create_PHierarchy(hbox)
- HBBox *hbox;
- {
- int i,j;
- int child_index;
- int min_child_index;
- int level;
- double min_insert_cost;
- Mesh *mptr;
- Polygon *pptr;
- Objectt *optr;
- BoundingBoxType *pbox;
-
- /* Add polygons of objects under node for object */
- if (hbox->object != 0 && hbox->poly == 0) {
- optr = hbox->object;
- if (optr->primid == MESH) { /* Only add polys for meshes ! */
- for(i=0,mptr=optr->meshes;i<optr->num_meshes;i++, mptr++) {
-
- /* Add first polygon */
- /* first_BVH = HBBox_Create(pptr->box, pptr, optr,
- hbox, level); */
-
- pptr = mptr->polys;
- pbox = (BoundingBoxType *) malloc(sizeof(BoundingBoxType));
- *pbox = BoxPoly(pptr);
- p_count++;
-
- BVH_AddBox_Child(hbox, pptr, optr, pbox);
- pptr = pptr->next;
-
- /* BVH_PrintBox(&Scene_BVH);
- BVH_PrintHier(&Scene_BVH); */
-
- for(j=1;j<mptr->num_polys;j++, pptr=pptr->next) {
- level = hbox->level;
- min_insert_cost = DAMN_LARGE;
- addition_pos = NULL;
- min_child_index = -1;
- child_index = 0;
-
- /* Create bounding box for the current polygon and add it to
- tree under the object node at the min-cost position */
- pbox = (BoundingBoxType *) malloc(sizeof(BoundingBoxType));
- *pbox = BoxPoly(pptr);
- BVH_AddBox_To_Hier(hbox, pptr, optr, pbox,
- level, &child_index,
- &min_child_index, &min_insert_cost);
-
- /* Insert new node, enlarge ancestor's boxes */
- if (!IsLeafBox(addition_pos)) {
- if (!IsFullBox(addition_pos)) {
- p_count++;
- BVH_AddBox_Child(addition_pos, pptr, optr, pbox);
- }
- } else {
- p_count++;
- BVH_AddBox_Sibling(addition_pos, pbox, pptr, optr,
- min_child_index);
- }
- if (Option.debug) printf("\tCost to insert %s%d's box = %g\n",
- pptr->name, pptr->id, min_insert_cost);
- }
- }
- }
- }
- else {
- /* Check all children bounding volumes */
- for(i=0; i<hbox->num_children; i++)
- BVH_Create_PHierarchy(hbox->child[i]);
- }
- }
-
- /**********************************************************************/
- /* Print object list of potential receivers */
- /**********************************************************************/
- void Print_ObjectList()
- {
- int i;
- Object_List *olptr;
-
- printf("\t> Object Receiver List {\n");
- olptr = objlist;
- for(i=0;i<objlist_size;i++) {
- printf("\t%s%d is%s a possible receiver. And is%s a possible obstructor\n",
- olptr->hbox->object->name, olptr->hbox->object->id,
- (olptr->is_receiver ? " " : " not"),
- (olptr->is_obstructor ? " " : " not"));
- olptr = olptr->next;
- }
- printf("\t}\n");
- }
-
- /**********************************************************************/
- /* Print candidate list for current shaft */
- /**********************************************************************/
- void Print_CandidateList()
- {
- int i;
- Object_List *olptr;
- char *tmp = " ";
-
- printf("\t> Shaft Candidate List {\n");
- olptr = objlist;
- for(i=0;i<objlist_size;i++) {
- if (olptr->hbox->object != 0)
- sprintf(tmp,"%s%d", olptr->hbox->object->name, olptr->hbox->object->id);
- else
- tmp = "No object";
- BoundsPrint(*olptr->hbox->box, stdout, tmp);
-
- printf("\tAt level %d. ",olptr->hbox->level);
- switch (olptr->is_receiver) {
- case OUTSIDE:
- fprintf(stderr,"PR_Clist: Is outside. Oh oh\n"); exit(1); break;
- case OVERLAP: printf("Overlaps.\n"); break;
- case INSIDE: printf("Is inside.\n"); break;
- case CONTAINS: printf("Contains\n"); break;
- default: fprintf(stderr, "PR_Clist: Invalid candidate box condition\n");
- exit(1);
- }
- olptr = olptr->next;
- }
- printf("\t}\n");
- }
-
- /**********************************************************************/
- /* Initialize object list of potential receivers to be empty */
- /**********************************************************************/
- void Init_ObjectList()
- {
- int i;
- Object_List *olptr, *tmp;
-
- if (Option.debug)
- printf("\t> Initializing object receiver list\n");
- olptr = objlist;
- for (i=0;i<objlist_size;i++) {
- tmp = olptr->next;
- free(olptr);
- olptr = tmp;
- }
- objlist = objlist_tail = 0;
- objlist_size = 0;
- objlist_receivers = 0;
- }
-
- /**********************************************************************/
- /* Add object containing potential receivers to object list */
- /**********************************************************************/
- void AddTo_ObjectList(hbox,obj_seen)
- HBBox *hbox;
- int obj_seen;
- {
- Object_List *olptr;
-
- /* Create object list node, set whether object seen or not */
- olptr = (Object_List *) malloc(sizeof(Object_List));
- olptr->hbox = hbox;
- olptr->next = (Object_List *)NULL;
- olptr->is_receiver = obj_seen; /* Mark if object is a receiver */
- olptr->is_obstructor = 0; /* Assume does not obstruct any receiver */
-
- if (objlist_size == 0) { /* First possible receiver */
- objlist = olptr;
- objlist_tail = olptr;
- } else {
- objlist_tail->next = olptr; /* Add to end of list */
- objlist_tail = olptr;
- }
- objlist_size++; /* Count total # of elements */
- if (obj_seen)
- objlist_receivers++; /* Count # of receivers */
- }
-
- #define At_Object_Level(hbox) ((hbox)->object != 0 && (hbox)->poly == 0)
- /**********************************************************************/
- /* Bounding volume hierarchy visibility test */
- /* return list of potentially visible objects */
- /**********************************************************************/
- void Make_ObjectList(shootPatch, hbox, obj_seen)
- Polygon *shootPatch;
- HBBox *hbox;
- int obj_seen;
- {
- int i;
-
- if (hbox->object != 0 && hbox->poly == 0) {
- /* Object cannot be a receiver and contain shooter,
- if object is convex and patches don't face in */
- if (obj_seen)
- if (hbox->object->primid != MESH)
- if (poly_object(shootPatch) == hbox->object)
- obj_seen = hbox->object->in_facingprim;
-
- /* Check if bounding volume of object can be seen or not
- but only if parent bounding volume can be seen */
- if (obj_seen)
- obj_seen = 1 - Bounds_Behind_Plane(hbox->box, shootPatch->normal[0],
- shootPatch->d);
- AddTo_ObjectList(hbox,obj_seen);
- }
-
- /* Check if this BV can be seen as pass a visibility flag
- down the hierarchy */
- else {
- obj_seen = 1 - Bounds_Behind_Plane(hbox->box, shootPatch->normal[0],
- shootPatch->d);
- }
-
- /* Check all children bounding volumes */
- for(i=0; i<hbox->num_children; i++) {
- Make_ObjectList(shootPatch, hbox->child[i], obj_seen);
- }
- }
-
-
- /**********************************************************************/
- /* Find out objects in front of receiver from list of objects in front*/
- /* of the source */
- /**********************************************************************/
- void Cull_ObjectList(rec)
- Polygon *rec;
- {
- int i;
- Object_List *olptr;
-
- for(i=0, olptr=objlist; i<objlist_size; i++, olptr=olptr->next) {
- olptr->is_obstructor = 0;
- if (olptr->is_receiver) {
- /* if ((hbox->object != poly_object(shootPatch)) &&
- (hbox->object != poly_object(rec))) */
- if (Bounds_Behind_Plane(olptr->hbox->box, rec->normal[0],
- rec->d) == 0) {
- olptr->is_obstructor = 1;
- }
- }
- }
- }
-