CCL Home Page
Up Directory CCL Part08
#! /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 4160 -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'\" \(4010 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.1.1 91/11/26 21:12:29 cek Exp Locker: cek $ */
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]			{WriteVerbatim(yytext);};
X"\n"			{};
X" "			{};
X^#			{return 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			WriteNewline();
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, linenumber;
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	yylval.c = strsave(buf);
X
X	/*
X	 * Set file/line if the line was of the form #n "filename"
X	 */
X	if ((i = sscanf(buf, "%d \"%[^\"]s\"", &linenumber, buf)) != 0) {
X		yylineno = linenumber;
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		} else
X			strcpy(yyfilename, buf);
X	}
X	return tHASHTHING;
X}
END_OF_FILE
if test 4010 -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/geom.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libray/libobj/geom.h'\"
else
echo shar: Extracting \"'libray/libobj/geom.h'\" \(4069 characters\)
sed "s/^X//" >'libray/libobj/geom.h' <<'END_OF_FILE'
X/*
X * geom.h
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: geom.h,v 4.0.1.1 92/02/07 13:10:58 cek Exp Locker: cek $
X *
X * $Log:	geom.h,v $
X * Revision 4.0.1.1  92/02/07  13:10:58  cek
X * patch6: Decreased MAXMODELDEPTH to keep from beating on the stack.
X * 
X * Revision 4.0  91/07/17  14:37:52  kolb
X * Initial version.
X * 
X */
X#ifndef OBJECT_H
X#define OBJECT_H
X
X#include "libcommon/common.h"
X#include "libcommon/transform.h"
X#include "bounds.h"
X
X/*
X * Constants for enter flag in HitNode.
X */
X#define EXITING		1
X#define ENTERING	2
X
X#define MAXMODELDEPTH	32		/* Maximum height of DAG. */
X
Xtypedef char * GeomRef;
Xtypedef GeomRef GeomCreateFunc();
X
X/*
X * If the object has a normal method, it's a primitive
X * otherwise it's an aggregate (or an instance)
X */
X#define IsAggregate(o)		((o)->methods->normal == NULL)
X
X/*
X * Geom methods.
X * (p) means applies only to primitive objects
X * (a) means applies only to aggregate objects
X */
Xtypedef struct Methods {
X	char		*(*name)();		/* Geom name */
X	GeomRef		(*create)();		/* Create and return ref */
X	int		(*intersect)(),		/* Ray/obj intersection */
X			(*normal)(),		/* Geom normal (p) */
X			(*enter)(),		/* Ray enter or exit? (p) */
X			(*convert)();		/* Convert from list (a) */
X	void		(*uv)(),		/* 2D mapping (p) */
X			(*stats)(),		/* Statistics */
X			(*bounds)(),		/* Bounding volume */
X			(*user)();		/* User-defined method */
X	struct Methods	*(*methods)();		/* object methods func. */
X	char		checkbounds,		/* check bbox before int.? */
X			closed;			/* properly closed? */
X} Methods;
X
Xtypedef void (*UserMethodType)();
X
X/*
X * Geom definition
X */
Xtypedef struct Geom {
X	char *name;			/* Geom name, if any. */
X	GeomRef obj;			/* Pointer to object info. */
X	Methods *methods;
X	unsigned long prims;		/* sum of # primitive objects */
X	Float bounds[2][3];		/* Bounding box */
X	Float timenow;			/* Geom's idea of what time it is */
X	short int animtrans;		/* transformation is animated */
X	short int frame;		/* frame for which obj is inited */
X	struct Surface *surf;		/* surface, if any */
X	struct Trans *trans;		/* Transformation information */
X	struct Trans *transtail;	/* Double linked list end */
X	struct Texture *texture;	/* Texture mapping info. */
X#ifdef SHAREDMEM
X	unsigned long *counter;		/* Geoms are shared, counters aren't */
X#else
X	unsigned long counter;		/* "mailbox" for grid intersection */
X#endif
X	struct Geom *next;		/* Next object. */
X} Geom;
X
X/*
X * Linked list of pointers to objects.
X */
Xtypedef struct GeomList {
X	Geom *obj;
X	struct GeomList *next;
X} GeomList;
X
X/*
X * Array of hit information.  Stores a path through an object DAG,
X * as well as the ray in 'model' (object) space and the distance from
X * the ray origin to the point of intersection.
X */
Xtypedef struct HitNode {
X	Geom *obj;			/* Geom hit */
X	Ray	ray;			/* Ray */
X	Float	mindist;		/* Amount of ray to ignore */
X	Float	dist;			/* Distance from ray origin to hit */
X	short	enter,			/* Enter (TRUE) or Leave (FALSE) obj */
X		dotrans;		/* transformations non-identity? */
X	Trans	trans;			/* parent-->obj and inverse trans */
X} HitNode;
X
X/*
X * Structure holding a list of HitNodes.  A maximum of MAXMODELDEPTH
X * nodes can be referenced.
X */
Xtypedef struct HitList {
X	int nodes;
X	HitNode data[MAXMODELDEPTH];
X} HitList;
X
Xextern char	*GeomName();
X
Xextern Geom	*GeomCreate(), *GeomCopy(), *GeomCopyNamed(),
X		*GeomComputeAggregateBounds();
X
X
Xextern GeomList	*GeomStackPush(), *GeomStackPop();
X
Xextern void 	PrimUV(), AggregatePrintInfo(),
X		IntersectStats();
X
Xextern int	AggregateConvert(), PrimNormal(),
X		TraceRay();	/* application-provided */
X
Xextern Methods	*MethodsCreate();
X
X#endif /* OBJECT_H */
END_OF_FILE
if test 4069 -ne `wc -c <'libray/libobj/geom.h'`; then
    echo shar: \"'libray/libobj/geom.h'\" unpacked with wrong size!
fi
# end of 'libray/libobj/geom.h'
fi
if test -f 'libray/libobj/intersect.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libray/libobj/intersect.c'\"
else
echo shar: Extracting \"'libray/libobj/intersect.c'\" \(3980 characters\)
sed "s/^X//" >'libray/libobj/intersect.c' <<'END_OF_FILE'
X/*
X * intersect.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: intersect.c,v 4.0 91/07/17 14:38:37 kolb Exp Locker: kolb $
X *
X * $Log:	intersect.c,v $
X * Revision 4.0  91/07/17  14:38:37  kolb
X * Initial version.
X * 
X */
X#include "geom.h"
X
Xstatic void AddToHitList();
X/*
X * Number of bounding volume tests.
X * External modules have read access via IntersectStats().
X */
Xstatic unsigned long BVTests;
X
X/*
X * Intersect object & ray.  Return distance from "pos" along "ray" to
X * intersection point.  Return value <= 0 indicates no intersection.
X */
Xint
Xintersect(obj, ray, hitlist, mindist, maxdist)
XGeom *obj;				/* Geom to be tested. */
XRay *ray;				/* Ray origin, direction. */
XHitList *hitlist;			/* Intersection path */
XFloat mindist, *maxdist;
X{
X	Ray newray;
X	Vector vtmp;
X	Trans *curtrans;	
X	Float distfact, nmindist, nmaxdist;
X
X	/*
X	 * Check ray/bounding volume intersection, if required.
X	 */
X	if (obj->methods->checkbounds) {
X		VecAddScaled(ray->pos, mindist, ray->dir, &vtmp);
X		if (OutOfBounds(&vtmp, obj->bounds)) {
X			nmaxdist = *maxdist;
X			BVTests++;
X			if (!BoundsIntersect(ray, obj->bounds, mindist,
X							&nmaxdist))
X				return FALSE;
X		}
X	}
X
X	newray = *ray;
X	nmindist = mindist;
X	nmaxdist = *maxdist;
X
X	/*
X	 * Transform the ray if necessary.
X	 */
X	if (obj->trans != (Trans *)0) {
X		/*
X		 * If object's idea of the current time is wrong,
X		 * update the transformations.
X		 */
X		if (obj->animtrans && !equal(obj->timenow, ray->time)) {
X			TransResolveAssoc(obj->trans);
X		}
X				
X		/*
X		 * Transforming the ray can change the distance between
X		 * the ray origin and the point of intersection.
X		 * We save the amount the ray is "stretched" and later
X		 * divide the computed distance by this amount.
X		 */
X		distfact = 1.;
X		for (curtrans = obj->transtail; curtrans; 
X		     curtrans = curtrans->prev)
X			distfact *= RayTransform(&newray, &curtrans->itrans);
X		nmindist *= distfact;
X		nmaxdist *= distfact;
X	}
X	/*
X	 * Geom has been updated to current time.
X	 */
X	obj->timenow = ray->time;
X
X	/*
X	 * Call correct intersection routine.
X	 */
X	if (IsAggregate(obj)) {
X		/*
X		 * Aggregate
X		 */
X		if (!(*obj->methods->intersect)
X		     (obj->obj, &newray, hitlist, nmindist, &nmaxdist))
X		return FALSE;
X	} else {
X		/*
X		 * Primitive
X		 */
X		if (!(*obj->methods->intersect)
X		      (obj->obj, &newray, nmindist, &nmaxdist))
X			return FALSE;
X		hitlist->nodes = 0;
X	}
X
X	/*
X	 * Had a hit -- add ray, distance and object to tail of hitlist.
X	 */
X	AddToHitList(hitlist, &newray, nmindist, nmaxdist, obj);
X
X	/*
X	 * Set dist to distance to intersection point from the origin
X	 * of the untransformed ray.
X	 */
X	if (obj->trans != (Trans *)0)
X		*maxdist = nmaxdist / distfact;
X	else
X		*maxdist = nmaxdist;
X
X	return TRUE;
X}
X
Xstatic void
XAddToHitList(hitlist, ray, mind, dist, obj)
XHitList *hitlist;
XRay *ray;
XFloat mind, dist;
XGeom *obj;
X{
X	HitNode *np;
X	Trans *list;
X
X	np = &hitlist->data[hitlist->nodes++];
X
X	np->ray = *ray;
X	np->obj = obj;
X	np->mindist = mind;
X	np->dist = dist;
X	np->enter = 0;
X
X	if (obj->trans) {
X		/*
X		 * Compute total transformation, forward and inverse,
X		 * for this object, and store in hitlist for use later.
X		 */
X		TransCopy(obj->trans, &np->trans);
X		for (list = obj->trans->next; list; list = list->next)
X			TransCompose(&np->trans, list, &np->trans);
X		np->dotrans = TRUE;
X	} else
X		np->dotrans = FALSE;
X}
X
X/*
X * Return intersection statistics.
X * Currently, this is limited to the # of bounding volume test performed.
X */
Xvoid
XIntersectStats(bvtests)
Xunsigned long *bvtests;
X{
X	*bvtests = BVTests;
X}
END_OF_FILE
if test 3980 -ne `wc -c <'libray/libobj/intersect.c'`; then
    echo shar: \"'libray/libobj/intersect.c'\" unpacked with wrong size!
fi
# end of 'libray/libobj/intersect.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 'libshade/misc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libshade/misc.c'\"
else
echo shar: Extracting \"'libshade/misc.c'\" \(4260 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.1.1 92/01/14 18:29:05 cek Exp Locker: cek $
X *
X * $Log:	misc.c,v $
X * Revision 4.0.1.1  92/01/14  18:29:05  cek
X * patch3: Added support for switching cpp on/off.
X * 
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
X	if (Options.cpp) {
X		yyin = popen(cmd, "r");
X		if (yyin == (FILE *)NULL)
X			RLerror(RL_PANIC, "popen of \"%s\" failed!\n", cmd);
X	} else {
X#endif
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#if defined(CPPSTDIN) && defined(POPEN)
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 4260 -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
Modified: Wed Dec 11 17:00:00 1996 GMT
Page accessed 1222 times since Sat Apr 17 21:59:32 1999 GMT