home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / macraysh.sit / Code / Source / geom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-27  |  8.8 KB  |  431 lines

  1. /*
  2.  * object.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * $Id: geom.c,v 4.0 91/07/17 14:37:47 kolb Exp Locker: kolb $
  17.  *
  18.  * $Log:    geom.c,v $
  19.  * Revision 4.0  91/07/17  14:37:47  kolb
  20.  * Initial version.
  21.  * 
  22.  */
  23. #include "geom.h"
  24. #include "list.h"
  25. #include "sampling.h"
  26.  
  27. void GeomBounds();
  28. static void GeomBoundsAnimated();
  29. void GeomResolveAssoc();    /* probably static */
  30.  
  31. Geom *
  32. GeomCreate(objptr, methods)
  33. GeomRef objptr;
  34. Methods *methods;
  35. {
  36.     Geom *obj;
  37.  
  38.     if (objptr == (GeomRef)NULL)
  39.         return (Geom *)NULL;
  40.         
  41.     obj = (Geom *)share_calloc(1, sizeof(Geom));
  42.     obj->obj = objptr;
  43.     obj->methods = methods;
  44.     obj->animtrans = FALSE;
  45.     obj->trans = obj->transtail = (Trans *) NULL;
  46.     obj->name = NULL ;
  47.     obj->frame = -1;    /* impossible value */
  48.     BoundsInit(obj->bounds);
  49.  
  50.     return obj;
  51. }
  52.  
  53. /*
  54.  * Return a copy of the given object.
  55.  * Note that surface, texturing, and transformation information
  56.  * is copied by reference.
  57.  */
  58. Geom *
  59. GeomCopy(obj)
  60. Geom *obj;
  61. {
  62.     Geom *new;
  63.  
  64.     new = GeomCreate(obj->obj, obj->methods);
  65.     /* Share texturing, name, #prims, surface info */
  66.     new->name = obj->name;
  67.     new->texture = obj->texture;
  68.     new->surf = obj->surf;
  69.     new->prims = obj->prims;
  70.     new->trans = obj->trans;
  71.     new->animtrans = obj->animtrans;
  72.     new->transtail = obj->transtail;
  73.     /* copy bounds */
  74.     BoundsCopy(obj->bounds, new->bounds);
  75.     return new;
  76. }
  77.  
  78. /*
  79.  * Report bounding box and number of primitives in object.
  80.  */
  81. void
  82. AggregatePrintInfo(obj)
  83. Geom *obj;
  84. {
  85.     if (obj->name && obj->name[0])
  86.         printf("%s \"%s\":\n", GeomName(obj), obj->name);
  87.     else
  88.         printf("%s:\n", GeomName(obj));
  89.     if (!UNBOUNDED(obj))
  90.         BoundsPrint(obj->bounds);
  91.     printf("\t%lu primitive%c\n",obj->prims,
  92.         obj->prims == 1 ? ' ' : 's');
  93. }
  94.  
  95. /*
  96.  * Convert the given object from a linked list of objects to
  97.  * the desired aggregate type.
  98.  */
  99. int
  100. AggregateConvert(obj, objlist)
  101. Geom *obj, *objlist;
  102. {
  103.     if (!IsAggregate(obj)) {
  104.         RLerror(RL_ABORT, "A %s isn't an aggregate.\n",
  105.             GeomName(obj),0,0);
  106.         return 0;
  107.     }
  108.  
  109.     return (*obj->methods->convert)(obj->obj, objlist);
  110. }
  111.  
  112. /*
  113.  * This should really be called
  114.  * GeomInitialize
  115.  * or something.
  116.  */
  117. void
  118. GeomComputeBounds(obj)
  119. Geom *obj;
  120. {
  121.     if (obj->frame == Sampling.framenum)
  122.         return;
  123.  
  124.     if (!obj->animtrans) {
  125.         /*
  126.          * If it isn't animated,
  127.          * just compute bbox directly 
  128.          */
  129.         GeomBounds(obj, obj->bounds);
  130.     } else {
  131.         /*
  132.          * Animated things are gonna get a bbox
  133.          * which is large enough to enclose all
  134.          * the places where the object goes.
  135.          */
  136.         GeomBoundsAnimated(obj);
  137.     }
  138.     /*
  139.      * Enlarge by EPSILON in each direction just to
  140.      * be on the safe side.
  141.      */
  142.     obj->bounds[LOW][X] -= EPSILON;
  143.     obj->bounds[HIGH][X] += EPSILON;
  144.     obj->bounds[LOW][Y] -= EPSILON;
  145.     obj->bounds[HIGH][Y] += EPSILON;
  146.     obj->bounds[LOW][Z] -= EPSILON;
  147.     obj->bounds[HIGH][Z] += EPSILON;
  148.     /*
  149.      * Mark the fact that that the obj is initialized
  150.      * for this frame.
  151.      */
  152.     obj->frame = Sampling.framenum;
  153.     obj->counter = 0;
  154. }
  155.  
  156. static void
  157. GeomBoundsAnimated(obj)
  158. Geom *obj;
  159. {
  160.     int i, m;
  161.     Float newbounds[2][3];
  162.     Float window, subwindow, jitter, subjitter;
  163.  
  164.     /*
  165.      * For each possible screen sample,
  166.      * choose TIME_SUB_SAMPLES times and recompute the
  167.      * bounds of obj at that time,
  168.      * expanding the computed bounding box appropriately.
  169.      */
  170.     BoundsInit(obj->bounds);
  171.     jitter = Sampling.shutter / Sampling.totsamples;
  172.     subjitter = jitter / (Float)TIME_SUB_SAMPLES;
  173.     window = Sampling.starttime;
  174.     for (i = 0; i < Sampling.totsamples; i++, window += jitter) {
  175.         subwindow = window;
  176.         for (m = 0; m < TIME_SUB_SAMPLES; m++, subwindow += subjitter) {
  177.             /*
  178.              * Set the current time.
  179.              */
  180.             TimeSet(subwindow + subjitter*nrand());
  181.             /*
  182.              * Resolve the objects geometric associations
  183.              */
  184.             GeomResolveAssoc(obj);
  185.             /*
  186.              * Compute bounds and expand current bounds.
  187.              */
  188.             GeomBounds(obj, newbounds);
  189.             BoundsEnlarge(obj->bounds, newbounds);
  190.         }
  191.     }
  192.     /*
  193.      * Also sample at time extremes, as for many
  194.      * movements, extremes occur at beginning/end times.
  195.      */
  196.     TimeSet(Sampling.starttime);
  197.     GeomResolveAssoc(obj);
  198.     GeomBounds(obj, newbounds);
  199.     BoundsEnlarge(obj->bounds, newbounds);
  200.  
  201.     TimeSet(Sampling.starttime + Sampling.shutter);
  202.     GeomResolveAssoc(obj);
  203.     GeomBounds(obj, newbounds);
  204.     BoundsEnlarge(obj->bounds, newbounds);
  205. }
  206.  
  207. void
  208. GeomResolveAssoc(obj)
  209. Geom *obj;
  210. {
  211.     /*
  212.      * PrimResolveAssoc(obj);
  213.      */
  214.     TransResolveAssoc(obj->trans);
  215. }
  216.  
  217. /*
  218.  * Set "bounds" of object to be the extent of the primitive.
  219.  */
  220. void
  221. GeomBounds(obj, bounds)
  222. Geom *obj;
  223. Float bounds[2][3];
  224. {
  225.       Trans *trans;
  226.  
  227.       if (!obj || !obj->methods->bounds)
  228.               RLerror(RL_ABORT, "Can't compute bounds of \"%s\".\n",GeomName(obj),0,0);
  229.       (*obj->methods->bounds) (obj->obj, bounds);
  230.       bounds[LOW][X] -= EPSILON;
  231.       bounds[LOW][Y] -= EPSILON;
  232.       bounds[LOW][Z] -= EPSILON;
  233.       bounds[HIGH][X] += EPSILON;
  234.       bounds[HIGH][Y] += EPSILON;
  235.       bounds[HIGH][Z] += EPSILON;
  236.       if (obj->trans) {
  237.               for (trans = obj->trans; trans; trans = trans->next)
  238.                       BoundsTransform(&trans->trans, bounds);
  239.       }
  240. }
  241.  
  242. char *
  243. GeomName(obj)
  244. Geom *obj;
  245. {
  246.     if (obj->methods->name)
  247.         return (*obj->methods->name)();
  248.  
  249.     return "unknown";
  250. }
  251.  
  252. void
  253. GeomStats(obj, tests, hits)
  254. Geom *obj;
  255. unsigned long *tests, *hits;
  256. {
  257.     if (obj && obj->methods->stats)
  258.         (*obj->methods->stats)(tests, hits);
  259.     else {
  260.         *tests = *hits = 0;
  261.     }
  262. }
  263.  
  264. /*
  265.  * Push an object onto the head of the given stack, returning
  266.  * the new head.
  267.  */
  268. GeomList *
  269. GeomStackPush(obj, list)
  270. Geom *obj;
  271. GeomList *list;
  272. {
  273.     GeomList *new;
  274.     /*
  275.      * Pretty simple.
  276.      * Make new element point to old head and return new head.
  277.      */
  278.     new = (GeomList *)Malloc(sizeof(GeomList));
  279.     new->obj = obj;
  280.     new->next = list;
  281.     return new;
  282. }
  283.  
  284. /*
  285.  * Pop the topmost object off of the given stack, returning the new head.
  286.  * The old head is freed, but the object it points to is not.
  287.  */
  288. GeomList *
  289. GeomStackPop(list)
  290. GeomList *list;
  291. {
  292.     GeomList *ltmp;
  293.  
  294.     ltmp = list->next;    /* Save new head. */
  295.     Free((voidstar)list);    /* Free old head. */
  296.     return ltmp;        /* Return new head. */
  297. }
  298.  
  299. Methods *
  300. MethodsCreate()
  301. {
  302.     return (Methods *)share_calloc(1, sizeof(Methods));
  303. }
  304.  
  305. /*
  306.  * Call appropriate routine to compute UV and, if non-null,
  307.  * dpdu and dpdv at given point on the given primitive.  The
  308.  * normal is used to facilitate computation of u, v, and the
  309.  * partial derivatives.
  310.  */
  311. void
  312. PrimUV(prim, pos, norm, uv, dpdu, dpdv)
  313. Geom *prim;
  314. Vector *pos, *norm, *dpdu, *dpdv;
  315. Vec2d *uv;
  316. {
  317.     /*
  318.      * Call appropriate inverse mapping routine
  319.      */
  320.     if (prim->methods->uv == NULL) {
  321.         uv->u = uv->v = 0.;
  322.         if (dpdu) {
  323.             dpdu->y = dpdu->z = 0.;
  324.             dpdu->x = 1.;
  325.         }
  326.         if (dpdv) {
  327.             dpdv->x = dpdv->z = 0.;
  328.             dpdv->y = 1.;
  329.         }    
  330.     } else
  331.         (*prim->methods->uv)(prim->obj,pos,norm,uv,dpdu,dpdv);
  332. }
  333.  
  334. int
  335. PrimNormal(prim, pos, norm, gnorm)
  336. Geom *prim;
  337. Vector *pos, *norm, *gnorm;
  338. {
  339.     /*
  340.      * Call appropriate normal routine
  341.      */
  342.     return (*prim->methods->normal) (prim->obj, pos, norm, gnorm);
  343. }
  344.  
  345. int
  346. PrimEnter(obj, ray, mind, hitd)
  347. Geom *obj;
  348. Ray *ray;
  349. Float mind, hitd;
  350. {
  351.     /*
  352.      * Call appropriate enter/leave routine
  353.      */
  354.     if (obj->methods->enter == NULL) {
  355.         Vector pos, nrm, gnrm;
  356.         /*
  357.          * Sleazy method:  Use hit point, find normal 
  358.          * and take dot prod with ray 
  359.          */
  360.         VecAddScaled(ray->pos, hitd, ray->dir, &pos);
  361.         PrimNormal(obj, &pos, &nrm, &gnrm);
  362.  
  363.         return dotp(&ray->dir, &gnrm) < 0.0;
  364.     }
  365.     else
  366.         return (*obj->methods->enter) (obj->obj, ray, mind, hitd);
  367. }
  368.  
  369. /*
  370.  * Walk through a linked-list of objects.  If the object is unbounded,
  371.  * unlink it it from the list and add it to the 'unbounded' list.
  372.  * If the object is bounded, enlarge the given bounding box if
  373.  * necessary.  Return pointer to unbounded list.
  374.  */
  375. Geom *
  376. GeomComputeAggregateBounds(bounded, unbounded, bounds)
  377. Geom **bounded, *unbounded;
  378. Float bounds[2][3];
  379. {
  380.     Geom *ltmp, *prev, *nextobj;
  381.  
  382.     BoundsInit(bounds);
  383.  
  384.     prev = (Geom *)0;
  385.  
  386.     for (ltmp = *bounded; ltmp; ltmp = nextobj) {
  387.         nextobj = ltmp->next;
  388.         GeomComputeBounds(ltmp);
  389.         if (UNBOUNDED(ltmp)) {
  390.             /*
  391.              * Geom is unbounded -- unlink it...
  392.              */
  393.             if (prev)
  394.                 prev->next = ltmp->next;
  395.             else
  396.                 *bounded = ltmp->next;
  397.             /*
  398.              * And add it to unbounded object list.
  399.              */
  400.             ltmp->next = unbounded;
  401.             unbounded = ltmp;
  402.         } else {
  403.             /*
  404.              * Geom is bounded.
  405.              */
  406.             BoundsEnlarge(bounds, ltmp->bounds);
  407.             prev = ltmp;
  408.         }
  409.     }
  410.     return unbounded;
  411. }
  412.  
  413. /*
  414.  * Find 'highest' animated object on the hitlist.
  415.  */
  416. int
  417. FirstAnimatedGeom(hitlist)
  418. HitList *hitlist;
  419. {
  420.     int i;
  421.  
  422.     for (i = hitlist->nodes -1; i; i--)
  423.         /*
  424.          * If object itself is animated, have
  425.          * to check other flag, too...
  426.          */
  427.         if (hitlist->data[i].obj->animtrans)
  428.             return i;
  429.     return 0;
  430. }
  431.