v21i011: A ray tracing program, Part04/08

Rich Salz rsalz at uunet.uu.net
Thu Feb 8 07:49:47 AEST 1990


Submitted-by: Craig Kolb <craig at weedeater.math.yale.edu>
Posting-number: Volume 21, Issue 11
Archive-name: rayshade/part04

#! /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 4 (of 8)."
# Contents:  src/Makefile src/malloc.c src/noise.c src/poly.c
#   src/texture.c src/triangle.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/Makefile'\"
else
echo shar: Extracting \"'src/Makefile'\" \(7691 characters\)
sed "s/^X//" >'src/Makefile' <<'END_OF_FILE'
X#
X# Makefile for rayshade.
X#
X# Craig Kolb
X#
X# $Id: Makefile,v 3.0 89/10/27 02:05:45 craig Exp $
X#
X# $Log:	Makefile,v $
X# Revision 3.0  89/10/27  02:05:45  craig
X# Baseline for first official release.
X# 
X# Location of Utah-raster library and include files, if appropriate.
X# If you are compiling with -DNORLE, leave these two undefined.
X#
XRLELIB = /usr/u/utah/lib/librle.a
XRLEINC = /usr/u/utah/include
X#
X# Linda compiler, if appropriate.
X#
X#LCC = /homes/systems/carriero/linda/v2.2/bin/clc
X#
X# Temporary file directory, bin direction, and executable name.
X#
XTMPDIR = /tmp
XBINDIR = /usr/u/craig/bin
XSHADENAME = rayshade
X#
X# Compiler flags.
X#
X# GENERIC (BSD):	CFLAGS = -I$(RLEINC) -DTMPDIR=\"$(TMPDIR)\"
X# SYSV:			add -DSYSV
X#
X# Multimax (shared memory):
X#			add -DMULTIMAX
X# Linda:		add -DLINDA (and move raytrace.c to raytrace.cl)
X#
X# Long ago, rayshade was compiled on the Amiga using Aztec C and:
X#			CFLAGS = +fi +C +D +L -DTMPDIR="t:" -DAZTEC
X# 
X# If you are not using the Utah Raster toolkit, add -DNORLE
X# If your compiler doesn't understand the void type, add -DNOVOID
X#
X# If your compiler has trouble with the definitions of
X# vecadd(), veccomb(), etc. in funcdefs.h, compile with -DDUMB_CPP
X#
X# Be sure to add any necessary floating-point hardware switches.
X# 
XCFLAGS = -I$(RLEINC) -DTMPDIR=\"$(TMPDIR)\" -O -DSYSV
X#
X# Libraries:
X# BSD:		LIBS = $(RLELIB) -lm
X# SYSV:		LIBS = $(RLELIB) -lm
X# AZTEC C (amiga):
X#		LIBS = $(RLELIB) -lUnixl32 -lmal32 -lml32 -lcl32
X#
X# Multimax:	LIBS = $(RLELIB) -lm -lpp
X#
X# If you have fast versions of malloc/free available, use them
X# (e.g., -lmalloc on MIPS machines).
X#
XLIBS = $(RLELIB) -lm -lmalloc
X#
X# Uncomment the following line if you want the
X# fast malloc routines in malloc.c to be used.
X#
X#MALLOC.O = malloc.o
X
X#
X# Change "raytrace.o" to "raytrace.lo" below if using Linda.
X#
XOBJ = 		main.o ray_options.o setup.o input.o input_yacc.o input_lex.o \
X		viewing.o object.o bounds.o voxels.o list.o surface.o \
X		raymath.o matrix.o raytrace.o intersect.o grid.o box.o cone.o \
X		cylinder.o hf.o plane.o poly.o sphere.o superq.o triangle.o \
X		texture.o noise.o shade.o atmosphere.o light.o outputp.o \
X		memory.o version.o $(MALLOC.O)
X
XSRC = 		main.c ray_options.c setup.c input.c input_yacc.c input_lex.c \
X		viewing.c object.c bounds.c voxels.c list.c surface.c \
X		raymath.c matrix.c raytrace.c intersect.c grid.c box.c cone.c \
X		cylinder.c hf.c plane.c poly.c sphere.c superq.c triangle.c \
X		texture.c noise.c shade.c atmosphere.c light.c outputp.c \
X		memory.c version.c
X#
X# Change $(CC) below to $(LCC) if using Linda.
X#
X$(SHADENAME): $(OBJ)
X	$(CC) $(CFLAGS) -o $(SHADENAME) $(OBJ) $(LIBS)
X
X#
X# Uncomment the following rule if using Linda.
X#
X#raytrace.lo: raytrace.cl
X#	$(LCC) $(CFLAGS) -c raytrace.cl
X
X#
X# End of configuration section
X#
Xinstall:	$(SHADENAME)
X		mv $(SHADENAME) $(BINDIR)/$(SHADENAME)
X
Xinput_yacc.c:	input_yacc.y
X		yacc -d input_yacc.y
X		mv y.tab.c input_yacc.c
X
Xinput_lex.c:	input_lex.l
X		lex -t input_lex.l > input_lex.c
X
Xclean:
X	@ /bin/rm -f $(OBJ) core
X
Xrealclean:
X	@ /bin/rm -f $(OBJ) core input_lex.c input_yacc.c y.tab.h
X
Xlint:
X	lint $(CFLAGS) $(SRC)
X
Xdepend:
X	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
X	 cc -M ${CFLAGS} ${SRC} | sed 's/\.\///; /\//d' \
X	) >Makefile.new
X	cp Makefile Makefile.bak
X	cp Makefile.new Makefile
X	rm -f Makefile.new
X
Xarchive:
X	(cd .. ;  tar cvf ../rayshade.arch.tar .)
X
Xkit:
X	(cd .. ; makekit -iPACKING_LIST -oMANIFEST)
X
X# DO NOT DELETE THIS LINE
Xmain.o: main.c
Xmain.o: constants.h
Xmain.o: typedefs.h
Xmain.o: datatypes.h
Xmain.o: primobj.h
Xmain.o: defaults.h
Xray_options.o: ray_options.c
Xray_options.o: constants.h
Xray_options.o: typedefs.h
Xray_options.o: datatypes.h
Xray_options.o: primobj.h
Xsetup.o: setup.c
Xsetup.o: constants.h
Xsetup.o: defaults.h
Xsetup.o: typedefs.h
Xsetup.o: datatypes.h
Xsetup.o: primobj.h
Xsetup.o: funcdefs.h
Xinput.o: input.c
Xinput.o: constants.h
Xinput.o: typedefs.h
Xinput.o: datatypes.h
Xinput.o: primobj.h
Xinput_yacc.o: input_yacc.c
Xinput_yacc.o: constants.h
Xinput_yacc.o: typedefs.h
Xinput_yacc.o: datatypes.h
Xinput_yacc.o: primobj.h
Xinput_yacc.o: funcdefs.h
Xinput_yacc.o: texture.h
Xinput_lex.o: input_lex.c
Xinput_lex.o: typedefs.h
Xinput_lex.o: datatypes.h
Xinput_lex.o: primobj.h
Xinput_lex.o: y.tab.h
Xviewing.o: viewing.c
Xviewing.o: constants.h
Xviewing.o: typedefs.h
Xviewing.o: datatypes.h
Xviewing.o: primobj.h
Xviewing.o: funcdefs.h
Xobject.o: object.c
Xobject.o: constants.h
Xobject.o: typedefs.h
Xobject.o: datatypes.h
Xobject.o: primobj.h
Xobject.o: funcdefs.h
Xobject.o: texture.h
Xbounds.o: bounds.c
Xbounds.o: constants.h
Xbounds.o: typedefs.h
Xbounds.o: datatypes.h
Xbounds.o: primobj.h
Xbounds.o: funcdefs.h
Xvoxels.o: voxels.c
Xvoxels.o: constants.h
Xvoxels.o: typedefs.h
Xvoxels.o: datatypes.h
Xvoxels.o: primobj.h
Xvoxels.o: funcdefs.h
Xlist.o: list.c
Xlist.o: constants.h
Xlist.o: typedefs.h
Xlist.o: datatypes.h
Xlist.o: primobj.h
Xlist.o: funcdefs.h
Xsurface.o: surface.c
Xsurface.o: constants.h
Xsurface.o: typedefs.h
Xsurface.o: datatypes.h
Xsurface.o: primobj.h
Xsurface.o: funcdefs.h
Xraymath.o: raymath.c
Xraymath.o: typedefs.h
Xraymath.o: datatypes.h
Xraymath.o: primobj.h
Xraymath.o: constants.h
Xraymath.o: funcdefs.h
Xmatrix.o: matrix.c
Xmatrix.o: typedefs.h
Xmatrix.o: datatypes.h
Xmatrix.o: primobj.h
Xmatrix.o: constants.h
Xmatrix.o: funcdefs.h
Xraytrace.o: raytrace.c
Xraytrace.o: typedefs.h
Xraytrace.o: datatypes.h
Xraytrace.o: primobj.h
Xraytrace.o: constants.h
Xraytrace.o: funcdefs.h
Xraytrace.o: raytrace.h
Xintersect.o: intersect.c
Xintersect.o: typedefs.h
Xintersect.o: datatypes.h
Xintersect.o: primobj.h
Xintersect.o: funcdefs.h
Xintersect.o: constants.h
Xgrid.o: grid.c
Xgrid.o: constants.h
Xgrid.o: typedefs.h
Xgrid.o: datatypes.h
Xgrid.o: primobj.h
Xgrid.o: funcdefs.h
Xbox.o: box.c
Xbox.o: constants.h
Xbox.o: typedefs.h
Xbox.o: datatypes.h
Xbox.o: primobj.h
Xbox.o: funcdefs.h
Xcone.o: cone.c
Xcone.o: typedefs.h
Xcone.o: datatypes.h
Xcone.o: primobj.h
Xcone.o: funcdefs.h
Xcone.o: constants.h
Xcylinder.o: cylinder.c
Xcylinder.o: typedefs.h
Xcylinder.o: datatypes.h
Xcylinder.o: primobj.h
Xcylinder.o: funcdefs.h
Xcylinder.o: constants.h
Xhf.o: hf.c
Xhf.o: typedefs.h
Xhf.o: datatypes.h
Xhf.o: primobj.h
Xhf.o: funcdefs.h
Xhf.o: constants.h
Xplane.o: plane.c
Xplane.o: constants.h
Xplane.o: typedefs.h
Xplane.o: datatypes.h
Xplane.o: primobj.h
Xplane.o: funcdefs.h
Xpoly.o: poly.c
Xpoly.o: constants.h
Xpoly.o: typedefs.h
Xpoly.o: datatypes.h
Xpoly.o: primobj.h
Xpoly.o: funcdefs.h
Xsphere.o: sphere.c
Xsphere.o: constants.h
Xsphere.o: typedefs.h
Xsphere.o: datatypes.h
Xsphere.o: primobj.h
Xsphere.o: funcdefs.h
Xsuperq.o: superq.c
Xsuperq.o: constants.h
Xsuperq.o: typedefs.h
Xsuperq.o: datatypes.h
Xsuperq.o: primobj.h
Xsuperq.o: funcdefs.h
Xtriangle.o: triangle.c
Xtriangle.o: constants.h
Xtriangle.o: typedefs.h
Xtriangle.o: datatypes.h
Xtriangle.o: primobj.h
Xtriangle.o: funcdefs.h
Xtexture.o: texture.c
Xtexture.o: constants.h
Xtexture.o: typedefs.h
Xtexture.o: datatypes.h
Xtexture.o: primobj.h
Xtexture.o: funcdefs.h
Xtexture.o: texture.h
Xnoise.o: noise.c
Xnoise.o: constants.h
Xnoise.o: typedefs.h
Xnoise.o: datatypes.h
Xnoise.o: primobj.h
Xnoise.o: funcdefs.h
Xshade.o: shade.c
Xshade.o: constants.h
Xshade.o: typedefs.h
Xshade.o: datatypes.h
Xshade.o: primobj.h
Xshade.o: funcdefs.h
Xatmosphere.o: atmosphere.c
Xatmosphere.o: typedefs.h
Xatmosphere.o: datatypes.h
Xatmosphere.o: primobj.h
Xatmosphere.o: constants.h
Xatmosphere.o: funcdefs.h
Xlight.o: light.c
Xlight.o: typedefs.h
Xlight.o: datatypes.h
Xlight.o: primobj.h
Xlight.o: funcdefs.h
Xlight.o: constants.h
Xoutputp.o: outputp.c
Xoutputp.o: typedefs.h
Xoutputp.o: datatypes.h
Xoutputp.o: primobj.h
Xoutputp.o: constants.h
Xoutputp.o: funcdefs.h
Xmemory.o: memory.c
Xmemory.o: typedefs.h
Xmemory.o: datatypes.h
Xmemory.o: primobj.h
Xmemory.o: funcdefs.h
Xversion.o: version.c
Xversion.o: patchlevel.h
END_OF_FILE
if test 7691 -ne `wc -c <'src/Makefile'`; then
    echo shar: \"'src/Makefile'\" unpacked with wrong size!
fi
# end of 'src/Makefile'
fi
if test -f 'src/malloc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/malloc.c'\"
else
echo shar: Extracting \"'src/malloc.c'\" \(9119 characters\)
sed "s/^X//" >'src/malloc.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char sccsid[] = "@(#)malloc.c	4.3 (Berkeley) 9/16/83";
X#endif
X
X/*
X * malloc.c (Caltech) 2/21/82
X * Chris Kingsley, kingsley at cit-20.
X *
X * This is a very fast storage allocator.  It allocates blocks of a small
X * number of different sizes, and keeps free lists of each size.  Blocks that
X * don't exactly fit are passed up to the next larger size.  In this
X * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
X * This is designed for use in a program that uses vast quantities of memory,
X * but bombs when it runs out.
X */
X
X#include <sys/types.h>
X
X#define	NULL 0
X
X/*
X * The overhead on a block is at least 4 bytes.  When free, this space
X * contains a pointer to the next free block, and the bottom two bits must
X * be zero.  When in use, the first byte is set to MAGIC, and the second
X * byte is the size index.  The remaining bytes are for alignment.
X * If range checking is enabled and the size of the block fits
X * in two bytes, then the top two bytes hold the size of the requested block
X * plus the range checking words, and the header word MINUS ONE.
X */
Xunion	overhead {
X	union	overhead *ov_next;	/* when free */
X	struct {
X		u_char	ovu_magic;	/* magic number */
X		u_char	ovu_index;	/* bucket # */
X#ifdef RCHECK
X		u_short	ovu_size;	/* actual block size */
X		u_int	ovu_rmagic;	/* range magic number */
X#endif
X	} ovu;
X#define	ov_magic	ovu.ovu_magic
X#define	ov_index	ovu.ovu_index
X#define	ov_size		ovu.ovu_size
X#define	ov_rmagic	ovu.ovu_rmagic
X};
X
X#define	MAGIC		0xff		/* magic # on accounting info */
X#define RMAGIC		0x55555555	/* magic # on range info */
X#ifdef RCHECK
X#define	RSLOP		sizeof (u_int)
X#else
X#define	RSLOP		0
X#endif
X
X/*
X * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
X * smallest allocatable block is 8 bytes.  The overhead information
X * precedes the data area returned to the user.
X */
X#define	NBUCKETS 30
Xstatic	union overhead *nextf[NBUCKETS];
Xextern	char *sbrk();
X
X#ifdef MSTATS
X/*
X * nmalloc[i] is the difference between the number of mallocs and frees
X * for a given block size.
X */
Xstatic	u_int nmalloc[NBUCKETS];
X#include <stdio.h>
X#endif
X
X#ifdef debug
X#define	ASSERT(p)   if (!(p)) botch("p"); else
Xstatic
Xbotch(s)
X	char *s;
X{
X
X	printf("assertion botched: %s\n", s);
X	abort();
X}
X#else
X#define	ASSERT(p)
X#endif
X
Xchar *
Xmalloc(nbytes)
X	register unsigned nbytes;
X{
X  	register union overhead *p;
X  	register int bucket = 0;
X  	register unsigned shiftr;
X
X	/*
X	 * Convert amount of memory requested into
X	 * closest block size stored in hash buckets
X	 * which satisfies request.  Account for
X	 * space used per block for accounting.
X	 */
X  	nbytes += sizeof (union overhead) + RSLOP;
X  	nbytes = (nbytes + 3) &~ 3;
X  	shiftr = (nbytes - 1) >> 2;
X	/* apart from this loop, this is O(1) */
X  	while (shiftr >>= 1)
X  		bucket++;
X	/*
X	 * If nothing in hash bucket right now,
X	 * request more memory from the system.
X	 */
X  	if (nextf[bucket] == NULL)
X  		morecore(bucket);
X  	if ((p = (union overhead *)nextf[bucket]) == NULL)
X  		return (NULL);
X	/* remove from linked list */
X  	nextf[bucket] = nextf[bucket]->ov_next;
X	p->ov_magic = MAGIC;
X	p->ov_index= bucket;
X#ifdef MSTATS
X  	nmalloc[bucket]++;
X#endif
X#ifdef RCHECK
X	/*
X	 * Record allocated size of block and
X	 * bound space with magic numbers.
X	 */
X  	if (nbytes <= 0x10000)
X		p->ov_size = nbytes - 1;
X	p->ov_rmagic = RMAGIC;
X  	*((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
X#endif
X  	return ((char *)(p + 1));
X}
X
X/*
X * Allocate more memory to the indicated bucket.
X */
Xstatic
Xmorecore(bucket)
X	register bucket;
X{
X  	register union overhead *op;
X  	register int rnu;       /* 2^rnu bytes will be requested */
X  	register int nblks;     /* become nblks blocks of the desired size */
X	register int siz;
X
X  	if (nextf[bucket])
X  		return;
X	/*
X	 * Insure memory is allocated
X	 * on a page boundary.  Should
X	 * make getpageize call?
X	 */
X  	op = (union overhead *)sbrk(0);
X  	if ((int)op & 0x3ff)
X  		sbrk(1024 - ((int)op & 0x3ff));
X	/* take 2k unless the block is bigger than that */
X  	rnu = (bucket <= 8) ? 11 : bucket + 3;
X  	nblks = 1 << (rnu - (bucket + 3));  /* how many blocks to get */
X  	if (rnu < bucket)
X		rnu = bucket;
X	op = (union overhead *)sbrk(1 << rnu);
X	/* no more room! */
X  	if ((int)op == -1) {
X		for (rnu=bucket; rnu < NBUCKETS; rnu++) {
X			if (nextf[rnu]) break;
X		}
X		if (rnu >= NBUCKETS)
X			return;
X		/* Split into halves until bucket-sized */
X		op = nextf[rnu];
X		nextf[rnu] = op->ov_next;
X		while (--rnu > bucket) {
X			siz = 1 << (rnu + 3);
X			op->ov_next = nextf[rnu]; /* == NULL */
X			nextf[rnu] = op;
X			op = (union overhead *)((caddr_t) op + siz);
X		}
X		nblks = 2;
X	}
X	/*
X	 * Round up to minimum allocation size boundary
X	 * and deduct from block count to reflect.
X	 */
X  	if ((int)op & 7) {
X  		op = (union overhead *)(((int)op + 8) &~ 7);
X  		nblks--;
X  	}
X	/*
X	 * Add new memory allocated to that on
X	 * free list for this hash bucket.
X	 */
X  	nextf[bucket] = op;
X  	siz = 1 << (bucket + 3);
X  	while (--nblks > 0) {
X		op->ov_next = (union overhead *)((caddr_t)op + siz);
X		op = (union overhead *)((caddr_t)op + siz);
X  	}
X	op->ov_next = NULL;
X}
X
Xfree(cp)
X	char *cp;
X{
X  	register int size;
X	register union overhead *op;
X
X  	if (cp == NULL)
X  		return;
X	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
X#ifdef debug
X  	ASSERT(op->ov_magic == MAGIC);		/* make sure it was in use */
X#else
X	if (op->ov_magic != MAGIC)
X		return;				/* sanity */
X#endif
X#ifdef RCHECK
X  	ASSERT(op->ov_rmagic == RMAGIC);
X	if (op->ov_index <= 13)
X		ASSERT(*(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC);
X#endif
X  	ASSERT(op->ov_index < NBUCKETS);
X  	size = op->ov_index;
X	op->ov_next = nextf[size];
X  	nextf[size] = op;
X#ifdef MSTATS
X  	nmalloc[size]--;
X#endif
X}
X
X/*
X * When a program attempts "storage compaction" as mentioned in the
X * old malloc man page, it realloc's an already freed block.  Usually
X * this is the last block it freed; occasionally it might be farther
X * back.  We have to search all the free lists for the block in order
X * to determine its bucket: 1st we make one pass thru the lists
X * checking only the first block in each; if that fails we search
X * ``realloc_srchlen'' blocks in each list for a match (the variable
X * is extern so the caller can modify it).  If that fails we just copy
X * however many bytes was given to realloc() and hope it's not huge.
X */
Xint realloc_srchlen = -1;	/* -1 => search whole list */
X
Xchar *
Xrealloc(cp, nbytes)
X	char *cp;
X	unsigned nbytes;
X{
X  	register u_int onb;
X	union overhead *op;
X  	char *res;
X	register int i;
X	int was_alloced = 0;
X
X  	if (cp == NULL)
X  		return (malloc(nbytes));
X	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
X	if (op->ov_magic == MAGIC) {
X		was_alloced++;
X		i = op->ov_index;
X	} else {
X		/*
X		 * Already free, doing "compaction".
X		 *
X		 * Search for the old block of memory on the
X		 * free list.  First, check the most common
X		 * case (last element free'd), then (this failing)
X		 * the last ``realloc_srchlen'' items free'd.
X		 * If all lookups fail, then assume the size of
X		 * the memory block being realloc'd is the
X		 * smallest possible.
X		 */
X		if ((i = findbucket(op, 1)) < 0 &&
X		    (i = findbucket(op, realloc_srchlen)) < 0)
X			i = 0;
X	}
X	onb = (1 << (i + 3)) - sizeof (*op) - RSLOP;
X	/* avoid the copy if same size block */
X	if (was_alloced &&
X	    nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP) {
X#ifdef RCHECK
X		op->ov_size = ((nbytes + sizeof(union overhead) + RSLOP) + 3 & ~3) -1;
X		*((u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP)) = RMAGIC;
X#endif
X		return(cp);
X	}
X  	if ((res = malloc(nbytes)) == NULL)
X  		return (NULL);
X  	if (cp != res)			/* common optimization */
X		bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
X  	if (was_alloced)
X		free(cp);
X  	return (res);
X}
X
X/*
X * Search ``srchlen'' elements of each free list for a block whose
X * header starts at ``freep''.  If srchlen is -1 search the whole list.
X * Return bucket number, or -1 if not found.
X */
Xstatic
Xfindbucket(freep, srchlen)
X	union overhead *freep;
X	int srchlen;
X{
X	register union overhead *p;
X	register int i, j;
X
X	for (i = 0; i < NBUCKETS; i++) {
X		j = 0;
X		for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
X			if (p == freep)
X				return (i);
X			j++;
X		}
X	}
X	return (-1);
X}
X
X#ifdef MSTATS
X/*
X * mstats - print out statistics about malloc
X *
X * Prints two lines of numbers, one showing the length of the free list
X * for each size category, the second showing the number of mallocs -
X * frees for each size category.
X */
Xmstats(s)
X	char *s;
X{
X  	register int i, j;
X  	register union overhead *p;
X  	int totfree = 0,
X  	totused = 0;
X
X  	fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
X  	for (i = 0; i < NBUCKETS; i++) {
X  		for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
X  			;
X  		fprintf(stderr, " %d", j);
X  		totfree += j * (1 << (i + 3));
X  	}
X  	fprintf(stderr, "\nused:\t");
X  	for (i = 0; i < NBUCKETS; i++) {
X  		fprintf(stderr, " %d", nmalloc[i]);
X  		totused += nmalloc[i] * (1 << (i + 3));
X  	}
X  	fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
X	    totused, totfree);
X}
X#endif
END_OF_FILE
if test 9119 -ne `wc -c <'src/malloc.c'`; then
    echo shar: \"'src/malloc.c'\" unpacked with wrong size!
fi
# end of 'src/malloc.c'
fi
if test -f 'src/noise.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/noise.c'\"
else
echo shar: Extracting \"'src/noise.c'\" \(9494 characters\)
sed "s/^X//" >'src/noise.c' <<'END_OF_FILE'
X/*
X * noise.c
X *
X * Copyright (C) 1989, Robert Skinner, Craig E. Kolb, F. Kenton Musgrave
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 "as is".  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: noise.c,v 3.0 89/10/27 02:05:57 craig Exp $
X *
X * $Log:	noise.c,v $
X * Revision 3.0  89/10/27  02:05:57  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#define MINX		-10000
X#define MINY		MINX
X#define MINZ		MINX
X
X#define SCURVE(a) ((a)*(a)*(3.0-2.0*(a)))
X#define REALSCALE ( 2.0 / 65536.0 )
X#define NREALSCALE ( 2.0 / 4096.0 )
X#define Hash3d(a,b,c) hashTable[hashTable[hashTable[(a) & 0xfff] ^ ((b) & 0xfff)] ^ ((c) & 0xfff)]
X#define Hash(a,b,c) (xtab[(xtab[(xtab[(a) & 0xff] ^ (b)) & 0xff] ^ (c)) & 0xff] & 0xff)
X
X#define INCRSUM(m,s,x,y,z)	((s)*(RTable[m]*0.5		\
X					+ RTable[m+1]*(x)	\
X					+ RTable[m+2]*(y)	\
X					+ RTable[m+3]*(z)))	\
X
X
X#define MAXSIZE 267
X
Xdouble		RTable[MAXSIZE];
Xstatic short	*hashTable;
X
Xstatic unsigned short xtab[256] =
X{
X   0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
X   0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
X   0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
X   0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
X   0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
X   0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
X   0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
X   0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
X   0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
X   0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
X   0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
X   0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
X   0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
X   0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
X   0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
X   0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
X   0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
X   0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
X   0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
X   0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
X   0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
X   0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
X   0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
X   0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
X   0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
X   0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
X   0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
X   0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
X   0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
X   0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
X   0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
X   0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
X};
X
Xdouble Chaos(), Marble();
X
XInitTextureTable()
X{
X	int i, j, temp;
X
X#ifdef SYSV
X	(void)srand48(0);
X#else
X	(void)srandom(0);
X#endif
X
X	hashTable = (short int *) malloc(4096*sizeof(short int));
X	for (i = 0; i < 4096; i++)
X		hashTable[i] = i;
X	for (i = 4095; i > 0; i--) {
X		j = (int)(nrand() * 4096);
X		temp = hashTable[i];
X		hashTable[i] = hashTable[j];
X		hashTable[j] = temp;
X	}
X}
X
X
XInitRTable()
X{
X	int i;
X	Vector rp;
X
X	InitTextureTable();
X
X	for (i = 0; i < MAXSIZE; i++) {
X	   	rp.x = rp.y = rp.z = (double)i;
X	   	RTable[i] = R(&rp)*REALSCALE - 1.0;
X 	}
X}
X
X
XR(v)
XVector *v;
X{
X	v->x *= .12345;
X	v->y *= .12345;
X	v->z *= .12345;
X
X	return Crc16(v, sizeof(Vector));
X}
X
X/*
X * Note that passing a double to Crc16 and interpreting it as
X * an array of chars means that machines with different floating-point
X * representation schemes will evaluate Noise(point) differently.
X */
Xint
XCrc16(buf, count)
Xregister char *buf;
Xregister int  count;
X{
X	register unsigned int crc = 0;
X
X	while (count--)
X		crc = (crc >> 8) ^ xtab[ (unsigned char) (crc ^ *buf++) ];
X
X	return crc;
X}
X
X
X/*
X * Robert's Skinner's Perlin-style "Noise" function
X */
Xdouble
XNoise(point)
XVector *point;
X{
X	register int	ix, iy, iz, jx, jy, jz;
X	double		x, y, z;
X	double	sx, sy, sz, tx, ty, tz;
X	double	sum;
X	short	m;
X
X
X	/* ensures the values are positive. */
X	x = point->x - MINX; y = point->y - MINY; z = point->z - MINZ;
X
X	/* its equivalent integer lattice point. */
X	ix = (int)x; iy = (int)y; iz = (int)z;
X	jx = ix+1; jy = iy + 1; jz = iz + 1;
X
X	sx = SCURVE(x - ix); sy = SCURVE(y - iy); sz = SCURVE(z - iz);
X
X	/* the complement values of sx,sy,sz */
X	tx = 1.0 - sx; ty = 1.0 - sy; tz = 1.0 - sz;
X
X	/*
X	 *  interpolate!
X	 */
X	m = Hash3d( ix, iy, iz ) & 0xFF;
X	sum = INCRSUM(m,(tx*ty*tz),(x-ix),(y-iy),(z-iz));
X
X	m = Hash3d( jx, iy, iz ) & 0xFF;
X	sum += INCRSUM(m,(sx*ty*tz),(x-jx),(y-iy),(z-iz));
X
X	m = Hash3d( ix, jy, iz ) & 0xFF;
X	sum += INCRSUM(m,(tx*sy*tz),(x-ix),(y-jy),(z-iz));
X
X	m = Hash3d( jx, jy, iz ) & 0xFF;
X	sum += INCRSUM(m,(sx*sy*tz),(x-jx),(y-jy),(z-iz));
X
X	m = Hash3d( ix, iy, jz ) & 0xFF;
X	sum += INCRSUM(m,(tx*ty*sz),(x-ix),(y-iy),(z-jz));
X
X	m = Hash3d( jx, iy, jz ) & 0xFF;
X	sum += INCRSUM(m,(sx*ty*sz),(x-jx),(y-iy),(z-jz));
X
X	m = Hash3d( ix, jy, jz ) & 0xFF;
X	sum += INCRSUM(m,(tx*sy*sz),(x-ix),(y-jy),(z-jz));
X
X	m = Hash3d( jx, jy, jz ) & 0xFF;
X	sum += INCRSUM(m,(sx*sy*sz),(x-jx),(y-jy),(z-jz));
X
X	return sum;
X
X} /* Noise() */
X
X/*
X * Vector-valued "Noise"
X */
XDNoise(point, result)
XVector *point, *result;
X{
X	register int	ix, iy, iz, jx, jy, jz;
X	double		x, y, z;
X	double px, py, pz, s;
X	double	sx, sy, sz, tx, ty, tz;
X	short	m;
X
X	/* ensures the values are positive. */
X	x = point->x - MINX; y = point->y - MINY; z = point->z - MINZ;
X
X	/* its equivalent integer lattice point. */
X	ix = (int)x; iy = (int)y; iz = (int)z;
X	jx = ix+1; jy = iy + 1; jz = iz + 1;
X
X	sx = SCURVE(x - ix); sy = SCURVE(y - iy); sz = SCURVE(z - iz);
X
X	/* the complement values of sx,sy,sz */
X	tx = 1.0 - sx; ty = 1.0 - sy; tz = 1.0 - sz;
X
X	/*
X	 *  interpolate!
X	 */
X	m = Hash3d( ix, iy, iz ) & 0xFF;
X	px = x-ix;  py = y-iy;  pz = z-iz;
X	s = tx*ty*tz;
X	result->x = INCRSUM(m,s,px,py,pz);
X	result->y = INCRSUM(m+4,s,px,py,pz);
X	result->z = INCRSUM(m+8,s,px,py,pz);
X
X	m = Hash3d( jx, iy, iz ) & 0xFF;
X	px = x-jx;
X	s = sx*ty*tz;
X	result->x += INCRSUM(m,s,px,py,pz);
X	result->y += INCRSUM(m+4,s,px,py,pz);
X	result->z += INCRSUM(m+8,s,px,py,pz);
X
X	m = Hash3d( jx, jy, iz ) & 0xFF;
X	py = y-jy;
X	s = sx*sy*tz;
X	result->x += INCRSUM(m,s,px,py,pz);
X	result->y += INCRSUM(m+4,s,px,py,pz);
X	result->z += INCRSUM(m+8,s,px,py,pz);
X
X	m = Hash3d( ix, jy, iz ) & 0xFF;
X	px = x-ix;
X	s = tx*sy*tz;
X	result->x += INCRSUM(m,s,px,py,pz);
X	result->y += INCRSUM(m+4,s,px,py,pz);
X	result->z += INCRSUM(m+8,s,px,py,pz);
X
X	m = Hash3d( ix, jy, jz ) & 0xFF;
X	pz = z-jz;
X	s = tx*sy*sz;
X	result->x += INCRSUM(m,s,px,py,pz);
X	result->y += INCRSUM(m+4,s,px,py,pz);
X	result->z += INCRSUM(m+8,s,px,py,pz);
X
X	m = Hash3d( jx, jy, jz ) & 0xFF;
X	px = x-jx;
X	s = sx*sy*sz;
X	result->x += INCRSUM(m,s,px,py,pz);
X	result->y += INCRSUM(m+4,s,px,py,pz);
X	result->z += INCRSUM(m+8,s,px,py,pz);
X
X	m = Hash3d( jx, iy, jz ) & 0xFF;
X	py = y-iy;
X	s = sx*ty*sz;
X	result->x += INCRSUM(m,s,px,py,pz);
X	result->y += INCRSUM(m+4,s,px,py,pz);
X	result->z += INCRSUM(m+8,s,px,py,pz);
X
X	m = Hash3d( ix, iy, jz ) & 0xFF;
X	px = x-ix;
X	s = tx*ty*sz;
X	result->x += INCRSUM(m,s,px,py,pz);
X	result->y += INCRSUM(m+4,s,px,py,pz);
X	result->z += INCRSUM(m+8,s,px,py,pz);
X}
X
Xdouble
XMarble(vec)
XVector *vec;
X{
X	double i;
X
X	i = sin(8. * Chaos(vec, 6) + 7. * vec->z) + 1;
X	i *= 0.5;
X	i = pow(i, 0.77);
X	return i;
X}
X
Xdouble
XChaos(vec, octaves)
XVector *vec;
Xint octaves;
X{
X	double f, s, t;
X	int n;
X	Vector tp;
X
X	s = f = 1.0;
X	t = 0.;
X
X	for (n = 0; n < octaves; n++) {
X		tp.x = f * vec->x;
X		tp.y = f * vec->y;
X		tp.z = f * vec->z;
X		t += Noise(&tp) * s;
X		f *= 2.0;
X		s *= 0.5;
X	}
X
X	return t;
X}
X
XVfBm(vec, omega, lambda, octaves, ans)
XVector *vec, *ans;
Xdouble omega, lambda;
Xint octaves;
X{
X	register int i;
X	double l, o;
X	Vector tp, n;
X
X	ans->x = ans->y = ans->z = 0.;
X
X	l = o = 1.;
X	for (i = 0; i < octaves; i++) {
X		tp.x = l * vec->x;
X		tp.y = l * vec->y;
X		tp.z = l * vec->z;
X		DNoise(&tp, &n);
X		ans->x += o * n.x;
X		ans->y += o * n.y;
X		ans->z += o * n.z;
X		l *= lambda;
X		o *= omega;
X		if (o < EPSILON)
X			break;
X	}
X}
X
Xdouble
XfBm(vec, omega, lambda, octaves)
Xregister Vector *vec;
Xdouble omega, lambda;
Xint octaves;
X{
X	register int i;
X	double l, n, a, o;
X	Vector tp;
X
X	a = 0; l = o = 1.;
X	for (i = 0; i < octaves; i++) {
X		tp.x = l * vec->x;
X		tp.y = l * vec->y;
X		tp.z = l * vec->z;
X		n = o * Noise(&tp);
X		a += n;
X		l *= lambda;
X		o *= omega;
X	}
X	return a;
X}
END_OF_FILE
if test 9494 -ne `wc -c <'src/noise.c'`; then
    echo shar: \"'src/noise.c'\" unpacked with wrong size!
fi
# end of 'src/noise.c'
fi
if test -f 'src/poly.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/poly.c'\"
else
echo shar: Extracting \"'src/poly.c'\" \(7502 characters\)
sed "s/^X//" >'src/poly.c' <<'END_OF_FILE'
X/*
X * poly.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: poly.c,v 3.0 89/10/27 02:05:59 craig Exp $
X *
X * $Log:	poly.c,v $
X * Revision 3.0  89/10/27  02:05:59  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/*
X * Create a reference to a polygon with vertices equal to those
X * on the linked-list "plist."
X */
XObject *
Xmakpoly(surf, plist, npoints)
Xchar *surf;
XPointList *plist;
Xint npoints;
X{
X	Polygon *poly;
X	Primitive *prim;
X	Object *newobj;
X	double indexval;
X	Vector edge1, edge2, anorm;
X	PointList *cur;
X	int i;
X	extern int yylineno, TrashBadPoly, Quiet;
X
X	prim = mallocprim();
X	prim->type = POLY;
X	prim->surf = find_surface(surf);
X	poly = (Polygon *)Malloc(sizeof(Polygon));
X	prim->objpnt.p_poly = poly;
X	newobj = new_object(NULL, POLY, (char *)prim, (Trans *)NULL);
X	/*
X	 * Allocate space for the vertices.
X	 */
X	poly->points = (Vector *)Malloc((unsigned)(npoints*sizeof(Vector)));
X	poly->npoints = npoints;
X
X	/*
X	 * Copy the vertices from the linked list to the array, freeing
X	 * the linked list as we go so that the caller doesn't have
X	 * to worry about doing so.
X	 */
X	i = npoints -1;
X	for(cur = plist;cur;cur = cur->next) {
X		poly->points[i--] = cur->vec;
X		free((char *)cur);
X	}
X	free((char *)plist);
X
X	/*
X	 * Find normal to polygon.  Check all edges before giving
X	 * up, just to be relatively nice about things.
X	 */
X	vecsub(poly->points[1], poly->points[0], &edge1);
X	for(i = 1;i < poly->npoints;i++) {
X		if(dotp(&edge1, &edge1) == 0.) {
X			if (TrashBadPoly) {
X				free((char *)poly->points);
X				free((char *)poly);
X				free((char *)prim);
X				free((char *)newobj);
X				return (Object *)0;
X			}
X		}
X		vecsub(poly->points[(i+1)%npoints], poly->points[i], &edge2);
X		if(crossp(&poly->norm, &edge1, &edge2) != 0.)
X			break;
X		edge1 = edge2;
X	}
X
X	if(i >= poly->npoints) {
X		/*
X 		 * If we walked all the way through the list,
X		 * then we didn't find a valid normal vector -- we
X		 * must have a degenerate polygon of some sort.
X		 */
X		fprintf(stderr,"Degenerate polygon (line %d).\n", yylineno);
X		free((char *)poly->points);
X		free((char *)poly);
X		free((char *)prim);
X		free((char *)newobj);
X		return (Object *)0;
X	}
X
X	/*
X	 * Compute and store the plane constant.
X	 */
X	poly->d = dotp(&poly->norm, &poly->points[0]);
X
X	/*
X	 * Find which part of the normal vector is "dominant."  This
X	 * is used to turn the point-in-polygon test into a 2D problem.
X	 */
X	anorm.x = abs(poly->norm.x);
X	anorm.y = abs(poly->norm.y);
X	anorm.z = abs(poly->norm.z);
X	indexval = max(anorm.y, anorm.z);
X	indexval = max(anorm.x, indexval);
X
X	if(indexval == anorm.x)
X		poly->index = XNORMAL;
X	else if(indexval == anorm.y)
X		poly->index = YNORMAL;
X	else
X		poly->index = ZNORMAL;
X
X	return newobj;
X}
X
X/*
X * Quadrants are defined as:
X *        |
X *   1    |   0
X *        |
X * -------c--------
X *        |
X *   2    |   3
X *        |
X */
X#define quadrant(p, c) ((p.u<c.u) ? ((p.v<c.v) ? 2 : 1) : ((p.v<c.v) ? 3 : 0))
X
X/*
X * Project a point in 3-space to the plane whose normal is indicated by "i."
X */
X#define project(r, p, i)	{switch(i) { \
X				case XNORMAL: \
X					r.u = p.y; \
X					r.v = p.z; \
X					break; \
X				case YNORMAL: \
X					r.u = p.x; \
X					r.v = p.z; \
X					break; \
X				case ZNORMAL: \
X					r.u = p.x; \
X					r.v = p.y; \
X					break; \
X  				} }
X/*
X * Perform ray-polygon intersection test.
X */
Xdouble
Xintpoly(pos, ray, obj)
XVector *pos, *ray;
XPrimitive *obj;
X{
X	register Polygon *poly;
X	register int winding, i;
X	int quad, lastquad;
X	double dist, left, right;
X	Vec2d center, cur, last;
X	extern unsigned long primtests[];
X
X	primtests[POLY]++;
X	poly = obj->objpnt.p_poly;
X	/*
X	 * First, find where ray hits polygon plane, projecting
X	 * along the polygon's dominant normal component.
X	 */
X
X	dist = dotp(&poly->norm, ray);
X	if(dist == 0.)
X		/*
X	 	 * No intersection with polygon plane.
X		 */
X		return 0.;
X
X	dist = (poly->d - dotp(&poly->norm, pos)) / dist;
X	if(dist <= 0.)
X		/*
X		 * The intersection point is behind the ray origin.
X		 */
X		return 0.;
X
X	/*
X	 * Compute the point of intersection, projected appropriately.
X	 */
X	if(poly->index == XNORMAL) {
X		center.u = pos->y + dist * ray->y;
X		center.v = pos->z + dist * ray->z;
X	} else if(poly->index == YNORMAL) {
X		center.v = pos->z + dist * ray->z;
X		center.u = pos->x + dist * ray->x;
X	} else {
X		center.u = pos->x + dist * ray->x;
X		center.v = pos->y + dist * ray->y;
X	}
X
X	/*
X	 * Is the point inside the polygon?
X	 *
X	 * Compute the winding number by finding the quadrant each
X	 * polygon point lies in with respect to the the point in
X	 * question, and computing a "delta" (winding number).  If we
X	 * end up going around in a complete circle around
X	 * the point (winding number is non-zero at the end), then
X	 * we're inside.  Otherwise, the point is outside.
X	 *
X	 * Note that we can turn this into a 2D problem by projecting
X	 * all the points along the axis defined by poly->index, which
X	 * is the "dominant" part of the polygon's normal vector.
X	 */
X	winding = 0;
X	project(last, poly->points[poly->npoints -1], poly->index);
X	lastquad = quadrant(last, center);
X	for(i = 0;i < poly->npoints; i++) {
X		project(cur, poly->points[i], poly->index);
X		quad = quadrant(cur, center);
X		if(quad != lastquad) {
X			if(((lastquad + 1) & 3) == quad)
X				winding++;
X			else if(((quad + 1) & 3) == lastquad)
X				winding--;
X			else {
X				/*
X				 * Find where edge crosses
X				 * center's X axis.
X				 */
X				right = last.u - cur.u;
X				left = last.v - cur.v;
X				left *= center.u - last.u;
X				if(left + last.v * right > right * center.v)
X					winding += 2;
X				else
X					winding -= 2;
X			}
X			lastquad = quad;
X		}
X		last = cur;
X
X	}
X	return (winding == 0 ? 0. : dist);
X}
X
X/*
X * Return the normal to the polygon surface.
X */
X/*ARGSUSED*/
Xnrmpoly(pos, obj, nrm)
XVector *pos, *nrm;
XPrimitive *obj;
X{
X	*nrm = obj->objpnt.p_poly->norm;
X}
X
X/*
X * Compute the extent of a polygon
X */
Xpolyextent(obj, bounds)
XPrimitive *obj;
Xdouble bounds[2][3];
X{
X	register Polygon *poly;
X	register int i;
X
X	poly = obj->objpnt.p_poly;
X
X	bounds[LOW][X] = bounds[HIGH][X] = poly->points[0].x;
X	bounds[LOW][Y] = bounds[HIGH][Y] = poly->points[0].y;
X	bounds[LOW][Z] = bounds[HIGH][Z] = poly->points[0].z;
X
X	for(i = 1;i < poly->npoints;i++) {
X		if(poly->points[i].x < bounds[LOW][X])
X			bounds[LOW][X] = poly->points[i].x;
X		if(poly->points[i].x > bounds[HIGH][X])
X			bounds[HIGH][X] = poly->points[i].x;
X		if(poly->points[i].y < bounds[LOW][Y])
X			bounds[LOW][Y] = poly->points[i].y;
X		if(poly->points[i].y > bounds[HIGH][Y])
X			bounds[HIGH][Y] = poly->points[i].y;
X		if(poly->points[i].z < bounds[LOW][Z])
X			bounds[LOW][Z] = poly->points[i].z;
X		if(poly->points[i].z > bounds[HIGH][Z])
X			bounds[HIGH][Z] = poly->points[i].z;
X	}
X}
END_OF_FILE
if test 7502 -ne `wc -c <'src/poly.c'`; then
    echo shar: \"'src/poly.c'\" unpacked with wrong size!
fi
# end of 'src/poly.c'
fi
if test -f 'src/texture.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/texture.c'\"
else
echo shar: Extracting \"'src/texture.c'\" \(7557 characters\)
sed "s/^X//" >'src/texture.c' <<'END_OF_FILE'
X/*
X * texture.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: texture.c,v 3.0 89/10/27 02:06:05 craig Exp $
X *
X * $Log:	texture.c,v $
X * Revision 3.0  89/10/27  02:06:05  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
X/*
X * Array of texturing functions indexed by type.
X */
Xint (*textures[])() =
X	{CheckerText, BlotchText, BumpText, MarbleText, fBmText, fBmBumpText,
X	 WoodText};
Xextern double Chaos(), Marble(), fBm(), Noise();
XColor	*read_colormap();
X
X/*
X * Return pointer to new texture structure.
X */
XTexture *
Xnew_texture(type)
Xchar type;
X{
X	Texture *new;
X
X	new = (Texture *)Malloc(sizeof(Texture));
X	new->type = type;
X	new->surf1 = (Surface *)NULL;
X	new->next = (Texture *)NULL;
X	new->trans = (Trans *)NULL;
X	return new;
X}
X
X/*
X * Apply appropriate textures to a surface.
X */
Xapply_textures(hitinfo, list)
XHitInfo *hitinfo;
XTexture *list;
X{
X	Texture *ttmp;
X	Vector ptmp;
X
X	for (ttmp = list; ttmp; ttmp = ttmp->next) {
X		ptmp = hitinfo->pos;
X		if (ttmp->trans) {
X			/*
X			 * Transform position and normal to texture space.
X			 */
X			transform_point(&ptmp,&ttmp->trans->world2obj);
X			TransformNormal(&hitinfo->norm,&ttmp->trans->obj2world);
X		}
X		/*
X		 * Make sure to use a normalized normal.
X		 */
X		(void)normalize(&hitinfo->norm);
X		(*textures[(int)ttmp->type])
X			(ttmp,&ptmp,&hitinfo->norm,&hitinfo->surf);
X		if (ttmp->trans) {
X			/*
X			 * Transform the normal back to world-space.
X			 */
X			TransformNormal(&hitinfo->norm,&ttmp->trans->world2obj);
X		}
X	}
X}
X
XTexture *
XNewWoodText()
X{
X	Texture *text;
X
X	text = new_texture(WOOD);
X	return text;
X}
X
XWoodText(text, pos, norm, surf)
XTexture *text;
XVector *pos, *norm;
XSurface *surf;
X{
X	double red, grn, blu;
X	double chaos, midBrown, brownLayer, greenLayer;
X	double perturb, brownPerturb, greenPerturb, grnPerturb;
X	double t;
X
X	chaos = Chaos(pos, 7);
X	t = sin(sin(8.*chaos + 7*pos->x +3.*pos->y));
X
X	greenLayer = brownLayer = abs(t);
X
X	perturb = fabs(sin(40.*chaos + 50*pos->z));
X
X	brownPerturb = .6*perturb + 0.3;
X	greenPerturb = .2*perturb + 0.8;
X	grnPerturb = .15*perturb + 0.85;
X	grn = 0.5 * pow(abs(brownLayer), 0.3);
X	brownLayer = pow(0.5 * (brownLayer+1.0), 0.6) * brownPerturb;
X	greenLayer = pow(0.5 * (greenLayer+1.0), 0.6) * greenPerturb;
X
X	red = (0.5*brownLayer + 0.35*greenLayer)*2.*grn;
X	blu = (0.25*brownLayer + 0.35*greenLayer)*2.0*grn;
X	grn *= max(brownLayer, greenLayer) * grnPerturb;
X
X	surf->diff.r *= red;
X	surf->diff.g *= grn;
X	surf->diff.b *= blu;
X
X	ScaleColor(0.3, surf->diff, &surf->amb);
X}
X
X/*
X * Create and return a reference to a "checker" texture.
X */
XTexture *
XNewCheckText(surf)
Xchar *surf;
X{
X	Texture *text;
X
X	text = new_texture(CHECKER);
X	text->surf1 = find_surface(surf);
X
X	return text;
X}
X
XTexture *
XNewfBmBumpText(offset, scale, h, lambda, octaves)
Xdouble h, lambda, scale, offset;
Xint octaves;
X{
X	Texture *text;
X
X	text = NewfBmText(offset, scale, h, lambda, octaves, 0., (char *)0);
X
X	text->type = FBMBUMP;
X
X	return text;
X}
X
XTexture *
XNewfBmText(offset, scale, h, lambda, octaves, thresh, mapname)
Xdouble h, lambda, scale, offset, thresh;
Xint octaves;
Xchar *mapname;
X{
X	double beta;
X	Texture *text;
X
X	text = new_texture(FBM);
X
X	text->args = (double *)Malloc(5 * sizeof(double));
X	beta = 1. + 2 * h;
X	text->args[0] = pow(lambda, -0.5 * beta);	/* omega */
X	text->args[1] = lambda;
X	text->args[2] = scale;
X	text->args[3] = offset;
X	text->args[4] = thresh;
X	text->size = (double)octaves;
X	if (mapname != (char *)0)
X		text->colormap = read_colormap(mapname);
X
X	return text;
X}
X
X/*
X * Create and return a reference to a "bump" texture.
X */
XTexture *
XNewBumpText(size)
Xdouble size;
X{
X	Texture *text;
X
X	text = new_texture(BUMP);
X	text->size = size;
X
X	return text;
X}
X
X/*
X * Create and return a reference to a "blotch" texture.
X */
XTexture *
XNewBlotchText(scale, surf)
Xdouble scale;
Xchar *surf;
X{
X	Texture *text;
X
X	text = new_texture(BLOTCH);
X	text->size = scale;
X	text->surf1 = find_surface(surf);
X
X	return text;
X}
X
XTexture *
XNewMarbleText(mapname)
Xchar *mapname;
X{
X	Texture *text;
X
X	text = new_texture(MARBLE);
X	if (mapname)
X		text->colormap = read_colormap(mapname);
X	return text;
X}
X
X/*
X * Apply "blotch" texture.
X */
XBlotchText(text, pos, norm, surf)
XTexture *text;
XVector *pos, *norm;
XSurface *surf;
X{
X	double val;
X
X	/*
X	 * "size" represents the 'average' noise value at a point.
X	 */
X	val = Noise(pos);
X	if (val > text->size) {
X		val = (val - text->size) / (1. - text->size);
X		blend_surface(surf, text->surf1, 1. - val, val);
X	}
X}
X
XfBmText(text, pos, norm, surf)
XTexture *text;
XVector *pos, *norm;
XSurface *surf;
X{
X	double val;
X	int index;
X
X	val = fBm(pos, text->args[0], text->args[1], (int)text->size);
X	if (val < text->args[4])
X		val = 0.;
X	else
X		val = text->args[3] + text->args[2] * (val - text->args[4]);
X	if (text->colormap) {
X		index = 255. * val;
X		if (index > 255) index = 255;
X		if (index < 0) index = 0;
X		surf->diff = text->colormap[index];
X		ScaleColor(.2, surf->diff, &surf->amb);
X	} else {
X		ScaleColor(val, surf->diff, &surf->diff);
X		ScaleColor(val, surf->amb, &surf->amb);
X	}
X}
X
X/*
X * Apply a "checker" texture.
X */
XCheckerText(text, pos, norm, surf)
XTexture *text;
XVector *pos, *norm;
XSurface *surf;
X{
X	int xp, yp, zp;
X
X	xp = pos->x > 0. ? pos->x : 1. - pos->x;
X	yp = pos->y > 0. ? pos->y : 1. - pos->y;
X	zp = pos->z > 0. ? pos->z : 1. - pos->z;
X
X	if ((xp + yp + zp) % 2)
X		*surf = *text->surf1;
X	/* else surface stays the same. */
X}
X
XfBmBumpText(text, pos, norm, surf)
XTexture *text;
XVector *pos, *norm;
XSurface *surf;
X{
X	Vector disp;
X	double w;
X
X	VfBm(pos, text->args[0], text->args[1], (int)text->size, &disp);
X	w = text->args[2];
X	norm->x += text->args[3] + disp.x * w;
X	norm->y += text->args[3] + disp.y * w;
X	norm->z += text->args[3] + disp.z * w;
X}
X
X/*
X * Apply a "bump" texture.
X */
XBumpText(text, pos, norm, surf)
XTexture *text;
XVector *pos, *norm;
XSurface *surf;
X{
X	Vector disp;
X
X	DNoise(pos, &disp);
X	norm->x += disp.x * text->size;
X	norm->y += disp.y * text->size;
X	norm->z += disp.z * text->size;
X	(void)normalize(norm);
X}
X
XMarbleText(text, pos, norm, surf)
XTexture *text;
XVector *pos, *norm;
XSurface *surf;
X{
X	double val;
X	int index;
X
X	val = Marble(pos);
X	if (text->colormap) {
X		index = (int)(255. * val);
X		surf->diff = text->colormap[index];
X	} else {
X		ScaleColor(val, surf->amb, &surf->amb);
X		ScaleColor(val, surf->diff, &surf->diff);
X	}
X}
X
XColor *
Xread_colormap(filename)
Xchar *filename;
X{
X	FILE *fp;
X	Color *map;
X	char buf[BUFSIZ];
X	int i;
X
X	fp = fopen(filename, "r");
X	if (fp == (FILE *)NULL)
X		yyerror("Cannot open colormap file.");
X
X	map = (Color *)Calloc(256, sizeof(Color));
X
X	for (i = 0; fgets(buf,BUFSIZ,fp) != NULL && i < 256; i++) {
X		sscanf(buf,"%lf %lf %lf",&map[i].r, &map[i].g, &map[i].b);
X		ScaleColor(1. / 255., map[i], &map[i]);
X	}
X	return map;
X}
END_OF_FILE
if test 7557 -ne `wc -c <'src/texture.c'`; then
    echo shar: \"'src/texture.c'\" unpacked with wrong size!
fi
# end of 'src/texture.c'
fi
if test -f 'src/triangle.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/triangle.c'\"
else
echo shar: Extracting \"'src/triangle.c'\" \(7297 characters\)
sed "s/^X//" >'src/triangle.c' <<'END_OF_FILE'
X/*
X * triangle.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: triangle.c,v 3.0 89/10/27 02:06:07 craig Exp $
X *
X * $Log:	triangle.c,v $
X * Revision 3.0  89/10/27  02:06:07  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#define within(x, a)		(((a) <= 0 && (x) >= (a) && (x) <= 0) || \
X					((a) > 0 && (x) >= 0 && (x) <= (a)))
X/*
X * Create and return reference to a triangle.
X */
XObject *
Xmaktri(type, surf, p1, p2, p3, n1, n2, n3)
Xint	type;
Xchar	*surf;
XVector	*p1, *p2, *p3, *n1, *n2, *n3;
X{
X	Triangle *triangle;
X	Primitive *prim;
X	Vector vc1, vc2, vc3, ptmp, anorm;
X	Object *newobj;
X	double indexval;
X	extern int yylineno, Quiet;
X
X	prim = mallocprim();
X	triangle = (Triangle *)Malloc(sizeof(Triangle));
X	prim->objpnt.p_triangle = triangle;
X	newobj = new_object(NULL, (char)type, (char *)prim, (Trans *)NULL);
X	prim->surf = find_surface(surf);
X
X	if (type == PHONGTRI) {
X		prim->type = PHONGTRI;
X		(void)normalize(n1);
X		(void)normalize(n2);
X		(void)normalize(n3);
X		triangle->vnorm = (Vector *)Malloc(3 * sizeof(Vector));
X		triangle->vnorm[0] = *n1;
X		triangle->vnorm[1] = *n2;
X		triangle->vnorm[2] = *n3;
X		triangle->b = (double *)Malloc(3 * sizeof(double));
X	}
X	else
X		prim->type = TRIANGLE;
X
X	vecsub(*p2, *p1, &vc1);
X	vecsub(*p3, *p2, &vc2);
X	vecsub(*p1, *p3, &vc3);
X
X	/* Find plane normal. */
X	rawcrossp(&triangle->nrm, &vc1, &vc2);
X	ptmp = triangle->nrm;
X	if (normalize(&ptmp) == 0.) {
X		if (!Quiet)
X			fprintf(stderr,"Degenerate triangle (line %d).\n",
X							yylineno);
X		free((char *)prim);
X		free((char *)triangle);
X		free((char *)newobj);
X		return (Object *)0;
X	}
X
X	triangle->d = dotp(&triangle->nrm, p1);
X
X	triangle->p1 = *p1;
X	triangle->p2 = *p2;
X	triangle->p3 = *p3;
X
X	triangle->e1 = vc1;
X	triangle->e2 = vc2;
X	triangle->e3 = vc3;
X
X	if (type == PHONGTRI && dotp(&triangle->vnorm[0], &ptmp) < 0.) {
X		/*
X		 * Reverse direction of surface normal on Phong
X		 * triangle if the surface normal points "away"
X		 * from the first vertex normal.
X		 */
X		scalar_prod(-1., triangle->nrm, &triangle->nrm);
X		triangle->d = -triangle->d;
X		scalar_prod(-1., triangle->e1, &triangle->e1);
X		scalar_prod(-1., triangle->e2, &triangle->e2);
X		scalar_prod(-1., triangle->e3, &triangle->e3);
X	}
X	/*
X	 * Find "dominant" part of normal vector.
X	 */
X	anorm.x = abs(triangle->nrm.x);
X	anorm.y = abs(triangle->nrm.y);
X	anorm.z = abs(triangle->nrm.z);
X	indexval = max(anorm.y, anorm.z);
X	indexval = max(anorm.x, indexval);
X	if (indexval == anorm.x)
X		triangle->index = XNORMAL;
X	else if (indexval == anorm.y)
X		triangle->index = YNORMAL;
X	else
X		triangle->index = ZNORMAL;
X
X	return newobj;
X}
X
X/*
X * Intersect ray with triangle.  See Snyder & Barr for details on
X * how this works.
X */
Xdouble
Xinttri(pos, ray, obj)
Xregister Vector           *pos, *ray;
XPrimitive       *obj;
X{
X	register Triangle     *triangle;
X	double qi1, qi2, s, k, b1, b2, b3;
X	extern unsigned long primtests[];
X
X	primtests[obj->type]++;
X
X	triangle = obj->objpnt.p_triangle;
X	/*
X	 * Plane intersection.
X	 */
X	k = dotp(&triangle->nrm, ray);
X	if (k == 0.)
X		return 0.;
X	s = (triangle->d - dotp(&triangle->nrm, pos)) / k;
X	if (s <= 0.)
X		return 0.;
X
X	if (triangle->index == XNORMAL) {
X		qi1 = pos->y + s * ray->y;
X		qi2 = pos->z + s * ray->z;
X		b1 = triangle->e2.y * (qi2 - triangle->p2.z) -
X				triangle->e2.z * (qi1 - triangle->p2.y);
X		if (!within(b1, triangle->nrm.x))
X			return 0.;
X		b2 = triangle->e3.y * (qi2 - triangle->p3.z) -
X				triangle->e3.z * (qi1 - triangle->p3.y);
X		if (!within(b2, triangle->nrm.x))
X			return 0.;
X		b3 = triangle->e1.y * (qi2 - triangle->p1.z) -
X				triangle->e1.z * (qi1 - triangle->p1.y);
X		if (!within(b3, triangle->nrm.x))
X			return 0.;
X	} else if (triangle->index == YNORMAL) {
X		qi1 = pos->x + s * ray->x;
X		qi2 = pos->z + s * ray->z;
X		b1 = triangle->e2.z * (qi1 - triangle->p2.x) -
X			triangle->e2.x * (qi2 - triangle->p2.z);
X		if (!within(b1, triangle->nrm.y))
X			return 0.;
X		b2 = triangle->e3.z * (qi1 - triangle->p3.x) -
X			triangle->e3.x * (qi2 - triangle->p3.z);
X		if (!within(b2, triangle->nrm.y))
X			return 0.;
X		b3 = triangle->e1.z * (qi1 - triangle->p1.x) -
X			triangle->e1.x * (qi2 - triangle->p1.z);
X		if (!within(b3, triangle->nrm.y))
X			return 0.;
X	} else {
X		qi1 = pos->x + s * ray->x;
X		qi2 = pos->y + s * ray->y;
X		b1 = triangle->e2.x * (qi2 - triangle->p2.y) -
X				triangle->e2.y * (qi1 - triangle->p2.x);
X		if (!within(b1, triangle->nrm.z))
X			return 0.;
X
X		b2 = triangle->e3.x * (qi2 - triangle->p3.y) -
X				triangle->e3.y * (qi1 - triangle->p3.x);
X		if (!within(b2, triangle->nrm.z))
X			return 0.;
X
X		b3 = triangle->e1.x * (qi2 - triangle->p1.y) -
X				triangle->e1.y * (qi1 - triangle->p1.x);
X		if (!within(b3, triangle->nrm.z))
X			return 0.;
X	}
X	/*
X	 * Take abs value if there was an intersection.
X	 */
X	if (obj->type == PHONGTRI) {
X		triangle->b[0] = abs(b1);
X		triangle->b[1] = abs(b2);
X		triangle->b[2] = abs(b3);
X	}
X	return s;
X}
X
Xnrmtri(pos, obj, nrm)
XVector           *pos, *nrm;
XPrimitive       *obj;
X{
X	Triangle *tri;
X
X	/*
X	 * Normals will be normalized later...
X	 */
X	if (obj->type == TRIANGLE) {
X		*nrm = obj->objpnt.p_triangle->nrm;
X	} else {
X		/*
X		 * Interpolate normals of Phong-shaded triangles.
X		 */
X		tri = obj->objpnt.p_triangle;
X		nrm->x = tri->b[0]*tri->vnorm[0].x+tri->b[1]*tri->vnorm[1].x+
X			tri->b[2]*tri->vnorm[2].x;
X		nrm->y = tri->b[0]*tri->vnorm[0].y+tri->b[1]*tri->vnorm[1].y+
X			tri->b[2]*tri->vnorm[2].y;
X		nrm->z = tri->b[0]*tri->vnorm[0].z+tri->b[1]*tri->vnorm[1].z+
X			tri->b[2]*tri->vnorm[2].z;
X	}
X}
X
Xtriextent(o, bounds)
XPrimitive *o;
Xdouble bounds[2][3];
X{
X	Triangle *tri;
X
X	tri = o->objpnt.p_triangle;
X
X	bounds[LOW][X] = bounds[HIGH][X] = tri->p1.x;
X	bounds[LOW][Y] = bounds[HIGH][Y] = tri->p1.y;
X	bounds[LOW][Z] = bounds[HIGH][Z] = tri->p1.z;
X
X	if (tri->p2.x < bounds[LOW][X]) bounds[LOW][X] = tri->p2.x;
X	if (tri->p2.x > bounds[HIGH][X]) bounds[HIGH][X] = tri->p2.x;
X	if (tri->p3.x < bounds[LOW][X]) bounds[LOW][X] = tri->p3.x;
X	if (tri->p3.x > bounds[HIGH][X]) bounds[HIGH][X] = tri->p3.x;
X
X	if (tri->p2.y < bounds[LOW][Y]) bounds[LOW][Y] = tri->p2.y;
X	if (tri->p2.y > bounds[HIGH][Y]) bounds[HIGH][Y] = tri->p2.y;
X	if (tri->p3.y < bounds[LOW][Y]) bounds[LOW][Y] = tri->p3.y;
X	if (tri->p3.y > bounds[HIGH][Y]) bounds[HIGH][Y] = tri->p3.y;
X
X	if (tri->p2.z < bounds[LOW][Z]) bounds[LOW][Z] = tri->p2.z;
X	if (tri->p2.z > bounds[HIGH][Z]) bounds[HIGH][Z] = tri->p2.z;
X	if (tri->p3.z < bounds[LOW][Z]) bounds[LOW][Z] = tri->p3.z;
X	if (tri->p3.z > bounds[HIGH][Z]) bounds[HIGH][Z] = tri->p3.z;
X}
END_OF_FILE
if test 7297 -ne `wc -c <'src/triangle.c'`; then
    echo shar: \"'src/triangle.c'\" unpacked with wrong size!
fi
# end of 'src/triangle.c'
fi
echo shar: End of archive 4 \(of 8\).
cp /dev/null ark4isdone
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