home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / macraysh.sit / Code / Source / shadow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-05  |  7.2 KB  |  312 lines

  1. /*
  2.  * shadow.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: shadow.c,v 4.0 91/07/17 14:35:34 kolb Exp Locker: kolb $
  17.  *
  18.  * $Log:    shadow.c,v $
  19.  * Revision 4.0  91/07/17  14:35:34  kolb
  20.  * Initial version.
  21.  * 
  22.  */
  23. #include "geom.h"
  24. #include "surface.h"
  25. #include "light.h"
  26.  
  27. /*
  28.  * Shadow stats.
  29.  * External functions have read access via ShadowStats().
  30.  */
  31. static unsigned long    ShadowRays, ShadowHits, CacheMisses, CacheHits;
  32. /*
  33.  * Options controlling how shadowing information is determined.
  34.  * Set by external modules via ShadowSetOptions().
  35.  */
  36. static long        ShadowOptions;
  37.  
  38. void LightCacheHit();
  39.  
  40. /*
  41.  * Trace ray from point of intersection to a light.  If an intersection
  42.  * occurs at a distance less than "dist" (the distance to the
  43.  * light source), then the point is in shadow, and TRUE is returned.
  44.  * Otherwise, the brightness/color of the light is computed ('result'),
  45.  * and FALSE is returned.
  46.  */
  47. int
  48. Shadowed(result, color, cache, ray, dist, noshadow)
  49. Color *result, *color;    /* resultant intensity, light color */
  50. ShadowCache *cache;    /* shadow cache for light */
  51. Ray *ray;        /* ray, origin on surface, dir towards light */
  52. Float dist;        /* distance from pos to light source */
  53. int noshadow;        /* If TRUE, no shadow ray is cast. */
  54. {
  55.     int i, smooth, enter;
  56.     HitList hitlist;
  57.     Ray tmpray;
  58.     ShadowCache *cp;
  59.     Vector hitpos, norm, gnorm;
  60.     Surface surf, *sptr, *prevsurf;
  61.     Float s, totaldist, statten;
  62.     Color res;
  63.  
  64.     if (noshadow || NOSHADOWS(ShadowOptions)) {
  65.         *result = *color;
  66.         return FALSE;
  67.     }
  68.  
  69.     ShadowRays++;
  70.     s = dist;
  71.     cp = &cache[ray->depth];
  72.     /*
  73.      * Check shadow cache.  SHADOWCACHE() is implied.
  74.      */
  75.     if (cp->obj) {
  76.         /*
  77.          * Transform ray to the space of the cached primitive.
  78.          */
  79.         tmpray = *ray;
  80.         if (cp->dotrans)
  81.             s *= RayTransform(&tmpray, &cp->trans);
  82.         /*
  83.          * s = distance to light source in 'primitive space'.
  84.          * Intersect ray with cached object.
  85.          */
  86.         if (cp->obj->animtrans) {
  87.             /*
  88.              * Geom has animated transformation --
  89.              * call intersect so that the transformation
  90.              * is resolved properly.
  91.              */
  92.             if (intersect(cp->obj, &tmpray, &hitlist,
  93.                 SHADOW_EPSILON, &s)) {
  94.                 CacheHits++;
  95.                 return TRUE;
  96.             }
  97.         } else if (IsAggregate(cp->obj)) {
  98.             if ((*cp->obj->methods->intersect)(cp->obj->obj,
  99.                 &tmpray, &hitlist, SHADOW_EPSILON, &s)) {
  100.                 CacheHits++;
  101.                 return TRUE;
  102.             }
  103.         } else if ((*cp->obj->methods->intersect)(cp->obj->obj,
  104.                     &tmpray, SHADOW_EPSILON, &s)) {
  105.             /* Hit cached object. */
  106.             CacheHits++;
  107.             return TRUE;
  108.         }
  109.         /*
  110.          * Did not hit anything -- zero out the cache.
  111.          */
  112.         CacheMisses++;
  113.         /*
  114.          * Transformed -- reset s for use below.
  115.          */
  116.         s = dist;
  117.         cp->obj = (Geom *)NULL;
  118.         cp->dotrans = FALSE;
  119.     }
  120.  
  121.     hitlist.nodes = 0;
  122.     if (!TraceRay(ray, &hitlist, SHADOW_EPSILON, &s)) {
  123.         /* Shadow ray didn't hit anything. */
  124.         *result = *color;
  125.         return FALSE;
  126.     }
  127.  
  128.     /*
  129.      * Otherwise, we've hit something.
  130.      */
  131.     ShadowHits++;
  132.  
  133.     /*
  134.      * If we're not worrying about transparent objects...
  135.      * This is ugly due to the fact that we have to find
  136.      * the surface associated with the object that was hit.
  137.      * GetShadingSurf() will always return a non-null value.
  138.      *
  139.      * ***NOTE**
  140.      * The transparency of the surface is checked below without
  141.      * applying textures, if any, to it.  This means that if
  142.      * an object may be made trasparent by a texture, its
  143.      * surface should have non-zero transparency *before* texturing
  144.      * as well.
  145.      */
  146.     if (!SHADOWTRANSP(ShadowOptions)) {
  147.         if (SHADOWCACHE(ShadowOptions))
  148.             LightCacheHit(&hitlist, cp);
  149.         return TRUE;
  150.     }
  151.  
  152.     /*
  153.      * We've hit a transparent object.  Attenuate the color of the light
  154.      * source and continue the ray until we hit background or a
  155.      * non-transparent object.  Note that this is incorrect if DefIndex or
  156.      * any of the indices of refraction of the surfaces differ.
  157.      */
  158.  
  159.     totaldist = 0.;
  160.     prevsurf = (Surface *)NULL;
  161.     res = *color;
  162.  
  163.     do {
  164.         /*
  165.          * Get a pointer to the surface to be used
  166.          * for shading...
  167.          */
  168.         sptr = GetShadingSurf(&hitlist);
  169.         if (sptr->transp < EPSILON) {
  170.             if (SHADOWCACHE(ShadowOptions))
  171.                 LightCacheHit(&hitlist, cp);
  172.             return TRUE;
  173.         }
  174.         /*
  175.          * Take specular transmission attenuation from
  176.          * previous intersection into account.
  177.          */
  178.         if (prevsurf) {
  179.             if (prevsurf->statten != 1.) {
  180.                 statten = pow(prevsurf->statten, s - totaldist);
  181.                 ColorScale(statten, res, &res);
  182.             }
  183.         }
  184.         /*
  185.          * Perform texturing and the like in case surface
  186.          * transparency is modulated.
  187.          */
  188.         /* copy the surface to be used... */
  189.         surf = *sptr;
  190.         enter = ComputeSurfProps(&hitlist, ray, &hitpos,
  191.             &norm, &gnorm, &surf, &smooth);
  192.         if (enter)
  193.             prevsurf = &surf;
  194.         else
  195.             prevsurf = (Surface *)NULL;
  196.         /*
  197.          * Attenuate light source by body color of surface.
  198.          */
  199.         ColorScale(surf.transp, res, &res);
  200.         ColorMultiply(res, surf.body, &res);
  201.         /*
  202.          * Return if attenuation becomes large.
  203.          * In this case, the light was attenuated to nothing,
  204.          * so we can't cache anything...
  205.          */
  206.         if (res.r < EPSILON && res.g < EPSILON && res.b < EPSILON)
  207.             return TRUE;
  208.         /*
  209.          * Min distance is previous max.
  210.          */
  211.         totaldist = s + EPSILON;
  212.         /*
  213.          * Max distance is dist to light source
  214.          */
  215.         s = dist;
  216.         /*
  217.          * Trace ray starting at new origin and in the
  218.          * same direction.
  219.          */
  220.         hitlist.nodes = 0;
  221.     } while (TraceRay(ray, &hitlist, totaldist, &s));
  222.  
  223.     *result = res;
  224.     return FALSE;
  225. }
  226.  
  227. void
  228. ShadowStats(shadowrays, shadowhit, cachehit, cachemiss)
  229. unsigned long *shadowrays, *shadowhit, *cachehit, *cachemiss;
  230. {
  231.     *shadowrays = ShadowRays;
  232.     *shadowhit = ShadowHits;
  233.     *cachehit = CacheHits;
  234.     *cachemiss = CacheMisses;
  235. }
  236.  
  237. void
  238. ShadowSetOptions(options)
  239. {
  240.     ShadowOptions = options;
  241. }
  242.  
  243. void
  244. LightCacheHit(hitlist, cache)
  245. HitList *hitlist;
  246. ShadowCache *cache;
  247. {
  248.     HitNode *np;
  249.     int i, n;
  250.  
  251.     i = 0;
  252.  
  253.     if (SHADOWCSG(ShadowOptions)) {
  254.         /*
  255.          * There's possibly a CSG object in the
  256.          * hitlist, so we can't simply cache the
  257.          * primitive that was hit.  Find the
  258.          * object lowest in hit that's not part
  259.          * of a CSG object, and cache it.
  260.          */
  261.         i = FirstCSGGeom(hitlist);
  262.     }
  263.  
  264.     if (SHADOWBLUR(ShadowOptions)) {
  265.         /*
  266.          * Something might be animated --
  267.          * gotta cache the puppy.
  268.          */
  269.         n = FirstAnimatedGeom(hitlist);
  270.         if (n > i)
  271.             i = n;
  272.     }
  273.  
  274.     /*
  275.      * Compute total world-->cached object
  276.      * transformation and store in cache->trans.
  277.      */
  278.     /*
  279.      * Find the first transformation...
  280.      */
  281.     np = &hitlist->data[i];
  282.     cache->obj = np->obj;
  283.     /*
  284.      * If the cached object is animated, then we don't
  285.      * want to include the object's transformation(s)
  286.      * in cache->trans (it's taken care of in shadowed()
  287.      * by calling intersect).
  288.      */
  289.     if (cache->obj->animtrans) {
  290.         i++;
  291.         np++;
  292.     }
  293.     cache->dotrans = FALSE;
  294.     while (i < hitlist->nodes -1) {
  295.         if (np->obj->trans) {
  296.             if (cache->dotrans) {
  297.                 MatrixMult(
  298.                     &np->obj->trans->itrans,
  299.                     &cache->trans,
  300.                     &cache->trans);
  301.             } else {
  302.                 MatrixCopy(
  303.                     &np->obj->trans->itrans,
  304.                     &cache->trans);
  305.                 cache->dotrans = TRUE;
  306.             }
  307.         }
  308.         i++;
  309.         np++;
  310.     }
  311. }
  312.