Multiple csg objects: The patches to csg.c and csg.h make it possible to have more than two objects in a CSG object. This is a little hack. ======================= cut here ======================== *** csg.h.orig Wed Jun 17 18:06:22 1992 --- csg.h Wed Jun 17 18:08:38 1992 *************** *** 34,40 **** typedef struct Csg { char operator; /* Union, Intersect, or Difference */ ! struct Geom *obj1, *obj2; int (*intmeth)(); /* Intersection method. */ Float bounds[2][3]; } Csg; --- 34,41 ---- typedef struct Csg { char operator; /* Union, Intersect, or Difference */ ! struct Geom *list; /* Csg objects */ ! int nobjs; /* Number of objects in the list */ int (*intmeth)(); /* Intersection method. */ Float bounds[2][3]; } Csg; *** csg.c.orig Wed Jun 17 17:46:54 1992 --- csg.c Wed Jun 17 18:02:01 1992 *************** *** 40,46 **** csg = (Csg *)share_malloc(sizeof(Csg)); csg->operator = op; ! csg->obj1 = csg->obj2 = (Geom *)NULL; switch(op) { --- 40,46 ---- csg = (Csg *)share_malloc(sizeof(Csg)); csg->operator = op; ! csg->list = (Geom *)NULL; switch(op) { *************** *** 82,123 **** return csgName; } - csg_intersect_objs(csg, ray, hit1, hit2, mindist, dist1, dist2) - Csg *csg; - Ray *ray; - HitList *hit1, *hit2; - Float mindist, *dist1, *dist2; - { - int operator; - - hit1->nodes = 0; - hit2->nodes = 0; - *dist1 = FAR_AWAY; - *dist2 = FAR_AWAY; - operator = csg->operator; - - if (!intersect(csg->obj1, ray, hit1, mindist, dist1) && - ((operator == CSG_INTERSECT) || (operator == CSG_DIFFERENCE))) { - /* - * Intersection and Difference cases: if you miss the first - * object, you missed the whole thing. - */ - return FALSE; - } - - if (!intersect(csg->obj2, ray, hit2, mindist, dist2) && - ((operator == CSG_INTERSECT) || - (hit1->nodes == 0) && (operator == CSG_UNION))) { - /* - * Intersect case: if you miss either object, you miss whole - * Union case: if you miss both object, you miss whole - */ - return FALSE; - } - - return TRUE; - } - int csg_enter_obj(hitp) HitList *hitp; --- 82,87 ---- *************** *** 130,143 **** } static int ! CsgUnionInt(ray, hit1p, hit2p, dist1, dist2, hitclose, distclose) Ray *ray; HitList *hit1p, *hit2p, **hitclose; Float dist1, dist2, *distclose; { ! Float distnext; HitList hitnext, *hittmp; while (TRUE) { if (hit2p->nodes == 0 || csg_enter_obj(hit2p)) { --- 94,120 ---- } static int ! CsgUnionInt(csg, ray, hit1p, hit2p, dist1, dist2, hitclose, distclose) ! Csg *csg; Ray *ray; HitList *hit1p, *hit2p, **hitclose; Float dist1, dist2, *distclose; { ! Float disttmp, distnext; HitList hitnext, *hittmp; + int sect, fl = 0; + if (dist1 > dist2) { + /* swap so 1 is closest */ + disttmp = dist2; + dist2 = dist1; + dist1 = disttmp; + hittmp = hit1p; + hit1p = hit2p; + hit2p = hittmp; + fl = 1; + } + while (TRUE) { if (hit2p->nodes == 0 || csg_enter_obj(hit2p)) { *************** *** 149,156 **** } else { distnext = FAR_AWAY; hitnext.nodes = 0; ! if (!intersect(hit1p->data[hit1p->nodes-1].obj, ! ray, &hitnext, dist2+EPSILON, &distnext)) { /* * None of obj1 beyond, return hit2 (leaving) */ --- 126,138 ---- } else { distnext = FAR_AWAY; hitnext.nodes = 0; ! if (fl || csg->nobjs == 1) ! sect = intersect(hit1p->data[hit1p->nodes-1].obj, ! ray, &hitnext, dist2+EPSILON, &distnext); ! else ! sect = CsgIntersect(csg, ! ray, &hitnext, dist2+EPSILON, &distnext); ! if (!sect) { /* * None of obj1 beyond, return hit2 (leaving) */ *************** *** 169,174 **** --- 151,157 ---- dist1 = dist2; CsgHitlistCopy(&hitnext, hit2p); dist2 = distnext; + fl ^= 1; /* and continue */ } } *************** *** 176,189 **** } static int ! CsgIntersectInt(ray, hit1p, hit2p, dist1, dist2, hitclose, distclose) Ray *ray; HitList *hit1p, *hit2p, **hitclose; Float dist1, dist2, *distclose; { HitList *hittmp, hitnext; ! Float distnext; while (TRUE) { if (!csg_enter_obj(hit2p)) { /* Ray is leaving obj2 */ --- 159,185 ---- } static int ! CsgIntersectInt(csg, ray, hit1p, hit2p, dist1, dist2, hitclose, distclose) ! Csg *csg; Ray *ray; HitList *hit1p, *hit2p, **hitclose; Float dist1, dist2, *distclose; { HitList *hittmp, hitnext; ! Float disttmp, distnext; ! int sect, fl = 0; + if (dist1 > dist2) { + /* swap so 1 is closest */ + disttmp = dist2; + dist2 = dist1; + dist1 = disttmp; + hittmp = hit1p; + hit1p = hit2p; + hit2p = hittmp; + fl = 1; + } + while (TRUE) { if (!csg_enter_obj(hit2p)) { /* Ray is leaving obj2 */ *************** *** 195,202 **** } else { distnext = FAR_AWAY; hitnext.nodes = 0; ! if (!intersect(hit1p->data[hit1p->nodes-1].obj, ! ray, &hitnext, dist2+EPSILON, &distnext)) { /* * None of obj1 beyond, so return miss */ --- 191,203 ---- } else { distnext = FAR_AWAY; hitnext.nodes = 0; ! if (fl || csg->nobjs == 1) ! sect = intersect(hit1p->data[hit1p->nodes-1].obj, ! ray, &hitnext, dist2+EPSILON, &distnext); ! else ! sect = CsgIntersect(csg, ! ray, &hitnext, dist2+EPSILON, &distnext); ! if (!sect) { /* * None of obj1 beyond, so return miss */ *************** *** 213,218 **** --- 214,220 ---- dist1 = dist2; CsgHitlistCopy(&hitnext, hit2p); dist2 = distnext; + fl ^= 1; /* and continue */ } } *************** *** 220,226 **** } static int ! CsgDifferenceInt(ray, hit1p, hit2p, dist1, dist2, hitclose, distclose) Ray *ray; HitList *hit1p, *hit2p, **hitclose; Float dist1, dist2, *distclose; --- 222,229 ---- } static int ! CsgDifferenceInt(csg, ray, hit1p, hit2p, dist1, dist2, hitclose, distclose) ! Csg *csg; Ray *ray; HitList *hit1p, *hit2p, **hitclose; Float dist1, dist2, *distclose; *************** *** 227,232 **** --- 230,236 ---- { Float distnext; HitList hitnext; + int sect; while (TRUE) { if (dist1 < dist2) { *************** *** 240,247 **** } else { distnext = FAR_AWAY; hitnext.nodes = 0; ! if (!intersect(hit1p->data[hit1p->nodes-1].obj, ! ray, &hitnext, dist2+EPSILON, &distnext)) { /* * None of obj1 beyond, so * return miss --- 244,256 ---- } else { distnext = FAR_AWAY; hitnext.nodes = 0; ! if (csg->nobjs == 1) ! sect = intersect(hit1p->data[hit1p->nodes-1].obj, ! ray, &hitnext, dist2+EPSILON, &distnext); ! else ! sect = CsgIntersect(csg, ! ray, &hitnext, dist2+EPSILON, &distnext); ! if (!sect) { /* * None of obj1 beyond, so * return miss *************** *** 298,341 **** HitList *hitlist; Float mindist, *maxdist; { ! Float dist1, dist2, disttmp, distclose; ! HitList hit1, hit2, *hit1p, *hit2p, *hitclose; ! hit1p = &hit1; ! hit2p = &hit2; ! if (!csg_intersect_objs(csg, ray, hit1p, hit2p, mindist, ! &dist1, &dist2)) { ! /* missed the csg object */ return FALSE; } ! if ((dist1 > dist2) && ! (csg->operator == CSG_UNION || csg->operator == CSG_INTERSECT)) { ! /* swap so 1 is closest (except in difference case) */ ! disttmp = dist2; ! dist2 = dist1; ! dist1 = disttmp; ! hit1p = &hit2; ! hit2p = &hit1; ! } ! /* ! * Call appropriate intersection method. If FALSE is return, ! * no hit of any kind was found. ! */ ! if (!(*csg->intmeth)(ray, hit1p, hit2p, dist1, dist2, ! &hitclose, &distclose)) ! return FALSE; ! /* ! * At this time, the closest hit is in hitclose and ! * distclose. ! */ ! if (distclose < mindist || distclose > *maxdist) return FALSE; ! CsgHitlistCopy(hitclose, hitlist); ! *maxdist = distclose; return TRUE; } --- 307,384 ---- HitList *hitlist; Float mindist, *maxdist; { ! Float distcsg, distobj, distclose; ! HitList hit1, hit2, *hitclose, *hitcsgp, *hitobjp; ! int operator, nobjs; ! Geom *obj; ! operator = csg->operator; ! ! hitcsgp = &hit1; ! distcsg = FAR_AWAY; ! obj = csg->list; ! hitcsgp->nodes = 0; ! if (!intersect(obj, ray, hitcsgp, mindist, &distcsg) && ! (operator == CSG_INTERSECT || operator == CSG_DIFFERENCE)) { ! /* ! * Intersection and Difference cases: if you miss the ! * first object, you missed the whole thing. ! */ return FALSE; } ! hitobjp = &hit2; ! hitclose = &hit1; ! distclose = distcsg; ! nobjs = csg->nobjs; ! csg->nobjs = 0; ! while(++csg->nobjs < nobjs) { ! obj = obj->next; ! hitobjp->nodes = 0; ! distobj = FAR_AWAY; ! if (!intersect(obj, ray, hitobjp, mindist, &distobj)) { ! if (operator == CSG_INTERSECT) { ! csg->nobjs = nobjs; ! return FALSE; ! } ! if (hitcsgp->nodes == 0) ! continue; ! } ! ! ! /* ! * Call appropriate intersection method. If FALSE is return, ! * no hit of any kind was found. ! */ ! if (!(*csg->intmeth)(csg, ray, hitcsgp, hitobjp, distcsg, distobj, ! &hitclose, &distclose) || distclose > *maxdist) { ! if (operator != CSG_UNION) { ! csg->nobjs = nobjs; ! return FALSE; ! } ! hitcsgp->nodes = 0; ! distcsg = FAR_AWAY; ! continue; ! } ! ! /* ! * At this time, the closest hit is in hitclose and ! * distclose. ! */ ! distcsg = distclose; ! hitcsgp = hitclose; ! if (hitcsgp == &hit1) ! hitobjp = &hit2; ! else ! hitobjp = &hit1; ! } ! if (hitcsgp->nodes == 0 || distcsg < mindist || distcsg > *maxdist) return FALSE; ! CsgHitlistCopy(hitcsgp, hitlist); ! *maxdist = distcsg; return TRUE; } *************** *** 355,387 **** Csg *csg; Float bounds[2][3]; { ! GeomComputeBounds(csg->obj1); ! GeomComputeBounds(csg->obj2); switch (csg->operator) { case CSG_UNION: ! bounds[LOW][X] = min(csg->obj1->bounds[LOW][X], csg->obj2->bounds[LOW][X]); ! bounds[HIGH][X] = max(csg->obj1->bounds[HIGH][X], csg->obj2->bounds[HIGH][X]); ! bounds[LOW][Y] = min(csg->obj1->bounds[LOW][Y], csg->obj2->bounds[LOW][Y]); ! bounds[HIGH][Y] = max(csg->obj1->bounds[HIGH][Y], csg->obj2->bounds[HIGH][Y]); ! bounds[LOW][Z] = min(csg->obj1->bounds[LOW][Z], csg->obj2->bounds[LOW][Z]); ! bounds[HIGH][Z] = max(csg->obj1->bounds[HIGH][Z], csg->obj2->bounds[HIGH][Z]); break; case CSG_INTERSECT: ! bounds[LOW][X] = max(csg->obj1->bounds[LOW][X], csg->obj2->bounds[LOW][X]); ! bounds[HIGH][X] = min(csg->obj1->bounds[HIGH][X], csg->obj2->bounds[HIGH][X]); ! bounds[LOW][Y] = max(csg->obj1->bounds[LOW][Y], csg->obj2->bounds[LOW][Y]); ! bounds[HIGH][Y] = min(csg->obj1->bounds[HIGH][Y], csg->obj2->bounds[HIGH][Y]); ! bounds[LOW][Z] = max(csg->obj1->bounds[LOW][Z], csg->obj2->bounds[LOW][Z]); ! bounds[HIGH][Z] = min(csg->obj1->bounds[HIGH][Z], csg->obj2->bounds[HIGH][Z]); break; case CSG_DIFFERENCE: - bounds[LOW][X] = csg->obj1->bounds[LOW][X]; - bounds[HIGH][X] = csg->obj1->bounds[HIGH][X]; - bounds[LOW][Y] = csg->obj1->bounds[LOW][Y]; - bounds[HIGH][Y] = csg->obj1->bounds[HIGH][Y]; - bounds[LOW][Z] = csg->obj1->bounds[LOW][Z]; - bounds[HIGH][Z] = csg->obj1->bounds[HIGH][Z]; break; default: RLerror(RL_ABORT, "Unknown csg operator type %d?\n", --- 398,438 ---- Csg *csg; Float bounds[2][3]; { ! Geom *obj; + for (obj = csg->list; obj; obj = obj->next) + GeomComputeBounds(obj); + + obj = csg->list; + bounds[LOW][X] = obj->bounds[LOW][X]; + bounds[HIGH][X] = obj->bounds[HIGH][X]; + bounds[LOW][Y] = obj->bounds[LOW][Y]; + bounds[HIGH][Y] = obj->bounds[HIGH][Y]; + bounds[LOW][Z] = obj->bounds[LOW][Z]; + bounds[HIGH][Z] = obj->bounds[HIGH][Z]; + switch (csg->operator) { case CSG_UNION: ! while (obj = obj->next) { ! bounds[LOW][X] = min(bounds[LOW][X], obj->bounds[LOW][X]); ! bounds[HIGH][X] = max(bounds[HIGH][X], obj->bounds[HIGH][X]); ! bounds[LOW][Y] = min(bounds[LOW][Y], obj->bounds[LOW][Y]); ! bounds[HIGH][Y] = max(bounds[HIGH][Y], obj->bounds[HIGH][Y]); ! bounds[LOW][Z] = min(bounds[LOW][Z], obj->bounds[LOW][Z]); ! bounds[HIGH][Z] = max(bounds[HIGH][Z], obj->bounds[HIGH][Z]); ! } break; case CSG_INTERSECT: ! while (obj = obj->next) { ! bounds[LOW][X] = max(bounds[LOW][X], obj->bounds[LOW][X]); ! bounds[HIGH][X] = min(bounds[HIGH][X], obj->bounds[HIGH][X]); ! bounds[LOW][Y] = max(bounds[LOW][Y], obj->bounds[LOW][Y]); ! bounds[HIGH][Y] = min(bounds[HIGH][Y], obj->bounds[HIGH][Y]); ! bounds[LOW][Z] = max(bounds[LOW][Z], obj->bounds[LOW][Z]); ! bounds[HIGH][Z] = min(bounds[HIGH][Z], obj->bounds[HIGH][Z]); ! } break; case CSG_DIFFERENCE: break; default: RLerror(RL_ABORT, "Unknown csg operator type %d?\n", *************** *** 424,454 **** Geom *list; { static int OpenAdvised = FALSE; ! /* ! * Currently, this only handles two objects. ! * Will be fixed in the future. ! * No really we promise. ! */ ! if (!list || !list->next) { ! RLerror(RL_WARN, "CSG needs at least two objects.\n"); return 0; } ! if (list->next->next) { ! RLerror(RL_WARN, "Currently, CSG only handles two objects.\n"); ! return 0; } /* * Things are put into lists backwards.... */ ! csg->obj2 = list; ! csg->obj1 = list->next; ! if ((!csg->obj1->methods->closed || !csg->obj2->methods->closed) && ! !OpenAdvised) { ! RLerror(RL_ADVISE, ! "Performing CSG with non-closed object(s).\n"); ! OpenAdvised = TRUE; } ! return csg->obj1->prims + csg->obj2->prims; } void --- 475,517 ---- Geom *list; { static int OpenAdvised = FALSE; ! Geom *obj, *prev; ! int prims = 0; ! int nobjs = 0; ! ! if (!list) { ! RLerror(RL_WARN, "CSG needs at least one object.\n"); return 0; } ! if (!list->next) { ! RLerror(RL_WARN, "CSG with only one object.\n"); } + prev = (Geom *)0; + for (obj = list; ; obj = obj->next) { + if ((!obj->methods->closed) && + !OpenAdvised) { + RLerror(RL_ADVISE, + "Performing CSG with non-closed object(s).\n"); + OpenAdvised = TRUE; + } + prims += obj->prims; + nobjs++; + if (!obj->next) + break; + prev = obj; + } /* * Things are put into lists backwards.... + * To make the Difference methode work, we move the last + * element of the list to the head. */ ! csg->list = obj; ! if (prev) { ! prev->next = 0; ! obj->next = list; } ! csg->nobjs = nobjs; ! return prims; } void