#! /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/animate.tex' <<'END_OF_FILE' X\chapter{Animation} X X\Rayshade provides basic animation animation support by Xallowing time-varying Xtransformations to be associated with primitives and aggregate objects. XCommands are provided for controlling the amount of time between each Xframe, the speed of the camera shutter, and the total number of frames Xto be rendered. X XBy default, rayshade renders a single frame, with the shutter open for Xan instant (0 units of time, in fact). The shutter speed in no way Xchanges the light-gathering properties of the camera, i.e. frames Xrendered using Xa longer exposure will not appear brighter than those with a shorter Xexposure. The only change will be in the potential amount of movement Xthat the Xframe ``sees'' during the time that the shutter is open. X XEach ray cast by \rayshade samples a particular moment in time. XThe time value assigned to a ray Xranges from the starting time of the current frame to the starting Xtime plus the amount of time the shutter is open. When Xa ray encounters an object or texture that possesses an animated Xtransformation, the transformed Xentity is moved into whatever position is appropriate Xfor the ray's current time value before intersection, shading, or texturing Xcomputations are performed. X XThe starting time of the current frame is computed using the Xlength of each frame Xthe current frame number, and the starting time of the first frame. X X\begin{defkey}{shutter}{{\em t}} X Specifies that the shutter is open for t units of X time for each exposure. X\end{defkey} XA larger value of {\em t} will lead to more motion blur in the final Ximage. Note that {\em t} may be greater than the actual length Xof a frame. By default, {\em t} is zero, which prevents all motion blur. X X\begin{defkey}{framelength}{{\em frameinc}} X Specifies the time increment between frames. X\end{defkey} XThe default time between frames is 1 unit. X X\begin{defkey}{starttime}{{\em time}} X Specifies the starting time of the first frame. X\end{defkey} XBy default, {\em time} is zero. X XVariables may be defined thorugh the use of the {\tt define} keyword: X X\begin{defkey}{define}{{\em name value}} X Associate {\em name} with the given {\em value}. Value may X be a constant or a parenthesized expression. X\end{defkey} XThe variable {\em name} may thereafter be used in expressions in the Xinput file. X XAn animated transformation is one for which animated expressions have Xbeen used to define one or more of its parameters (e.g. the angle through Xwhich a rotation occurs). An animated expression is one that makes Xuse of a time-varying (``animated'') variable or function. X XThere are two supported animated variables. XThe first, {\tt time}, is equal to the current time. XWhen a ray encounters an animated Xtransformation defined using an expression containing {\tt time}, the ray Xsubstitutes its time value into the expression before evaluation. XUsing the {\tt time} variable in an animated expression is the most Xbasic way to create blur-causing motion. X XThe second animated variable, {\tt frame}, is equal to the current Xframe number. Unlike the {\tt time} variable, {\tt frame} takes on Xa single value for the duration of each frame. Thus, transforms Xanimated through the use of the {\tt frame} variable will not exhibit Xmotion blurring. X XAlso supported is the {\tt linear} function. This function uses X{\tt time} implicitly to interplate between two values. X X\begin{defkey}{linear}{{\tt (} {\em Stime, Sval, Etime, Eval} {\tt )}} X Linearly interpolate between {\em Sval} at time X {\em Stime} and {\em Eval} at time {\em Etime}. X If the current time is less than {\em Stime}, the function X returns {\em Sval}. If the current time is greater than X {\em Etime}, {\em Eval} is returned. X\end{defkey} X XThe following example shows the use of the {\tt time} variable to Xanimate a sphere by translating it downwards over five frames. XNote thet the {\tt shutter} keyword is used to set the shutter duration Xin order to induce motion blurring. X X\begin{verbatim} X frames 5 X shutter 1 X sphere 1 0 0 2 translate 0 0 (-time) X\end{verbatim} X XFurther examples of animation may be found in the Examples directory Xof the \rayshade distribution. END_OF_FILE if test 4149 -ne `wc -c <'Doc/Guide/animate.tex'`; then echo shar: \"'Doc/Guide/animate.tex'\" unpacked with wrong size! fi # end of 'Doc/Guide/animate.tex' fi if test -f 'etc/rsconvert/lex.l' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'etc/rsconvert/lex.l'\" else echo shar: Extracting \"'etc/rsconvert/lex.l'\" \(4148 characters\) sed "s/^X//" >'etc/rsconvert/lex.l' <<'END_OF_FILE' X/* lex.l */ 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/* $Id: lex.l,v 4.0 91/07/17 14:29:16 kolb Exp Locker: kolb $ */ X%{ X#include "config.h" X#include X#ifdef I_STRING X#include X#else X#include X#endif X#include "libcommon/common.h" X#include "y.tab.h" X%} Xalpha [a-zA-Z] Xspecial [\.\_-] Xdigit [0-9] Xexp [Ee][-+]?{digit}+ Xstring ({alpha}|"/")({alpha}|{digit}|{special}|"/")* X%p 3000 X%% X[\t\n] {WriteVerbatim(yytext);}; X" " {}; X^# {handlehash();} X"/*" {skipcomments();} Xadaptive {return(tADAPTIVE);} Xaperture {return(tAPERTURE);} Xbackground {return(tBACKGROUND);} Xblotch {return(tBLOTCH);} Xbox {return(tBOX);} Xbump {return(tBUMP);} Xchecker {return(tCHECKER);} Xcone {return(tCONE);} Xcontrast {return(tCONTRAST);} Xcutoff {return(tCUTOFF);} Xcylinder {return(tCYL);} Xdefend {return(tENDDEF);} Xdefine {return(tSTARTDEF);} Xdirectional {return(tDIRECTIONAL);} Xendfile {return(tENDFILE);} Xextended {return(tEXTENDED);} Xeyep {return(tEYEP);} Xfbm {return(tFBM);} Xfbmbump {return(tFBMBUMP);} Xfocaldist {return(tFOCALDIST);} Xfog {return(tFOG);} Xfov {return(tFOV);} Xgloss {return(tGLOSS);} Xgrid {return(tGRID);} Xheightfield {return(tHEIGHTFIELD);} Xjittered {return(tJITTERED);} Xlight {return(tLIGHT);} Xlist {return(tLIST);} Xlookp {return(tLOOKP);} Xmarble {return(tMARBLE);} Xmaxdepth {return(tMAXDEPTH);} Xmist {return(tMIST);} Xobject {return(tOBJECT);} Xoutfile {return(tOUTFILE);} Xplane {return(tPLANE);} Xpoint {return(tPOINT);} Xpoly {return(tPOLY);} Xresolution {return(tRESOLUTION);} Xrotate {return(tROTATE);} Xsamples {return(tSAMPLES);} Xscale {return(tSCALE);} Xscreen {return(tSCREEN);} Xsphere {return(tSPHERE);} Xsuperq {return(tSUPERQ);} Xsurface {return(tSURFACE);} Xtexture {return(tTEXTURE);} Xtransform {return(tTRANSFORM);} Xtranslate {return(tTRANSLATE);} Xtriangle {return(tTRIANGLE);} Xup {return(tUP);} Xwood {return(tWOOD);} X{string} {yylval.c = strsave(yytext); X return(tSTRING);} X[+-]?{digit}+ {yylval.i = atoi(yytext); X return(tINT);} X X[+-]?{digit}+"."{digit}*({exp})? | X[+-]?{digit}*"."{digit}+({exp})? | X[+-]?{digit}+{exp} {yylval.d = atof(yytext); return(tFLOAT);} X X. {return yytext[0];} X X%% Xyywrap() {return(1);} X/* X * Skip over comments. X */ Xskipcomments() X{ X char c; X X WriteVerbatim("/*"); X while (1) { X while ((c = input()) != '*') X WriteChar(c); X WriteChar(c); X if ((c = input()) == '/') { X WriteChar(c); X return; X } X unput(c); X } X} X/* X * Deal with ccp-produced lines of the form: X * # n "filename" X * and X * # n X * Where filename is the name of the file being processed, and n is X * the current line number in that file. X */ Xhandlehash() X{ X char buf[BUFSIZ]; X int i; X extern int yylineno; X extern char yyfilename[]; X X /* X * Read the entire line into buf. X */ X for (i = 0; (buf[i] = input()) != '\n'; i++) X ; X unput(buf[i]); /* To make sure consecutive # lines work. */ X buf[i] = (char)NULL; /* Replace newline with NULL. */ X X /* X * Check to see if it's #include or X * #define. X * If so just spit out the line. X */ X if (strncmp("include", buf, 7) == 0 || strncmp("define", buf, 6) == 0) { X WriteVerbatim("#"); X WriteVerbatim(buf); X return; X } X /* X * Complain if the line was not of the form #n "filename" X */ X if ((i = sscanf(buf, "%d \"%[^\"]s\"", &yylineno, yyfilename)) == 0) { X yyerror("Unknown '#' control."); X exit(1); X } X if (i == 1) { X#ifdef SYSV X if (strchr(buf, '"') != (char *)0) { X#else X if (index(buf, '"') != (char *)0) { X#endif X /* X * Filename was "", which means stdin. X */ X strcpy(yyfilename, "stdin"); X } X } X} END_OF_FILE if test 4148 -ne `wc -c <'etc/rsconvert/lex.l'`; then echo shar: \"'etc/rsconvert/lex.l'\" unpacked with wrong size! fi # end of 'etc/rsconvert/lex.l' fi if test -f 'libray/libobj/cylinder.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libobj/cylinder.c'\" else echo shar: Extracting \"'libray/libobj/cylinder.c'\" \(4773 characters\) sed "s/^X//" >'libray/libobj/cylinder.c' <<'END_OF_FILE' X/* X * cylinder.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: cylinder.c,v 4.0 91/07/17 14:37:12 kolb Exp Locker: kolb $ X * X * $Log: cylinder.c,v $ X * Revision 4.0 91/07/17 14:37:12 kolb X * Initial version. X * X */ X#include "geom.h" X#include "cylinder.h" X Xstatic Methods *iCylinderMethods = NULL; Xstatic char cylName[] = "cylinder"; X Xunsigned long CylTests, CylHits; X XCylinder * XCylinderCreate(r, bot, top) XFloat r; XVector *bot, *top; X{ X Cylinder *cyl; X Float len; X Vector axis; X X if (r <= 0.) { X RLerror(RL_WARN, "Invalid cylinder radius.\n"); X return (Cylinder*)NULL; X } X X VecSub(*top, *bot, &axis); X X len = VecNormalize(&axis); X X if (len < EPSILON) { X RLerror(RL_WARN, "Degenerate cylinder.\n"); X return (Cylinder *)NULL; X } X X cyl = (Cylinder *)share_malloc(sizeof(Cylinder)); X CoordSysTransform(bot, &axis, r, len, &cyl->trans); X return cyl; X} X XMethods * XCylinderMethods() X{ X if (iCylinderMethods == (Methods *)NULL) { X iCylinderMethods = MethodsCreate(); X iCylinderMethods->name = CylinderName; X iCylinderMethods->create = (GeomCreateFunc *)CylinderCreate; X iCylinderMethods->methods = CylinderMethods; X iCylinderMethods->intersect = CylinderIntersect; X iCylinderMethods->normal = CylinderNormal; X iCylinderMethods->uv = CylinderUV; X iCylinderMethods->bounds = CylinderBounds; X iCylinderMethods->stats = CylinderStats; X iCylinderMethods->checkbounds = TRUE; X iCylinderMethods->closed = FALSE; X } X return iCylinderMethods; X} X X/* X * Ray-cylinder intersection test. X */ Xint XCylinderIntersect(cyl, ray, mindist, maxdist) XCylinder *cyl; XRay *ray; XFloat mindist, *maxdist; X{ X Float t1, t2, a, b, c, zpos1, zpos2, disc; X Float distfact; X Ray newray; X Vector nray, npos; X Float nmin; X X CylTests++; X X /* X * Transform ray into canonical cylinder space. X */ X newray = *ray; X distfact = RayTransform(&newray, &cyl->trans.itrans); X nray = newray.dir; X npos = newray.pos; X nmin = mindist * distfact; X X a = nray.x * nray.x + nray.y * nray.y; X if (a < EPSILON*EPSILON) X /* |nray.z| == 1. */ X return FALSE; X X b = nray.x * npos.x + nray.y * npos.y; X c = npos.x*npos.x + npos.y*npos.y - 1; X disc = b*b - a*c; X if(disc < 0.) X return FALSE; X disc = sqrt(disc); X t1 = (-b + disc) / a; X t2 = (-b - disc) / a; X if (t1 < nmin && t2 < nmin) X return FALSE; X zpos1 = npos.z + t1 * nray.z; X zpos2 = npos.z + t2 * nray.z; X X if (t1 < nmin || zpos1 < 0. || zpos1 > 1.) { X if (t2 < nmin || zpos2 < 0. || zpos2 > 1.) X return FALSE; X else X t1 = t2 / distfact; X X } else { X if (t2 < nmin || zpos2 < 0. || zpos2 > 1.) X t1 /= distfact; X else { X t1 = min(t1, t2) / distfact; X } X } X X if (t1 < *maxdist) { X *maxdist = t1; X CylHits++; X return TRUE; X } X return FALSE; X} X Xint XCylinderNormal(cyl, pos, nrm, gnrm) XCylinder *cyl; XVector *pos, *nrm, *gnrm; X{ X /* X * Transform position into cylinder space. X */ X *nrm = *pos; X PointTransform(nrm, &cyl->trans.itrans); X /* X * The normal is equal to the point of intersection in cylinder X * space, but with Z = 0.; X */ X nrm->z = 0.; X X /* X * Tranform normal back to world space. X */ X NormalTransform(nrm, &cyl->trans.itrans); X *gnrm = *nrm; X return FALSE; X} X Xvoid XCylinderUV(cyl, pos, norm, uv, dpdu, dpdv) XCylinder *cyl; XVector *pos, *norm, *dpdu, *dpdv; XVec2d *uv; X{ X Vector npos; X X npos = *pos; X PointTransform(&npos, &cyl->trans.itrans); X X uv->v = npos.z; X /* X * Due to roundoff error, |npos.x| may be > 1. X */ X if (npos.x > 1.) X uv->u = 0.; X else if (npos.x < -1.) X uv->u = 0.5; X else X uv->u = acos(npos.x) / TWOPI; X if (npos.y < 0.) X uv->u = 1. - uv->u; X X if (dpdu) { X dpdv->x = dpdv->y = 0.; X dpdv->z = 1.; X dpdu->x = -npos.y; X dpdu->y = npos.x; X dpdu->z = 0.; X VecTransform(dpdu, &cyl->trans.trans); X VecTransform(dpdv, &cyl->trans.trans); X (void)VecNormalize(dpdu); X (void)VecNormalize(dpdv); X } X} X Xvoid XCylinderBounds(cyl, bounds) XCylinder *cyl; XFloat bounds[2][3]; X{ X bounds[LOW][X] = bounds[LOW][Y] = -1; X bounds[HIGH][X] = bounds[HIGH][Y] = 1; X bounds[LOW][Z] = 0.; X bounds[HIGH][Z] = 1; X /* X * Transform bounding box to world space. X */ X BoundsTransform(&cyl->trans.trans, bounds); X} X Xchar * XCylinderName() X{ X return cylName; X} X Xvoid XCylinderStats(tests, hits) Xunsigned long *tests, *hits; X{ X *tests = CylTests; X *hits = CylHits; X} X Xvoid XCylinderMethodRegister(meth) XUserMethodType meth; X{ X if (iCylinderMethods) X iCylinderMethods->user = meth; X} END_OF_FILE if test 4773 -ne `wc -c <'libray/libobj/cylinder.c'`; then echo shar: \"'libray/libobj/cylinder.c'\" unpacked with wrong size! fi # end of 'libray/libobj/cylinder.c' fi if test -f 'libray/libobj/disc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libobj/disc.c'\" else echo shar: Extracting \"'libray/libobj/disc.c'\" \(4405 characters\) sed "s/^X//" >'libray/libobj/disc.c' <<'END_OF_FILE' X/* X * disc.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: disc.c,v 4.0 91/07/17 14:37:23 kolb Exp Locker: kolb $ X * X * $Log: disc.c,v $ X * Revision 4.0 91/07/17 14:37:23 kolb X * Initial version. X * X */ X#include "geom.h" X#include "disc.h" X Xstatic Methods *iDiscMethods = NULL; Xstatic char discName[] = "disc"; X Xunsigned long DiscTests, DiscHits; X XDisc * XDiscCreate(r, pos, norm) XFloat r; XVector *pos, *norm; X{ X Disc *disc; /* Pointer to new disc. */ X X if (r < EPSILON) { X RLerror(RL_WARN, "Degenerate disc.\n"); X /* X * Don't create this primitive. X */ X return (Disc *)NULL; X } X X if (VecNormalize(norm) == 0.) { X RLerror(RL_WARN, "Degenerate disc normal.\n"); X return (Disc *)NULL; X } X /* X * Allocate new Disc. X */ X disc = (Disc *)share_malloc(sizeof(Disc)); X /* X * Initialize new disc. X * We store the square of the radius to save us a sqrt(). X */ X disc->radius = r*r; X disc->pos = *pos; X disc->norm = *norm; X /* X * Compute plane constant. X */ X disc->d = dotp(pos, norm); X /* X * Allocate new primitive X */ X return disc; X} X XMethods * XDiscMethods() X{ X if (iDiscMethods == (Methods *)NULL) { X iDiscMethods = MethodsCreate(); X iDiscMethods->name = DiscName; X iDiscMethods->create = (GeomCreateFunc *)DiscCreate; X iDiscMethods->methods = DiscMethods; X iDiscMethods->intersect = DiscIntersect; X iDiscMethods->normal = DiscNormal; X iDiscMethods->uv = DiscUV; X iDiscMethods->bounds = DiscBounds; X iDiscMethods->stats = DiscStats; X iDiscMethods->checkbounds = FALSE; X iDiscMethods->closed = FALSE; X } X return iDiscMethods; X} X Xint XDiscIntersect(disc, ray, mindist, maxdist) XDisc *disc; XRay *ray; XFloat mindist, *maxdist; X{ X Vector hit; X Float denom, dist; X X DiscTests++; X X denom = dotp(&disc->norm, &ray->dir); X if (fabs(denom) < EPSILON) X /* Edge-on intersection */ X return FALSE; X X dist = (disc->d - dotp(&disc->norm, &ray->pos)) / denom; X if (dist < mindist || dist > *maxdist) X /* Too close or too far */ X return FALSE; X /* X * Find difference between point of intersection and center of disc. X */ X VecAddScaled(ray->pos, dist, ray->dir, &hit); X VecSub(hit, disc->pos, &hit); X /* X * If hit point is <= disc->radius from center, we've hit the disc. X */ X if (dotp(&hit, &hit) <= disc->radius) { X *maxdist = dist; X DiscHits++; X return TRUE; X } X return FALSE; X} X Xint XDiscNormal(disc, pos, nrm, gnrm) XDisc *disc; XVector *pos, *nrm, *gnrm; X{ X *gnrm = *nrm = disc->norm; X return FALSE; X} X Xvoid XDiscUV(disc, pos, norm, uv, dpdu, dpdv) XDisc *disc; XVector *pos, *norm, *dpdu, *dpdv; XVec2d *uv; X{ X Float dist, val; X X dist = (pos->x - disc->pos.x) * (pos->x - disc->pos.x) + X (pos->y - disc->pos.y) * (pos->y - disc->pos.y) + X (pos->z - disc->pos.z) * (pos->z - disc->pos.z); X X if (dist < EPSILON) { X uv->u = uv->v = 0.; X return; X } X X dist = sqrt(dist); X uv->v = dist / sqrt(disc->radius); /* should store r and r*r */ X X val = pos->x / dist; X X if (fabs(val) > 1.) X uv->u = 0.5; X else { X uv->u = acos(val) / TWOPI; X if (pos->y < 0.) X uv->u = 1. - uv->u; X } X X if (dpdu) { X VecSub(*pos, disc->pos, dpdv); X /* dpdu = dpdv X norm */ X VecCross(dpdv, norm, dpdu); X } X} X Xvoid XDiscBounds(disc, bounds) XDisc *disc; XFloat bounds[2][3]; X{ X Float extent, rad; X X rad = sqrt(disc->radius); X /* X * Project disc along each of X, Y and Z axes. X */ X extent = rad * sqrt(1. - disc->norm.x * disc->norm.x); X bounds[LOW][X] = disc->pos.x - extent; X bounds[HIGH][X] = disc->pos.x + extent; X extent = rad * sqrt(1. - disc->norm.y * disc->norm.y); X bounds[LOW][Y] = disc->pos.y - extent; X bounds[HIGH][Y] = disc->pos.y + extent; X extent = rad * sqrt(1. - disc->norm.z * disc->norm.z); X bounds[LOW][Z] = disc->pos.z - extent; X bounds[HIGH][Z] = disc->pos.z + extent; X} X Xchar * XDiscName() X{ X return discName; X} X Xvoid XDiscStats(tests, hits) Xunsigned long *tests, *hits; X{ X *tests = DiscTests; X *hits = DiscHits; X} X Xvoid XDiscMethodRegister(meth) XUserMethodType meth; X{ X if (iDiscMethods) X iDiscMethods->user = meth; X} END_OF_FILE if test 4405 -ne `wc -c <'libray/libobj/disc.c'`; then echo shar: \"'libray/libobj/disc.c'\" unpacked with wrong size! fi # end of 'libray/libobj/disc.c' fi if test -f 'libray/libobj/roots.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libobj/roots.c'\" else echo shar: Extracting \"'libray/libobj/roots.c'\" \(4798 characters\) sed "s/^X//" >'libray/libobj/roots.c' <<'END_OF_FILE' X/* X * Roots3And4.c X * X * Utility functions to find cubic and quartic roots, X * coefficients are passed like this: X * X * c[0] + c[1]*x + c[2]*x^2 + c[3]*x^3 + c[4]*x^4 = 0 X * X * The functions return the number of non-complex roots and X * put the values into the s array. X * X * Author: Jochen Schwarze (schwarze@isa.de) X * X * Jan 26, 1990 Version for Graphics Gems X * Oct 11, 1990 Fixed sign problem for negative q's in SolveQuartic X * (reported by Mark Podlipec), X * Old-style function definitions, X * IsZero() as a macro X * Nov 23, 1990 Some systems do not declare acos() and cbrt() in X * , though the functions exist in the library. X * If large coefficients are used, EQN_EPS should be X * reduced considerably (e.g. to 1E-30), results will be X * correct but multiple roots might be reported more X * than once. X */ X X#include "libcommon/common.h" X Xextern double sqrt(), cbrt(), cos(), acos(); X X/* epsilon surrounding for near zero values */ X X/* X * In case M_PI isn't defined in math.h X */ X#ifndef M_PI X#define M_PI PI X#endif X X#define EQN_EPS 1e-9 X#define IsZero(x) ((x) > -EQN_EPS && (x) < EQN_EPS) X X#ifndef CBRT X#define cbrt(x) ((x) > 0.0 ? pow((double)(x), 1.0/3.0) : \ X ((x) < 0.0 ? -pow((double)-(x), 1.0/3.0) : 0.0)) X#endif X X Xint SolveQuadric(c, s) X double c[ 3 ]; X double s[ 2 ]; X{ X double p, q, D; X X /* normal form: x^2 + px + q = 0 */ X X p = c[ 1 ] / (2 * c[ 2 ]); X q = c[ 0 ] / c[ 2 ]; X X D = p * p - q; X X if (IsZero(D)) X { X s[ 0 ] = - p; X return 1; X } X else if (D > 0) X { X double sqrt_D = sqrt(D); X X s[ 0 ] = sqrt_D - p; X s[ 1 ] = - sqrt_D - p; X return 2; X } X else /* if (D < 0) */ X return 0; X} X X Xint SolveCubic(c, s) X double c[ 4 ]; X double s[ 3 ]; X{ X int i, num; X double sub; X double A, B, C; X double sq_A, p, q; X double cb_p, D; X X /* normal form: x^3 + Ax^2 + Bx + C = 0 */ X X A = c[ 2 ] / c[ 3 ]; X B = c[ 1 ] / c[ 3 ]; X C = c[ 0 ] / c[ 3 ]; X X /* substitute x = y - A/3 to eliminate quadric term: X x^3 +px + q = 0 */ X X sq_A = A * A; X p = 1.0/3 * (- 1.0/3 * sq_A + B); X q = 1.0/2 * (2.0/27 * A * sq_A - 1.0/3 * A * B + C); X X /* use Cardano's formula */ X X cb_p = p * p * p; X D = q * q + cb_p; X X if (IsZero(D)) X { X if (IsZero(q)) /* one triple solution */ X { X s[ 0 ] = 0; X num = 1; X } X else /* one single and one double solution */ X { X double u = cbrt(-q); X s[ 0 ] = 2 * u; X s[ 1 ] = - u; X num = 2; X } X } X else if (D < 0) /* Casus irreducibilis: three real solutions */ X { X double phi = 1.0/3 * acos(-q / sqrt(-cb_p)); X double t = 2 * sqrt(-p); X X s[ 0 ] = t * cos(phi); X s[ 1 ] = - t * cos(phi + M_PI / 3); X s[ 2 ] = - t * cos(phi - M_PI / 3); X num = 3; X } X else /* one real solution */ X { X double sqrt_D = sqrt(D); X double u = cbrt(sqrt_D - q); X double v = - cbrt(sqrt_D + q); X X s[ 0 ] = u + v; X num = 1; X } X X /* resubstitute */ X X sub = 1.0/3 * A; X X for (i = 0; i < num; ++i) X s[ i ] -= sub; X X return num; X} X X Xint SolveQuartic(c, s) X double c[ 5 ]; X double s[ 4 ]; X{ X double coeffs[ 4 ]; X double z, u, v, sub; X double A, B, C, D; X double sq_A, p, q, r; X int i, num; X X /* normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 */ X X A = c[ 3 ] / c[ 4 ]; X B = c[ 2 ] / c[ 4 ]; X C = c[ 1 ] / c[ 4 ]; X D = c[ 0 ] / c[ 4 ]; X X /* substitute x = y - A/4 to eliminate cubic term: X x^4 + px^2 + qx + r = 0 */ X X sq_A = A * A; X p = - 3.0/8 * sq_A + B; X q = 1.0/8 * sq_A * A - 1.0/2 * A * B + C; X r = - 3.0/256*sq_A*sq_A + 1.0/16*sq_A*B - 1.0/4*A*C + D; X X if (IsZero(r)) X { X /* no absolute term: y(y^3 + py + q) = 0 */ X X coeffs[ 0 ] = q; X coeffs[ 1 ] = p; X coeffs[ 2 ] = 0; X coeffs[ 3 ] = 1; X X num = SolveCubic(coeffs, s); X X s[ num++ ] = 0; X } X else X { X /* solve the resolvent cubic ... */ X X coeffs[ 0 ] = 1.0/2 * r * p - 1.0/8 * q * q; X coeffs[ 1 ] = - r; X coeffs[ 2 ] = - 1.0/2 * p; X coeffs[ 3 ] = 1; X X (void) SolveCubic(coeffs, s); X X /* ... and take the one real solution ... */ X X z = s[ 0 ]; X X /* ... to build two quadric equations */ X X u = z * z - r; X v = 2 * z - p; X X if (IsZero(u)) X u = 0; X else if (u > 0) X u = sqrt(u); X else X return 0; X X if (IsZero(v)) X v = 0; X else if (v > 0) X v = sqrt(v); X else X return 0; X X coeffs[ 0 ] = z - u; X coeffs[ 1 ] = q < 0 ? -v : v; X coeffs[ 2 ] = 1; X X num = SolveQuadric(coeffs, s); X X coeffs[ 0 ]= z + u; X coeffs[ 1 ] = q < 0 ? v : -v; X coeffs[ 2 ] = 1; X X num += SolveQuadric(coeffs, s + num); X } X X /* resubstitute */ X X sub = 1.0/4 * A; X X for (i = 0; i < num; ++i) X s[ i ] -= sub; X X return num; X} X END_OF_FILE if test 4798 -ne `wc -c <'libray/libobj/roots.c'`; then echo shar: \"'libray/libobj/roots.c'\" unpacked with wrong size! fi # end of 'libray/libobj/roots.c' fi if test -f 'libray/libobj/sphere.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libobj/sphere.c'\" else echo shar: Extracting \"'libray/libobj/sphere.c'\" \(4775 characters\) sed "s/^X//" >'libray/libobj/sphere.c' <<'END_OF_FILE' X/* X * sphere.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: sphere.c,v 4.0 91/07/17 14:39:17 kolb Exp Locker: kolb $ X * X * $Log: sphere.c,v $ X * Revision 4.0 91/07/17 14:39:17 kolb X * Initial version. X * X */ X#include "geom.h" X#include "sphere.h" X Xstatic Methods *iSphereMethods = NULL; Xstatic char sphereName[] = "sphere"; X Xunsigned long SphTests, SphHits; X X/* X * Create & return reference to a sphere. X */ XSphere * XSphereCreate(r, pos) XFloat r; XVector *pos; X{ X Sphere *sphere; X X if (r < EPSILON) { X RLerror(RL_WARN, "Degenerate sphere.\n"); X return (Sphere *)NULL; X } X X sphere = (Sphere *)share_malloc(sizeof(Sphere)); X /* X * sphere->rsq holds the square of the radius. X */ X sphere->r = r; X sphere->rsq = r*r; X sphere->x = pos->x; X sphere->y = pos->y; X sphere->z = pos->z; X X return sphere; X} X XMethods * XSphereMethods() X{ X if (iSphereMethods == (Methods *)NULL) { X iSphereMethods = MethodsCreate(); X iSphereMethods->create = (GeomCreateFunc *)SphereCreate; X iSphereMethods->methods = SphereMethods; X iSphereMethods->name = SphereName; X iSphereMethods->intersect = SphereIntersect; X iSphereMethods->normal = SphereNormal; X iSphereMethods->uv = SphereUV; X iSphereMethods->enter = SphereEnter; X iSphereMethods->bounds = SphereBounds; X iSphereMethods->stats = SphereStats; X iSphereMethods->checkbounds = TRUE; X iSphereMethods->closed = TRUE; X } X return iSphereMethods; X} X X/* X * Ray/sphere intersection test. X */ Xint XSphereIntersect(sph, ray, mindist, maxdist) XSphere *sph; XRay *ray; XFloat mindist, *maxdist; X{ X Float xadj, yadj, zadj; X Float b, t, s; X X SphTests++; X /* X * Translate ray origin to object space and negate everything. X * (Thus, we translate the sphere into ray space, which saves X * us a couple of negations below.) X */ X xadj = sph->x - ray->pos.x; X yadj = sph->y - ray->pos.y; X zadj = sph->z - ray->pos.z; X X /* X * Solve quadratic equation. X */ X b = xadj * ray->dir.x + yadj * ray->dir.y + zadj * ray->dir.z; X t = b * b - xadj * xadj - yadj * yadj - zadj * zadj + sph->rsq; X if (t < 0.) X return FALSE; X t = (Float)sqrt((double)t); X s = b - t; X if (s > mindist) { X if (s < *maxdist) { X *maxdist = s; X SphHits++; X return TRUE; X } X return FALSE; X } X s = b + t; X if (s > mindist && s < *maxdist) { X *maxdist = s; X SphHits++; X return TRUE; X } X return FALSE; X} X X/* X * Compute normal to sphere at pos X */ Xint XSphereNormal(sphere, pos, nrm, gnrm) XSphere *sphere; XVector *pos, *nrm, *gnrm; X{ X nrm->x = (pos->x - sphere->x) / sphere->r; X nrm->y = (pos->y - sphere->y) / sphere->r; X nrm->z = (pos->z - sphere->z) / sphere->r; X *gnrm = *nrm; X return FALSE; X} X X/* X * Determine if ray enters (TRUE) or leaves (FALSE) sphere at pos X */ Xint XSphereEnter(sphere, ray, mind, hitd) XSphere *sphere; XRay *ray; XFloat mind, hitd; X{ X Vector pos; X X VecAddScaled(ray->pos, mind, ray->dir, &pos); X pos.x -= sphere->x; X pos.y -= sphere->y; X pos.z -= sphere->z; X X return dotp(&pos, &pos) > sphere->rsq; X} X X/*ARGSUSED*/ Xvoid XSphereUV(sphere, pos, norm, uv, dpdu, dpdv) XSphere *sphere; XVector *pos, *norm, *dpdu, *dpdv; XVec2d *uv; X{ X Float phi, theta; X Vector realnorm; X X realnorm.x = pos->x - sphere->x; X realnorm.y = pos->y - sphere->y; X realnorm.z = pos->z - sphere->z; X VecNormalize( &realnorm ); X if (realnorm.z > 1.) /* roundoff */ X phi = PI; X else if (realnorm.z < -1.) X phi = 0; X else X phi = acos(-realnorm.z); X X uv->v = phi / PI; X X if (fabs(uv->v) < EPSILON || equal(uv->v, 1.)) X uv->u = 0.; X else { X theta = realnorm.x / sin(phi); X if (theta > 1.) X theta = 0.; X else if (theta < -1.) X theta = 0.5; X else X theta = acos(theta) / TWOPI; X X if (realnorm.y > 0) X uv->u = theta; X else X uv->u = 1 - theta; X } X if (dpdu != (Vector *)0) { X dpdu->x = -realnorm.y; X dpdu->y = realnorm.x; X dpdu->z = 0.; X (void)VecNormalize(dpdu); X (void)VecNormCross(&realnorm, dpdu, dpdv); X } X} X Xvoid XSphereBounds(s, bounds) XSphere *s; XFloat bounds[2][3]; X{ X bounds[LOW][X] = s->x - s->r; X bounds[HIGH][X] = s->x + s->r; X bounds[LOW][Y] = s->y - s->r; X bounds[HIGH][Y] = s->y + s->r; X bounds[LOW][Z] = s->z - s->r; X bounds[HIGH][Z] = s->z + s->r; X} X Xchar * XSphereName() X{ X return sphereName; X} X Xvoid XSphereStats(tests, hits) Xunsigned long *tests, *hits; X{ X *tests = SphTests; X *hits = SphHits; X} X Xvoid XSphereMethodRegister(meth) XUserMethodType meth; X{ X if (iSphereMethods) X iSphereMethods->user = meth; X} END_OF_FILE if test 4775 -ne `wc -c <'libray/libobj/sphere.c'`; then echo shar: \"'libray/libobj/sphere.c'\" unpacked with wrong size! fi # end of 'libray/libobj/sphere.c' fi if test -f 'libray/libsurf/surfshade.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libsurf/surfshade.c'\" else echo shar: Extracting \"'libray/libsurf/surfshade.c'\" \(4829 characters\) sed "s/^X//" >'libray/libsurf/surfshade.c' <<'END_OF_FILE' X/* X * surfshade.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: surfshade.c,v 4.0 91/07/17 14:41:15 kolb Exp Locker: kolb $ X * X * $Log: surfshade.c,v $ X * Revision 4.0 91/07/17 14:41:15 kolb X * Initial version. X * X */ X#include "libobj/geom.h" X#include "surface.h" X X/* X * Compute surface properties from given hitlist X * Returns TRUE if ray is entering object, FALSE otherwise. X */ Xint XComputeSurfProps(hitlist, ray, pos, norm, gnorm, surf, smooth) XHitList *hitlist; /* Hit information (path through DAG) */ XRay *ray; /* Ray in world space */ XVector *pos; /* Intersection point */ XVector *norm, *gnorm; /* shading normal, geometric normal (return values) */ XSurface *surf; /* Copy of surface to use, texture-modified */ Xint *smooth; X{ X HitNode *hp; X int i; X Ray rtmp; X Geom *prim, *obj; X Float k, kp; X int texturing, transforming, entering; X Trans prim2model, world2model; X X hp = hitlist->data; X prim = hp->obj; X X /* X * Compute point of intersection in "primitive space". X */ X VecAddScaled(hp->ray.pos, hp->dist, hp->ray.dir, pos); X X /* X * Find normal to primitive at point of intersection. X */ X *smooth = PrimNormal(prim, pos, norm, gnorm); X X texturing = transforming = FALSE; X X /* X * Walk down hit list, constructing world<-->primitive transformation X * and determining if we need to perform texture mapping. X * The last node is the World node, which cannot be textured or X * transformed, so we skip it. X */ X for (i = 0, hp = hitlist->data; i < hitlist->nodes -1; hp++, i++) { X obj = hp->obj; X if (hp->dotrans) { X /* X * Here we're actually computing prim2world. X * When finished, we invert it. X */ X if (transforming) { X TransCompose(&hp->trans, &world2model, X &world2model); X } else { X TransCopy(&hp->trans, &world2model); X } X transforming = TRUE; X } X if (obj->texture) X texturing = TRUE; X } X X /* X * Determine if we're entering or exiting the surface, X * flipping surface normals if necessary. X */ X k = dotp(&hitlist->data[0].ray.dir, norm); X if (*smooth) { X /* X * If gnorm and shading norm differ and X * their dot products with the ray have X * different signs, use the geometric normal X * instead, ala Snyder & Barr's paper. X */ X kp = dotp(&hitlist->data[0].ray.dir, gnorm); X if (k <= 0. && kp > 0. || k >= 0. && kp < 0.) X k = kp; X } X X if (k > 0.) { X /* flip normals */ X VecScale(-1., *gnorm, gnorm); X VecScale(-1., *norm, norm); X /* X * Normal indicates that we're exiting. X * Only set entering to TRUE if csg has indicated X * that the ray is, indeed, entering. X */ X entering = (hitlist->data[0].enter == ENTERING); X } else { X /* X * Normal indicates that we're entering. X * Set entering flag as such unless csg has X * told us that we're exiting. X */ X entering = !(hitlist->data[0].enter == EXITING); X } X X /* X * If there are no transformations, then world2model is identity. X */ X if (!transforming) X TransInit(&world2model); X /* X * If we're not performing texturing, we simply need to compute X * the normal and point of intersection to world space. X */ X if (!texturing) { X /* X * At this point 'world2model' is really 'prim2world'. X */ X if (transforming) { X NormalTransform(norm, &world2model.itrans); X NormalTransform(gnorm, &world2model.itrans); X VecAddScaled(ray->pos, X hitlist->data[hitlist->nodes -1].dist, X ray->dir, pos); X } X return entering; X } X /* X * world2model currently transforms from primitive to world space. X * Invert it to get transformation from world to primitive space. X */ X TransInvert(&world2model, &world2model); X TransInit(&prim2model); X rtmp = hitlist->data[0].ray; X /* X * Walk down hitlist. X */ X for (hp = hitlist->data, i = 0; i < hitlist->nodes -1; i++, hp++) { X obj = hp->obj; X if (hp->dotrans) { X NormalTransform(norm, &hp->trans.itrans); X if (texturing) { X /* X * Compose prim<-->model and world<-->model X * with current transformation. X */ X TransCompose(&hp->trans, &prim2model, X &prim2model); X TransCompose(&hp->trans, &world2model, X &world2model); X /* X * Transform point and ray to model space. X */ X PointTransform(pos, &hp->trans.trans); X (void)RayTransform(&rtmp, &hp->trans.trans); X } X } X /* X * Apply textures X */ X if (obj->texture) X TextApply(obj->texture, prim, &rtmp, pos, norm, X gnorm, surf, &prim2model, &world2model); X } X return entering; X} END_OF_FILE if test 4829 -ne `wc -c <'libray/libsurf/surfshade.c'`; then echo shar: \"'libray/libsurf/surfshade.c'\" unpacked with wrong size! fi # end of 'libray/libsurf/surfshade.c' fi if test -f 'libray/libtext/texture.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libtext/texture.c'\" else echo shar: Extracting \"'libray/libtext/texture.c'\" \(4973 characters\) sed "s/^X//" >'libray/libtext/texture.c' <<'END_OF_FILE' X/* X * texture.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: texture.c,v 4.0 91/07/17 14:44:11 kolb Exp Locker: kolb $ X * X * $Log: texture.c,v $ X * Revision 4.0 91/07/17 14:44:11 kolb X * Initial version. X * X */ X#include "texture.h" X X/* X * Transformation structures used to map from texture space to X * model/primitive/world space. X */ XTrans prim2model, model2text, prim2text, world2text; X X#define ApplyMapping(m,o,p,n,c,u,v) (*m->method)(m, o, p, n, c, u, v) X XTexture * XTextCreate(data, meth) XTextRef data; Xvoid (*meth)(); X{ X Texture *res; X X res = (Texture *)share_calloc(1, sizeof(Texture)); X res->data = data; X res->method = meth; X res->trans = (Trans *)NULL; X res->next = (Texture *)NULL; X res->animtrans = FALSE; X return res; X} X X/* X * Apply appropriate textures to a surface. X */ Xvoid XTextApply(tlist, prim, ray, pos, norm, gnorm, surf, p2model, world2model) XTexture *tlist; /* Textures */ XGeom *prim; XRay *ray; XVector *pos, *norm, *gnorm; /* pos, shading norm, geo. norm */ XSurface *surf; XTrans *p2model, *world2model; X{ X Vector ptmp; X Texture *ttmp; X X prim2model = *p2model; X /* X * Walk down texture list, applying each in turn. X */ X for (ttmp = tlist; ttmp; ttmp = ttmp->next) { X /* X * Make copies of pos & ray to pass to the texturing function. X */ X ptmp = *pos; X if (ttmp->trans) { X /* X * 'take' the inverse of ttmp->trans, since X * transforming a texture means applying the X * inverse of the transformation X * to the point of intersection, etc. X */ X if (ttmp->animtrans) { X /* X * Resolve animated associations. X * We currently do not store a time X * for the texture, so we can't know if X * we're already resolved for the current X * ray->time. X */ X TransResolveAssoc(ttmp->trans); X TransComposeList(ttmp->trans, &model2text); X TransInvert(&model2text, &model2text); X } else X TransInvert(ttmp->trans, &model2text); X /* X * We compose ttmp->trans, which maps from model to X * texture space, with prim2model and world2model X * to get prim2text and world2text. X */ X TransCompose(&model2text, &prim2model, &prim2text); X TransCompose(&model2text, world2model, &world2text); X /* X * Transform intersection point to texture space. X * Ray and normal are passed in model space. X */ X ModelPointToText(&ptmp); X } else { X /* X * By default, texture and model space are identical. X */ X TransInit(&model2text); X TransCopy(&prim2model, &prim2text); X TransCopy(world2model, &world2text); X } X X /* X * Call texture function. X */ X (*ttmp->method) (ttmp->data,prim,ray,&ptmp,norm,gnorm,surf); X } X} X X/* X * Compute UV at 'pos' on given primitive. X */ XTextToUV(mapping, prim, pos, norm, u, v, dpdu, dpdv) XMapping *mapping; XGeom *prim; XVector *pos, *norm, *dpdu, *dpdv; XFloat *u, *v; X{ X Vec2d uv; X Vector ptmp; X RSMatrix t; X X ptmp = *pos; X X if (mapping->flags & PRIMSPACE) { X /* X * Convert point and normal to primitive space. X */ X TextPointToPrim(&ptmp); X } else { X /* X * Convert point and normal to object space. X */ X TextPointToModel(&ptmp); X } X X ApplyMapping(mapping, prim, &ptmp, norm, &uv, dpdu, dpdv); X X /* X * Transform UV by model2text. We set X = u and Y = v, X * while Z = 0. X * Although the UV coordinates may be in prim space, X * we treat them as if they are model-space coords. X * This is due to the fact that we want the texture X * to be applied in model space. X */ X ptmp.x = uv.u; X ptmp.y = uv.v; X ptmp.z = 0.; X PointTransform(&ptmp, &model2text.trans); X *u = ptmp.x; X *v = ptmp.y; X if (dpdu == (Vector *)NULL || dpdv == (Vector *)NULL) X return; X /* X * Here's the ugly part. X * Build initial UVN-->XYZ matrix... X */ X ArbitraryMatrix(dpdu->x, dpdu->y, dpdu->z, X dpdv->x, dpdv->y, dpdv->z, X norm->x, norm->y, norm->z, 0., 0., 0., &t); X /* X * ...transform to model space... X */ X MatrixMult(&t, &prim2model.trans, &t); X /* X * ... apply model2text in UVN space. X */ X MatrixMult(&model2text.itrans, &t, &t); X dpdu->x = t.matrix[0][0]; X dpdu->y = t.matrix[0][1]; X dpdu->z = t.matrix[0][2]; X dpdv->x = t.matrix[1][0]; X dpdv->y = t.matrix[1][1]; X dpdv->z = t.matrix[1][2]; X (void)VecNormalize(dpdu); X (void)VecNormalize(dpdv); X} X X/* X * Append 'text' to the given linked list of textures. X * Note that 'text' may be a list, too. X */ XTexture * XTextAppend(text, list) XTexture *text, *list; X{ X Texture *tp; X X if (list) { X /* X * Walk to the end of the list X */ X for (tp = list;tp->next ;tp = tp->next) X ; X tp->next = text; X return list; X } X /* else */ X return text; X} END_OF_FILE if test 4973 -ne `wc -c <'libray/libtext/texture.c'`; then echo shar: \"'libray/libtext/texture.c'\" unpacked with wrong size! fi # end of 'libray/libtext/texture.c' fi if test -f 'libshade/misc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libshade/misc.c'\" else echo shar: Extracting \"'libshade/misc.c'\" \(4080 characters\) sed "s/^X//" >'libshade/misc.c' <<'END_OF_FILE' X/* X * misc.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: misc.c,v 4.0 91/07/17 14:46:31 kolb Exp Locker: kolb $ X * X * $Log: misc.c,v $ X * Revision 4.0 91/07/17 14:46:31 kolb X * Initial version. X * X */ X#include "rayshade.h" X#ifdef RUSAGE X#include X#include X#else X#ifdef TIMES X#include X#include X#include X#endif X#endif X#include "options.h" X#include "stats.h" X XFloat RSabstmp; /* Temporary value used by fabs macro. Ugly. */ Xstatic void RSmessage(); X X/* X * Open input file and call yyparse(). X */ Xvoid XRSReadInputFile() X{ X extern FILE *yyin; /* lex/yacc file pointer */ X extern char yyfilename[]; X X#if defined(CPPSTDIN) && defined(POPEN) X char cmd[BUFSIZ]; X X if (Options.cppargs != (char *)NULL) X sprintf(cmd, "%s %s ", CPPSTDIN, Options.cppargs); X else X /* fromstdin */ X sprintf(cmd, "%s %s ", CPPSTDIN, CPPMINUS); X X if (Options.inputname == (char *)NULL) { X (void)strcpy(yyfilename, "stdin"); X } else { X (void)strcpy(yyfilename, Options.inputname); X (void)strcat(cmd, Options.inputname); X } X yyin = popen(cmd, "r"); X if (yyin == (FILE *)NULL) X RLerror(RL_PANIC, "popen of \"%s\" failed!\n", cmd); X#else X if (Options.inputname == (char *)NULL) { X yyin = stdin; X (void)strcpy(yyfilename, "stdin"); X } else { X (void)strcpy(yyfilename, Options.inputname); X yyin = fopen(Options.inputname, "r"); X if (yyin == (FILE *)NULL) X RLerror(RL_PANIC, X "Cannot open %s.\n",Options.inputname); X } X#endif X /* X * Initialize symbol table. X */ X SymtabInit(); X (void)yyparse(); X} X Xvoid XOpenStatsFile() X{ X if (Options.statsname == (char *)NULL || Stats.fstats != stderr) X return; /* Not specified or already opened. */ X X Stats.fstats = fopen(Options.statsname, "w"); X if (Stats.fstats == (FILE *)NULL) { X RLerror(RL_PANIC, X "Cannot open stats file %s.\n", Options.statsname); X } X} X Xvoid XRLerror(level, pat, arg1, arg2, arg3) Xint level; Xchar *pat, *arg1, *arg2, *arg3; X{ X switch (level) { X case RL_ADVISE: X if (!Options.quiet) X RSmessage("Warning", pat, arg1, arg2, arg3); X break; X case RL_WARN: X RSmessage("Warning", pat, arg1, arg2, arg3); X break; X case RL_ABORT: X RSmessage("Error", pat, arg1, arg2, arg3); X exit(1); X break; X case RL_PANIC: X RSmessage("Fatal error", pat, arg1, arg2, arg3); X exit(2); X break; X default: X RSmessage("Unknown error", pat, arg1, arg2, arg3); X exit(3); X } X} X Xstatic void XRSmessage(type, pat, arg1, arg2, arg3) Xchar *type, *pat, *arg1, *arg2, *arg3; X{ X extern FILE *yyin; X extern int yylineno; X extern char yyfilename[]; X X if (yyin) { X /* X * cleanup() hasn't nulled yyin, so line # X * info is valid. X */ X fprintf(stderr,"%s: %s: %s, line %d: ", X Options.progname, type, X yyfilename == (char *)NULL ? "stdin" : X yyfilename, yylineno); X } else { X fprintf(stderr,"%s: %s: ", Options.progname, type); X } X fprintf(stderr, pat, arg1, arg2, arg3); X} X X#ifdef RUSAGE Xvoid XRSGetCpuTime(usertime, systime) XFloat *usertime, *systime; X{ X struct rusage usage; X X getrusage(RUSAGE_SELF, &usage); X X *usertime = (Float)usage.ru_utime.tv_sec + X (Float)usage.ru_utime.tv_usec / 1000000.; X *systime = (Float)usage.ru_stime.tv_sec + X (Float)usage.ru_stime.tv_usec / 1000000.; X} X X#else X#ifdef TIMES X Xvoid XRSGetCpuTime(usertime, systime) XFloat *usertime, *systime; X{ X extern CLOCKTYPE times(); X struct tms time; X X (void)times(&time); X *usertime = (Float)time.tms_utime / (Float)HZ; X *systime = (Float)time.tms_stime / (Float)HZ; X} X X#else /* !RUSAGE && !TIMES */ X Xvoid XRSGetCpuTime(usertime, systime) XFloat *usertime, *systime; X{ X *usertime = *systime = 0.; X} X X#endif /* TIMES */ X#endif /* RUSAGE */ END_OF_FILE if test 4080 -ne `wc -c <'libshade/misc.c'`; then echo shar: \"'libshade/misc.c'\" unpacked with wrong size! fi # end of 'libshade/misc.c' fi if test -f 'libshade/stats.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libshade/stats.c'\" else echo shar: Extracting \"'libshade/stats.c'\" \(4043 characters\) sed "s/^X//" >'libshade/stats.c' <<'END_OF_FILE' X/* X * stats.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: stats.c,v 4.0 91/07/17 14:47:41 kolb Exp Locker: kolb $ X * X * $Log: stats.c,v $ X * Revision 4.0 91/07/17 14:47:41 kolb X * Initial version. X * X */ X#include X#include "rayshade.h" X#include "options.h" X#include "stats.h" X XRSStats Stats; /* Statistical information */ XGeom *GeomRep = NULL; /* Linked list of object representatives */ X Xstatic void PrintGeomStats(); X Xvoid XStatsPrint() X{ X extern void PrintMemoryStats(); X unsigned long TotalRays; X X#ifndef LINDA X RSGetCpuTime(&Stats.Utime, &Stats.Stime); X#endif X ShadowStats(&Stats.ShadowRays, &Stats.ShadowHits, X &Stats.CacheHits, &Stats.CacheMisses); X IntersectStats(&Stats.BVTests); X X TotalRays = Stats.EyeRays + Stats.ShadowRays + Stats.ReflectRays X + Stats.RefractRays; X Stats.ShadowHits += Stats.CacheHits; X Stats.HitRays += Stats.ShadowHits; X#ifdef LINDA X fprintf(Stats.fstats,"Workers:\t\t\t%d\n",Options.workers); X#endif X fprintf(Stats.fstats,"Eye rays:\t\t\t%lu\n", Stats.EyeRays); X fprintf(Stats.fstats,"Shadow rays:\t\t\t%lu\n",Stats.ShadowRays); X fprintf(Stats.fstats,"Reflected rays:\t\t\t%lu\n",Stats.ReflectRays); X fprintf(Stats.fstats,"Refracted rays:\t\t\t%lu\n",Stats.RefractRays); X fprintf(Stats.fstats,"Total rays:\t\t\t%lu\n", TotalRays); X if (TotalRays != 0) X fprintf(Stats.fstats,"Intersecting rays:\t\t%lu (%3.3f%%)\n", X Stats.HitRays, X 100. * (float)Stats.HitRays / (float)TotalRays); X if (Stats.ShadowRays != 0) { X if (Options.cache) X fprintf(Stats.fstats, X "Shadow cache hits:\t\t%lu (%lu misses)\n", X Stats.CacheHits, Stats.CacheMisses); X fprintf(Stats.fstats,"Total shadow hits:\t\t%lu (%3.3f%%)\n", X Stats.ShadowHits, 100.*(float)Stats.ShadowHits / X (float)Stats.ShadowRays); X } X fprintf(Stats.fstats,"Supersampled pixels:\t\t%lu\n", X Stats.SuperSampled); X fprintf(Stats.fstats,"B.V. intersection tests:\t%lu\n",Stats.BVTests); X PrintGeomStats(); X#ifdef LINDA X fprintf(Stats.fstats,"Average CPU time/processor:\t"); X#else X fprintf(Stats.fstats,"Total CPU time (sec):\t\t"); X#endif X fprintf(Stats.fstats,"%2.2f (%2.2fu + %2.2fs)\n", X Stats.Utime+Stats.Stime, Stats.Utime, Stats.Stime); X if (TotalRays != 0.) X fprintf(Stats.fstats,"Seconds / ray:\t\t\t%4.4f\n", X (Stats.Utime + Stats.Stime) / (Float)TotalRays); X if (Stats.HitRays != 0.) X fprintf(Stats.fstats,"Seconds / intersecting ray:\t%4.4f\n", X (Stats.Utime + Stats.Stime)/(Float)Stats.HitRays); X PrintMemoryStats(Stats.fstats); X} X Xstatic void XPrintGeomStats() X{ X Geom *otmp; X unsigned long tests, hits, totaltests, totalhits; X char *name; X extern void GeomStats(); X X totaltests = totalhits = 0; X X for (otmp = GeomRep; otmp; otmp = otmp->next) { X GeomStats(otmp, &tests, &hits); X if (tests <= 0) X continue; X name = GeomName(otmp); X fprintf(Stats.fstats, X "%c%s intersection tests:\t%lu (%lu hit, %f%%)\n", X toupper((int)name[0]), &name[1], tests, hits, X 100.*(float)hits/(float)tests); X if (!IsAggregate(otmp)) { X totaltests += tests; X totalhits += hits; X } X } X fprintf(Stats.fstats,"Total prim. intersection tests:\t%lu", X totaltests); X if (totaltests == 0) X fprintf(Stats.fstats,"\n"); X else X fprintf(Stats.fstats," (%lu hit, %f%%)\n", totalhits, X 100.*(float)totalhits/(float)totaltests); X} X Xvoid XStatsAddRep(obj) XGeom *obj; X{ X Geom *otmp; X X for (otmp = GeomRep; otmp; otmp = otmp->next) { X if (otmp->methods->stats == obj->methods->stats) X return; X } X X /* X * Stats method didn't match anything found so far. Add X * a copy of obj to head of GeomRep list. X */ X otmp = GeomCopy(obj); X otmp->next = GeomRep; X GeomRep = otmp; X} END_OF_FILE if test 4043 -ne `wc -c <'libshade/stats.c'`; then echo shar: \"'libshade/stats.c'\" unpacked with wrong size! fi # end of 'libshade/stats.c' fi echo shar: End of archive 8 \(of 19\). cp /dev/null ark8isdone 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