This is shadow.c in view mode; [Download] [Up]
/* * shadow.c * * Copyright (C) 1989, 1991, Craig E. Kolb * All rights reserved. * * This software may be freely copied, modified, and redistributed * provided that this copyright notice is preserved on all copies. * * You may not distribute this software, in whole or in part, as part of * any commercial product without the express consent of the authors. * * There is no warranty or other guarantee of fitness of this software * for any purpose. It is provided solely "as is". * * $Id$ * * $Log$ */ #include "libobj/object.h" #include "libsurf/surface.h" #include "light.h" /* * Shadow stats. * External functions have read access via ShadowStats(). */ static unsigned long ShadowRays, ShadowHits, CacheMisses, CacheHits; /* * Options controlling how shadowing information is determined. * Set by external modules via ShadowSetOptions(). */ static long ShadowOptions; /* * Trace ray from point of intersection to a light. If an intersection * occurs at a distance less than "dist" (the distance to the * light source), then the point is in shadow, and TRUE is returned. * Otherwise, the brightness/color of the light is computed ('result'), * and FALSE is returned. */ int Shadowed(result, color, cache, ray, dist, noshadow) Color *result, *color; /* resultant intensity, light color */ ShadowCache *cache; /* shadow cache for light */ Ray *ray; /* ray, origin on surface, dir towards light */ Float dist; /* distance from pos to light source */ int noshadow; /* If TRUE, no shadow ray is cast. */ { Float s; int i, smooth; HitList hitlist; Ray tmpray; HitNode *np; ShadowCache *cp; Vector hitpos, norm, gnorm; Surface surf, *sptr; Float atten, totaldist; if (noshadow || NOSHADOWS(ShadowOptions)) { *result = *color; return FALSE; } ShadowRays++; s = dist; cp = &cache[ray->depth]; /* * Check shadow cache. SHADOWCACHE() is implied. */ if (cp->obj) { /* * Transform ray to the space of the cached primitive. */ tmpray = *ray; if (cp->dotrans) s *= RayTransform(&tmpray, &cp->trans); /* * s = distance to light source in 'primitive space'. * Intersect ray with cached object. */ if (IsAggregate(cp->obj)) { if ((*cp->obj->methods->intersect)(cp->obj->obj, &tmpray, &hitlist, SHADOW_EPSILON, &s)) { CacheHits++; return TRUE; } } else if ((*cp->obj->methods->intersect)(cp->obj->obj, &tmpray, SHADOW_EPSILON, &s)) { /* Hit cached object. */ CacheHits++; return TRUE; } /* * Did not hit anything -- zero out the cache. */ CacheMisses++; /* * Transformed -- reset s for use below. */ s = dist; cp->obj = (Object *)NULL; cp->dotrans = FALSE; } hitlist.nodes = 0; if (!TraceRay(ray, &hitlist, SHADOW_EPSILON, &s)) { /* Shadow ray didn't hit anything. */ *result = *color; return FALSE; } /* * Otherwise, we've hit something. */ ShadowHits++; /* * If we're not worrying about transparent objects... * This is ugly due to the fact that we have to find * the surface associated with the object that was hit. * GetShadingSurf() will always return a non-null value. */ sptr = GetShadingSurf(&hitlist); if (!SHADOWTRANSP(ShadowOptions) || sptr->transp == 0.) { if (SHADOWCACHE(ShadowOptions)) { if (SHADOWCSG(ShadowOptions)) { /* * There's possibly a CSG object in the * hitlist, so we can't simply cache the * primitive that was hit. Find the * object lowest in hit that's not part * of a CSG object, and cache it. */ i = FirstCSGObj(&hitlist); } else { /* * Cache the primitive that was hit. */ i = 0; } /* * Compute total world-->cached object * transformation and store in cp->trans. */ /* * Find the first transformation... */ np = &hitlist.data[i]; cp->obj = np->obj; cp->dotrans = FALSE; while (i < hitlist.nodes -1) { if (np->obj->trans) { if (cp->dotrans) { MatrixMult( &np->obj->trans->itrans, &cp->trans, &cp->trans); } else { MatrixCopy( &np->obj->trans->itrans, &cp->trans); cp->dotrans = TRUE; } } i++; np++; } } return TRUE; } /* * We've hit a transparent object. Attenuate the color of the light * source and continue the ray until we hit background or a * non-transparent object. Note that this is incorrect if DefIndex or * any of the indices of refraction of the surfaces differ. * * "atten" is a misnomer. */ atten = 1.; totaldist = 0.; do { /* * If surf.transp is 0 at this point, we could * cache the object and return 0 directly. * This would mean that if transp is to be set to nonzero * by a texture, the surface should also have nonzero * transp *before* texturing or else shadows won't * work correctly. */ /* * Perform texturing and the like in case surface * transparency is modulated. */ (void)ComputeSurfProps(&hitlist, &ray, &hitpos, &norm, &gnorm, &surf, &smooth); atten *= surf.transp; /* * Return if attenuation becomes large ('atten' is small). */ if (atten < EPSILON) return TRUE; /* * Max distance is previous max minus previous distance * traveled. */ totaldist = s + EPSILON; s = dist; /* * Trace ray starting at new origin and in the * same direction. */ hitlist.nodes = 0; } while (TraceRay(ray, &hitlist, totaldist, &s)); ColorScale(atten, *color, result); return FALSE; } void ShadowStats(shadowrays, shadowhit, cachehit, cachemiss) unsigned long *shadowrays, *shadowhit, *cachehit, *cachemiss; { *shadowrays = ShadowRays; *shadowhit = ShadowHits; *cachehit = CacheHits; *cachemiss = CacheMisses; } void ShadowSetOptions(options) { ShadowOptions = options; if (SHADOWCACHE(ShadowOptions) && SHADOWTRANSP(ShadowOptions)) { /* * Ensure that if shadowtransp is true that * caching is disabled. We don't really have to do * this, but the code isn't yet in place to handle * this properly. */ ShadowOptions &= ~SHADOW_CACHE; } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.