#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'Doc/Guide/lights.tex' <<'END_OF_FILE' X\chapter{Light Sources} X XThe lighting in a scene is determined by the number, type, and nature Xof the light sources defined in the input file. Available light sources Xrange from simple directional sources to more realistic but computationally Xcostly quadrilateral area light sources. Typically, you will want to use Xpoint or directional light sources while developing images. When Xfinal renderings are made, these simple light sources may be replaced by Xthe more complex ones. X XNo matter what kind of light source you use, you will need to Xspecify its intensity. XIn this chapter, an {\em Intensity\/} is either a red-green-blue triple Xindicating the color of the light source, or a single value that is Xinterpreted as the intensity of a ``white'' light. XIn the current version of {\rayshade}, the intensity of a light does Xnot decrease as Xone moves farther from it. X XIf you do not define a light source, {\rayshade} will create a directional Xlight source of intensity 1.0 defined by the vector (1., -1., 1.). XThis default light source is designed to work well when default Xviewing parameters and surface values are being used. X XYou may define any number of light sources, but keep in mind that Xit will require more time to render images that include many Xlight sources. It should also be noted that the light sources themselves Xwill not appear in the image, even if they are placed in frame. X X\section{Light Source Types} X XThe amount of ambient light present in a scene is controlled by a Xpseudo light source of type {\em ambient}. X X\begin{defkey}{light}{{\em Intensity\/} ambient} X Define the amount of ambient light present in the entire X scene. X\end{defkey} X XThere is only one ambient light source; its default intensity is X{1, 1, 1}. If more than one ambient light source is defined, Xonly the last instance is used. A surface's ambient color Xis multiplied by the intensity of the ambient source to give the Xtotal ambient light reflected from the surface. X XDirectional sources are described by a direction alone, and are useful Xfor modeling light sources that are effectively infinitely far away Xfrom the objects they illuminate. X X\begin{defkey}{light}{{\em Intensity\/} {\tt directional} \evec{direction}} X Define a light source with the given intensity that is X defined to be in the given direction from every point X it illuminates. The direction need not be normalized. X\end{defkey} X XPoint sources are defined as a single point in space. They produce Xshadows with sharp edges and are a good replacement for extended Xand other computationally expensive light source. X X\begin{defkey}{light}{{\em Intensity\/} {\tt point} \evec{pos}} X Place a point light source with the given intensity at the X given position. X\end{defkey} X XSpotlights are useful for creating dramatic localized lighting effects. XThey are defined by their position, the direction in which they Xare pointing, and the width of the beam of light they produce. X X\begin{defkey}{light}{{\em Intensity\/} {\tt spot} \evec{pos} \evec{to} X {$\alpha$} [ $\theta_{in}$ $\theta_{out}$ ]} X Place a spotlight at \evec{pos}, oriented as to be pointing at X \evec{to}. The intensity of the light falls off as X $(cosine \theta)^{\alpha}$, where $\theta$ is the angle between the X spotlight's main axis and the vector from the spotlight to the X point being illuminated. $\theta_{in}$ and X $\theta_{out}$ may be used to control the radius of the cone of light X produced by the spotlight. X\end{defkey} X$\theta_{in}$ is the the angle at which Xthe light source begins to be attenuated. At $\theta_{out}$, Xthe spotlight intensity is zero. XThis affords control Xover how ``fuzzy'' the edges of the spotlight are. If neither angle Xis given, they both are effectively set to 180 degrees. X XExtended sources are meant to model spherical light sources. Unlike Xpoint sources, extended sources actually possess a radius, and as such Xare capable or producing shadows with fuzzy edges ({\em penumbrae}). If Xyou do not specifically desire penumbrae in your image, use a point Xsource instead. X X\begin{defkey}{light}{{\em Intensity\/} {\tt extended} {\em radius} \evec{pos} } X Create an extended light source at the given position and with X the given {\em radius}. X\end{defkey} XThe shadows cast by Xextended sources are modeled by taking samples of the source at Xdifferent locations on its surface. When the source is partially Xhidden from a given point in space, that point is in partial shadow Xwith respect to the extended source, and the sampling process is Xusually able to determine this fact. X XQuadrilateral light sources are computationally more expensive than extended Xlight sources, but are more flexible and produce more realistic results. XThis is due to the fact that an area source is approximated by a Xnumber of point sources whose positions are jittered to reduce aliasing. XBecause each of these point sources has shading calculations performed Xindividually, area sources may be placed relatively close to the Xobjects it illuminates, and a reasonable image will result. X X\begin{defkey}{light}{{\em Intensity\/} {\tt area} \evec{p1} \evec{p2} {\em usamp} X \evec{p3} {\em vsamp}} X Create a quadrilateral area light source. X The $u$ axis X is defined by the vector from \evec{p1} to \evec{p2}. Along X this axis a total of {\em usamp} samples will be taken. X The $v$ axis of the light source is defined by the vector X from \evec{p1} to \evec{p3}. Along this axis a total of X {\em vsamp} samples will be taken. X\end{defkey} XThe values of {\em usamp} and {\em vsamp} are usually chosen to be Xproportional to the lengths of the $u$ and $v$ axes. Choosing a Xrelatively high number of samples will result in a good approximation Xto a ``real'' quadrilateral source. However, because complete Xlighting calculations are performed for each sample, Xthe computational cost is directly proportional to the product Xof {\em usamp} and {\em vsamp}. X X\section{Shadows} X XIn order to determine the color of a point on the surface Xof any object, it is necessary Xto determine if that point is in shadow with respect to each Xdefined light source. If the point is totally in shadow with respect to Xa light source, then the light source makes no contribution to the Xpoint's final color. X XThis shadowing determination is made by tracing rays from the point Xof intersection to each light source. These ``shadow feeler'' rays Xcan add substantially to the overall rendering time. This is especially Xtrue if extended or area light sources are used. If at any point you Xwish to disable shadow determination on a global scale, there is Xa command-line option ({\tt -n}) that allows you to do so. It is also Xpossible Xto disable the casting of shadows onto given objects through the use Xof the {\tt noshadow} keyword in surface descriptions. In addition, Xthe {\tt noshadow} keyword may be given following the definition Xof a light source, causing the light source to cast no shadows onto Xany surface. X XDetermining if a point is in shadow with respect to a light source Xis relatively simple if all the objects in a scene are opaque. In Xthis case, one simply traces a ray from the point to the light source. XIf the ray hits an object before it reaches the light source, then Xthe point is in shadow. X XShadow determination Xbecomes more complicated if there are one or more objects with Xnon-zero transparency between the point and the light source. XTransparent objects may not completely block the light from a source, Xbut merely attenuate it. In such cases, it is necessary to compute the Xamount of attenuation at each intersection and to continue Xthe shadow ray until it either reaches the light source or until Xthe light is completely attenuated. X XBy default, {\rayshade} computes shadow attenuation by assuming Xthat the index of refraction of the transparent object is the Xsame as that of the medium through which the ray is traveling. XTo disable Xpartial shadowing due to transparent objects, the {\tt shadowtransp} Xkeyword should be given somewhere in the input file. X X\begin{defkey}{shadowtransp}{} X The intensity of light striking a point is {\em not} affected by X intervening transparent objects. X\end{defkey} XIf you enclose an object behind a transparent surface, and you wish Xthe inner object to be illuminated, you must not use the {\tt shadowtransp} Xkeyword or the {\tt -o} option. END_OF_FILE if test 8327 -ne `wc -c <'Doc/Guide/lights.tex'`; then echo shar: \"'Doc/Guide/lights.tex'\" unpacked with wrong size! fi # end of 'Doc/Guide/lights.tex' fi if test -f 'libray/libobj/poly.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libobj/poly.c'\" else echo shar: Extracting \"'libray/libobj/poly.c'\" \(8071 characters\) sed "s/^X//" >'libray/libobj/poly.c' <<'END_OF_FILE' X/* X * poly.c X * X * Copyright (C) 1989, 1991, Craig E. Kolb X * All rights reserved. X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: poly.c,v 4.0.1.1 91/11/26 21:25:34 cek Exp Locker: cek $ X * X * $Log: poly.c,v $ X * Revision 4.0.1.1 91/11/26 21:25:34 cek X * patch3: Additional check for degenerate polygon. X * X * Revision 4.0 91/07/17 14:39:00 kolb X * Initial version. X * X */ X#include "geom.h" X#include "poly.h" X Xstatic Methods *iPolygonMethods = NULL; Xstatic char polyName[] = "polygon"; X Xunsigned long PolyTests, PolyHits; X X/* X * Create a reference to a polygon with vertices equal to those X * on the linked-list "plist." X */ XPolygon * XPolygonCreate(plist, npoints, flipflag) XPointList *plist; Xint npoints, flipflag; X{ X Polygon *poly; X Float indexval; X Vector *prev, *cur, anorm; X PointList *curp, *pltmp; X int i; X X if (npoints < 3) { X RLerror(RL_WARN, "Degenerate polygon.\n"); X return (Polygon *)NULL; X } X X poly = (Polygon *)share_malloc(sizeof(Polygon)); X /* X * Allocate space for the vertices. X */ X poly->points = (Vector *)Malloc((unsigned)(npoints*sizeof(Vector))); X poly->npoints = npoints; X X /* X * Copy the vertices from the linked list to the array, freeing X * the linked list as we go so that the caller doesn't have X * to worry about doing so. X */ X i = npoints -1; X for(curp = plist; curp != (PointList *)0; curp = pltmp) { X poly->points[i--] = curp->vec; X pltmp = curp->next; X free((voidstar)curp); X } X X /* X * Find normal to polygon. X */ X poly->norm.x = poly->norm.y = poly->norm.z = 0.; X prev = &poly->points[poly->npoints -1]; X for(i = 0,cur = poly->points;i < poly->npoints;i++, prev = cur, cur++) { X poly->norm.x += (prev->y - cur->y) * (prev->z + cur->z); X poly->norm.y += (prev->z - cur->z) * (prev->x + cur->x); X poly->norm.z += (prev->x - cur->x) * (prev->y + cur->y); X } X X if (VecNormalize(&poly->norm) == 0.) { X /* X * Degenerate normal --> degenerate polygon X */ X RLerror(RL_WARN, "Degenerate polygon.\n"); X free((voidstar)poly->points); X return (Polygon *)NULL; X } X X /* X * If filflag is true, flip the normal. X */ X if (flipflag) X VecScale(-1, poly->norm, &poly->norm); X X /* X * Compute and store the plane constant. X */ X poly->d = dotp(&poly->norm, &poly->points[0]); X X /* X * Find the "dominant" part of the normal vector. This X * is used to turn the point-in-polygon test into a 2D problem. X */ X anorm.x = fabs(poly->norm.x); X anorm.y = fabs(poly->norm.y); X anorm.z = fabs(poly->norm.z); X indexval = max(anorm.y, anorm.z); X indexval = max(anorm.x, indexval); X X if (indexval == anorm.x) X poly->index = XNORMAL; X else if (indexval == anorm.y) X poly->index = YNORMAL; X else X poly->index = ZNORMAL; X X return poly; X} X XMethods * XPolygonMethods() X{ X if (iPolygonMethods == (Methods *)NULL) { X iPolygonMethods = MethodsCreate(); X iPolygonMethods->create = (GeomCreateFunc *)PolygonCreate; X iPolygonMethods->methods = PolygonMethods; X iPolygonMethods->name = PolygonName; X iPolygonMethods->intersect = PolygonIntersect; X iPolygonMethods->normal = PolygonNormal; X iPolygonMethods->uv = PolygonUV; X iPolygonMethods->bounds = PolygonBounds; X iPolygonMethods->stats = PolygonStats; X iPolygonMethods->checkbounds = TRUE; X iPolygonMethods->closed = FALSE; X } X return iPolygonMethods; X} X X/* X * Quadrants are defined as: X * | X * 1 | 0 X * | X * -------c-------- X * | X * 2 | 3 X * | X */ X#define quadrant(p, c) ((p.upos; X dir = ray->dir; X /* X * First, find where ray hits polygon plane, projecting X * along the polygon's dominant normal component. X */ X X dist = dotp(&poly->norm, &dir); X if(fabs(dist) < EPSILON) X /* X * No intersection with polygon plane. X */ X return FALSE; X X dist = (poly->d - dotp(&poly->norm, &pos)) / dist; X if(dist < mindist || dist > *maxdist) X /* X * Intersection point behind origin or too far. X */ X return FALSE; X X /* X * Compute the point of intersection, projected appropriately. X */ X if(poly->index == XNORMAL) { X center.u = pos.y + dist * dir.y; X center.v = pos.z + dist * dir.z; X } else if(poly->index == YNORMAL) { X center.v = pos.z + dist * dir.z; X center.u = pos.x + dist * dir.x; X } else { X center.u = pos.x + dist * dir.x; X center.v = pos.y + dist * dir.y; X } X X /* X * Is the point inside the polygon? X * X * Compute the winding number by finding the quadrant each X * polygon point lies in with respect to the the point in X * question, and computing a "delta" (winding number). If we X * end up going around in a complete circle around X * the point (winding number is non-zero at the end), then X * we're inside. Otherwise, the point is outside. X * X * Note that we can turn this into a 2D problem by projecting X * all the points along the axis defined by poly->index, X * the "dominant" part of the polygon's normal vector. X */ X winding = 0; X VecProject(last, poly->points[poly->npoints -1], poly->index); X lastquad = quadrant(last, center); X for(i = 0; i < poly->npoints; i++, last = cur) { X VecProject(cur, poly->points[i], poly->index); X quad = quadrant(cur, center); X if (quad == lastquad) X continue; X if(((lastquad + 1) & 3) == quad) X winding++; X else if(((quad + 1) & 3) == lastquad) X winding--; X else { X /* X * Find where edge crosses X * center's X axis. X */ X right = last.u - cur.u; X left = (last.v - cur.v) * (center.u - last.u); X if(left + last.v * right > right * center.v) X winding += 2; X else X winding -= 2; X } X lastquad = quad; X } X X if (winding != 0) { X *maxdist = dist; X PolyHits++; X return TRUE; X } X return FALSE; X} X X/* X * Return the normal to the polygon surface. X */ X/*ARGSUSED*/ Xint XPolygonNormal(poly, pos, nrm, gnrm) XPolygon *poly; XVector *pos, *nrm, *gnrm; X{ X *gnrm = *nrm = poly->norm; X return FALSE; X} X X/*ARGSUSED*/ Xvoid XPolygonUV(poly, pos, norm, uv, dpdu, dpdv) XPolygon *poly; XVector *pos, *norm, *dpdu, *dpdv; XVec2d *uv; X{ X /* X * Since there's no nice way to do this, we wimp out and X * do the following... X * X * Of course, we could force the user to specify U and V X * axes, but forcing them to use X and Y as U and V is X * just as arbitrary and much simpler to deal with. X */ X uv->u = pos->x; X uv->v = pos->y; X if (dpdu) { X dpdu->x = 1.; X dpdu->y = dpdu->z = 0.; X dpdv->x = dpdv->z = 0.; X dpdv->y = 1.; X } X} X X/* X * Compute the extent of a polygon X */ Xvoid XPolygonBounds(poly, bounds) XPolygon *poly; XFloat bounds[2][3]; X{ X register int i; X X bounds[LOW][X] = bounds[HIGH][X] = poly->points[0].x; X bounds[LOW][Y] = bounds[HIGH][Y] = poly->points[0].y; X bounds[LOW][Z] = bounds[HIGH][Z] = poly->points[0].z; X X for (i = 1 ;i < poly->npoints; i++) { X if (poly->points[i].x < bounds[LOW][X]) X bounds[LOW][X] = poly->points[i].x; X if (poly->points[i].x > bounds[HIGH][X]) X bounds[HIGH][X] = poly->points[i].x; X if (poly->points[i].y < bounds[LOW][Y]) X bounds[LOW][Y] = poly->points[i].y; X if (poly->points[i].y > bounds[HIGH][Y]) X bounds[HIGH][Y] = poly->points[i].y; X if (poly->points[i].z < bounds[LOW][Z]) X bounds[LOW][Z] = poly->points[i].z; X if (poly->points[i].z > bounds[HIGH][Z]) X bounds[HIGH][Z] = poly->points[i].z; X } X} X Xchar * XPolygonName() X{ X return polyName; X} X Xvoid XPolygonStats(tests, hits) Xunsigned long *tests, *hits; X{ X *tests = PolyTests; X *hits = PolyHits; X} X Xvoid XPolygonMethodRegister(meth) XUserMethodType meth; X{ X if (iPolygonMethods) X iPolygonMethods->user = meth; X} END_OF_FILE if test 8071 -ne `wc -c <'libray/libobj/poly.c'`; then echo shar: \"'libray/libobj/poly.c'\" unpacked with wrong size! fi # end of 'libray/libobj/poly.c' fi if test -f 'libray/libobj/torus.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libobj/torus.c'\" else echo shar: Extracting \"'libray/libobj/torus.c'\" \(8916 characters\) sed "s/^X//" >'libray/libobj/torus.c' <<'END_OF_FILE' X/* X * torus.c X * X * Copyright (C) 1990, 1991, Mark Podlipec, Craig E. Kolb X * All rights reserved. X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: torus.c,v 4.0 91/07/17 14:39:28 kolb Exp Locker: kolb $ X * X * $Log: torus.c,v $ X * Revision 4.0 91/07/17 14:39:28 kolb X * Initial version. X * X */ X#include "geom.h" X#include "torus.h" X Xstatic Methods *iTorusMethods = NULL; Xstatic char torusName[] = "torus"; Xunsigned long TorusTests, TorusHits; X X/* X * Create & return reference to a torus. X */ XTorus * XTorusCreate(a, b, pos, norm) XFloat a, b; XVector *pos, *norm; X{ X Torus *torus; X Vector tmpnrm; X X if ((a < EPSILON) || (b < EPSILON)) { X RLerror(RL_WARN, "Degenerate torus.\n"); X return (Torus *)NULL; X } X X tmpnrm = *norm; X if (VecNormalize(&tmpnrm) == 0.) { X RLerror(RL_WARN, "Degenerate torus normal.\n"); X return (Torus *)NULL; X } X X torus = (Torus *)share_malloc(sizeof(Torus)); X X /* X * torus->aa holds the square of the swept radius. X * torus->bb holds the square of the tube radius. X */ X torus->a = a; X torus->b = b; X torus->aa = a*a; X torus->bb = b*b; X CoordSysTransform(pos, &tmpnrm, 1., 1., &torus->trans); X X return torus; X} X X/* X * Ray/torus intersection test. X */ Xint XTorusIntersect(torus, inray, mindist, maxdist) XTorus *torus; XRay *inray; XFloat mindist, *maxdist; X{ X Vector pos,ray; X double c[5],s[4], dist, nmin; X Float distfactor; X register int num,i; X X TorusTests++; X X /* Transform ray into toroid space */ X { X Ray tmpray; X tmpray = *inray; X distfactor = RayTransform(&tmpray, &torus->trans.itrans); X ray = tmpray.dir; X pos = tmpray.pos; X nmin = mindist * distfactor; X } X X /* X * Original Equations for Toroid with position of (0,0,0) and axis (0,0,1) X * X * Equation for two circles of radius b centered at (-a,0,0) and (a,0,0) X * X * ((R-a)^2 + z*2 - b*b) * ((R+a)^2 + z*z - b*b) = 0 X * X * a is swept radius X * b is tube radius X * X * subsitute R*R = x*x + y*y to rotate about z-axis X * X * and substitute the parametric ray equations: X * X * x = x0 + t * x1; X * y = y0 + t * y1; X * z = z0 + t * z1; X * X * to get a Quartic in t. X * X * c4*t^4 + c3*t^3 + c2*t^2 + c1*t + c0 = 0 X * X * where the coefficients are: X * X * c4 = (x1s + y1s + z1s) * (x1s + y1s + z1s); X * c3 = 4.0 * (tx + ty + tz) * (x1s + y1s + z1s); X * c2 = 2.0 * (x1s + y1s + z1s) * (x0s + y0s + z0s - as - bs) X * + 4.0 * (tx + ty + tz) * (tx + ty + tz) X * + 4.0 * as * z1s; X * c1 = 4.0 * (tx + ty + tz) * (x0s + y0s + z0s - as - bs) X * + 8.0 * as * tz; X * c0 = (x0s + y0s + z0s - as - bs) * (x0s + y0s + z0s - as - bs) X * + 4.0 * as * (z0s - bs); X * X * as is swept radius squared X * bs is tube radius squared X * (x0,y0,z0) is origin of ray to be tested X * (x1,y1,z1) is direction vector of ray to be tested X * tx is x0 * x1 X * ty is y0 * y1 X * tz is z0 * z1 X * X * Since the direction vector (x1,y1,z1) is normalized: X * (x1s + y1s + z1s) = 1.0 X * X * Also let g2s = (x1 * x0) + (y1 * y0) + (z1 * z0) X * and let g0s = (x0 * x0) * (y0 * y0) + (z0 * z0) - as - bs X * since these terms are used fairly often X */ X { X register Float g0s,g2s; X register Float as,bs; X register Float z0s,z1s,tz; X X as = torus->aa; X bs = torus->bb; X z0s = pos.z * pos.z; X z1s = ray.z * ray.z; X tz = pos.z * ray.z; X g0s = pos.x * pos.x + pos.y * pos.y + z0s - as - bs; X g2s = pos.x * ray.x + pos.y * ray.y + tz; X X c[4] = 1.0; X c[3] = 4.0 * g2s; X c[2] = 2.0 * (g0s + 2.0 * g2s * g2s + 2.0 * as * z1s); X c[1] = 4.0 * (g2s*g0s + 2.0*as*tz); X c[0] = g0s * g0s + 4.0 * as * (z0s - bs); X } X X /* use GraphGem's Solve Quartic to find roots */ X num = SolveQuartic(c,s); X X /* no roots - return 0. */ X if (num==0) return FALSE; X X /* of roots return the smallest root > EPSILON */ X dist = 0.0; X for(i=0;i nmin) { X /* first valid root */ X if (dist == 0.0) dist = s[i]; X /* else update only if it's closer to ray origin */ X else if (s[i] < dist) dist = s[i]; X } X } X dist /= distfactor; X if (dist > mindist && dist < *maxdist) { X *maxdist = dist; X TorusHits++; X return TRUE; X } X return FALSE; X} X X/* X * Compute the normal to a torus at a given location on its surface X */ Xint XTorusNormal(torus, rawpos, nrm, gnrm) XTorus *torus; XVector *rawpos, *nrm, *gnrm; X{ X Vector pos; X register Float dist,posx,posy,xm,ym; X X /* Transform intersection point to torus space. */ X pos = *rawpos; X PointTransform(&pos, &torus->trans.itrans); X X/* X * The code for the toroid is simpified by always having the axis X * be the z-axis and then transforming information to and from X * toroid space. X * X * Flatten toroid by ignoring z. Now imagine a knife cutting from X * center of toroid to the ray intersection point(x,y). The point X * on the tube axis(a circle about the origin with radius 'a') X * where the knife cuts is (xm,ym,zm=0). Unflattening the toroid, X * the normal at the point [x,y,z] is (x-xm,y-ym,z). Of course, we X * must transform the normal back into world coordinates. X * Instead of messing with tan-1,sin and cos, we can find (xm,ym) X * by using the proportions: X * X * xm x ym y X * ---- = ---- and ---- = ---- X * a dist a dist X * X * a is the swept radius X * [x,y,z] is the point on the toroids surface X * dist is the distance from the z-axis (x*x + y*y). X * [xm,ym,zm=0] is the point on the tube's axis X * X */ X X /* find distance from axis */ X posx = pos.x; X posy = pos.y; X dist = sqrt(posx * posx + posy * posy); X X if (dist > EPSILON) X { X xm = torus->a * posx / dist; X ym = torus->a * posy / dist; X } X else /* ERROR - dist should not be < EPSILON (should never happen)*/ X { X xm = 0.0; X ym = 0.0; X } X X /* normal is vector from [xm,ym,zm] to [x,y,z] */ X nrm->x = posx - xm; X nrm->y = posy - ym; X nrm->z = pos.z; /* note by default zm is 0 */ X X /* Transform normal back to world space. */ X NormalTransform(nrm, &torus->trans.itrans); X *gnrm = *nrm; X return FALSE; X} X Xvoid XTorusUV(torus, pos, norm, uv, dpdu, dpdv) XTorus *torus; XVector *pos, *norm, *dpdu, *dpdv; XVec2d *uv; X{ X Vector npos; X Float costheta, sintheta, rad, cosphi; X X npos = *pos; X PointTransform(&npos, &torus->trans.itrans); X /* X * u = theta / 2PI X */ X rad = sqrt(npos.x*npos.x + npos.y*npos.y); X costheta = npos.x / rad; X sintheta = npos.y / rad; X if (costheta > 1.) /* roundoff */ X uv->u = 0.; X else if (costheta < -1.) X uv->u = 0.5; X else X uv->u = acos(costheta) / TWOPI; X if (sintheta < 0.) X uv->u = 1. - uv->u; X if (dpdu) { X dpdu->x = -npos.y; X dpdu->y = npos.x; X dpdu->z = 0.; X VecTransform(dpdu, &torus->trans.trans); X (void)VecNormalize(dpdu); X } X /* X * sinphi = npos.z / tor->b; X * cosphi = rad - tor->a; X * cosphi is negated in order to make texture 'seam' X * occur on the interior of the torus. X */ X cosphi = -(rad - torus->a) / torus->b; X if (cosphi > 1.) X uv->v = 0.; X else if (cosphi < -1.) X uv->v = 0.5; X else X uv->v = acos(cosphi) / TWOPI; X if (npos.z > 0.) /* if sinphi > 0... */ X uv->v = 1. - uv->v; X /* X * dpdv = norm X dpdu X */ X if (dpdv) { X VecCross(norm, dpdu, dpdv); X VecTransform(dpdv, &torus->trans.trans); X (void)VecNormalize(dpdv); X } X} X X/* X * Return the extent of a torus. X */ Xvoid XTorusBounds(torus, bounds) XTorus *torus; XFloat bounds[2][3]; X{ X bounds[LOW][X] = bounds[LOW][Y] = -(torus->a+torus->b); X bounds[HIGH][X] = bounds[HIGH][Y] = torus->a+torus->b; X bounds[LOW][Z] = -torus->b; X bounds[HIGH][Z] = torus->b; X /* X * Transform bounding box to world space. X */ X BoundsTransform(&torus->trans.trans, bounds); X} X Xchar * XTorusName() X{ X return torusName; X} X Xvoid XTorusStats(tests, hits) Xunsigned long *tests, *hits; X{ X *tests = TorusTests; X *hits = TorusHits; X} X XMethods * XTorusMethods() X{ X if (iTorusMethods == NULL) { X iTorusMethods = MethodsCreate(); X iTorusMethods->create = (GeomCreateFunc *)TorusCreate; X iTorusMethods->methods = TorusMethods; X iTorusMethods->name = TorusName; X iTorusMethods->intersect = TorusIntersect; X iTorusMethods->bounds = TorusBounds; X iTorusMethods->normal = TorusNormal; X iTorusMethods->uv = TorusUV; X iTorusMethods->stats = TorusStats; X iTorusMethods->checkbounds = TRUE; X iTorusMethods->closed = TRUE; X } X return iTorusMethods; X} X Xvoid XTorusMethodRegister(meth) XUserMethodType meth; X{ X if (iTorusMethods) X iTorusMethods->user = meth; X} END_OF_FILE if test 8916 -ne `wc -c <'libray/libobj/torus.c'`; then echo shar: \"'libray/libobj/torus.c'\" unpacked with wrong size! fi # end of 'libray/libobj/torus.c' fi if test -f 'libshade/options.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libshade/options.c'\" else echo shar: Extracting \"'libshade/options.c'\" \(9192 characters\) sed "s/^X//" >'libshade/options.c' <<'END_OF_FILE' X/* X * options.c X * X * Copyright (C) 1989, 1991, Craig E. Kolb X * All rights reserved. X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: options.c,v 4.0.1.3 92/01/14 18:29:59 cek Exp Locker: cek $ X * X * $Log: options.c,v $ X * Revision 4.0.1.3 92/01/14 18:29:59 cek X * patch3: Added "-u" (cpp) option. X * X * Revision 4.0.1.2 91/12/13 12:09:53 cek X * patch3: Fixed "-W" option typo. X * X * Revision 4.0.1.1 91/10/05 18:23:15 cek X * patch1: Changes for new window/crop options. X * patch1: Corrected help message. X * X * Revision 4.0 91/07/17 14:46:47 kolb X * Initial version. X * X */ X#include "rayshade.h" X#include "options.h" X#include "stats.h" X#include "viewing.h" X XRSOptions Options; X Xstatic void usage(); X Xvoid XRSOptionsSet(argc, argv) Xint argc; Xchar **argv; X{ X extern void OpenStatsFile(); X X Options.progname = strsave(argv[0]); X Options.inputname = (char *)NULL; X X while (--argc) { X argv++; X if (argv[0][0] != '-') { X /* X * Must be the input file name. X * If already given, complain and then exit. X */ X if (Options.inputname != (char *)NULL) { X usage(); X exit(1); X } X Options.inputname = strsave(argv[0]); X continue; X } X /* else */ X switch(argv[0][1]) { X case 'A': X /* X * First frame number X */ X Options.startframe = atoi(argv[1]); X argv++; argc--; X break; X#ifdef URT X case 'a': X Options.alpha = !Options.alpha; X break; X#endif X case 'C': X Options.cutoff.r = atof(argv[1]); X Options.cutoff.g = atof(argv[2]); X Options.cutoff.b = atof(argv[3]); X Options.cutoff_set = TRUE; X argv += 3; argc -= 3; X break; X#ifdef URT X case 'c': X Options.appending = TRUE; X break; X#endif X case 'D': X Options.maxdepth = atoi(argv[1]); X Options.maxdepth_set = TRUE; X argv++; argc--; X break; X case 'E': X Options.eyesep = atof(argv[1]); X Options.eyesep_set = TRUE; X argc--; argv++; X break; X#ifdef URT X case 'e': X Options.exp_output = TRUE; X break; X#endif X case 'F': X Options.report_freq = atoi(argv[1]); X if (Options.report_freq < 1) X Options.report_freq = 1; X Options.freq_set = TRUE; X argv++; argc--; X break; X case 'f': X Options.flipnorm = !Options.flipnorm; X break; X case 'G': X Options.gamma = atof(argv[1]); X argv++; argc--; X break; X case 'g': X Options.gaussian = !Options.gaussian; X break; X case 'h': X usage(); X exit(0); X break; X case 'j': X Options.jitter = !Options.jitter; X Options.jitter_set = TRUE; X break; X case 'l': X Options.stereo = LEFT; X break; X#ifdef URT X case 'm': X Options.samplemap = !Options.samplemap; X break; X#endif X case 'N': X Options.totalframes = atof(argv[1]); X Options.totalframes_set = TRUE; X argv++; argc--; X break; X case 'n': X Options.no_shadows = !Options.no_shadows; X break; X case 'O': X Options.imgname = strsave(argv[1]); X argv++; X argc--; X break; X case 'o': X Options.shadowtransp = !Options.shadowtransp; X break; X case 'P': X Options.cppargs = argv[1]; X argv++; argc--; X break; X case 'p': X /* X * Preview-quality rendering X * no shadows X * max depth of 0 X * 1 jittered sample/pixel X */ X Options.no_shadows = TRUE; X Options.maxdepth = 0; X Options.maxdepth_set = TRUE; X Options.jitter = TRUE; X Options.jitter_set = TRUE; X Options.samples = 1; X Options.samples_set = TRUE; X break; X case 'q': X Options.quiet = TRUE; X break; X case 'R': X Screen.xres = atoi(argv[1]); X Screen.yres = atoi(argv[2]); X Options.resolution_set = TRUE; X argv += 2; X argc -= 2; X break; X case 'r': X Options.stereo = RIGHT; X break; X case 'S': X Options.samples = atoi(argv[1]); X if (Options.samples < 1) X Options.samples = 1; X Options.samples_set = TRUE; X argv++; argc--; X break; X case 's': X Options.cache = !Options.cache; X break; X case 'T': X Options.contrast.r = atof(argv[1]); X Options.contrast.g = atof(argv[2]); X Options.contrast.b = atof(argv[3]); X Options.contrast_set = TRUE; X argv += 3; X argc -= 3; X break; X case 'u': X Options.cpp = !Options.cpp; X break; X case 'v': X Options.verbose = TRUE; X break; X case 'V': X Options.verbose = TRUE; X if (argv[1][0] == '-') { X /* User probably blew it, and X * it's difficult to remove a file X * that begins with '-'... X */ X usage(); X exit(2); X } X Options.statsname = strsave(argv[1]); X OpenStatsFile(); X argv++; argc--; X break; X case 'W': X Options.window[LOW][X] = atoi(argv[1]); X Options.window[HIGH][X] = atoi(argv[2]); X Options.window[LOW][Y] = atoi(argv[3]); X Options.window[HIGH][Y] = atoi(argv[4]); X Options.window_set = TRUE; X argv += 4; argc -= 4; X break; X case 'X': X Options.crop[LOW][X] = atof(argv[1]); X Options.crop[HIGH][X] = atof(argv[2]); X Options.crop[LOW][Y] = atof(argv[3]); X Options.crop[HIGH][Y] = atof(argv[4]); X Options.crop_set = TRUE; X argv += 4; argc -= 4; X break; X default: X RLerror(RL_PANIC,"Bad argument: %s\n",argv[0]); X } X } X} X Xvoid XRSOptionsList() X{ X if (Options.totalframes > 1) { X fprintf(Stats.fstats,"Rendering frames %d through %d.\n", X Options.startframe, Options.endframe); X } else { X fprintf(Stats.fstats,"Rendering frame %d.\n", Options.startframe); X } X X fprintf(Stats.fstats,"Screen resolution: %d x %d\n", X Screen.xres,Screen.yres); X fprintf(Stats.fstats,"Image window: (%d - %d), (%d - %d).\n", X Screen.minx, Screen.maxx, Screen.miny, Screen.maxy); X X if (Options.jitter) X fprintf(Stats.fstats,"Using jittered sampling, "); X fprintf(Stats.fstats,"Max sampling rate %d %s/pixel.\n", X Options.samples*Options.samples, X Options.samples == 1 ? "sample" : "samples"); X X fprintf(Stats.fstats, X "Maximum contrast: %g red, %g green, %g blue.\n", X Options.contrast.r, Options.contrast.g, X Options.contrast.b); X fprintf(Stats.fstats,"Maximum ray depth: %d. Cutoff thresh: %g %g %g.\n", X Options.maxdepth, X Options.cutoff.r, Options.cutoff.g, Options.cutoff.b); X if (Options.stereo == LEFT) X fprintf(Stats.fstats,"Rendering image for left eye.\n"); X else if (Options.stereo == RIGHT) X fprintf(Stats.fstats,"Rendering image for right eye.\n"); X if (Options.no_shadows) { X fprintf(Stats.fstats,"No shadows are rendered.\n"); X } else if (Options.shadowtransp) { X fprintf(Stats.fstats, X "Object opacity affects depth of shadowing.\n"); X } X if (!Options.cache) X fprintf(Stats.fstats,"Shadow caching is disabled.\n"); X if (Options.totalframes != 1) X fprintf(Stats.fstats,"Rendering %d frames.\n", X Options.totalframes); X} X Xstatic void Xusage() X{ X fprintf(stderr,"usage: %s [options] [filename]\n", Options.progname); X fprintf(stderr,"Where options include:\n"); X fprintf(stderr,"\t-A frame\t(Begin with given frame #.)\n"); X#ifdef URT X fprintf(stderr,"\t-a \t\t(Toggle writing of alpha channel.)\n"); X#endif X fprintf(stderr,"\t-C thresh\t(Set adaptive ray tree cutoff value.)\n"); X#ifdef URT X fprintf(stderr,"\t-c \t\t(Continue interrupted rendering.)\n"); X#endif X fprintf(stderr,"\t-D depth\t(Set maximum ray tree depth.)\n"); X fprintf(stderr,"\t-E eye_sep\t(Set eye separation in stereo pairs.)\n"); X#ifdef URT X fprintf(stderr,"\t-e \t\t(Write exponential RLE file.)\n"); X#endif X fprintf(stderr,"\t-F freq\t\t(Set frequency of status report.)\n"); X fprintf(stderr,"\t-f \t\t(Flip all triangle normals.)\n"); X fprintf(stderr,"\t-G gamma\t(Use given gamma correction exponent.)\n"); X fprintf(stderr,"\t-g \t\t(Use Gaussian pixel filter.)\n"); X fprintf(stderr,"\t-h \t\t(Print this message.)\n"); X fprintf(stderr,"\t-j \t\t(Toggle jittered sampling.)\n"); X fprintf(stderr,"\t-l \t\t(Render image for left eye view.)\n"); X#ifdef URT X fprintf(stderr,"\t-m \t\t(Output sample map in alpha channel.)\n"); X#endif X fprintf(stderr,"\t-N number\t(Render given number of frames.)\n"); X fprintf(stderr,"\t-n \t\t(Do not render shadows.)\n"); X fprintf(stderr,"\t-O outfile \t(Set output file name.)\n"); X fprintf(stderr,"\t-o \t\t(Toggle opacity effect on shadowing.)\n"); X fprintf(stderr,"\t-P cpp-args\t(Options to pass to C pre-processor.\n"); X fprintf(stderr,"\t-p \t\t(Preview-quality rendering.)\n"); X fprintf(stderr,"\t-q \t\t(Run quietly.)\n"); X fprintf(stderr,"\t-R xres yres\t(Render at given resolution.)\n"); X fprintf(stderr,"\t-r \t\t(Render image for right eye view.)\n"); X fprintf(stderr,"\t-S samples\t(Max density of samples^2 samples.)\n"); X fprintf(stderr,"\t-s \t\t(Don't cache shadowing information.)\n"); X fprintf(stderr,"\t-T r g b\t(Set contrast threshold (0. - 1.).)\n"); X fprintf(stderr,"\t-V filename \t(Write verbose output to filename.)\n"); X fprintf(stderr,"\t-v \t\t(Verbose output.)\n"); X fprintf(stderr,"\t-W x x y y \t(Render subwindow.)\n"); X fprintf(stderr,"\t-X l r b t \t(Crop window.)\n"); X} END_OF_FILE if test 9192 -ne `wc -c <'libshade/options.c'`; then echo shar: \"'libshade/options.c'\" unpacked with wrong size! fi # end of 'libshade/options.c' fi if test -f 'libshade/viewing.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libshade/viewing.c'\" else echo shar: Extracting \"'libshade/viewing.c'\" \(8784 characters\) sed "s/^X//" >'libshade/viewing.c' <<'END_OF_FILE' X/* X * viewing.c X * X * Copyright (C) 1989, 1991, Craig E. Kolb, Rod G. Bogart X * All rights reserved. X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: viewing.c,v 4.0.1.1 91/09/29 15:53:09 cek Exp Locker: cek $ X * X * $Log: viewing.c,v $ X * Revision 4.0.1.1 91/09/29 15:53:09 cek X * patch1: Added support for window and crop commands. X * X * Revision 4.0 91/07/17 14:48:18 kolb X * Initial version. X * X */ X#include "rayshade.h" X#include "viewing.h" X#include "libcommon/sampling.h" X#include "options.h" X#include "defaults.h" X#include "picture.h" X#include "stats.h" X XRSCamera Camera; XRSScreen Screen; X Xvoid SampleScreen(), SampleScreenFiltered(); X Xvoid XRSViewing() X{ X Float magnitude; X X VecSub(Camera.lookp, Camera.pos, &Camera.dir); X Screen.firstray = Camera.dir; X X Camera.lookdist = VecNormalize(&Camera.dir); X if (VecNormCross(&Camera.dir, &Camera.up, &Screen.scrni) == 0.) X RLerror(RL_PANIC, X "The view and up directions are identical?\n"); X (void)VecNormCross(&Screen.scrni, &Camera.dir, &Screen.scrnj); X X /* X * Add stereo separation if desired. X */ X if (Options.stereo) { X if (Options.stereo == LEFT) X magnitude = -.5 * Options.eyesep; X else X magnitude = .5 * Options.eyesep; X Camera.pos.x += magnitude * Screen.scrni.x; X Camera.pos.y += magnitude * Screen.scrni.y; X Camera.pos.z += magnitude * Screen.scrni.z; X VecSub(Camera.lookp, Camera.pos, &Screen.firstray); X Camera.dir = Screen.firstray; X Camera.lookdist = VecNormalize(&Camera.dir); X (void)VecNormCross(&Camera.dir, &Camera.up, &Screen.scrni); X (void)VecNormCross(&Screen.scrni, &Camera.dir, &Screen.scrnj); X } X X magnitude = 2.*Camera.lookdist * tan(deg2rad(0.5*Camera.hfov)) / X Screen.xres; X X VecScale(magnitude, Screen.scrni, &Screen.scrnx); X magnitude = 2.*Camera.lookdist * tan(deg2rad(0.5*Camera.vfov)) / X Screen.yres; X#ifndef URT X /* X * If using "generic" file format, render top-to-bottom (yick). X */ X magnitude *= -1; X#endif X VecScale(magnitude, Screen.scrnj, &Screen.scrny); X X Screen.firstray.x -= 0.5*Screen.yres*Screen.scrny.x + X 0.5*Screen.xres*Screen.scrnx.x; X Screen.firstray.y -= 0.5*Screen.yres*Screen.scrny.y + X 0.5*Screen.xres*Screen.scrnx.y; X Screen.firstray.z -= 0.5*Screen.yres*Screen.scrny.z + X 0.5*Screen.xres*Screen.scrnx.z; X X if (Camera.focaldist == UNSET) X Camera.focaldist = Camera.lookdist; X} X X/* X * Adjust the initial ray to account for an aperture and a focal X * distance. The ray argument is assumed to be an initial ray, and X * always reset to the eye point. It is assumed to be unit length. X */ Xvoid Xfocus_blur_ray(ray) XRay *ray; X{ X Vector circle_point, aperture_inc; X extern void UnitCirclePoint(); X /* X * Find a point on a unit circle and scale by aperture size. X * This simulates rays passing thru different parts of the aperture. X * Treat the point as a vector and rotate it so the circle lies X * in the plane of the screen. Add the aperture increment to the X * starting position of the ray. Stretch the ray to be focaldist X * in length. Subtract the aperture increment from the end of the X * long ray. This insures that the ray heads toward a point at X * the specified focus distance, so that point will be in focus. X * Normalize the ray, and that's it. Really. X */ X UnitCirclePoint(&circle_point, ray->sample); X VecComb(Camera.aperture * circle_point.x, Screen.scrni, X Camera.aperture * circle_point.y, Screen.scrnj, X &aperture_inc); X VecAdd(aperture_inc, Camera.pos, &(ray->pos)); X VecScale(Camera.focaldist, ray->dir, &(ray->dir)); X VecSub(ray->dir, aperture_inc, &(ray->dir)); X (void)VecNormalize(&ray->dir); X} X Xvoid XViewingSetup() X{ X#define SWAP(a,b) (tmp = (a), (a) = (b), (b) = tmp) X X Float tmp; X int xwidth, ywidth; X X if (Options.stereo && Options.eyesep == UNSET) X RLerror(RL_PANIC, X "No eye separation specified for stereo rendering.\n"); X /* X * Because we want the user to be able to override the input file X * through the command line, we have to initialize some variables to X * bogus values so that when the file is being parsed, it is X * possible to tell if a given variable has been set on the X * command line. X * X * If such variables are not set to legal values on the command X * line or in the input file, we must do it here. X */ X if (Screen.xres == UNSET) X Screen.xres = XRESOLUTION; X if (Screen.yres == UNSET) X Screen.yres = YRESOLUTION; X X /* X * The window to be rendered is defined by applying X * the crop window to the sub window. The subwindow X * is defined using pixel numbers, and must be within X * [0, xres -1],[0, yres -1]. The default is the entire X * screen. The crop window is specified using normalized X * coordinates. X */ X X if (!Options.window_set) { X /* If no window set, set equal to entire screen. */ X Options.window[LOW][X] = Options.window[LOW][Y] = 0; X Options.window[HIGH][X] = Screen.xres -1; X Options.window[HIGH][Y] = Screen.yres -1; X } X X /* Truncate crop window to legal limits. */ X if (Options.crop[LOW][X] > Options.crop[HIGH][X]) X SWAP(Options.crop[LOW][X], Options.crop[HIGH][X]); X if (Options.crop[LOW][Y] > Options.crop[HIGH][Y]) X SWAP(Options.crop[LOW][Y], Options.crop[HIGH][Y]); X if (Options.crop[LOW][X] < 0.) Options.crop[LOW][X] = 0.; X if (Options.crop[LOW][Y] < 0.) Options.crop[LOW][Y] = 0.; X if (Options.crop[HIGH][X] > 1.) Options.crop[HIGH][X] = 1.; X if (Options.crop[HIGH][Y] > 1.) Options.crop[HIGH][Y] = 1.; X X xwidth = Options.window[HIGH][X] - Options.window[LOW][X]; X ywidth = Options.window[HIGH][Y] - Options.window[LOW][Y]; X X /* Compute x and y extents of window to be renered. */ X Screen.minx = (int)(Options.window[LOW][X] + X Options.crop[LOW][X] * xwidth); X Screen.maxx = (int)(Options.window[LOW][X] + X Options.crop[HIGH][X] * xwidth); X Screen.miny = (int)(Options.window[LOW][Y] + X Options.crop[LOW][Y] * ywidth); X Screen.maxy = (int)(Options.window[LOW][Y] + X Options.crop[HIGH][Y] * ywidth); X X#ifdef URT X /* X * If using the URT, we should use the RLE file header to X * determine cropped window size. Screen size X * (Screen.xres, Screen.yres) is determined from command X * line or input file, as usual. X * X * If the cropped window computed in PictureSetWindow() X * is not equal the cropped window computed above, X * a warning message is issued. X */ X if (Options.appending) { X /* X * Read image header to determine window size. X */ X PictureSetWindow(); X } X#endif X X Screen.xsize = Screen.maxx - Screen.minx + 1; X Screen.ysize = Screen.maxy - Screen.miny + 1; X X /* X * Sanity check. X */ X if (Screen.minx < 0 || Screen.miny < 0 || X Screen.maxx >= Screen.xres || Screen.maxy >= Screen.yres) X RLerror(RL_PANIC, "Invalid window specification.\n"); X X /* X * If not defined in the input file, calculate VFOV X * by hand. This assumes that pixels are square, which is X * probably a bad idea. ("aspect" option?) X */ X if (Camera.vfov == UNSET) X Camera.vfov = Camera.hfov * Screen.yres / Screen.xres; X} X Xvoid XSampleScreenFiltered(x, y, u, v, ray, color, sample) XFloat x, y; XRay *ray; XPixel *color; Xint sample, u, v; X{ X SampleScreen(x, y, ray, color, sample); X color->r *= Sampling.filter[u][v]; X color->g *= Sampling.filter[u][v]; X color->b *= Sampling.filter[u][v]; X color->alpha *= Sampling.filter[u][v]; X} X Xvoid XSampleScreen(x, y, ray, color, sample) XFloat x, y; /* Screen position to sample */ XRay *ray; /* ray, with origin and medium properly set */ XPixel *color; /* resulting color */ Xint sample; /* sample number */ X{ X Float dist; X HitList hitlist; X Color ctmp, fullintens; X extern void focus_blur_ray(), ShadeRay(); X X /* X * Calculate ray direction. X */ X Stats.EyeRays++; X ray->dir.x = Screen.firstray.x + x*Screen.scrnx.x + y*Screen.scrny.x; X ray->dir.y = Screen.firstray.y + x*Screen.scrnx.y + y*Screen.scrny.y; X ray->dir.z = Screen.firstray.z + x*Screen.scrnx.z + y*Screen.scrny.z; X X (void)VecNormalize(&ray->dir); X X ray->sample = sample; X X if (Camera.aperture > 0.0) { X /* X * If the aperture is open, adjust the initial ray X * to account for depth of field. X */ X focus_blur_ray(ray); X } X X /* X * Do the actual ray trace. X */ X fullintens.r = fullintens.g = fullintens.b = 1.; X dist = FAR_AWAY; X hitlist.nodes = 0; X (void)TraceRay(ray, &hitlist, EPSILON, &dist); X ShadeRay(&hitlist, ray, dist, &Screen.background, &ctmp, &fullintens); X color->r = ctmp.r; X color->g = ctmp.g; X color->b = ctmp.b; X if (hitlist.nodes != 0) { X color->alpha = 1.; X } else { X color->alpha = 0.; X } X} END_OF_FILE if test 8784 -ne `wc -c <'libshade/viewing.c'`; then echo shar: \"'libshade/viewing.c'\" unpacked with wrong size! fi # end of 'libshade/viewing.c' fi echo shar: End of archive 12 \(of 19\). cp /dev/null ark12isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 19 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0