#! /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 '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;imvec.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= (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 (dlist[i].y - r; X if (dlist[i].z - r; X if (dlist[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 X#include 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