v21i010: A ray tracing program, Part03/08
Rich Salz
rsalz at bbn.com
Thu Feb 8 07:49:29 AEST 1990
Submitted-by: Craig Kolb <craig at 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 at 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 at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list