home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume21
/
rayshade
/
part17
< prev
next >
Wrap
Text File
|
1991-07-21
|
40KB
|
1,690 lines
Newsgroups: comp.sources.misc
From: Rayshade Construction Co. <rayshade@weedeater.math.YALE.EDU>
Subject: v21i020: rayshade - A raytracing package for UNIX, Part17/19
Message-ID: <1991Jul21.223416.3881@sparky.IMD.Sterling.COM>
X-Md4-Signature: a4d125964e11af669e118c42f54e0e56
Date: Sun, 21 Jul 1991 22:34:16 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: Rayshade Construction Co. <rayshade@weedeater.math.YALE.EDU>
Posting-number: Volume 21, Issue 20
Archive-name: rayshade/part17
Environment: UNIX, !16BIT
#! /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 <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 17 (of 19)."
# Contents: libray/libobj/blob.c rayview/glmethods.c
# Wrapped by kolb@woody on Wed Jul 17 17:57:00 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'libray/libobj/blob.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'libray/libobj/blob.c'\"
else
echo shar: Extracting \"'libray/libobj/blob.c'\" \(18207 characters\)
sed "s/^X//" >'libray/libobj/blob.c' <<'END_OF_FILE'
X/*
X * blob.c
X *
X * Copyright (C) 1990, 1991, Mark Podlipec, Craig E. Kolb
X * All rights reserved.
X *
X * This software may be freely copied, modified, and redistributed
X * provided that this copyright notice is preserved on all copies.
X *
X * You may not distribute this software, in whole or in part, as part of
X * any commercial product without the express consent of the authors.
X *
X * There is no warranty or other guarantee of fitness of this software
X * for any purpose. It is provided solely "as is".
X *
X * $Id: blob.c,v 4.0 91/07/17 14:36:07 kolb Exp Locker: kolb $
X *
X * $Log: blob.c,v $
X * Revision 4.0 91/07/17 14:36:07 kolb
X * Initial version.
X *
X */
X#include "geom.h"
X#include "blob.h"
X
Xstatic Methods *iBlobMethods = NULL;
Xstatic char blobName[] = "blob";
X
Xunsigned long BlobTests, BlobHits;
X
X/*
X * Blob/Metaball Description
X *
X * In this implementation a Blob is made up of a threshold T, and a
X * group of 1 or more Metaballs. Each metaball 'i' is defined by
X * its position (xi,yi,zi), its radius ri, and its strength si.
X * Around each Metaball is a density function di(Ri) defined by:
X *
X * di(Ri) = c4i * Ri^4 + c2i * Ri^2 + c0i 0 <= Ri <= ri
X * di(Ri) = 0 ri < Ri
X *
X * where
X * c4i = si / (ri^4)
X * c2i = -(2 * si) / (ri^2)
X * c0i = si
X * Ri^2 is the distance from a point (x,y,z) to the center of
X * the Metaball - (xi,yi,zi).
X *
X * The density function looks sort of like a W (Float-u) with the
X * center hump crossing the d-axis at si and the two humps on the
X * side being tangent to the R-axis at -ri and +ri. Only the
X * range [0,ri] is being used.
X * I chose this function so that derivative = 0 at the points 0 and +ri.
X * This keeps the surface smooth when the densities are added. I also
X * wanted no Ri^3 and Ri terms, since the equations are easier to
X * solve without them. This led to the symmetry about the d-axis and
X * the derivative being equal to zero at -ri as well.
X *
X * The surface of the Blob is defined by:
X *
X *
X * N
X * ---
X * F(x,y,z) = \ di(Ri) = T
X * /
X * ---
X * i=0
X *
X * where
X *
X * di(Ri) is given above
X * Ri^2 = (x-xi)^2 + (y-yi)^2 + (z-zi)^2
X * N is number of Metaballs in Blob
X * T is the threshold
X * (xi,yi,zi) is the center of Metaball i
X *
X */
X
X/*****************************************************************************
X * Create & return reference to a metaball.
X */
XBlob *
XBlobCreate(T, mlist, npoints)
XFloat T;
XMetaList *mlist;
Xint npoints;
X{
X Blob *blob;
X int i;
X MetaList *cur;
X
X/*
X * There has to be at least one metaball in the blob.
X * Note: if there's only one metaball, the blob
X * will be a sphere.
X */
X if (npoints < 1)
X {
X RLerror(RL_WARN, "blob field not correct.\n");
X return (Blob *)NULL;
X }
X
X/*
X * Initialize primitive and Geom structures
X */
X blob = (Blob *)Malloc(sizeof(Blob));
X blob->T = T;
X blob->list=(MetaVector *)
X Malloc( (unsigned)(npoints*sizeof(MetaVector)) );
X blob->num = npoints;
X
X/*
X * Initialize Metaball list
X */
X for(i=0;i<npoints;i++)
X {
X cur = mlist;
X if ( (cur->mvec.c0 < EPSILON) || (cur->mvec.rs < EPSILON) )
X {
X RLerror(RL_WARN,"Degenerate metaball in blob (sr).\n");
X return (Blob *)NULL;
X }
X /* store radius squared */
X blob->list[i].rs = cur->mvec.rs * cur->mvec.rs;
X /* Calculate and store coefficients for each metaball */
X blob->list[i].c0 = cur->mvec.c0;
X blob->list[i].c2 = -(2.0 * cur->mvec.c0) / blob->list[i].rs;
X blob->list[i].c4 = cur->mvec.c0 /
X (blob->list[i].rs * blob->list[i].rs);
X blob->list[i].x = cur->mvec.x;
X blob->list[i].y = cur->mvec.y;
X blob->list[i].z = cur->mvec.z;
X mlist = mlist->next;
X free((voidstar)cur);
X }
X /*
X * Allocate room for Intersection Structures and
X * Allocate room for an array of pointers to point to
X * the Intersection Structures.
X */
X blob->ilist = (MetaInt *)Malloc( 2 * blob->num * sizeof(MetaInt));
X blob->iarr = (MetaInt **)Malloc( 2 * blob->num * sizeof(MetaInt *));
X return blob;
X}
X
XMethods *
XBlobMethods()
X{
X if (iBlobMethods == (Methods *)NULL) {
X iBlobMethods = MethodsCreate();
X iBlobMethods->create = (GeomCreateFunc *)BlobCreate;
X iBlobMethods->methods = BlobMethods;
X iBlobMethods->name = BlobName;
X iBlobMethods->intersect = BlobIntersect;
X iBlobMethods->normal = BlobNormal;
X iBlobMethods->bounds = BlobBounds;
X iBlobMethods->stats = BlobStats;
X iBlobMethods->checkbounds = TRUE;
X iBlobMethods->closed = TRUE;
X }
X return iBlobMethods;
X}
X
X/*****************************************************************************
X * Function used by qsort() when sorting the Ray/Blob intersection list
X */
Xint
XMetaCompare(A,B)
Xchar *A,*B;
X{
X MetaInt **AA,**BB;
X
X AA = (MetaInt **) A;
X BB = (MetaInt **) B;
X if (AA[0]->bound == BB[0]->bound) return(0);
X if (AA[0]->bound < BB[0]->bound) return(-1);
X return(1); /* AA[0]->bound is > BB[0]->bound */
X}
X
X/*****************************************************************************
X * Ray/metaball intersection test.
X */
Xint
XBlobIntersect(blob, ray, mindist, maxdist)
XBlob *blob;
XRay *ray;
XFloat mindist, *maxdist;
X{
X double c[5], s[4];
X Float dist;
X MetaInt *ilist,**iarr;
X register int i,j,inum;
X extern void qsort();
X
X BlobTests++;
X
X ilist = blob->ilist;
X iarr = blob->iarr;
X
X/*
X * The first step in calculating the Ray/Blob intersection is to
X * divide the Ray into intervals such that only a fixed set of
X * Metaballs contribute to the density function along that interval.
X * This is done by finding the set of intersections between the Ray
X * and each Metaball's Sphere/Region of influence, which has a
X * radius ri and is centered at (xi,yi,zi).
X * Intersection information is kept track of in the MetaInt
X * structure and consists of:
X *
X * type indicates whether this intersection is the start(R_START)
X * of a Region or the end(R_END) of one.
X * pnt the Metaball of this intersection
X * bound the distance from Ray origin to this intersection
X *
X * This list is then sorted by bound and used later to find the Ray/Blob
X * intersection.
X */
X
X inum = 0;
X for(i=0; i < blob->num; i++)
X {
X register Float xadj, yadj, zadj;
X register Float b, t, rs;
X register Float dmin,dmax;
X
X rs = blob->list[i].rs;
X xadj = blob->list[i].x - ray->pos.x;
X yadj = blob->list[i].y - ray->pos.y;
X zadj = blob->list[i].z - ray->pos.z;
X
X /*
X * Ray/Sphere of Influence intersection
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 + rs;
X
X /*
X * don't except imaginary or single roots. A single root is a ray
X * tangent to the Metaball's Sphere/Region. The Metaball's
X * contribution to the overall density function at this point is
X * zero anyway.
X */
X if (t > 0.0) /* we have two roots */
X {
X t = sqrt(t);
X dmin = b - t;
X /*
X * only interested in stuff in front of ray origin
X */
X if (dmin < mindist) dmin = mindist;
X dmax = b + t;
X if (dmax > dmin) /* we have a valid Region */
X {
X /*
X * Initialize min/start and max/end Intersections Structures
X * for this Metaball
X */
X ilist[inum].type = R_START;
X ilist[inum].pnt = i;
X ilist[inum].bound = dmin;
X for(j=0;j<5;j++) ilist[inum].c[j] = 0.0;
X iarr[inum] = &(ilist[inum]);
X inum++;
X
X ilist[inum].type = R_END;
X ilist[inum].pnt = i;
X ilist[inum].bound = dmax;
X for(j=0;j<5;j++) ilist[inum].c[j] = 0.0;
X iarr[inum] = &(ilist[inum]);
X inum++;
X } /* End of valid Region */
X } /* End of two roots */
X } /* End of loop through metaballs */
X
X /*
X * If there are no Ray/Metaball intersections there will
X * not be a Ray/Blob intersection. Exit now.
X */
X if (inum == 0)
X {
X return FALSE;
X }
X
X /*
X * Sort Intersection list. No sense using qsort if there's only
X * two intersections.
X *
X * Note: we actually aren't sorting the Intersection structures, but
X * an array of pointers to the Intersection structures.
X * This is faster than sorting the Intersection structures themselves.
X */
X if (inum==2)
X {
X MetaInt *t;
X if (ilist[0].bound > ilist[1].bound)
X {
X t = iarr[0];
X iarr[0] = iarr[1];
X iarr[1] = t;
X }
X }
X else qsort((voidstar)(iarr), (unsigned)inum, sizeof(MetaInt *),
X MetaCompare);
X
X/*
X* Finding the Ray/Blob Intersection
X*
X* The non-zero part of the density function for each Metaball is
X*
X* di(Ri) = c4i * Ri^4 + c2i * Ri^2 + c0i
X*
X* To find find the Ray/Blob intersection for one metaball
X* substitute for distance
X*
X* Ri^2 = (x-xi)^2 + (y-yi)^2 + (z-zi)^2
X*
X* and then substitute the Ray equations:
X*
X* x = x0 + x1 * t
X* y = y0 + y1 * t
X* z = z0 + z1 * t
X*
X* to get a big mess :^). Actually, it's a Quartic in t and it's fully
X* listed farther down. Here's a short version:
X*
X* c[4] * t^4 + c[3] * t^3 + c[2] * t^2 + c[1] * t + c[0] = T
X*
X* Don't forget that the Blob is defined by the density being equal to
X* the threshold T.
X* To calculate the intersection of a Ray and two or more Metaballs,
X* the coefficients are calculated for each Metaball and then added
X* together. We can do this since we're working with polynomials.
X* The points of intersection are the roots of the resultant equation.
X*
X* The algorithm loops through the intersection list, calculating
X* the coefficients if an intersection is the start of a Region and
X* adding them to all intersections in that region.
X* When it detects a valid interval, it calculates the
X* roots from the starting intersection's coefficients and if any of
X* the roots are in the interval, the smallest one is returned.
X*
X*/
X
X {
X register Float *tmpc;
X MetaInt *strt,*tmp;
X register int istrt,itmp;
X register int num,exitflag,inside;
X
X /*
X * Start the algorithm outside the first interval
X */
X inside = 0;
X istrt = 0;
X strt = iarr[istrt];
X if (strt->type != R_START)
X RLerror(RL_WARN,"MetaInt sanity check FAILED!\n");
X
X /*
X * Loop through intersection. If a root is found the code
X * will return at that point.
X */
X while( istrt < inum )
X {
X /*
X * Check for multiple intersections at the same point.
X * This is also where the coefficients are calculated
X * and spread throughout that Metaball's sphere of
X * influence.
X */
X do
X {
X /* find out which metaball */
X i = strt->pnt;
X /* only at starting boundaries do this */
X if (strt->type == R_START)
X {
X register MetaVector *ml;
X register Float a1,a0;
X register Float xd,yd,zd;
X register Float c4,c2,c0;
X
X /* we're inside */
X inside++;
X
X /* As promised, the full equations
X *
X * c[4] = c4*a2*a2;
X * c[3] = 4.0*c4*a1*a2;
X * c[2] = 4.0*c4*a1*a1 + 2.0*c4*a2*a0 + c2*a2;
X * c[1] = 4.0*c4*a1*a0 + 2.0*c2*a1;
X * c[0] = c4*a0*a0 + c2*a0 + c0;
X *
X * where
X * a2 = (x1*x1 + y1*y1 + z1*z1) = 1.0 because the ray
X * is normalized
X * a1 = (xd*x1 + yd*y1 + zd*z1)
X * a0 = (xd*xd + yd*yd + zd*zd)
X * xd = (x0 - xi)
X * yd = (y0 - yi)
X * zd = (z0 - zi)
X * (xi,yi,zi) is center of Metaball
X * (x0,y0,z0) is Ray origin
X * (x1,y1,z1) is normalized Ray direction
X * c4,c2,c0 are the coefficients for the
X * Metaball's density function
X *
X */
X
X /*
X * Some compilers would recalculate
X * this each time its used.
X */
X ml = &(blob->list[i]);
X
X xd = ray->pos.x - ml->x;
X yd = ray->pos.y - ml->y;
X zd = ray->pos.z - ml->z;
X a1 = (xd * ray->dir.x + yd * ray->dir.y
X + zd * ray->dir.z);
X a0 = (xd * xd + yd * yd + zd * zd);
X
X c0 = ml->c0;
X c2 = ml->c2;
X c4 = ml->c4;
X
X c[4] = c4;
X c[3] = 4.0*c4*a1;
X c[2] = 2.0*c4*(2.0*a1*a1 + a0) + c2;
X c[1] = 2.0*a1*(2.0*c4*a0 + c2);
X c[0] = c4*a0*a0 + c2*a0 + c0;
X
X /*
X * Since we've gone through the trouble of calculating the
X * coefficients, put them where they'll be used.
X * Starting at the current intersection(It's also the start of
X * a region), add the coefficients to each intersection until
X * we reach the end of this region.
X */
X itmp = istrt;
X tmp = strt;
X while( (tmp->pnt != i) ||
X (tmp->type != R_END) )
X {
X tmpc = tmp->c;
X for(j=0;j<5;j++)
X *tmpc++ += c[j];
X itmp++;
X tmp = iarr[itmp];
X }
X
X } /* End of start of a Region */
X /*
X * Since the intersection wasn't the start
X * of a region, it must the end of one.
X */
X else inside--;
X
X /*
X * If we are inside a region(or regions) and the next
X * intersection is not at the same place, then we have
X * the start of an interval. Set the exitflag.
X */
X if ((inside > 0)
X && (strt->bound != iarr[istrt+1]->bound) )
X exitflag = 1;
X else
X /* move to next intersection */
X {
X istrt++;
X strt = iarr[istrt];
X exitflag = 0;
X }
X /*
X * Check to see if we're at the end. If so then exit with
X * no intersection found.
X */
X if (istrt >= inum)
X {
X return FALSE;
X }
X } while(!exitflag);
X /* End of Search for valid interval */
X
X /*
X * Find Roots along this interval
X */
X
X /* get coefficients from Intersection structure */
X tmpc = strt->c;
X for(j=0;j<5;j++) c[j] = *tmpc++;
X
X /* Don't forget to put in threshold */
X c[0] -= blob->T;
X
X /* Use Graphic Gem's Quartic Root Finder */
X num = SolveQuartic(c,s);
X
X /*
X * If there are roots, search for roots within the interval.
X */
X dist = 0.0;
X if (num>0)
X {
X for(j=0;j<num;j++)
X {
X /*
X * Not sure if EPSILON is truly needed, but it might cause
X * small cracks between intervals in some cases. In any case
X * I don't believe it hurts.
X */
X if ((s[j] >= (strt->bound - EPSILON))
X && (s[j] <= (iarr[istrt+1]->bound +
X EPSILON) ) )
X {
X if (dist == 0.0)
X /* first valid root */
X dist = s[j];
X else if (s[j] < dist)
X /* else only if smaller */
X dist = s[j];
X }
X }
X /*
X * Found a valid root
X */
X if (dist > mindist && dist < *maxdist)
X {
X *maxdist = dist;
X BlobHits++;
X return TRUE;
X /* Yeah! Return valid root */
X }
X }
X
X /*
X * Move to next intersection
X */
X istrt++;
X strt = iarr[istrt];
X
X } /* End of loop through Intersection List */
X } /* End of Solving for Ray/Blob Intersection */
X
X /*
X * return negative
X */
X return FALSE;
X}
X
X
X/***********************************************
X * Find the Normal of a Blob at a given point
X *
X * The normal of a surface at a point (x0,y0,z0) is the gradient of that
X * surface at that point. The gradient is the vector
X *
X * Fx(x0,y0,z0) , Fy(x0,y0,z0) , Fz(x0,y0,z0)
X *
X * where Fx(),Fy(),Fz() are the partial dervitives of F() with respect
X * to x,y and z respectively. Since the surface of a Blob is made up
X * of the sum of one or more polynomials, the normal of a Blob at a point
X * is the sum of the gradients of the individual polynomials at that point.
X * The individual polynomials in this case are di(Ri) i = 0,...,num .
X *
X * To find the gradient of the contributing polynomials
X * take di(Ri) and substitute U = Ri^2;
X *
X * di(U) = c4i * U^2 + c2i * U + c0i
X *
X * dix(U) = 2 * c4i * Ux * U + c2i * Ux
X *
X * U = (x-xi)^2 + (y-yi)^2 + (z-zi)^2
X *
X * Ux = 2 * (x-xi)
X *
X * Rearranging we get
X *
X * dix(x0,y0,z0) = 4 * c4i * xdi * disti + 2 * c2i * xdi
X * diy(x0,y0,z0) = 4 * c4i * ydi * disti + 2 * c2i * ydi
X * diz(x0,y0,z0) = 4 * c4i * zdi * disti + 2 * c2i * zdi
X *
X * where
X * xdi = x0-xi
X * ydi = y0-yi
X * zdi = y0-yi
X * disti = xdi*xdi + ydi*ydi + zdi*zdi
X * (xi,yi,zi) is the center of Metaball i
X * c4i,c2i,c0i are the coefficients of Metaball i's density function
X */
Xint
XBlobNormal(blob, pos, nrm, gnrm)
XBlob *blob;
XVector *pos, *nrm, *gnrm;
X{
X register int i;
X
X /*
X * Initialize normals to zero
X */
X nrm->x = nrm->y = nrm->z = 0.0;
X /*
X * Loop through Metaballs. If the point is within a Metaball's
X * Sphere of influence, calculate the gradient and add it to the
X * normals
X */
X for(i=0;i < blob->num; i++)
X {
X register MetaVector *sl;
X register Float dist,xd,yd,zd;
X
X sl = &(blob->list[i]);
X xd = pos->x - sl->x;
X yd = pos->y - sl->y;
X zd = pos->z - sl->z;
X
X dist = xd*xd + yd*yd + zd*zd;
X if (dist <= sl->rs )
X {
X register Float temp;
X
X /* temp is negative so normal points out of blob */
X temp = -2.0 * (2.0 * sl->c4 * dist + sl->c2);
X nrm->x += xd * temp;
X nrm->y += yd * temp;
X nrm->z += zd * temp;
X
X }
X }
X (void)VecNormalize(nrm);
X *gnrm = *nrm;
X return FALSE;
X}
X
X
X/*****************************************************************************
X * Calculate the extent of the Blob
X */
Xvoid
XBlobBounds(blob, bounds)
XBlob *blob;
XFloat bounds[2][3];
X{
X Float r;
X Float minx,miny,minz,maxx,maxy,maxz;
X int i;
X
X /*
X * Loop through Metaballs to find the minimun and maximum in each
X * direction.
X */
X for( i=0; i< blob->num; i++)
X {
X register Float d;
X
X r = sqrt(blob->list[i].rs);
X if (i==0)
X {
X minx = blob->list[i].x - r;
X miny = blob->list[i].y - r;
X minz = blob->list[i].z - r;
X maxx = blob->list[i].x + r;
X maxy = blob->list[i].y + r;
X maxz = blob->list[i].z + r;
X }
X else
X {
X d = blob->list[i].x - r;
X if (d<minx) minx = d;
X d = blob->list[i].y - r;
X if (d<miny) miny = d;
X d = blob->list[i].z - r;
X if (d<minz) minz = d;
X d = blob->list[i].x + r;
X if (d>maxx) maxx = d;
X d = blob->list[i].y + r;
X if (d>maxy) maxy = d;
X d = blob->list[i].z + r;
X if (d>maxz) maxz = d;
X }
X }
X bounds[LOW][X] = minx;
X bounds[HIGH][X] = maxx;
X bounds[LOW][Y] = miny;
X bounds[HIGH][Y] = maxy;
X bounds[LOW][Z] = minz;
X bounds[HIGH][Z] = maxz;
X}
X
Xchar *
XBlobName()
X{
X return blobName;
X}
X
Xvoid
XBlobStats(tests, hits)
Xunsigned long *tests, *hits;
X{
X *tests = BlobTests;
X *hits = BlobHits;
X}
X
Xvoid
XBlobMethodRegister(meth)
XUserMethodType meth;
X{
X if (iBlobMethods)
X iBlobMethods->user = meth;
X}
END_OF_FILE
if test 18207 -ne `wc -c <'libray/libobj/blob.c'`; then
echo shar: \"'libray/libobj/blob.c'\" unpacked with wrong size!
fi
# end of 'libray/libobj/blob.c'
fi
if test -f 'rayview/glmethods.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'rayview/glmethods.c'\"
else
echo shar: Extracting \"'rayview/glmethods.c'\" \(17863 characters\)
sed "s/^X//" >'rayview/glmethods.c' <<'END_OF_FILE'
X/*
X * glmethods.c
X *
X * Support routines for SGI/RS6000 machines.
X *
X * Copyright (C) 1989, 1991, Craig E. Kolb, Allan Snyder
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: glmethods.c,v 4.0 91/07/17 17:38:43 kolb Exp Locker: kolb $
X *
X * $Log: glmethods.c,v $
X * Revision 4.0 91/07/17 17:38:43 kolb
X * Initial version
X *
X */
X#include <gl.h>
X#include <device.h>
X#include "rayshade.h"
X#include "options.h"
X#include "viewing.h"
X
X#include "libsurf/surface.h"
X
X#include "libobj/box.h"
X#include "libobj/cone.h"
X#include "libobj/csg.h"
X#include "libobj/cylinder.h"
X#include "libobj/disc.h"
X#include "libobj/grid.h"
X#include "libobj/instance.h"
X#include "libobj/list.h"
X#include "libobj/plane.h"
X#include "libobj/poly.h"
X#include "libobj/sphere.h"
X#include "libobj/triangle.h"
X
X#include "liblight/light.h"
X#include "liblight/extended.h"
X#include "liblight/infinite.h"
X#include "liblight/point.h"
X#include "liblight/spot.h"
X
X#define CIRCLE_SAMPLES 20 /* # of samples around circle (cone/cyl/etc) */
X#define DEFAULT_NEAR .2 /* default value for near clipping plane */
X#define DEFAULT_FAR 350. /* default far clipping plane */
X#define PLANE_RAD 450. /* radius of disc used to represent planes */
X
X#ifndef SPHERELIB
X#define SPHERE_LEVEL 3
X#endif
X
X/*
X * Pass a normal stored in a Vector to the geometry pipeline.
X */
X#define GLNormal(w) (glnrm[0] = (w)->x, glnrm[1] = (w)->y, \
X glnrm[2] = (w)->z, n3f(glnrm))
X
Xstatic void GLBoxDraw(), GLConeDraw(), GLCsgDraw(), GLCylinderDraw(),
X GLDiscDraw(),
X GLGridDraw(), GLHfDraw(), GLInstanceDraw(),
X GLListDraw(), GLPlaneDraw(), GLPolygonDraw(),
X GLSphereDraw(), GLTorusDraw(), GLTriangleDraw(),
X GLBoundsDraw(),
X GLInfiniteLight(), GLPointLight(), GLSpotLight(),
X GLExtendedLight();
X
Xstatic short cursurf = 1,
X curlight = 1;
X
Xstatic Object GLBoxObject,
X GLCylObject,
X GLSphereObject,
X GLBoxObjectDefine(),
X GLCylObjectDefine();
X
Xextern Object GLSphereObjectDefine();
X
Xstatic int Doublebuffered;
X
Xstatic float Ident[4][4] = {1., 0., 0., 0.,
X 0., 1., 0., 0.,
X 0., 0., 1., 0.,
X 0., 0., 0., 1.},
X glnrm[3];
X
Xstatic float **CirclePoints;
X
Xstatic void LightDraw(), GeomDraw(), GLMultMatrix(),
X GLPushSurface(), GLPopSurface(), LightDrawInit(),
X ObjectInit(), GLDrawFrame(), ScreenDrawInit(), DrawInit(),
X GLUnitCircle(), GLDisc(), ComputeClippingPlanes();
X
XFloat CurrentTime;
X
Xstatic unsigned long BackPack; /* Packed background color */
Xstatic long Zinit; /* maximum Zbuffer value */
X
XMethodsRegister()
X{
X BoxMethodRegister(GLBoxDraw);
X ConeMethodRegister(GLConeDraw);
X CsgMethodRegister(GLCsgDraw);
X CylinderMethodRegister(GLCylinderDraw);
X DiscMethodRegister(GLDiscDraw);
X GridMethodRegister(GLGridDraw);
X /*HfMethodRegister(GLHfDraw);*/
X InstanceMethodRegister(GLInstanceDraw);
X ListMethodRegister(GLListDraw);
X PlaneMethodRegister(GLPlaneDraw);
X PolygonMethodRegister(GLPolygonDraw);
X SphereMethodRegister(GLSphereDraw);
X /* Have to write sphere routine for RS6000... */
X /*TorusMethodRegister(GLTorusDraw);*/
X TriangleMethodRegister(GLTriangleDraw);
X
X InfiniteMethodRegister(GLInfiniteLight);
X PointMethodRegister(GLPointLight);
X ExtendedMethodRegister(GLExtendedLight);
X SpotMethodRegister(GLSpotLight);
X}
X
Xvoid
XRender()
X{
X short val;
X float tmp;
X
X DrawInit();
X qdevice(ESCKEY);
X qdevice(SPACEKEY);
X qdevice(REDRAW);
X
X DrawFrames();
X
X while (TRUE) {
X switch (qread(&val)) {
X case ESCKEY:
X exit(0);
X break;
X case REDRAW:
X reshapeviewport();
X DrawFrames();
X break;
X case SPACEKEY:
X if (!val)
X DrawFrames();
X break;
X }
X }
X}
X
XDrawFrames()
X{
X int i;
X for (i = 0; i < Options.totalframes; i++)
X GLDrawFrame(i);
X}
X
Xstatic void
XDrawInit()
X{
X extern Surface DefaultSurface;
X
X ScreenDrawInit();
X ObjectInit();
X LightDrawInit();
X /*
X * Push the default surface.
X */
X GLPushSurface(&DefaultSurface);
X}
X
Xstatic void
XScreenDrawInit()
X{
X /*
X * Open window, initialize graphics, etc.
X */
X#ifdef sgi
X foreground();
X#endif
X prefsize(Screen.xsize, Screen.ysize);
X winopen("rayview");
X RGBmode();
X mmode(MVIEWING);
X
X if (Options.totalframes > 1) {
X Doublebuffered = TRUE;
X doublebuffer();
X }
X
X gconfig();
X /*
X * Initialize viewing matrix.
X */
X GLViewingInit();
X
X zbuffer(TRUE);
X
X BackPack = (unsigned char)(255*Screen.background.r) |
X ((unsigned char)(255*Screen.background.g) << 8) |
X ((unsigned char)(255*Screen.background.b) << 16);
X Zinit = getgdesc(GD_ZMAX);
X lsetdepth(0, Zinit);
X}
X
X/*
X * Draw the World object.
X */
Xstatic void
XGLDrawFrame(frame)
Xint frame;
X{
X extern Geom *World;
X
X RSStartFrame(frame);
X CurrentTime = Options.framestart;
X TimeSet(CurrentTime);
X
X czclear(BackPack, Zinit);
X
X /*
X * Draw the World object
X */
X GeomDraw(World);
X if (Doublebuffered)
X swapbuffers();
X}
X
XGLViewingInit()
X{
X float near, far, aspect, dist, T[4][4];
X short ang;
X extern Geom *World;
X
X ang = Camera.vfov * 10 + 0.5;
X aspect = Camera.hfov / Camera.vfov;
X
X T[0][0]=Screen.scrni.x; T[0][1]=Screen.scrnj.x; T[0][2]= -Camera.dir.x;
X T[1][0]=Screen.scrni.y; T[1][1]=Screen.scrnj.y; T[1][2]= -Camera.dir.y;
X T[2][0]=Screen.scrni.z; T[2][1]=Screen.scrnj.z; T[2][2]= -Camera.dir.z;
X
X T[0][3] = T[1][3] = T[2][3] = 0.;
X
X T[3][0] = -dotp(&Camera.lookp, &Screen.scrni);
X T[3][1] = -dotp(&Camera.lookp, &Screen.scrnj);
X T[3][2] = dotp(&Camera.lookp, &Camera.dir);
X T[3][3] = 1.;
X
X ComputeClippingPlanes(&near, &far, World->bounds);
X
X loadmatrix(Ident);
X perspective(ang, aspect, near, far);
X polarview((float)Camera.lookdist, 0, 0, 0);
X multmatrix(T);
X}
X
X
Xstatic void
XObjectInit()
X{
X CircleDefine();
X GLBoxObject = GLBoxObjectDefine();
X
X#ifdef SPHERELIB
X GLSphereObject = GLSphereObjectDefine();
X#else
X GLSphereObject = GLSphereObjectDefine(SPHERE_LEVEL);
X#endif
X
X GLCylObject = GLCylObjectDefine();
X}
X
Xstatic void
XGeomDraw(obj)
XGeom *obj;
X{
X Trans *ct;
X /*
X * If object has a surface associated with it,
X * start using it.
X */
X if (obj->surf)
X GLPushSurface(obj->surf);
X if (obj->trans) {
X /*
X * Take care of any animated transformations that
X * exist.
X */
X if (obj->animtrans && !equal(obj->timenow, CurrentTime)) {
X TransResolveAssoc(obj->trans);
X obj->timenow = CurrentTime;
X }
X pushmatrix();
X /*
X * Apply in reverse order.
X */
X for (ct = obj->transtail; ct; ct = ct->prev)
X GLMultMatrix(&ct->trans);
X }
X
X if (obj->methods->user) {
X /*
X * Call proper method
X */
X (*obj->methods->user)(obj->obj);
X } else {
X /*
X * Draw bounding box.
X */
X GLBoundsDraw(obj->bounds);
X }
X
X if (obj->surf)
X GLPopSurface();
X if (obj->trans)
X popmatrix();
X}
X
Xstatic float surfprops[] = {AMBIENT, 0, 0, 0,
X DIFFUSE, 0, 0, 0,
X SPECULAR, 0, 0, 0,
X SHININESS, 0,
X LMNULL};
Xstatic float *amb = &surfprops[1],
X *diff = &surfprops[5],
X *spec = &surfprops[9],
X *shine = &surfprops[13];
X
Xstatic void
XGLPushSurface(surf)
XSurface *surf;
X{
X static Surface *lastsurf = NULL;
X
X /*
X * Start using the given surface.
X * In the case of the use of an "applysurf",
X * the same surface will be applied to many
X * primitives individually. By saving the
X * pointer to the last surface, we keep from
X * lmdef'ing the surface when we don't need to.
X */
X if (surf != lastsurf) {
X amb[0] = surf->amb.r; amb[1] = surf->amb.g;
X amb[2] = surf->amb.b;
X diff[0] = surf->diff.r; diff[1] = surf->diff.g;
X diff[2] = surf->diff.b;
X spec[0] = surf->spec.r; spec[1] = surf->spec.g;
X spec[2] = surf->spec.b;
X shine[0] = surf->srexp;
X lmdef(DEFMATERIAL, cursurf, 15, surfprops);
X lastsurf = surf;
X }
X lmbind(MATERIAL, cursurf);
X cursurf++;
X}
X
Xstatic void
XGLMultMatrix(trans)
XRSMatrix *trans;
X{
X float newmat[4][4];
X /*
X * Multiply in the given transformation.
X */
X newmat[0][0] = trans->matrix[0][0]; newmat[0][1] = trans->matrix[0][1];
X newmat[0][2] = trans->matrix[0][2]; newmat[0][3] = 0.;
X newmat[1][0] = trans->matrix[1][0]; newmat[1][1] = trans->matrix[1][1];
X newmat[1][2] = trans->matrix[1][2]; newmat[1][3] = 0.;
X newmat[2][0] = trans->matrix[2][0]; newmat[2][1] = trans->matrix[2][1];
X newmat[2][2] = trans->matrix[2][2]; newmat[2][3] = 0.;
X newmat[3][0] = trans->translate.x; newmat[3][1] = trans->translate.y;
X newmat[3][2] = trans->translate.z ; newmat[3][3] = 1.;
X multmatrix(newmat);
X}
X
Xstatic void
XGLPopSurface()
X{
X cursurf--;
X lmbind(MATERIAL, cursurf-1);
X}
X
Xstatic void
XGLBoundsDraw(bounds)
XFloat bounds[2][3];
X{
X float sx, sy, sz;
X
X pushmatrix();
X
X translate(bounds[LOW][X], bounds[LOW][Y], bounds[LOW][Z]);
X scale( bounds[HIGH][X] - bounds[LOW][X],
X bounds[HIGH][Y] - bounds[LOW][Y],
X bounds[HIGH][Z] - bounds[LOW][Z]);
X pushmatrix();
X callobj(GLBoxObject);
X popmatrix();
X popmatrix();
X}
X
Xstatic void
XGLBoxDraw(box)
XBox *box;
X{
X GLBoundsDraw(box->bounds);
X}
X
X
Xstatic void
XGLConeDraw(cone)
XCone *cone;
X{
X int i, j;
X float norm[3], normconst, ZeroVect[3], tmpv[3];
X
X ZeroVect[0] = ZeroVect[1] = ZeroVect[2] = 0.;
X /*
X * Sides.
X * For the normal, assume we are finding the normal at
X * (C_P[i].x, C_P[i].y, 1.) at this point, the unnormalized
X * normal = (C_P[i].x, C_P[i].y, -tantheta^2). When we normalize,
X * then length of the vector is simply equal to:
X * sqrt(CP[i].x^2 + CP[i].y^2 + tantheta^4) ==
X * sqrt(1. + tantheta^4)
X * In our case, tantheta = 1., so...
X */
X
X normconst = 1. / sqrt(2.);
X norm[2] = -normconst;
X
X pushmatrix();
X GLMultMatrix(&cone->trans.trans);
X
X for (i = 0; i < CIRCLE_SAMPLES; i++) {
X j = (i + 1) % CIRCLE_SAMPLES;
X norm[0] = CirclePoints[i][0] * normconst;
X norm[1] = CirclePoints[i][1] * normconst;
X n3f(norm);
X bgnpolygon();
X if (cone->start_dist > EPSILON) {
X tmpv[2] = cone->start_dist;
X tmpv[0] = CirclePoints[i][0] * cone->start_dist;
X tmpv[1] = CirclePoints[i][1] * cone->start_dist;
X v3f(tmpv);
X tmpv[0] = CirclePoints[j][0] * cone->start_dist;
X tmpv[1] = CirclePoints[j][1] * cone->start_dist;
X v3f(tmpv);
X } else
X v3f(ZeroVect);
X tmpv[2] = 1.;
X tmpv[0] = CirclePoints[j][0];
X tmpv[1] = CirclePoints[j][1];
X v3f(tmpv);
X tmpv[0] = CirclePoints[i][0];
X tmpv[1] = CirclePoints[i][1];
X v3f(tmpv);
X endpolygon();
X }
X popmatrix();
X}
X
Xstatic void
XGLCsgDraw(csg)
XCsg *csg;
X{
X /*
X * Punt by drawing both objects.
X */
X GeomDraw(csg->obj1);
X GeomDraw(csg->obj2);
X}
X
Xstatic void
XGLCylinderDraw(cyl)
XCylinder *cyl;
X{
X pushmatrix();
X GLMultMatrix(&cyl->trans.trans);
X callobj(GLCylObject);
X popmatrix();
X}
X
Xstatic void
XGLDiscDraw(disc)
XDisc *disc;
X{
X GLDisc((Float)sqrt(disc->radius), &disc->pos, &disc->norm);
X}
X
Xstatic void
XGLDisc(rad, pos, norm)
XFloat rad;
XVector *pos, *norm;
X{
X RSMatrix m, tmp;
X Vector atmp;
X
X /*
X * This is kinda disgusting...
X */
X ScaleMatrix(rad, rad, 1., &m);
X if (fabs(norm->z) == 1.) {
X atmp.x = 1.;
X atmp.y = atmp.z = 0.;
X } else {
X atmp.x = norm->y;
X atmp.y = -norm->x;
X atmp.z= 0.;
X }
X
X RotationMatrix(atmp.x, atmp.y, atmp.z, -acos(norm->z), &tmp);
X MatrixMult(&m, &tmp, &m);
X TranslationMatrix(pos->x, pos->y, pos->z, &tmp);
X MatrixMult(&m, &tmp, &m);
X pushmatrix();
X GLMultMatrix(&m);
X /*
X * Draw unit circle.
X */
X GLUnitCircle(0., TRUE);
X popmatrix();
X}
X
Xstatic void
XGLGridDraw(grid)
XGrid *grid;
X{
X Geom *ltmp;
X
X for (ltmp = grid->unbounded; ltmp; ltmp = ltmp->next)
X GeomDraw(ltmp);
X for (ltmp = grid->objects; ltmp; ltmp = ltmp->next)
X GeomDraw(ltmp);
X}
X
Xstatic void
XGLHfDraw(){}
X
Xstatic void
XGLInstanceDraw(inst)
XInstance *inst;
X{
X GeomDraw(inst->obj);
X}
X
Xstatic void
XGLListDraw(list)
XList *list;
X{
X Geom *ltmp;
X
X for (ltmp = list->unbounded; ltmp; ltmp = ltmp->next)
X GeomDraw(ltmp);
X for (ltmp = list->list; ltmp; ltmp = ltmp->next)
X GeomDraw(ltmp);
X}
X
Xstatic void
XGLPlaneDraw(plane)
XPlane *plane;
X{
X /*
X * Draw a really big disc.
X */
X GLDisc((Float)PLANE_RAD, &plane->pos, &plane->norm);
X}
X
Xstatic void
XGLPolygonDraw(poly)
Xregister Polygon *poly;
X{
X register int i;
X
X GLNormal(&poly->norm);
X
X bgnpolygon();
X for (i = 0; i < poly->npoints; i++)
X v3d(&poly->points[i]);
X endpolygon();
X}
X
Xstatic void
XGLSphereDraw(sph)
XSphere *sph;
X{
X pushmatrix();
X translate(sph->x, sph->y, sph->z);
X scale(sph->r, sph->r, sph->r);
X callobj(GLSphereObject);
X popmatrix();
X}
X
Xstatic void
XGLTorusDraw(){}
X
Xstatic void
XGLTriangleDraw(tri)
Xregister Triangle *tri;
X{
X /*
X * If Float is a double, use v3d,
X * otherwise use v3f.
X */
X if (tri->type != PHONGTRI) {
X GLNormal(&tri->nrm);
X bgnpolygon();
X v3d(&tri->p[0]); v3d(&tri->p[1]); v3d(&tri->p[2]);
X endpolygon();
X } else {
X bgnpolygon();
X GLNormal(&tri->vnorm[0]);
X v3d(&tri->p[0]);
X GLNormal(&tri->vnorm[1]);
X v3d(&tri->p[1]);
X GLNormal(&tri->vnorm[2]);
X v3d(&tri->p[2]);
X endpolygon();
X }
X}
X
Xfloat lightprops[] = {POSITION, 0., 0., 0., 0.,
X LCOLOR, 0, 0, 0,
X LMNULL};
X
Xfloat *lpos = &lightprops[1],
X *lcolor = &lightprops[6];
X
Xfloat lmodel[] = {AMBIENT, 1., 1., 1.,
X ATTENUATION, 1., 0.,
X LOCALVIEWER, 0.,
X#ifdef sgi
X ATTENUATION2, 0.,
X TWOSIDE, 1.,
X#endif
X LMNULL};
X
Xstatic void
XLightDrawInit()
X{
X Light *light;
X extern Light *Lights;
X
X for (light = Lights; light; light = light->next)
X LightDraw(light);
X
X switch (curlight-1) {
X case 8:
X lmbind(LIGHT7, 8);
X case 7:
X lmbind(LIGHT6, 7);
X case 6:
X lmbind(LIGHT5, 6);
X case 5:
X lmbind(LIGHT4, 5);
X case 4:
X lmbind(LIGHT3, 4);
X case 3:
X lmbind(LIGHT2, 3);
X case 2:
X lmbind(LIGHT1, 2);
X case 1:
X lmbind(LIGHT0, 1);
X }
X
X lmodel[1] = Options.ambient.r;
X lmodel[2] = Options.ambient.g;
X lmodel[3] = Options.ambient.b;
X
X#ifdef sgi
X lmdef(DEFLMODEL, 1, 14, lmodel);
X#else
X lmdef(DEFLMODEL, 1, 10, lmodel);
X#endif
X lmbind(LMODEL, 1);
X}
X
Xstatic void
XLightDraw(light)
XLight *light;
X{
X if (!light || !light->methods->user)
X return;
X lcolor[0] = light->color.r;
X lcolor[1] = light->color.g;
X lcolor[2] = light->color.b;
X (*light->methods->user)(light->light);
X}
X
Xstatic void
XGLExtendedLight(ext)
XExtended *ext;
X{
X lpos[0] = ext->pos.x;
X lpos[1] = ext->pos.y;
X lpos[2] = ext->pos.z;
X lpos[3] = 1.;
X lmdef(DEFLIGHT, curlight++, 10, lightprops);
X}
X
X
Xstatic void
XGLInfiniteLight(inf)
XInfinite *inf;
X{
X lpos[0] = inf->dir.x;
X lpos[1] = inf->dir.y;
X lpos[2] = inf->dir.z;
X lpos[3] = 0.;
X lmdef(DEFLIGHT, curlight++, 10, lightprops);
X}
X
Xstatic void
XGLPointLight(pt)
XPointlight *pt;
X{
X lpos[0] = pt->pos.x;
X lpos[1] = pt->pos.y;
X lpos[2] = pt->pos.z;
X lpos[3] = 1.;
X lmdef(DEFLIGHT, curlight++, 10, lightprops);
X}
X
Xstatic void
XGLSpotLight(spot)
XSpotlight *spot;
X{
X}
X
Xstatic float boxfaces[6][4][3] = {
X{ {1., 1., 1.},
X {0., 1., 1.},
X {0., 0., 1.},
X {1., 0., 1.} },
X{ {1., 0., 1.},
X {0., 0., 1.},
X {0., 0., 0.},
X {1., 0., 0.} },
X{ {1., 0., 0.},
X {0., 0., 0.},
X {0., 1., 0.},
X {1., 1., 0.} },
X{ {0., 1., 0.},
X {0., 1., 1.},
X {1., 1., 1.},
X {1., 1., 0.} },
X{ {1., 1., 1.},
X {1., 0., 1.},
X {1., 0., 0.},
X {1., 1., 0.} },
X{ {0., 0., 1.},
X {0., 1., 1.},
X {0., 1., 0.},
X {0., 0., 0.}}};
X
Xfloat boxnorms[6][3] = {
X {0, 0, 1},
X {0, -1, 0},
X {0, 0, -1},
X {0, 1, 0},
X {1, 0, 0,},
X {-1, 0, 0}};
X
X/*
X * Define a unit cube centered at (0.5, 0.5, 0.5)
X */
Xstatic Object
XGLBoxObjectDefine()
X{
X int i, box;
X
X makeobj(box = genobj());
X for (i = 0; i < 6; i++) {
X n3f(boxnorms[i]);
X polf(4, boxfaces[i]);
X }
X closeobj();
X return box;
X}
X
Xstatic void
XGLUnitCircle(z, up)
Xfloat z;
Xint up;
X{
X int i;
X float norm[3];
X
X norm[0] = norm[1] = 0.;
X bgnpolygon();
X
X if (up) {
X norm[2] = 1.;
X n3f(norm);
X for (i = 0; i < CIRCLE_SAMPLES; i++) {
X CirclePoints[i][2] = z;
X v3f(CirclePoints[i]);
X }
X } else {
X norm[2] = -1.;
X n3f(norm);
X for (i = CIRCLE_SAMPLES -1; i; i--) {
X CirclePoints[i][2] = z;
X v3f(CirclePoints[i]);
X }
X }
X
X endpolygon();
X}
X
Xstatic Object
XGLCylObjectDefine()
X{
X int i, j, cyl;
X float norm[3];
X
X makeobj(cyl = genobj());
X norm[2] = 0;
X for (i = 0; i < CIRCLE_SAMPLES; i++) {
X j = (i+1)%CIRCLE_SAMPLES;
X norm[0] = CirclePoints[i][0];
X norm[1] = CirclePoints[i][1];
X#ifdef sgi
X n3f(norm);
X bgnpolygon();
X CirclePoints[i][2] = 0;
X v3f(CirclePoints[i]);
X CirclePoints[j][2] = 0;
X v3f(CirclePoints[j]);
X CirclePoints[j][2] = 1;
X v3f(CirclePoints[j]);
X CirclePoints[i][2] = 1;
X v3f(CirclePoints[i]);
X endpolygon();
X#else
X n3f(norm);
X pmv(CirclePoints[i][0], CirclePoints[i][1], 0.);
X pdr(CirclePoints[j][0], CirclePoints[j][1], 0.);
X pdr(CirclePoints[j][0], CirclePoints[j][1], 1.);
X pdr(CirclePoints[i][0], CirclePoints[i][1], 1.);
X pclos();
X#endif
X }
X closeobj();
X return cyl;
X}
X
X/*
X * Fill CirclePoints[t] with X and Y values cooresponding to points
X * along the unit circle. The size of CirclePoints is equal to
X * CIRCLE_SAMPLES.
X */
XCircleDefine()
X{
X int i;
X double theta, dtheta;
X
X dtheta = 2.*M_PI / (double)CIRCLE_SAMPLES;
X CirclePoints = (float **)malloc(CIRCLE_SAMPLES * sizeof(float *));
X for (i = 0, theta = 0; i < CIRCLE_SAMPLES; i++, theta += dtheta) {
X CirclePoints[i] = (float *)malloc(3 * sizeof(float));
X CirclePoints[i][0] = cos(theta);
X CirclePoints[i][1] = sin(theta);
X /* Z is left unset. */
X }
X}
X
X/*
X * Given world bounds, determine near and far
X * clipping planes. Only problem occurs when there are
X * unbbounded objects (planes)...
X */
Xstatic void
XComputeClippingPlanes(near, far, bounds)
Xfloat *near, *far;
XFloat bounds[2][3];
X{
X Vector e, c;
X double rad, d;
X
X
X /*
X * Compute 'radius' of scene.
X */
X rad = max(max((bounds[HIGH][X] - bounds[LOW][X])*0.5,
X (bounds[HIGH][Y] - bounds[LOW][Y])*0.5),
X (bounds[HIGH][Z] - bounds[LOW][Z])*0.5);
X
X c.x = (bounds[LOW][X] + bounds[HIGH][X])*0.5;
X c.y = (bounds[LOW][Y] + bounds[HIGH][Y])*0.5;
X c.z = (bounds[LOW][Z] + bounds[HIGH][Z])*0.5;
X
X /*
X * Compute position of eye relative to the center of the sphere.
X */
X VecSub(Camera.pos, c, &e);
X d = VecNormalize(&e);
X if (d <= rad)
X /*
X * Eye is inside sphere.
X */
X *near = DEFAULT_NEAR;
X else
X *near = (d - rad)*0.2;
X *far = (d + rad)*2.;
X}
END_OF_FILE
if test 17863 -ne `wc -c <'rayview/glmethods.c'`; then
echo shar: \"'rayview/glmethods.c'\" unpacked with wrong size!
fi
# end of 'rayview/glmethods.c'
fi
echo shar: End of archive 17 \(of 19\).
cp /dev/null ark17isdone
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
exit 0 # Just in case...