rsalz@bbn.com (Rich Salz) (02/08/90)
Submitted-by: Craig Kolb <craig@weedeater.math.yale.edu> Posting-number: Volume 21, Issue 10 Archive-name: rayshade/part03 #! /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 3 (of 8)." # Contents: BLURB.UTAH src/bounds.c src/cone.c src/cylinder.c # src/intersect.c src/light.c src/object.c src/ray_options.c # src/voxels.c PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'BLURB.UTAH' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'BLURB.UTAH'\" else echo shar: Extracting \"'BLURB.UTAH'\" \(6402 characters\) sed "s/^X//" >'BLURB.UTAH' <<'END_OF_FILE' X X THE UTAH RASTER TOOLKIT X XThe Utah Raster toolkit is a collection of programs and C routines for Xdealing with raster images commonly encountered in computer graphics. It Xprovides the following major functions: X X * A device and system independent image format for storing images X and information about them. Called the RLE format, it uses X run length encoding to reduce storage space for most images. X X * A library of C routines for reading, writing and manipulating X images stored in the RLE format. X X * A collections of programs for manipulating and displaying RLE X images. X X XThe Format: X X The device independent RLE file has two parts, the header, which stores X information about the image (size, position, channel information, X color maps, comments, etc), and the actual image data in a run length X encoded format. The RLE format often requires about a third of the X available space for most "image synthesis" style images. If the image X does not compress well, the RLE format stores it as straight pixel data X with little extra overhead. The format has been developed over the past X five years at Utah. X XThe Library: X X C routines are provided for setting up and reading the image header, X and for reading and writing the image a scanline at a time. Images can X be read or written using two different methods. Using the "row" method, X the library performs the RLE encoding and decoding. With the "raw" method, X scanlines are constructed directly with RLE opcodes. Additional routines X are available for generating dither matrices (e.g., for display programs X running on devices with less than 24 bits of color). X XThe Tools: X applymap - Apply color map values to pixel values. X avg4 - Downfilter an image by 1/4, generating a matte channel if one X didn't previously exist X comp - Digital image compositor. Provides the operations over, atop, X in, out, xor, plus, minus and diff on two images. X crop - Crop an image. X dvi2rle - Convert TeX output into anti-aliased images. X fant - Rotate and/or scale in image by an arbitrary (float) value. X mcut - Quantize an image from 24 to eight bits using the median cut X algorithm. X mergechan - Merge several channels from different files into a single X RLE file. X pyrmask - Blend images using Gaussian pyrimids. X repos - Change the position in the RLE header. X rleClock - Generate an image of a clock. X rleaddcom - Add a comment to the RLE file's header. X rlebg - Generate a solid or variable background. X rlebox - Find the actual non-background area of an image. X rleflip - Rotate an image by 90/180 degree increments. X rlehdr - Dump the contents of the RLE header in human readable form. X rlehisto - Generate the histogram of an RLE file. X rleldmap - Load a color map into an RLE file from a variety of sources. X rlemandl - Generate Mandlebrot sets as RLE files. X rlenoise - Adds random noise to an image. X rlepatch - Overlay several smaller images over a larger one. X rlescale - Generates gray scale and color scale RLE files. X rlesetbg - Set the background color stored in the RLE header. X rlesplit - Split a file containing several images into several files. X rleswap - Swap, copy or delete channels in an RLE file. X rletops - Convert an RLE image to PostScript (graylevel). X rlezoom - Enlarge an image with pixel replication. X smush - Perform a simple Gaussian filter on an image. X to8 - Convert a 24 bit RGB image to an eight bit dithered one. X tobw - Convert 24 bits to 8 bits black and white. X unexp - Convert an "exponential" image to a displayable one. X unslice - Quickly assemble an image from several horizontal strips X X Format conversion programs are provided for: X - Simple pixel streams (color & B&W) X - Targa image format X - Cubicomp image format X - PostScript X - MacPaint X - Sun rasterfiles X - Wastatch paint systems X X Display programs are provided for: X getap - Apollo workstations X getbob - HP Series 300 ("bobocat") running Windows 9000 X getcx3d - Chromatics CX1500 display X getfb - BRL "libfb" displays X getgmr - Grinnell GMR-27 (remember those?) X getX - Workstations running the X window system X getX11 - Workstations running X11 X getOrion - Orion displays X getren - HP 98721 "Rennasance" display X getsun - Suns running Suntools X getmac - Macintosh. X getmex - Iris running Mex X getqcr - Photograph images with the Matrix QCR-Z camera. X getiris - Iris in raw 24 bit mode. X - [Note display programs for a particular device are X simple to add] X X All the tools are designed to pipe together, so they can be used as X filters on images much like the standard Unix tools filter text. X XPlus: X X The raster toolkit also includes Unix man pages for the library and X commands, some sample images, and additional documentation. X XSystem Requirements: X X We have successfully ported the Raster Toolkit to a number of Unix X systems, including 4.2/4.3bsd (Vax, Sun, etc), Apollo Domain/IX, HP X Series 3000, SGI Iris, Gould UTX. Display programs are included for X several devices. Creating display programs for additional devices is X a straightforward task. X XDistribution: X X For ARPAnet sites, the toolkit may be obtained via anonymous FTP to the X site cs.utah.edu, in the file pub/toolkit-2.0.tar (or, if you cannot FTP X that large a file at once, in pub/toolkit-2.0.tar.1, pub/toolkit-2.0.tar.2 X and pub/toolkit-2.0.tar.3). Sites not on the ARPAnet can obtain the Raster X Toolkit on a 9-track, 1600 bpi tar format tape by sending check or X money order for $200.00, payable to the Department of Computer Science, X to: X X Attn: Utah Raster Toolkit, Loretta Looser X Department of Computer Science X University of Utah X Salt Lake City, UT, 84112 X X Courtesy Mike Muuss at BRL, the Raster Toolkit is also included as X contributed software in the BRL-CAD distribution. X X [Note: because of the size of the distribution, we can not distribute X it via mail or UUCP] X X Although the Raster Toolkit software is copyrighted, it may be freely X re-distributed on a "GNU-like" basis. X XFor further technical information on the Raster Toolkit, send mail Xto: X toolkit-request@cs.utah.edu (ARPA) X {ihnp4,decvax}!utah-cs!toolkit-request (UUCP) X X END_OF_FILE if test 6402 -ne `wc -c <'BLURB.UTAH'`; then echo shar: \"'BLURB.UTAH'\" unpacked with wrong size! fi chmod +x 'BLURB.UTAH' # end of 'BLURB.UTAH' fi if test -f 'src/bounds.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/bounds.c'\" else echo shar: Extracting \"'src/bounds.c'\" \(5679 characters\) sed "s/^X//" >'src/bounds.c' <<'END_OF_FILE' X/* X * bounds.c X * X * Copyright (C) 1989, Craig E. Kolb X * X * This software may be freely copied, modified, and redistributed, X * provided that this copyright notice is preserved on all copies. X * X * There is no warranty or other guarantee of fitness for this software, X * it is provided solely . Bug reports or fixes may be sent X * to the author, who may or may not act on them as he desires. X * X * You may not include this software in a program or other software product X * without supplying the source, or without informing the end-user that the X * source is available for no extra charge. X * X * If you modify this software, you should include a notice giving the X * name of the person performing the modification, the date of modification, X * and the reason for such modification. X * X * $Id: bounds.c,v 3.0 89/10/27 02:05:46 craig Exp $ X * X * $Log: bounds.c,v $ X * Revision 3.0 89/10/27 02:05:46 craig X * Baseline for first official release. X * X */ X#include <stdio.h> X#include <math.h> X#include "constants.h" X#include "typedefs.h" X#include "funcdefs.h" X X#ifndef HUGE X#define HUGE 1.701411e38 X#endif X X/* X * Ray-bounding box intersection test. X */ Xdouble XIntBounds(ray, bounds) XRay *ray; Xdouble bounds[2][3]; X{ X double t, tmin, tmax, bmin, bmax; X double dir, pos; X extern unsigned long BVTests; X X BVTests++; X tmin = 0.; X tmax = FAR_AWAY; X X dir = ray->dir.x; X pos = ray->pos.x; X X if (dir < 0) { X bmin = bounds[HIGH][X]; X bmax = bounds[LOW][X]; X } else { X bmax = bounds[HIGH][X]; X bmin = bounds[LOW][X]; X } X X if (dir != 0.) { /* check x-faces */ X t = (bmax - pos) / dir; X if (t < 0.) X return 0.; X if (t <= tmax) X tmax = t; X t = (bmin - pos) / dir; X if (t >= 0.) { X if (t > tmax) X return 0.; X tmin = t; X } X } else if (pos < bmin || pos > bmax) X return 0.; X X dir = ray->dir.y; X pos = ray->pos.y; X X if (dir < 0) { X bmin = bounds[HIGH][Y]; X bmax = bounds[LOW][Y]; X } else { X bmax = bounds[HIGH][Y]; X bmin = bounds[LOW][Y]; X } X X if (dir != 0.) { /* check y-faces */ X t = (bmax - pos) / dir; X if (t < 0.) X return 0.; X if (t <= tmax) { X if (t < tmin) X return 0.; X tmax = t; X } X t = (bmin - pos) / dir; X if (t >= tmin) { X if (t > tmax) X return 0.; X tmin = t; X } X } else if (pos < bmin || pos > bmax) X return 0.; X X dir = ray->dir.z; X pos = ray->pos.z; X X if (dir < 0) { X bmin = bounds[HIGH][Z]; X bmax = bounds[LOW][Z]; X } else { X bmax = bounds[HIGH][Z]; X bmin = bounds[LOW][Z]; X } X X if (dir != 0.) { /* check z-faces */ X t = (bmax - pos) / dir; X if (t < 0.) X return 0.; X if (t <= tmax) { X if (t < tmin) X return 0.; X tmax = t; X } X t = (bmin - pos) / dir; X if (t >= tmin) { X if (t > tmax) X return 0.; X tmin = t; X } X } else if (pos < bmin || pos > bmax) X return 0.; X X return tmin; X} X X/* X * Transform an object's bounding box by the given transformation X * matrix. X */ Xtransform_bounds(trans, objbounds) XTransInfo *trans; Xdouble objbounds[2][3]; X{ X Vector v, tmp; X double bounds[2][3]; X int x, y, z; X X init_bounds(bounds); X X /* X * Find bounding box of transformed corners of bounding box. X */ X for (x = 0 ; x < 2; x++) { X v.x = objbounds[x][X]; X for (y = 0; y < 2; y++) { X v.y = objbounds[y][Y]; X for (z = 0; z < 2; z++) { X v.z = objbounds[z][Z]; X tmp = v; X transform_point(&tmp, trans); X if (tmp.x < bounds[LOW][X]) X bounds[LOW][X] = tmp.x; X if (tmp.x > bounds[HIGH][X]) X bounds[HIGH][X] = tmp.x; X if (tmp.y < bounds[LOW][Y]) X bounds[LOW][Y] = tmp.y; X if (tmp.y > bounds[HIGH][Y]) X bounds[HIGH][Y] = tmp.y; X if (tmp.z < bounds[LOW][Z]) X bounds[LOW][Z] = tmp.z; X if (tmp.z > bounds[HIGH][Z]) X bounds[HIGH][Z] = tmp.z; X } X } X } X X for (x = 0; x < 3; x++) { X objbounds[LOW][x] = bounds[LOW][x]; X objbounds[HIGH][x] = bounds[HIGH][x]; X } X} X Xinit_bounds(bounds) Xdouble bounds[2][3]; X{ X bounds[LOW][X] = bounds[LOW][Y] = bounds[LOW][Z] = HUGE; X bounds[HIGH][X] = bounds[HIGH][Y] = bounds[HIGH][Z] = -HUGE; X} X X/* X * Walk through a linked-list of objects. If the object is unbounded, X * unlink it it from the list and add it to the 'unbounded' list. X * If the object is bounded, enlarge the given bounding box if X * necessary. Return pointer to unbounded list. X */ XObjList * Xfind_bounds(list, bounds) XObjList **list; Xdouble bounds[2][3]; X{ X ObjList *ltmp, *prev, *oltmp; X ObjList *unbounded; X Object *otmp; X X init_bounds(bounds); X prev = unbounded = (ObjList *)0; X X for (ltmp = *list; ltmp; ltmp = ltmp->next) { X otmp = ltmp->data; X if (otmp->bounds[LOW][X] > otmp->bounds[HIGH][X]) { X /* X * Object is unbounded -- unlink it... X */ X if (prev) X prev->next = ltmp->next; X else X *list = ltmp->next; X /* X * And add it to unbounded object list. X */ X oltmp = (ObjList *)Malloc(sizeof(ObjList)); X oltmp->data = otmp; X oltmp->next = unbounded; X unbounded = oltmp; X } else { X /* X * Object is bounded. X */ X enlarge_bounds(bounds, otmp->bounds); X prev = ltmp; X } X } X return unbounded; X} X X#define SetIfLess(a, b) (a = (a) < (b) ? (a) : (b)) X#define SetIfGreater(a, b) (a = (a) > (b) ? (a) : (b)) X X/* X * Find bounding box of the union of two bounding boxes. X */ Xenlarge_bounds(old, new) Xdouble old[2][3], new[2][3]; X{ X SetIfLess(old[LOW][X], new[LOW][X]); X SetIfLess(old[LOW][Y], new[LOW][Y]); X SetIfLess(old[LOW][Z], new[LOW][Z]); X SetIfGreater(old[HIGH][X], new[HIGH][X]); X SetIfGreater(old[HIGH][Y], new[HIGH][Y]); X SetIfGreater(old[HIGH][Z], new[HIGH][Z]); X} X Xprint_bounds(box) Xdouble box[2][3]; X{ X extern FILE *fstats; X fprintf(fstats,"\tX: %f to %f\n",box[LOW][X], box[HIGH][X]); X fprintf(fstats,"\tY: %f to %f\n",box[LOW][Y], box[HIGH][Y]); X fprintf(fstats,"\tZ: %f to %f\n",box[LOW][Z], box[HIGH][Z]); X} END_OF_FILE if test 5679 -ne `wc -c <'src/bounds.c'`; then echo shar: \"'src/bounds.c'\" unpacked with wrong size! fi # end of 'src/bounds.c' fi if test -f 'src/cone.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/cone.c'\" else echo shar: Extracting \"'src/cone.c'\" \(6421 characters\) sed "s/^X//" >'src/cone.c' <<'END_OF_FILE' X/* X * cone.c X * X * Copyright (C) 1989, Craig E. Kolb X * X * This software may be freely copied, modified, and redistributed, X * provided that this copyright notice is preserved on all copies. X * X * There is no warranty or other guarantee of fitness for this software, X * it is provided solely . Bug reports or fixes may be sent X * to the author, who may or may not act on them as he desires. X * X * You may not include this software in a program or other software product X * without supplying the source, or without informing the end-user that the X * source is available for no extra charge. X * X * If you modify this software, you should include a notice giving the X * name of the person performing the modification, the date of modification, X * and the reason for such modification. X * X * $Id: cone.c,v 3.0 89/10/27 02:05:47 craig Exp $ X * X * $Log: cone.c,v $ X * Revision 3.0 89/10/27 02:05:47 craig X * Baseline for first official release. X * X */ X#include <stdio.h> X#include <math.h> X#include "typedefs.h" X#include "funcdefs.h" X#include "constants.h" X XObject * Xmakcone(surf, cent, ax, br, ar, trans) Xchar *surf; XVector *cent, *ax; Xdouble br, ar; XTransInfo *trans; X{ X Cone *cone; X Primitive *prim; X Object *newobj; X extern int yylineno, Quiet; X double len, dtmp; X Vector axis, base, tmp; X X prim = mallocprim(); X prim->surf = find_surface(surf); X prim->type = CONE; X newobj = new_object(NULL, CONE, (char *)prim, (Trans *)NULL); X cone = (Cone *)Malloc(sizeof(Cone)); X prim->objpnt.p_cone = cone; X X /* X * Cones are defined by a basepoint, an apex point, and X * base and apex radii. The cone is stored as X * the origin of the cone, the change in radius per X * unit distance from the origin of the cone, the maximum z-value X * of the cone, and "start_pos", X * the distance along the axis from the cone origin where X * the first endcap appears (where the passed "basepoint" X * appears). X * X * The intcone() routine intersects a ray with a cone aligned X * along the Z axis. Thus, we must define a transformation X * matrix which will transform an axis-aligned cone to the desired. X */ X X /* X * The passed basepoint must be closer to the origin of the X * cone than the apex point, implying that the base radius X * must be smaller than the apex radius. If the values passed X * reflect the opposite, we switch everything. X */ X if(ar < br) { X tmp = *cent; X *cent = *ax; X *ax = tmp; X dtmp = br; X br = ar; X ar = dtmp; X } else if (equal(ar, br)) { X /* X * If the base and apex radii are equal, then we X * can treat the cone as a cylinder. X */ X return makcyl(surf, cent, ax, br, trans); X } X /* X * Find the axis and axis length. X */ X vecsub(*ax, *cent, &axis); X len = normalize(&axis); X if (len < EPSILON) { X if (!Quiet) X fprintf(stderr,"Degenerate cone (line %d).\n", X yylineno); X free((char *)cone); X free((char *)prim); X free((char *)newobj); X return (Object *)0; X } X cone->apex_rad = ar; X /* X * "tantheta" is the change in radius per unit length along X * the cone axis. X */ X cone->tantheta = (ar - br) / len; X /* X * Start pos defines the point along the axis where the first X * endcap should be placed. X */ X cone->start_pos = br / cone->tantheta; X /* X * Find the true base (origin) of the cone. X */ X scalar_prod(-cone->start_pos, axis, &base); X vecadd(base, *cent, &base); X /* X * The apex endcap is placed cone->len units from the cone X * origin. X */ X cone->end_pos = cone->start_pos + len; X /* X * Calculate rotation matrix to map from world space to cone space. X */ X/* if (equal(axis.z*axis.z, 1.)) { X tmp.x = 0.; X tmp.y = -axis.z; X tmp.z = 0.; X } else { */ X tmp.x = axis.y; X tmp.y = -axis.x; X tmp.z = 0.; X /*} */ X rotate(trans, &tmp, acos(axis.z)); X translate(trans, &base); X cone->tantheta *= cone->tantheta; X X return newobj; X} X X/* X * Ray-cone intersection test. This routine is far from optimal, but X * it's straight-forward and it works... X */ Xdouble Xintcone(pos, ray, obj) XVector *pos, *ray; XPrimitive *obj; X{ X double t1, t2, a, b, c, disc, zpos, et1, et2; X double x, y; X extern unsigned long primtests[]; X Cone *cone; X X primtests[CONE]++; X cone = obj->objpnt.p_cone; X X /* X * Recall that 'tantheta' is really tantheta^2. X */ X a = ray->x * ray->x + ray->y * ray->y - ray->z*ray->z*cone->tantheta; X b = ray->x * pos->x + ray->y * pos->y - cone->tantheta*ray->z*pos->z; X c = pos->x*pos->x + pos->y*pos->y - cone->tantheta*pos->z*pos->z; X X if (equal(a, 0.)) { X /* X * Only one intersection point... X */ X t1 = -c / b; X zpos = pos->z + t1 * ray->z; X if (t1 < EPSILON || zpos < cone->start_pos || X zpos > cone->end_pos) X t1 = FAR_AWAY; X t2 = FAR_AWAY; X } else { X disc = b*b - a*c; X if(disc < 0.) X return 0.; /* No possible intersection */ X disc = sqrt(disc); X t1 = (-b + disc) / a; X t2 = (-b - disc) / a; X /* X * Clip intersection points. X */ X zpos = pos->z + t1 * ray->z; X if (t1 < EPSILON || zpos < cone->start_pos || X zpos > cone->end_pos) X t1 = FAR_AWAY; X zpos = pos->z + t2 * ray->z; X if (t2 < EPSILON || zpos < cone->start_pos || X zpos > cone->end_pos) X t2 = FAR_AWAY; X } X /* X * Find t for both endcaps. X */ X et1 = (cone->start_pos - pos->z) / ray->z; X x = pos->x + et1 * ray->x; X y = pos->y + et1 * ray->y; X if (x*x + y*y > cone->start_pos*cone->start_pos*cone->tantheta) X et1 = FAR_AWAY; X et2 = (cone->end_pos - pos->z) / ray->z; X x = pos->x + et2 * ray->x; X y = pos->y + et2 * ray->y; X if (x*x + y*y > cone->end_pos*cone->end_pos*cone->tantheta) X et2 = FAR_AWAY; X X t1 = min(t1, min(t2, min(et1, et2))); X return (t1 == FAR_AWAY ? 0. : t1); X} X X/* X * Compute the normal to a cone at a given location on its surface. X */ Xnrmcone(pos, obj, nrm) XVector *pos, *nrm; XPrimitive *obj; X{ X Cone *cone; X X cone = obj->objpnt.p_cone; X X if (equal(pos->z, cone->start_pos)) { X nrm->x = nrm->y = 0.; X nrm->z = -1.; X } else if (equal(pos->z, cone->end_pos)) { X nrm->x = nrm->y = 0.; X nrm->z = 1.; X } else { X /* X * The following is equal to X * (pos X (0, 0, 1)) X pos X */ X nrm->x = pos->x * pos->z; X nrm->y = pos->y * pos->z; X nrm->z = -pos->x * pos->x - pos->y * pos->y; X } X} X X/* X * Return the extent of a cone. X */ Xconeextent(o, bounds) XPrimitive *o; Xdouble bounds[2][3]; X{ X Cone *cone; X X cone = o->objpnt.p_cone; X X bounds[LOW][X] = bounds[LOW][Y] = -cone->apex_rad; X bounds[HIGH][X] = bounds[HIGH][Y] = cone->apex_rad; X bounds[LOW][Z] = cone->start_pos; X bounds[HIGH][Z] = cone->end_pos; X} END_OF_FILE if test 6421 -ne `wc -c <'src/cone.c'`; then echo shar: \"'src/cone.c'\" unpacked with wrong size! fi # end of 'src/cone.c' fi if test -f 'src/cylinder.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/cylinder.c'\" else echo shar: Extracting \"'src/cylinder.c'\" \(4819 characters\) sed "s/^X//" >'src/cylinder.c' <<'END_OF_FILE' X/* X * cylinder.c X * X * Copyright (C) 1989, Craig E. Kolb X * X * This software may be freely copied, modified, and redistributed, X * provided that this copyright notice is preserved on all copies. X * X * There is no warranty or other guarantee of fitness for this software, X * it is provided solely . Bug reports or fixes may be sent X * to the author, who may or may not act on them as he desires. X * X * You may not include this software in a program or other software product X * without supplying the source, or without informing the end-user that the X * source is available for no extra charge. X * X * If you modify this software, you should include a notice giving the X * name of the person performing the modification, the date of modification, X * and the reason for such modification. X * X * $Id: cylinder.c,v 3.0 89/10/27 02:05:48 craig Exp $ X * X * $Log: cylinder.c,v $ X * Revision 3.0 89/10/27 02:05:48 craig X * Baseline for first official release. X * X */ X#include <stdio.h> X#include <math.h> X#include "typedefs.h" X#include "funcdefs.h" X#include "constants.h" X XObject * Xmakcyl(surf, cent, ax, r, trans) Xchar *surf; XVector *cent, *ax; Xdouble r; XTransInfo *trans; X{ X Cylinder *cyl; X Primitive *prim; X Object *newobj; X double len; X extern int yylineno, Quiet; X Vector axis, dir; X X if (r <= 0.) { X if (!Quiet) X fprintf(stderr,"Invalid cylinder radius (line %d)\n", X yylineno); X return (Object *)0; X } X X prim = mallocprim(); X newobj = new_object(NULL, CYL, (char *)prim, (Trans *)NULL); X prim->surf = find_surface(surf); X prim->type = CYL; X cyl = (Cylinder *)Malloc(sizeof(Cylinder)); X prim->objpnt.p_cylinder = cyl; X X axis.x = ax->x - cent->x; X axis.y = ax->y - cent->y; X axis.z = ax->z - cent->z; X X len = normalize(&axis); X if(len < EPSILON) { X if (!Quiet) X fprintf(stderr,"Degenerate cylinder (line %d).\n", X yylineno); X free((char *)cyl); X free((char *)prim); X return (Object *)0; X } X X cyl->rad = r*r; X cyl->len = len; X /* X * Define matrix to transform from axis-aligned to desired cylinder. X */ X dir.x = axis.y; X dir.y = -axis.x; X dir.z = 0.; X rotate(trans, &dir, acos(axis.z)); X translate(trans, cent); X X return newobj; X} X X/* X * Ray-cylinder intersection test. X */ Xdouble Xintcyl(pos, ray, obj) XVector *pos, *ray; XPrimitive *obj; X{ X double t1, t2, a, b, c, zpos1, zpos2, et1, et2, x, y, disc; X extern unsigned long primtests[]; X Cylinder *cyl; X X primtests[CYL]++; X cyl = obj->objpnt.p_cylinder; X X a = ray->x * ray->x + ray->y * ray->y; X c = pos->x*pos->x + pos->y*pos->y - cyl->rad; X X if (a < EPSILON*EPSILON) { /* |ray->z| == 1. */ X if(c < EPSILON*EPSILON) /* Within endcap */ X /* Wrong if origin is inside cylinder. */ X return min(-pos->z / ray->z, X (cyl->len - pos->z) / ray->z); X return 0.; X } X X b = ray->x * pos->x + ray->y * pos->y; X disc = b*b - a*c; X if(disc < 0.) X return 0.; X disc = sqrt(disc); X t1 = (-b + disc) / a; X t2 = (-b - disc) / a; X if(t1 < EPSILON && t2 < EPSILON) X return 0.; X zpos1 = pos->z + t1 * ray->z; X zpos2 = pos->z + t2 * ray->z; X if ((zpos1 > cyl->len && zpos2 > cyl->len) || X (zpos1 < 0. && zpos2 < 0.)) X return 0.; X if (t1 < EPSILON) X t1 = FAR_AWAY; X if (t2 < EPSILON) X t2 = FAR_AWAY; X if (t1 == FAR_AWAY && t2 == FAR_AWAY) X return 0.; X /* X * Don't bother checking endcaps if both intersection points X * are on the cylinder. X */ X if ((zpos1 > 0. && zpos1 < cyl->len && zpos2 > 0. && zpos2 < cyl->len)) X return min(t1, t2); X /* X * It's possible to get rid of the ray-disc intersection tests X * (by looking at t1, t2 and zpos1, zpos), but the code gets messy. X */ X if (zpos1 < 0. || zpos1 > cyl->len) X t1 = FAR_AWAY; X if (zpos2 < 0. || zpos2 > cyl->len) X t2 = FAR_AWAY; X et1 = -pos->z / ray->z; X x = pos->x + et1 * ray->x; X y = pos->y + et1 * ray->y; X if (x*x + y*y > cyl->rad) X et1 = FAR_AWAY; X et2 = (cyl->len - pos->z) / ray->z; X x = pos->x + et2 * ray->x; X y = pos->y + et2 * ray->y; X if (x*x + y*y > cyl->rad) X et2 = FAR_AWAY; X t1 = min(t1, min(t2, min(et1, et2))); X return (t1 == FAR_AWAY ? 0. : t1); X} X Xnrmcyl(pos, obj, nrm) XVector *pos, *nrm; XPrimitive *obj; X{ X Cylinder *cyl; X double dist; X X cyl = obj->objpnt.p_cylinder; X X dist = pos->x*pos->x + pos->y*pos->y; X if (dist+EPSILON < cyl->rad) { X if (equal(pos->z,0.)) { X /* X * Hit on lower endcap. X */ X nrm->x = nrm->y = 0.; X nrm->z = -1.; X } else { X /* X * Hit on upper endcap. X */ X nrm->x = nrm->y = 0.; X nrm->z = 1.; X } X } else { /* Hit along cylinder. */ X nrm->x = pos->x; X nrm->y = pos->y; X nrm->z = 0.; X /* Will be normalized by ShadeRay(). */ X } X} X Xcylextent(o, bounds) XPrimitive *o; Xdouble bounds[2][3]; X{ X Cylinder *cyl; X double r; X cyl = o->objpnt.p_cylinder; X X r = sqrt(cyl->rad); X bounds[LOW][X] = bounds[LOW][Y] = -r; X bounds[HIGH][X] = bounds[HIGH][Y] = r; X bounds[LOW][Z] = 0.; X bounds[HIGH][Z] = cyl->len; X} END_OF_FILE if test 4819 -ne `wc -c <'src/cylinder.c'`; then echo shar: \"'src/cylinder.c'\" unpacked with wrong size! fi # end of 'src/cylinder.c' fi if test -f 'src/intersect.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/intersect.c'\" else echo shar: Extracting \"'src/intersect.c'\" \(6514 characters\) sed "s/^X//" >'src/intersect.c' <<'END_OF_FILE' X/* X * intersect.c X * X * Copyright (C) 1989, Craig E. Kolb X * X * This software may be freely copied, modified, and redistributed, X * provided that this copyright notice is preserved on all copies. X * X * There is no warranty or other guarantee of fitness for this software, X * it is provided solely . Bug reports or fixes may be sent X * to the author, who may or may not act on them as he desires. X * X * You may not include this software in a program or other software product X * without supplying the source, or without informing the end-user that the X * source is available for no extra charge. X * X * If you modify this software, you should include a notice giving the X * name of the person performing the modification, the date of modification, X * and the reason for such modification. X * X * $Id: intersect.c,v 3.0 89/10/27 02:05:53 craig Exp $ X * X * $Log: intersect.c,v $ X * Revision 3.0 89/10/27 02:05:53 craig X * Baseline for first official release. X * X */ X#include <math.h> X#include <stdio.h> X#include "typedefs.h" X#include "funcdefs.h" X#include "constants.h" X X/* X * Primitive intersection routines X */ Xdouble (*objint[])() = {intsph, intbox, inttri, intsup, intplane, intcyl, X intpoly, inttri, intcone, inthf}; X/* X * Primitive normal routines X */ Xint (*objnrm[])() = {nrmsph, nrmbox, nrmtri, nrmsup, nrmplane, nrmcyl, X nrmpoly, nrmtri, nrmcone, nrmhf}; X/* X * object extent box routines X */ Xint (*objextent[])() = {sphextent, boxextent, triextent, supextent, X planeextent, cylextent, polyextent, triextent, X coneextent, hfextent}; X Xunsigned long int primtests[PRIMTYPES], primhits[PRIMTYPES]; X Xchar *primnames[PRIMTYPES] = { "Sphere", "Box", "Triangle", "Superq", "Plane", X "Cylinder", "Polygon", "Phongtri", "Cone", X "Heightfield"}; X X/* X * Flags indicating whether or not we should check for intersection X * with an object's bounding box before we check for intersection X * with the object. X */ Xchar CheckBounds[] = {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, X TRUE, FALSE, FALSE, FALSE}; X X/* X * Top-level raytracing routine. Increment ray number, initialize X * intersection information and trace ray through "World" object. X */ Xdouble XTraceRay(source, ray, hitinfo) XPrimitive *source; XRay *ray; XHitInfo *hitinfo; X{ X extern Object *World; X extern double intersect(); X X return intersect(World, source, ray, hitinfo); X} X X/* X * Intersect object & ray. Return distance from "pos" along "ray" to X * intersection point. Return value <= 0 indicates no intersection. X */ Xdouble Xintersect(obj, source, ray, hitinfo) XObject *obj; /* Object to be tested. */ XPrimitive *source; /* Prim, if any, that pos is on. */ XRay *ray; /* Ray origin, direction. */ XHitInfo *hitinfo; /* Data on intersection (pos, norm) */ X{ X Ray newray; X double dist, distfact, TransformRay(); X extern int Cache; X X /* X * Check ray/bounding volume intersection, if required. X */ X if (CheckBounds[obj->type] && X OutOfBounds(&ray->pos, obj->bounds) && X IntBounds(ray, obj->bounds) < EPSILON) X return 0.; X X newray = *ray; X X /* X * Transform the ray if necessary. X */ X if (obj->trans != (Trans *)0) { 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 = TransformRay(&newray, &obj->trans->world2obj); X } X X /* X * Call correct intersection routine. X */ X if (obj->type == GRID) X dist = int_grid((Grid *)obj->data, source, &newray, hitinfo); X else if (obj->type == LIST) X dist = int_list((List *)obj->data, source, &newray, hitinfo); X else X dist = int_primitive((Primitive *)obj->data, source, &newray, X hitinfo); X X if (dist < EPSILON) X return 0.; X X /* X * If this is a shadow ray, don't bother with texture mapping X * or transformation of normal. X */ X if (ray->shadow) { X if (obj->trans == (Trans *)0) X return dist; X else if (Cache) X /* X * Keep track of total transformation applied to ray X * if necessary. X */ X mmult(hitinfo->totaltrans, &obj->trans->world2obj, X hitinfo->totaltrans); X return dist / distfact; X } X /* X * Perform texture mapping. X */ X if (obj->texture) X apply_textures(hitinfo, obj->texture); X X if (obj->trans) { X /* X * Transform hitinfo structure. As things stand, X * this just means transforming the normal and X * dividing "dist" by the amount the ray was X * stretched. X */ X dist /= distfact; X TransformNormal(&hitinfo->norm, &obj->trans->world2obj); X } X X return dist; X} X X/* X * Intersect ray & primitive object. X */ Xdouble Xint_primitive(prim, source, ray, hitinfo) XPrimitive *prim, *source; XRay *ray; XHitInfo *hitinfo; X{ X double dist; X X if (prim == source && prim->type != HF) X /* X * Don't check for intersection with "source", unless X * source is a height field. (Height fields may shadow X * themselves.) X */ X return 0.; X X dist = (*objint[prim->type]) (&ray->pos, &ray->dir, prim); X X if (dist < EPSILON) X return 0.; X X primhits[prim->type]++; X hitinfo->prim = prim; X hitinfo->surf = *prim->surf; X X if (ray->shadow) X return dist; /* If a shadow ray, don't bother with normal */ X /* X * Calculate point of intersection in object space. X * (The point of intersection in world space is X * calculated in ShadeRay().) X */ X addscaledvec(ray->pos, dist, ray->dir, &hitinfo->pos); X X /* X * Find normal to primitive. X */ X (*objnrm[prim->type]) (&hitinfo->pos, prim, &hitinfo->norm); X X /* X * Make sure normal points towards ray origin. If surface is X * transparent, keep as-is, as the normal indicates whether we're X * entering or exiting. If the prim is a superquadric, don't flip, X * as this leads to strange edge effects. X */ X if (dotp(&ray->dir, &hitinfo->norm) > 0 && hitinfo->surf.transp == 0. && X prim->type != SUPERQ) { X scalar_prod(-1., hitinfo->norm, &hitinfo->norm); X } X X return dist; X} X Xprint_prim_stats() X{ X long int totaltests, totalhits; X extern FILE *fstats; X int i; X X totaltests = totalhits = 0; X for (i = 0; i < PRIMTYPES; i++) { X if (primtests[i] == 0) X continue; X fprintf(fstats,"%s intersection tests:\t%ld (%ld hit, %f%%)\n", X primnames[i], primtests[i], X primhits[i], X 100.*(float)primhits[i]/(float)primtests[i]); X totaltests += primtests[i]; X totalhits += primhits[i]; X } X fprintf(fstats,"Total intersection tests:\t%ld", totaltests); X if (totaltests == 0) X fprintf(fstats,"\n"); X else X fprintf(fstats," (%ld hit, %f%%)\n", totalhits, X 100.*(float)totalhits/(float)totaltests); X} END_OF_FILE if test 6514 -ne `wc -c <'src/intersect.c'`; then echo shar: \"'src/intersect.c'\" unpacked with wrong size! fi # end of 'src/intersect.c' fi if test -f 'src/light.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/light.c'\" else echo shar: Extracting \"'src/light.c'\" \(5124 characters\) sed "s/^X//" >'src/light.c' <<'END_OF_FILE' X/* X * light.c X * X * Copyright (C) 1989, Craig E. Kolb X * X * This software may be freely copied, modified, and redistributed, X * provided that this copyright notice is preserved on all copies. X * X * There is no warranty or other guarantee of fitness for this software, X * it is provided solely . Bug reports or fixes may be sent X * to the author, who may or may not act on them as he desires. X * X * You may not include this software in a program or other software product X * without supplying the source, or without informing the end-user that the X * source is available for no extra charge. X * X * If you modify this software, you should include a notice giving the X * name of the person performing the modification, the date of modification, X * and the reason for such modification. X * X * $Id: light.c,v 3.0 89/10/27 16:17:22 craig Exp $ X * X * $Log: light.c,v $ X * Revision 3.0 89/10/27 16:17:22 craig X * Baseline for first official release. X * X */ X#include <stdio.h> X#include <math.h> X#include "typedefs.h" X#include "funcdefs.h" X#include "constants.h" X Xint nlight; /* # of lights defined */ Xint NoShadows; /* Don't trace shadow rays */ Xint Cache = TRUE; /* Use shadow-caching */ Xint ClearShadows; /* Shadow rays pass through transp. objects */ XLight light[LIGHTS]; /* array of lights */ Xdouble lightdist; /* distance to light */ Xunsigned long CacheWorked, CacheFailed, ShadowHits; X/* X * Calculate ray from position to light # lnum. X */ Xlightray(lp, objpos, lray) XLight *lp; XVector *objpos, *lray; X{ X if(lp->type == DIRECTIONAL) { X /* X * Directional sources only have direction. X */ X *lray = lp->pos; X lightdist = FAR_AWAY; X } else { X /* X * Calculate ray from position to center of X * light source. X */ X vecsub(lp->pos, *objpos, lray); X lightdist = normalize(lray); X } X} X X/* X * Find a coordinate system perpendicular to the ray from X * a point of intersection to the center of an extended light source. X */ XLightCoordSys(lp, pos, vector, xaxis, yaxis) XLight *lp; XVector *pos, *vector, *xaxis, *yaxis; X{ X /* X * Vector should *not* be normalized, xaxis & yaxis should be. X */ X vector->x = lp->pos.x - pos->x; X vector->y = lp->pos.y - pos->y; X vector->z = lp->pos.z - pos->z; X xaxis->x = vector->y; X xaxis->y = -vector->x; X xaxis->z = 0.; X if (normalize(xaxis) == 0.) { X xaxis->x = 0.; X xaxis->y = -vector->z; X xaxis->z = vector->y; X if (normalize(xaxis) == 0.) X fprintf(stderr,"LightCoordSys: Can't find X axis!\n"); X yaxis->x = (vector->y * vector->y) + (vector->z * vector->z); X yaxis->y = -vector->x * vector->y; X yaxis->z = -vector->x * vector->z; X (void)normalize(yaxis); X } else { X yaxis->x = vector->x * vector->z; X yaxis->y = vector->y * vector->z; X yaxis->z = -(vector->x * vector->x) -(vector->y * vector->y); X (void)normalize(yaxis); X } X} X X/* X * Trace ray from point of intersection to a light. If an intersection X * occurs at a distance less than "lightdist" (the distance to the X * light source), then the point is in shadow, and 0 is returned. X * Otherwise, the brightness (color) of the light is returned. This X * color may be modulated by any translucent objects which fall between X * the point of intersection and the light source. X */ Xinshadow(result, source, lp, pos, ray) XColor *result; XPrimitive *source; XLight *lp; XVector *pos, *ray; X{ X double s; X Ray tmpray, tray; X HitInfo hitinfo; X double atten, totaldist, TransformRay(); X extern int level; X extern unsigned long ShadowRays; X extern double TraceRay(); X X if (NoShadows) { X *result = lp->color; X return FALSE; X } X X ShadowRays++; X tmpray.pos = *pos; X tmpray.dir = *ray; /* Medium not needed. */ X tmpray.shadow = TRUE; X hitinfo.totaltrans = &lp->trans[level]; X X /* X * Check shadow cache if necessary. (The following implies X * ... && Cache) X */ X if (lp->cache[level]) { X tray = tmpray; X s = TransformRay(&tray, &lp->trans[level]); X s = int_primitive(lp->cache[level], source, &tray, &hitinfo)/s; X if (s > EPSILON && s < lightdist) { X CacheWorked++; X return TRUE; X } X CacheFailed++; X lp->cache[level] = (Primitive *)0; X } X X if (Cache) X init_trans(hitinfo.totaltrans); X X s = TraceRay(source, &tmpray, &hitinfo); X X if (s < EPSILON || s > lightdist) { X *result = lp->color; X return FALSE; /* Not in shadow. */ X } X X /* X * Otherwise, we've hit something. X */ X ShadowHits++; X if (!ClearShadows || hitinfo.surf.transp == 0.) { X if (Cache) X lp->cache[level] = hitinfo.prim; X return TRUE; X } X /* X * We've hit a transparent object. Attenuate the color X * of the light source and continue the ray until X * we hit background or a non-transparent object. X * Note that this is incorrect if any of the surfaces hit (or X * DefIndex) have differing indices of refraction. X */ X atten = 1.; X totaldist = s; X do { X atten *= hitinfo.surf.transp; X if (atten < EPSILON) X return TRUE; X addscaledvec(tmpray.pos, s, tmpray.dir, &tmpray.pos); X /* X * Trace ray starting at new origin and in the X * same direction. X */ X s = TraceRay(hitinfo.prim, &tmpray, &hitinfo); X totaldist += s; X } while (s > EPSILON && totaldist < lightdist); X X ScaleColor(atten, lp->color, result); X return FALSE; X} END_OF_FILE if test 5124 -ne `wc -c <'src/light.c'`; then echo shar: \"'src/light.c'\" unpacked with wrong size! fi # end of 'src/light.c' fi if test -f 'src/object.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/object.c'\" else echo shar: Extracting \"'src/object.c'\" \(4915 characters\) sed "s/^X//" >'src/object.c' <<'END_OF_FILE' X/* X * object.c X * X * Copyright (C) 1989, Craig E. Kolb X * X * This software may be freely copied, modified, and redistributed, X * provided that this copyright notice is preserved on all copies. X * X * There is no warranty or other guarantee of fitness for this software, X * it is provided solely . Bug reports or fixes may be sent X * to the author, who may or may not act on them as he desires. X * X * You may not include this software in a program or other software product X * without supplying the source, or without informing the end-user that the X * source is available for no extra charge. X * X * If you modify this software, you should include a notice giving the X * name of the person performing the modification, the date of modification, X * and the reason for such modification. X * X * $Id: object.c,v 3.0 89/10/27 02:05:58 craig Exp $ X * X * $Log: object.c,v $ X * Revision 3.0 89/10/27 02:05:58 craig X * Baseline for first official release. X * X */ X#include <stdio.h> X#include <math.h> X#include "constants.h" X#include "typedefs.h" X#include "funcdefs.h" X#include "texture.h" X XObject *World; /* World Object */ XObjList *Objects; /* Linked list of defined objects */ Xint WorldXSize, WorldYSize, WorldZSize; /* World grid resolution */ X X/* X * Create a new object with the given properties. X */ XObject * Xnew_object(name, type, data, trans) Xchar *name, *data; Xchar type; XTrans *trans; X{ X Object *new; X X new = (Object *)share_malloc(sizeof(Object)); X new->name = strsave(name); X new->type = type; X new->data = data; X new->trans = trans; X#ifdef LINDA X /* X * If the counter is in shared memory, processes will X * be modifying it left-and-right. So, we cheat and X * make counter a pointer to a non-shared location and X * store the value there. X */ X new->counter = (unsigned long *)malloc(sizeof(unsigned long)); X *new->counter = 0; X#else X new->counter = 0; X#endif X new->texture = (Texture *)0; X /* X * bounds is left uninitialized. X */ X return new; X} X X/* X * Add a copy of the named object to parent object X */ XObject * Xadd_child_named(name, parent) Xchar *name; XObject *parent; X{ X Object *child, *newobj; X int i; X X child = get_object_named(name); X if (child == (Object *)0) { X fprintf(stderr,"There is no object named \"%s\".\n",name); X exit(1); X } X /* X * Create new object that points to child X * and add to 'parent' list. X */ X newobj = add_child(child, parent); X /* X * New object's bounding box is initally the same X * as the child's. X */ X for (i = 0; i < 3; i++) { X newobj->bounds[0][i] = child->bounds[0][i]; X newobj->bounds[1][i] = child->bounds[1][i]; X } X return newobj; X} X X/* X * Add primitive object to parent object. X */ Xadd_prim(child, parent) XObject *child, *parent; X{ X ObjList *newnode; X X newnode = (ObjList *)share_malloc(sizeof(ObjList)); X newnode->data = child; X if (parent == (Object *)0) { X newnode->next = (ObjList *)World->data; X World->data = (char *)newnode; X } else { X newnode->next = (ObjList *)parent->data; X parent->data = (char *)newnode; X } X} X X/* X * Make a copy of "child" and attach it to parent's linked list X * of objects. X */ XObject * Xadd_child(child, parent) XObject *child, *parent; X{ X Object *newobj; X ObjList *newnode; X X newobj = new_object(NULL, child->type, child->data, child->trans); X newobj->texture = child->texture; X newnode = (ObjList *)share_malloc(sizeof(ObjList)); X newnode->data = newobj; X if (parent == (Object *)0) { X newnode->next = (ObjList *)World->data; X World->data = (char *)newnode; X } else { X newnode->next = (ObjList *)parent->data; X parent->data = (char *)newnode; X } X return newobj; X} X X/* X * Return pointer to named object, NULL if no such object has been defined. X */ XObject * Xget_object_named(name) Xchar *name; X{ X ObjList *ltmp; X for (ltmp = Objects; ltmp; ltmp = ltmp->next) X if (strcmp(name, ltmp->data->name) == 0) X return ltmp->data; X return (Object *)0; X} X X/* X * Add object to list of defined objects. X */ Xadd_to_objects(obj) XObject *obj; X{ X ObjList *ltmp; X extern int Verbose; X extern FILE *fstats; X X ltmp = (ObjList *)Malloc(sizeof(ObjList)); X ltmp->data = obj; X ltmp->next = Objects; X Objects = ltmp; X if (Verbose) { X /* X * Report bounding box of named object. X */ X fprintf(fstats,"Object \"%s\" extent:\n", obj->name); X print_bounds(obj->bounds); X } X} X X/* X * Allocate space for a string, copy string into space. X */ Xchar * Xstrsave(s) Xchar *s; X{ X char *tmp; X X if (s == (char *)0) X return (char *)0; X X tmp = (char *)Malloc((unsigned)strlen(s) + 1); X strcpy(tmp, s); X return tmp; X} X X/* X * Set "bounds" of primitive to be the extent of the primitive. X */ Xset_prim_bounds(obj) XObject *obj; X{ X extern int (*objextent[])(); X X (*objextent[((Primitive *)obj->data)->type]) X ((Primitive *)obj->data, obj->bounds); X obj->bounds[LOW][X] -= EPSILON; X obj->bounds[HIGH][X] += EPSILON; X obj->bounds[LOW][Y] -= EPSILON; X obj->bounds[HIGH][Y] += EPSILON; X obj->bounds[LOW][Z] -= EPSILON; X obj->bounds[HIGH][Z] += EPSILON; X} X END_OF_FILE if test 4915 -ne `wc -c <'src/object.c'`; then echo shar: \"'src/object.c'\" unpacked with wrong size! fi # end of 'src/object.c' fi if test -f 'src/ray_options.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/ray_options.c'\" else echo shar: Extracting \"'src/ray_options.c'\" \(6048 characters\) sed "s/^X//" >'src/ray_options.c' <<'END_OF_FILE' X/* X * ray_options.c X * X * Copyright (C) 1989, Craig E. Kolb X * X * This software may be freely copied, modified, and redistributed, X * provided that this copyright notice is preserved on all copies. X * X * There is no warranty or other guarantee of fitness for this software, X * it is provided solely . Bug reports or fixes may be sent X * to the author, who may or may not act on them as he desires. X * X * You may not include this software in a program or other software product X * without supplying the source, or without informing the end-user that the X * source is available for no extra charge. X * X * If you modify this software, you should include a notice giving the X * name of the person performing the modification, the date of modification, X * and the reason for such modification. X * X * $Id: ray_options.c,v 3.0 89/10/27 02:06:00 craig Exp $ X * X * $Log: ray_options.c,v $ X * Revision 3.0 89/10/27 02:06:00 craig X * Baseline for first official release. X * X */ X#include <stdio.h> X#ifdef SYSV X#include <string.h> X#else X#include <strings.h> X#endif X#include "constants.h" X#include "typedefs.h" X Xint Verbose; /* Blabbering flag */ Xint TrashBadPoly; /* Discard even mildly bad polygons */ Xint Quiet; /* Don't be so verbose flag */ Xchar *progname; /* argv[0] */ X X#ifdef LINDA Xint Workers; /* # of workers */ X#endif X Xparse_options(argc, argv) Xint argc; Xchar **argv; X{ X extern char *infilename; X extern double RedContrast, GreenContrast, BlueContrast, atof(); X extern int pixel_div, JitSamples, Xres, Yres, Jittered, Cache; X extern int Stereo, StartLine, Appending, NoShadows, ClearShadows; X extern double Separation, TreeCutoff; X extern char outfilename[]; X extern FILE *fstats; X X progname = argv[0]; X fstats = stderr; X X while(--argc) { X argv++; X if(argv[0][0] != '-') X break; X switch(argv[0][1]) { X case 'C': X RedContrast = atof(argv[1]); X GreenContrast = atof(argv[2]); X BlueContrast = atof(argv[3]); X argv += 3; X argc -= 3; X break; X case 'c': X ClearShadows = TRUE; X break; X case 'E': X Separation = atof(argv[1]); X argc--; argv++; X break; X case 'h': X usage(); X exit(0); X break; X case 'j': X Jittered = TRUE; X break; X case 'L': X StartLine = atoi(argv[1]); X Appending = TRUE; X argc--; argv++; X break; X case 'l': X Stereo = LEFT; X break; X case 'n': X NoShadows = TRUE; X break; X case 'O': X strcpy(outfilename, argv[1]); X argv++; X argc--; X break; X case 'P': X pixel_div = atoi(argv[1]); X if(pixel_div < 0) X pixel_div = 0; X argv++; X argc--; X break; X case 'p': X TrashBadPoly = TRUE; X break; X case 'q': X Quiet = TRUE; X break; X case 'R': X Xres = atoi(argv[1]); X Yres = atoi(argv[2]); X argv += 2; X argc -= 2; X break; X case 'r': X Stereo = RIGHT; X break; X case 'S': X JitSamples = atoi(argv[1]); X if (JitSamples < 1) X JitSamples = 1; X argv++; argc--; X break; X case 's': X Cache = !Cache; X break; X case 'T': X TreeCutoff = atof(argv[1]); X argv++; argc--; X break; X case 'v': X Verbose = TRUE; X break; X case 'V': X Verbose = TRUE; X if (argv[1][0] == '-') { X /* User probably blew it, and X * it's difficult to remove a file X * that begins with '-'... X */ X usage(); X exit(2); X } X fstats = fopen(argv[1], "w"); X if (fstats == (FILE *)0) { X fprintf(stderr,"Cannot write to stats file %s\n",argv[0]); X exit(2); X } X argv++; argc--; X break; X#ifdef LINDA X case 'W': X Workers = atoi(argv[1]); X if (Workers < 0 || Workers > 17) { X fprintf(stderr,"%d workers?!?\n", X Workers); X exit(3); X } X argv++; argc--; X break; X#endif X default: X fprintf(stderr,"Bad argument: \"%s\"\n",argv[0]); X usage(); X exit(1); X } X } X X if(argc > 1) { X usage(); X exit(1); X } else if(argc == 1) X infilename = argv[0]; X else X infilename = (char *)NULL; X X /* X * Although the user may have defined the output file name X * in the input file, it's best to force them to give a filename X * on the command line if using the -L option. This saves situations X * where they forget to specify an output file to append to but X * aren't informed of it until startpic() is called (after the X * entire input file is read). X */ X if (Appending && *outfilename == (char)NULL) { X fprintf(stderr,"The -L option requires the -O option.\n"); X exit(4); X } X X if (Stereo && Separation == 0.) { X fprintf(stderr,"You must specify eye separation (-E) in order "); X fprintf(stderr,"to enable Stereo mode.\n"); X exit(4); X } X} X Xusage() X{ X fprintf(stderr,"usage: %s [options] [filename]\n", progname); X fprintf(stderr,"Where options include:\n"); X fprintf(stderr,"\t-C r g b\t(Set contrast threshold (0. - 1.).)\n"); X fprintf(stderr,"\t-c \t\t(Trace shadow rays through clear objects.)\n"); X fprintf(stderr,"\t-E eye_sep\t(Set eye separation.)\n"); X fprintf(stderr,"\t-h \t\t(Print this message.)\n"); X fprintf(stderr,"\t-j \t\t(Antialias using jittered sampling.)\n"); X fprintf(stderr,"\t-L line#\t(Begin rendering at specified line.)\n"); X fprintf(stderr,"\t-l \t\t(Render image for left eye view.)\n"); X fprintf(stderr,"\t-n \t\t(Don't compute shadows.)\n"); X fprintf(stderr,"\t-O outfile \t(Specify output file name.)\n"); X fprintf(stderr,"\t-P pixel_divs\t(Set max depth for adaptive supersampling.)\n"); X fprintf(stderr,"\t-p \t\t(Discard polygons with degenerate edges.)\n"); X fprintf(stderr,"\t-q \t\t(Run quietly.)\n"); X fprintf(stderr,"\t-R xres yres\t(Render at given resolution.)\n"); X fprintf(stderr,"\t-r \t\t(Render image for right eye view.)\n"); X fprintf(stderr,"\t-S samples\t(Use samples^2 jittered samples.)\n"); X fprintf(stderr,"\t-s \t\t(Don't cache shadowing information.)\n"); X fprintf(stderr,"\t-T thresh\t(Set adaptive ray tree cutoff value.)\n"); X fprintf(stderr,"\t-V filename \t(Write verbose output to filename.)\n"); X fprintf(stderr,"\t-v \t\t(Verbose output.)\n"); X#ifdef LINDA X fprintf(stderr,"\t-W workers (Specify number of worker processes.)\n"); X#endif X} END_OF_FILE if test 6048 -ne `wc -c <'src/ray_options.c'`; then echo shar: \"'src/ray_options.c'\" unpacked with wrong size! fi # end of 'src/ray_options.c' fi if test -f 'src/voxels.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/voxels.c'\" else echo shar: Extracting \"'src/voxels.c'\" \(4916 characters\) sed "s/^X//" >'src/voxels.c' <<'END_OF_FILE' X/* X * voxels.c X * X * Copyright (C) 1989, Craig E. Kolb X * X * This software may be freely copied, modified, and redistributed, X * provided that this copyright notice is preserved on all copies. X * X * There is no warranty or other guarantee of fitness for this software, X * it is provided solely . Bug reports or fixes may be sent X * to the author, who may or may not act on them as he desires. X * X * You may not include this software in a program or other software product X * without supplying the source, or without informing the end-user that the X * source is available for no extra charge. X * X * If you modify this software, you should include a notice giving the X * name of the person performing the modification, the date of modification, X * and the reason for such modification. X * X * $Id: voxels.c,v 3.0 89/10/27 02:06:09 craig Exp $ X * X * $Log: voxels.c,v $ X * Revision 3.0 89/10/27 02:06:09 craig X * Baseline for first official release. X * X */ X#include <math.h> X#include <stdio.h> X#include "constants.h" X#include "typedefs.h" X#include "funcdefs.h" X X/* X * Process World object, converting to a Grid or List. X */ XSetupWorld() X{ X extern FILE *fstats; X extern Object *World; X extern int WorldXSize, WorldYSize, WorldZSize, Verbose; X X if (World->type == GRID) X list2grid(World, WorldXSize, WorldYSize, WorldZSize); X else X make_list(World); X X if (Verbose) { X fprintf(fstats,"World extent:\n"); X print_bounds(World->bounds); X } X} X X/* X * Add object to grid's unbounded list. X */ Xmake_unbounded(obj, grid) XObject *obj; XGrid *grid; X{ X ObjList *tmp; X X tmp = (ObjList *)Malloc(sizeof(ObjList)); X X tmp->data = obj; X tmp->next = grid->unbounded; X grid->unbounded = tmp; X} X X/* X * Place an object in a grid. X */ Xengrid(obj, grid) XObject *obj; XGrid *grid; X{ X int x, y, z, low[3], high[3]; X ObjList *ltmp; X X /* X * This routine should *never* be passed an unbounded object, but... X */ X if (pos2grid(grid, obj->bounds[LOW], low) == 0 || X pos2grid(grid, obj->bounds[HIGH], high) == 0 || X obj->bounds[LOW][X] > obj->bounds[HIGH][X]) { X /* X * Object is partially on wholly outside of X * grid -- this should never happen, but just X * in case... X */ X make_unbounded(obj, grid); X fprintf(stderr,"Strange, engrid got an unbounded object...\n"); X return; X } X X /* X * For each voxel that intersects the object's bounding X * box, add pointer to this object to voxel's linked list. X */ X for (x = low[X]; x <= high[X]; x++) { X for (y = low[Y]; y <= high[Y]; y++) { X for (z = low[Z]; z <= high[Z]; z++) { X ltmp = (ObjList *)share_malloc(sizeof(ObjList)); X ltmp->data = obj; X ltmp->next = grid->cells[x][y][z]; X grid->cells[x][y][z] = ltmp; X } X } X } X} X X/* X * Convert 3D point to index into grid's voxels. X */ Xpos2grid(grid, pos, index) XGrid *grid; Xdouble pos[3]; Xint index[3]; X{ X index[X] = (int)(x2voxel(grid, pos[0])); X index[Y] = (int)(y2voxel(grid, pos[1])); X index[Z] = (int)(z2voxel(grid, pos[2])); X X if (index[X] == grid->xsize) X index[X] = grid->xsize -1; X if (index[Y] == grid->ysize) X index[Y] = grid->ysize -1; X if (index[Z] == grid->zsize) X index[Z] = grid->zsize -1; X X if (index[X] < 0 || index[X] >= grid->xsize || X index[Y] < 0 || index[Y] >= grid->ysize || X index[Z] < 0 || index[Z] >= grid->zsize) X return 0; X return 1; X} X X/* X * Convert a linked list of objects to a Grid. X */ Xlist2grid(obj, xsize, ysize, zsize) XObject *obj; Xint xsize, ysize, zsize; X{ X Grid *grid; X Object *otmp; X ObjList *ltmp; X int x, y, i; X extern ObjList *find_bounds(); X X grid = (Grid *)Malloc(sizeof(Grid)); X X /* X * Find bounding box of bounded objects and get list of X * unbounded objects. X */ X grid->unbounded = find_bounds((ObjList **)&obj->data, obj->bounds); X X grid->xsize = xsize; grid->ysize = ysize; grid->zsize = zsize; X X for (i = 0; i < 3; i++) { X obj->bounds[LOW][i] -= 2. * EPSILON; X obj->bounds[HIGH][i] += 2. * EPSILON; X grid->bounds[LOW][i] = obj->bounds[LOW][i]; X grid->bounds[HIGH][i] = obj->bounds[HIGH][i]; X } X grid->voxsize[X] = (grid->bounds[HIGH][X]-grid->bounds[LOW][X])/xsize; X grid->voxsize[Y] = (grid->bounds[HIGH][Y]-grid->bounds[LOW][Y])/ysize; X grid->voxsize[Z] = (grid->bounds[HIGH][Z]-grid->bounds[LOW][Z])/zsize; X X /* X * Allocate voxels. X */ X grid->cells = (ObjList ****)share_malloc(xsize * sizeof(ObjList ***)); X for (x = 0; x < xsize; x++) { X grid->cells[x] = (ObjList ***)share_malloc(ysize*sizeof(ObjList **)); X for (y = 0; y < ysize; y++) X grid->cells[x][y] = (ObjList **)share_calloc((unsigned)zsize, X sizeof(ObjList *)); X } X X /* X * obj->data now holds a linked list of bounded objects. X */ X for(ltmp = (ObjList *)obj->data; ltmp; ltmp = ltmp->next) { X otmp = ltmp->data; X engrid(otmp, grid); X free(ltmp); X } X obj->type = GRID; X obj->data = (char *)grid; X} X#ifdef MULTIMAX X Xchar * Xshare_calloc(num, siz) Xint num; Xunsigned int siz; X{ X char *res; X X res = share_malloc(num*siz); X bzero(res, num*siz); X return res; X} X#endif END_OF_FILE if test 4916 -ne `wc -c <'src/voxels.c'`; then echo shar: \"'src/voxels.c'\" unpacked with wrong size! fi # end of 'src/voxels.c' fi echo shar: End of archive 3 \(of 8\). cp /dev/null ark3isdone MISSING="" for I in 1 2 3 4 5 6 7 8 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 8 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.