prt: a parallel raytracer. Part 1 of 3.

Kory Hamzeh kory at avatar.avatar.com
Thu Dec 6 14:37:54 AEST 1990


Archive-name: prt/Part01

Here is a parallel raytracer I wrote which runs on machines that are
networked together via TCP/IP.

#! /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 1 (of 3)."
# Contents:  Makefile README bound.c data.c example1.dat externs.h
#   hsphere.c intersect.c main.c output.c poly.c quadric.c ring.c
#   sphere.c stack.c tokens.l trace.c vector.c
# Wrapped by kory at avatar on Wed Dec  5 18:23:13 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1847 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# Makefile for rt. A bitchin' Raytracer
X#
X# Copyright (C) 1990, Kory Hamzeh
X#
X
XCFLAGS= -O -c
XYFLAGS=-d
XLDFLAGS=-g
XLIBS=-lm
X
X#
X# .h files go here
X#
XHFILES= \
X	rt.h \
X	externs.h
X
X#
X# .c files here
X#
XCFILES= \
X	main.c \
X	data.c \
X	input.c \
X	output.c \
X	trace.c \
X	sphere.c \
X	hsphere.c \
X	poly.c \
X	cone.c \
X	ring.c \
X	quadric.c \
X	intersect.c \
X	shade.c \
X	bound.c \
X	stack.c \
X	vector.c
X
X#
X# .o files here
X#
XOFILES = \
X	main.o \
X	data.o \
X	input.o \
X	output.o \
X	trace.o \
X	sphere.o \
X	hsphere.o \
X	poly.o \
X	cone.o \
X	ring.o \
X	quadric.o \
X	intersect.o \
X	shade.o \
X	stack.o \
X	bound.o \
X	vector.o
X
Xall: rt prt nffconv
X
Xrt: $(OFILES)
X	$(CC) $(LDFLAGS) -o rt $(OFILES) $(LIBS)
X
Xprt: prt.c
X	$(CC) -g -o prt prt.c
X
Xnffconv: nff.y tokens.l
X	lex tokens.l
X	yacc $(YFLAGS) nff.y
X	cc -c lex.yy.c
X	cc -c y.tab.c
X	cc -o nffconv y.tab.o lex.yy.o
X	rm -f y.tab.c y.tab.h lex.yy.c lex.yy.o y.tab.o
X
X.c.o:
X	$(CC) $(CFLAGS) $<
X
Xclean:
X	rm -f nffconv prt rt core *.o
X
X#
X# AUTOMATICALLY UPDATED BY MAKEDEPEND
Xbound.o: bound.c
Xbound.o: rt.h
Xbound.o: externs.h
Xcone.o: cone.c
Xcone.o: rt.h
Xcone.o: externs.h
Xdata.o: data.c
Xdata.o: rt.h
Xhsphere.o: hsphere.c
Xhsphere.o: rt.h
Xhsphere.o: externs.h
Xinput.o: input.c
Xinput.o: rt.h
Xinput.o: externs.h
Xintersect.o: intersect.c
Xintersect.o: rt.h
Xintersect.o: externs.h
Xmain.o: main.c
Xmain.o: rt.h
Xmain.o: externs.h
Xmtile.o: mtile.c
Xnoise.o: noise.c
Xnoise.o: rt.h
Xnoise.o: externs.h
Xoutput.o: output.c
Xoutput.o: rt.h
Xoutput.o: externs.h
Xpoly.o: poly.c
Xpoly.o: rt.h
Xpoly.o: externs.h
Xquadric.o: quadric.c
Xquadric.o: rt.h
Xquadric.o: externs.h
Xring.o: ring.c
Xring.o: rt.h
Xring.o: externs.h
Xshade.o: shade.c
Xshade.o: rt.h
Xshade.o: externs.h
Xsphere.o: sphere.c
Xsphere.o: rt.h
Xsphere.o: externs.h
Xstack.o: stack.c
Xstack.o: rt.h
Xstack.o: externs.h
Xtrace.o: trace.c
Xtrace.o: rt.h
Xtrace.o: externs.h
Xvector.o: vector.c
Xvector.o: rt.h
END_OF_FILE
if test 1847 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(5002 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
X                      prt: A parallel raytracer.
X                   Copyright (C) 1990, Kory Hamzeh
X
XINTRODUCTION
X
XThis is the first release of prt, and for that very reason, it's version 1.0. 
X
XPrt is a parallel raytracer I wrote which will run across machines that 
Xare networked together via TCP/IP. Prt consists of two programs:
X
X	- prt: the front end system
X	- rt: the raytracing engine.
X
XPrt requires the name of the input file, output image file name, and a list
Xof hosts which will run rt. It then uses rsh to start rt on the given hosts.
XRt reads the input file from its standard in and pipes the image back to
Xprt on its standard out. Prt also monitors the standard error stream for
Xerror/diagnostics from rt.
X
XUsing rsh might not be the most efficient way to run parallel processes, but
Xit's simple and very portable. I've run prt on up to 5 Sun SPARCstations and
Xhave gotten excellent performance. The speed improvement is very close to
Xlinear as the number of hosts increase.
X
XIn this archive set, there is a file named FORMAT which contains the prt
Xinput database format. Please read it.
X
XI have also included two example input files: example1.dat and example2.dat.
XI have many more available. Contact me if you are interested.
X
X
XBUILDING PRT
X
XTo build prt, make sure you have unshared all of the shar files. Then type:
X
X	make prt
X
XIt should require very little or no change on most BSD systems. Prt uses
Xthe select system call, so make sure your system supports it (all BSD and
Xmost System V systems now have a select system call).
X
XNext, you need to build rt on all of the hosts which you plan to use. Copy
Xthe files on all of the hosts you want to use, and type:
X
X	make rt
X
XI have also written a program called nffconv which converts input
Xdatabases in NFF format to a prt format. To build nffconv, type:
X
X	make nffconv
X
XThe SURFACE primitive in prt is much more robust than that of NFF ray-
Xtracers. You might have to tweak the outfile of nffconv to get a pretty
Xpicture.
X
X
XRUNNING PRT
X
XBefore you run prt, make sure that:
X
X	1. You have built rt on all of the target hosts.
X	2. You have an account on all of the target hosts and can run rsh.
X	3. Rsh does not produce any more output other than the output
X	   of the program. Type:
X
X		rsh <hostname> rt
X
X	   then type a Control-D character. All you should see is:
X
X		rt: no light sources were specified.
X
X	   If you see any other output (including a request for password
X	   prompt), then you need to correct it. 
X
XPrt has the following usage format:
X
X	prt [-v] [-s] [-l] [-r] [-c sample_count] input-file
X		output-file host [host ... ]
X
XThe options are:
X
X	-v	Verbose mode. Good for debugging and impatient people.
X
X	-s	Don't trace shadow rays. For testing an object database.
X
X	-l	Don't trace reflected rays. For testing an object database.
X
X	-r	Don't trace refracted rays. For testing an object database.
X
X	-c	This option specifies the number of samples per pixel 
X		for stochastic sampling. The default is 1 (no sampling).
X
XSince prt uses two pipes per rt connection, you can specify up to 30 hosts
Xon the command line. I am trying to figure out a way to increase this. If 
Xanyone has any ideas, please let me know.
X
XYou can run rt directly if you want. It has the same usage format as prt
Xwith the exception of the host list. Rt has several more options that are
Xonly used when started by prt. If you are interested, look in main.c.
X
XRUNNING NFFCONV
X
XNffconv makes a good faith attempt at converting NFF formatted files to
Xa format that prt can use. By "good faith" I mean that it makes a lot of
Xassumptions about the surface properties. Prt's surface properties are more
Xrobust than NFF's.
X
XSince prt does not yet handle polygon patches, nnfconv will complain and
Xexit if your input database contains any polygon patches.
X
XUsage for nffconv is:
X
X	nffconv <input-file >output-file.
X
X
XFUTURE PLANS
X
XSince this is the first public release of prt, I expect that there are some
Xbugs/portability issues. The next release should be less buggy/more portable.
XI would like to add the torus object type and polygon patches. The only reason 
Xthat these two objects haven't been added yet is because the math required is
Xbeyond me at this point. I also have come up with a much better load balancing 
Xscheme which will adjust the load on a per machine basis in real time. I have 
Xnot had a chance to implement this.
X
X
XACKNOWLEDGEMENTS
X
XThe code for cone intersection and building the bounding boxes were pretty
Xmuch lifted from the MTV raytracer. Mark, I hope you don't mind.
X
XI would also like to thank Eric Haines and George Kyriazis for their help 
Xearly on in the design of the raytracer engine.
X
XPlease report bugs/patches/etc to me at:
X
X	kory at avatar.com
X
XI am very intereseted to hear what kind of images you have done and what kind
Xof performance you have achieved.
X
XIf you create cool object files, please send me a copy so that I can archive
Xthem and make them available to others.
X
XEnjoy and happy tracing,
X--kory
Xkory at avatar.com
X
END_OF_FILE
if test 5002 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'bound.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bound.c'\"
else
echo shar: Extracting \"'bound.c'\" \(3740 characters\)
sed "s/^X//" >'bound.c' <<'END_OF_FILE'
X
X/*
X * bound.c
X * 
X * This module contains the code for creating a bounding box hierarchy. Most of
X * the code here has stolen from MTV's raytracer.
X *
X * Copyright (C) 1990, Kory Hamzeh.
X */
X
X#include <stdio.h>
X#include <math.h>
X
X#include "rt.h"
X#include "externs.h"
X
Xstatic int      axis;
X
X/*
X * Build_bounding_slabs()
X * 
X * This function attempts to use median cut to generate tighter bounding volumes
X * than the old code...
X */
X
XBuild_bounding_slabs()
X{
X	int             low = 0;
X	int             high, i;
X
X	high = nobjects;
X	while (Sort_split(low, high) == 0)
X	{
X		low = high;
X		high = nobjects;
X	}
X}
X
X/*
X * Compslabs()
X * 
X * Compare the given slabs of the current axis.
X */
X
X
XCompslabs(a, b)
XOBJECT        **a, **b;
X{
X	double          am, bm;
X
X	switch (axis)
X	{
X	case 0:
X		am = (*a)->b_min.x + (*a)->b_max.x;
X		bm = (*b)->b_min.x + (*b)->b_max.x;
X		break;
X
X	case 1:
X		am = (*a)->b_min.y + (*a)->b_max.y;
X		bm = (*b)->b_min.y + (*b)->b_max.y;
X		break;
X
X	case 2:
X		am = (*a)->b_min.z + (*a)->b_max.z;
X		bm = (*b)->b_min.z + (*b)->b_max.z;
X		break;
X	}
X
X	if (am < bm)
X		return (-1);
X	else if (am == bm)
X		return (0);
X	else
X		return (1);
X}
X
X/*
X * Find the most dominant axis for this group of objects.
X */
X
XFind_axis(first, last)
Xint             first, last;
X{
X	OBJECT         *obj;
X	VECTOR          mins, maxs;
X	double          d, e;
X	int             i, which;
X
X	d = -HUGE;
X
X	mins.x = mins.y = mins.z = HUGE;
X	maxs.x = maxs.y = maxs.z = -HUGE;
X
X	for (i = first; i < last; i++)
X	{
X		obj = objects[i];
X
X		if (obj->b_min.x < mins.x)
X			mins.x = obj->b_min.x;
X		if (obj->b_min.y < mins.y)
X			mins.y = obj->b_min.y;
X		if (obj->b_min.z < mins.z)
X			mins.z = obj->b_min.z;
X
X		if (obj->b_max.x > maxs.x)
X			maxs.x = obj->b_max.x;
X		if (obj->b_max.y > maxs.y)
X			maxs.y = obj->b_max.y;
X		if (obj->b_max.z > maxs.z)
X			maxs.z = obj->b_max.z;
X	}
X
X	e = maxs.x - mins.x;
X
X	if (e > d)
X	{
X		d = e;
X		which = 0;
X	}
X
X	e = maxs.y - mins.y;
X
X	if (e > d)
X	{
X		d = e;
X		which = 1;
X	}
X
X	e = maxs.z - mins.z;
X
X	if (e > d)
X	{
X		d = e;
X		which = 0;
X	}
X
X	return (which);
X}
X
X
XSort_split(first, last)
Xint             first, last;
X{
X	OBJECT         *cp;
X	COMPOSITE      *cd;
X	int             size, i, j;
X	double          dmin, dmax;
X	int             m;
X
X	axis = Find_axis(first, last);
X
X	size = last - first;
X
X	qsort((char *) (objects + first), size, sizeof(OBJECT *), Compslabs);
X
X	if (size <= GROUP_SIZE)
X	{
X		/* build a box to contain them */
X
X		cp = (OBJECT *) malloc(sizeof(OBJECT));
X		cp->type = T_COMPOSITE;
X		cd = (COMPOSITE *) malloc(sizeof(COMPOSITE));
X		cd->num = size;
X
X		for (i = 0; i < size; i++)
X		{
X			cd->child[i] = objects[first + i];
X		}
X
X		dmin = HUGE;
X		dmax = -HUGE;
X
X		for (j = 0; j < size; j++)
X		{
X			if (cd->child[j]->b_min.x < dmin)
X				dmin = cd->child[j]->b_min.x;
X			if (cd->child[j]->b_max.x > dmax)
X				dmax = cd->child[j]->b_max.x;
X		}
X
X		cp->b_min.x = dmin;
X		cp->b_max.x = dmax;
X
X		dmin = HUGE;
X		dmax = -HUGE;
X
X		for (j = 0; j < size; j++)
X		{
X			if (cd->child[j]->b_min.y < dmin)
X				dmin = cd->child[j]->b_min.y;
X			if (cd->child[j]->b_max.y > dmax)
X				dmax = cd->child[j]->b_max.y;
X		}
X
X		cp->b_min.y = dmin;
X		cp->b_max.y = dmax;
X
X		dmin = HUGE;
X		dmax = -HUGE;
X
X		for (j = 0; j < size; j++)
X		{
X			if (cd->child[j]->b_min.z < dmin)
X				dmin = cd->child[j]->b_min.z;
X			if (cd->child[j]->b_max.z > dmax)
X				dmax = cd->child[j]->b_max.z;
X		}
X
X		cp->b_min.z = dmin;
X		cp->b_max.z = dmax;
X
X
X		cp->obj = (void *) cd;
X		root = cp;
X
X		if (nobjects < MAX_PRIMS)
X		{
X			objects[nobjects++] = cp;
X			return (1);
X		}
X		else
X		{
X			fprintf(stderr, "%s: too many primitives, max is %d\n",
X				my_name, MAX_PRIMS);
X			exit(0);
X		}
X	}
X	else
X	{
X		m = (first + last) / 2;
X		Sort_split(first, m);
X		Sort_split(m, last);
X		return (0);
X	}
X}
END_OF_FILE
if test 3740 -ne `wc -c <'bound.c'`; then
    echo shar: \"'bound.c'\" unpacked with wrong size!
fi
# end of 'bound.c'
fi
if test -f 'data.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'data.c'\"
else
echo shar: Extracting \"'data.c'\" \(957 characters\)
sed "s/^X//" >'data.c' <<'END_OF_FILE'
X
X/*
X * data.c - Contains all of the data declarations.
X */
X
X#include <math.h>
X#include "rt.h"
X
Xint             verbose = 0;
Xchar           *my_name;
Xchar            input_file[64];
Xchar            output_file[64];
Xint             nlights = 0;
Xint             nobjects = 0;
Xint             shadow = 1;
Xint             reflect = 1;
Xint             refract = 1;
Xint		y_start = 0;
Xint		y_inc = 1;
Xint		do_image_size = 1;
X
XVIEW_INFO       view;
XSURFACE        *cur_surface;
XBACKGROUND      bkgnd;
XLIGHT          *lights[MAX_LIGHTS];
XOBJECT         *objects[MAX_PRIMS];
XOBJECT         *object_stack[STACK_SIZE];
XOBJECT         *root;
XINSTANCE       *instances[MAX_INSTANCE];
X
Xint             num_instance = 0;
Xint             stack_cnt = 0;
Xint             sample_cnt = 1;
X
Xint             n_rays = 0;
Xint             n_intersects = 0;
Xint             n_shadows = 0;
Xint             n_shadinter = 0;
Xint             n_reflect = 0;
Xint             n_refract = 0;
X
END_OF_FILE
if test 957 -ne `wc -c <'data.c'`; then
    echo shar: \"'data.c'\" unpacked with wrong size!
fi
# end of 'data.c'
fi
if test -f 'example1.dat' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'example1.dat'\"
else
echo shar: Extracting \"'example1.dat'\" \(1086 characters\)
sed "s/^X//" >'example1.dat' <<'END_OF_FILE'
X#
X#
Xfrom 3 4 7
Xat 3 2 2
Xup 0 1 0
Xangle 40 
Xresolution 800 700 
Xbackground .1 .1 .1 n
Xlight 3 4.9 3 
X#
X# floor
X#
Xsurface 0 0 0 0  0 0 0 0  0 0 .4  0 0 .4  0 0 0 0 0
Xpolygon 4
X0 0 0
X6 0 0
X6 0 8
X0 0 8
X#
X# Walls - non-reflective off white
X#
Xsurface 0 0 0 0  0 0 0 0  .3 .3 .3  .4 .4 .4 0 0 0  0 0
Xpolygon 4
X0 0 0
X0 5 0
X6 5 0
X6 0 0
Xpolygon 4
X6 0 0
X6 5 0
X6 5 8
X6 0 8
Xpolygon 4
X6 0 8
X6 5 8
X0 5 8
X0 0 8
Xpolygon 4
X0 0 8
X0 5 8
X0 5 0
X0 0 0
Xpolygon 4
X0 5 0
X0 5 8
X6 5 8
X6 5 0
X#
X# Pedastal - Highly reflective metal
X#
Xsurface 1 1 1 .8  0 0 0 0  0 0 0  0 0 0  0 0 0 0 0
Xpolygon 4
X1 0 3
X1 1 3
X3 1 3
X3 0 3
Xpolygon 4
X3 1 3
X3 1 1
X3 0 1
X3 0 3
Xpolygon 4
X1 0 3
X1 0 1
X1 1 1
X1 1 3
Xsurface 1 1 1 1  0 0 0 0  0 0 0  0 0 0  0 0 0 0 0
Xpolygon 4		# top 
X1 1 3
X1 1 1
X3 1 1
X3 1 3
X#
X# sphere on pedastal
X#
Xsurface 0 0 0 0  0 0 0 0  .3 0 .12  .7 0 .28  .9 .9 .9 50 0
Xsphere 1.75 1.5 2 .5
X#
X# sphere of ground
X#
Xsurface .9 .9 .9 .9    0 0 0 0  .3 .2 .4  .3 .2 .4    .9 .9 .9 70 0
Xsphere 3.4 .4 1.5  .4
X#
X# crystal ball on ground
X#
Xsurface .9 .9 .9 .3  .9 .9 .9 .9  0 0 0  0 0 0 .9 .9 .9 70 1.5
Xsphere 4.5 .75 2.25 .75
X
X
END_OF_FILE
if test 1086 -ne `wc -c <'example1.dat'`; then
    echo shar: \"'example1.dat'\" unpacked with wrong size!
fi
# end of 'example1.dat'
fi
if test -f 'externs.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'externs.h'\"
else
echo shar: Extracting \"'externs.h'\" \(886 characters\)
sed "s/^X//" >'externs.h' <<'END_OF_FILE'
X
X/*
X * externs.h - This file contains all of the external data definitions.
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
Xextern int      verbose;
Xextern char    *my_name;
Xextern char     input_file[];
Xextern char     output_file[];
Xextern int      nlights;
Xextern int      nobjects;
Xextern int      shadow;
Xextern int      reflect;
Xextern int      refract;
Xextern int	y_start;
Xextern int	y_inc;
Xextern int 	do_image_size;
X
Xextern VIEW_INFO view;
Xextern SURFACE *cur_surface;
Xextern BACKGROUND bkgnd;
Xextern LIGHT   *lights[];
Xextern OBJECT  *objects[];
Xextern OBJECT  *object_stack[];
Xextern OBJECT  *root;
Xextern INSTANCE *instances[];
X
Xextern int      num_instance;
Xextern int      stack_cnt;
Xextern int      sample_cnt;
Xextern int      n_rays;
Xextern int      n_intersects;
Xextern int      n_shadows;
Xextern int      n_shadinter;
Xextern int      n_reflect;
Xextern int      n_refract;
END_OF_FILE
if test 886 -ne `wc -c <'externs.h'`; then
    echo shar: \"'externs.h'\" unpacked with wrong size!
fi
# end of 'externs.h'
fi
if test -f 'hsphere.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hsphere.c'\"
else
echo shar: Extracting \"'hsphere.c'\" \(4502 characters\)
sed "s/^X//" >'hsphere.c' <<'END_OF_FILE'
X
X/*
X * hsphere.c - This module contain all of the code that relates to
X *             hallow spheres.
X *
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <malloc.h>
X#include <math.h>
X
X#include "rt.h"
X#include "externs.h"
X
X
Xint Hsphere_intersect(), Hsphere_normal();
X
X
X/*
X * Build_hsphere()
X *
X * Given some info on a sphere object, build a complete object stucture.
X */
X
XBuild_hsphere(s)
XHSPHERE *s;
X{
X    OBJECT *o;
X
X    if(nobjects == MAX_PRIMS)
X    {
X	fprintf(stderr, "%s: too many objects specified\n", my_name);
X	exit(1);
X    }
X
X    if((o = (OBJECT *) malloc(sizeof(OBJECT))) == NULL)
X    {
X	fprintf(stderr, "%s: malloc failed\n", my_name);
X	exit(1);
X    }
X
X    s->radius2 = s->radius * s->radius;
X    s->i_radius2 = s->i_radius * s->i_radius;
X    
X    o->type = T_HSPHERE;
X    o->obj  = s;
X    o->surf = cur_surface;
X    o->inter = Hsphere_intersect;
X    o->normal = Hsphere_normal;
X
X    objects[nobjects++] = o;
X
X    /*
X     * Setup of bounding box for this puppy.
X     */
X
X    o->b_min.x = s->center.x - s->radius;
X    o->b_min.y = s->center.y - s->radius;
X    o->b_min.z = s->center.z - s->radius;
X
X    o->b_max.x = s->center.x + s->radius;
X    o->b_max.y = s->center.y + s->radius;
X    o->b_max.z = s->center.z + s->radius;
X    
X}
X
X
X/*
X * Hsphere_intersect()
X *
X * Check given sphere for intersection with given ray. Return TRUE if
X * an intersection takes place.
X */
X
XHsphere_intersect(obj, ray, inter)
XOBJECT *obj;
XRAY *ray;
XINTERSECT *inter;
X{
X    HSPHERE *s;
X    VECTOR oc;
X    double l2oc, tca, t2hc, i_t2hc, disc, i_disc;
X    double t, i_t;
X    int which, inside1, inside2;
X    
X    s = obj->obj;
X
X    /* calculate the origin to center vector */
X    
X    VecSub(s->center, ray->pos, oc);
X    l2oc = VecDot(oc, oc);
X
X    /* find out the closest approach along the ray */
X    tca = VecDot(oc, ray->dir);
X    t2hc = s->radius2 - l2oc + (tca * tca);
X    i_t2hc = s->i_radius2 - l2oc + (tca * tca);
X    
X    /* if the discriminator < 0, then the ray will not hit */
X    if(t2hc < MIN_T)
X    {
X	if(i_t2hc < MIN_T)
X	{
X	    return (0);			/* didn't hit either one */
X	}
X	else
X	{
X	    which = 2;			/* hit the inside one	*/
X	}
X    }
X    else
X    {
X	if(i_t2hc < MIN_T)		/* hit the outside one	*/
X	{
X	    which = 1;
X	}
X	else
X	{
X	    which = 0;			/* don't know yet	*/
X	}
X    }
X
X    /* only find the sqrt root of the one we need */
X    switch(which)
X    {
X    case 0 :		/* damm it jim! We need both! */
X	disc = sqrt(t2hc);
X	i_disc = sqrt(i_t2hc);
X	if(l2oc > s->radius2 + MIN_T)
X	{
X	    inside1 = 0;
X	    t = tca - disc;
X	}
X	else
X	{
X	    inside1 = 1;
X	    t = tca + disc;
X	}
X	
X	/* reverse the inside flag for this one */
X	if(l2oc > s->i_radius2 + MIN_T)
X	{
X	    inside2 = 1;
X	    i_t = tca - i_disc;
X	}
X	else
X	{
X	    inside2 = 0;
X	    i_t = tca + i_disc;
X	}
X
X	/*
X	 * figure out which of the spheres we hit. If we have
X	 * hit both, then take the close one.
X	 */
X
X	if(t < MIN_T)	/* didn't hit the outside one, try the inside */
X	{
X	    if(i_t < MIN_T) /* yikes!! All this cpu time and we missed both */
X	    {
X		return (0);
X	    }
X	    else
X	    {		    /* we hit this one */
X		inter->t = i_t;
X		inter->inside = inside2;
X		inter->obj = obj;
X		return (1);
X	    }
X	}
X	else
X	{
X	    inter->obj = obj;
X	    if(i_t < MIN_T)	/* hit the outside one only	*/
X	    {
X		inter->t = t;
X		inter->inside = inside1;
X		return (1);
X	    }
X	    else		/* hit both, chose the close one */
X	    {
X		if(i_t < t - MIN_T)
X		{
X		    inter->t = i_t;
X		    inter->inside = inside2;
X		}
X		else
X		{
X		    inter->t = t;
X		    inter->inside = inside1;
X		}
X		return (1);
X	    }
X	}
X	break;
X
X    case 1 :
X	disc = sqrt(t2hc);
X	/* if ray is inside object, set the inside flag */
X	if(l2oc > s->radius2 + MIN_T)
X	{
X	    inter->inside = 0;
X	    t = tca - disc;
X	}
X	else
X	{
X	    inter->inside = 1;
X	    t = tca + disc;
X	}
X	break;
X
X    case 2 :
X	i_disc = sqrt(i_t2hc);
X	/* if ray is inside object, set the inside flag to FALSE */
X	if(l2oc > s->i_radius2 + MIN_T)
X	{
X	    inter->inside = 1;
X	    t = tca - i_disc;
X	}
X	else
X	{
X	    inter->inside = 0;
X	    t = tca + i_disc;
X	}
X	break;
X    }
X    
X
X    if(t < MIN_T)
X	return (0);
X
X    inter->obj = obj;
X    inter->t = t;
X
X    return (1);
X    
X}
X
X
X/*
X * Hsphere_normal()
X *
X * Return the normal to a sphere at a given point along the surface.
X */
X
XHsphere_normal(sphere, ray, ip, normal)
XHSPHERE *sphere;
XRAY    *ray;
XVECTOR *ip;
XVECTOR *normal;
X{
X
X    VecSub(*ip, sphere->center, *normal);
X    VecNormalize(normal);
X    if(VecDot(ray->dir, *normal) >= 0)
X	VecNegate(*normal);
X}
X
X
X 
END_OF_FILE
if test 4502 -ne `wc -c <'hsphere.c'`; then
    echo shar: \"'hsphere.c'\" unpacked with wrong size!
fi
# end of 'hsphere.c'
fi
if test -f 'intersect.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'intersect.c'\"
else
echo shar: Extracting \"'intersect.c'\" \(3930 characters\)
sed "s/^X//" >'intersect.c' <<'END_OF_FILE'
X
X/*
X * intersect.c - The module check for eye/object intersection
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <math.h>
X#include "rt.h"
X#include "externs.h"
X
X
X/*
X * Intersect()
X * 
X * Check to see if given ray intersect any objects. If so, fill in the given
X * intersect structure and return 1. Else, return 0.
X */
X
XIntersect(ray, inter)
XRAY            *ray;
XINTERSECT      *inter;
X{
X	int             i, iflag;
X	INTERSECT       minter;
X	OBJECT         *obj;
X	COMPOSITE      *cd;
X
X	iflag = 0;
X	/*
X	 * If the root object is not a slab, then slimply call its inter
X	 * intersect routine and return.
X	 */
X
X	if (root->type != T_COMPOSITE)
X		return ((*root->inter) (root, ray, inter));
X
X	/*
X	 * Push root node an top of stack and check to set if we hit
X	 * anything.
X	 */
X
X	stack_cnt = 0;
X
X	Check_and_push(root, ray);
X
X	while (stack_cnt != 0)
X	{
X
X		obj = Pop_object();
X
X		/*
X		 * If this object is a composite type, then check and push
X		 * all of its childeren onto the stack.
X		 */
X
X
X		if (obj->type == T_COMPOSITE)
X		{
X			cd = (COMPOSITE *) obj->obj;
X			for (i = 0; i < cd->num; i++)
X				Check_and_push(cd->child[i], ray);
X		}
X		else
X		{
X
X			if ((*obj->inter) (obj, ray, inter))
X			{
X				if (iflag == 0)	/* first intersection */
X				{
X					iflag = 1;
X					minter.t = inter->t;
X					minter.obj = inter->obj;
X				}
X				else if (minter.t > inter->t)
X				{
X					minter.t = inter->t;
X					minter.obj = obj;
X				}
X			}
X		}
X	}
X
X	if (iflag)
X	{
X		inter->t = minter.t;
X		inter->obj = minter.obj;
X		return (1);
X	}
X	else
X		return (0);
X
X}
X
X/*
X * Check_and_push()
X * 
X * Check to see of this ray penatrate this bbox around the object. If so, push
X * it on the stack.
X */
X
XCheck_and_push(obj, ray)
XOBJECT         *obj;
XRAY            *ray;
X{
X
X	VECTOR          mn, mx, r_dir, r_org;
X	double          t_near, t_far, t1, t2, t3;
X	int             i;
X
X	r_dir = ray->dir;
X	r_org = ray->pos;
X
X	mn = obj->b_min;
X	mx = obj->b_max;
X
X	t_near = -HUGE;
X	t_far = HUGE;
X
X	/* test the X slab */
X	if (fabs(r_dir.x) < MIN_T)	/* parralel to the X slab */
X	{
X		if (r_org.x < mn.x || r_org.x > mx.x)
X			return;	/* can't possible hit this puppy */
X	}
X	else
X	{
X		/* ray is not parallel to the X slab. calc intersection dist */
X
X		t1 = (mn.x - r_org.x) / r_dir.x;
X		t2 = (mx.x - r_org.x) / r_dir.x;
X
X		if (t1 > t2)
X		{
X			if (t2 > t_near)
X				t_near = t2;
X			if (t1 < t_far)
X				t_far = t1;
X		}
X		else
X		{
X			if (t1 > t_near)
X				t_near = t1;
X			if (t2 < t_far)
X				t_far = t2;
X		}
X
X		if (t_near > t_far)
X			return;	/* no hitter			 */
X
X		if (t_far < MIN_T)
X			return;	/* no hitter			 */
X	}
X
X	/* test the Y slab */
X	if (fabs(r_dir.y) < MIN_T)	/* parralel to the Y slab */
X	{
X		if (r_org.y < mn.y || r_org.y > mx.y)
X			return;	/* can't possible hit this puppy */
X	}
X	else
X	{
X		/* this is not parallel to the Y slab. calc intersection dist */
X
X		t1 = (mn.y - r_org.y) / r_dir.y;
X		t2 = (mx.y - r_org.y) / r_dir.y;
X
X		if (t1 > t2)
X		{
X			if (t2 > t_near)
X				t_near = t2;
X			if (t1 < t_far)
X				t_far = t1;
X		}
X		else
X		{
X			if (t1 > t_near)
X				t_near = t1;
X			if (t2 < t_far)
X				t_far = t2;
X		}
X
X		if (t_near > t_far)
X			return;	/* no hitter			 */
X
X		if (t_far < MIN_T)
X			return;	/* no hitter			 */
X	}
X
X	/* test the Z slab */
X	if (fabs(r_dir.z) < MIN_T)	/* parralel to the Z slab */
X	{
X		if (r_org.z < mn.z || r_org.z > mx.z)
X			return;	/* can't possible hit this puppy */
X	}
X	else
X	{
X		/* ray is not parallel to the Z slab. calc intersection dist */
X
X		t1 = (mn.z - r_org.z) / r_dir.z;
X		t2 = (mx.z - r_org.z) / r_dir.z;
X
X		if (t1 > t2)
X		{
X			if (t2 > t_near)
X				t_near = t2;
X			if (t1 < t_far)
X				t_far = t1;
X		}
X		else
X		{
X			if (t1 > t_near)
X				t_near = t1;
X			if (t2 < t_far)
X				t_far = t2;
X		}
X
X		if (t_near > t_far)
X			return;	/* no hitter			 */
X
X		if (t_far < MIN_T)
X			return;	/* no hitter			 */
X	}
X
X	/*
X	 * This object passed all of the test. So this ray will hit this
X	 * puppy. Push at on the stack.
X	 */
X
X	Push_object(obj);
X
X}
END_OF_FILE
if test 3930 -ne `wc -c <'intersect.c'`; then
    echo shar: \"'intersect.c'\" unpacked with wrong size!
fi
# end of 'intersect.c'
fi
if test -f 'main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(4291 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X
X/*
X * * main.c - Main module for raytracer *
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <math.h>
X
X#include "rt.h"
X#include "externs.h"
X
X
X
Xmain(argc, argv)
Xint             argc;
Xchar           *argv[];
X{
X	long            timest, timeend;
X	int             i;
X
X	time(&timest);
X
X	my_name = argv[0];
X
X	/*
X	 * check command line options
X	 */
X
X	++argv;
X	--argc;
X	while (argc > 0 && *argv[0] == '-')
X	{
X		if (!strcmp(*argv, "-v"))	/* verbose mode		 */
X		{
X			verbose = 1;
X			--argc;
X			++argv;
X		}
X		else if (!strcmp(*argv, "-s"))	/* shadows off		 */
X		{
X			shadow = 0;
X			--argc;
X			++argv;
X		}
X		else if (!strcmp(*argv, "-l"))	/* disable reflections	 */
X		{
X			reflect = 0;
X			--argc;
X			++argv;
X		}
X		else if (!strcmp(*argv, "-r"))	/* disable refractions	 */
X		{
X			refract = 0;
X			++argv;
X			--argc;
X		}
X		else if (!strcmp(*argv, "-d"))	/* disable sampling	 */
X		{
X			sample_cnt = 0;
X			++argv;
X			--argc;
X		}
X		else if (!strcmp(*argv, "-z"))	/* disable image size	 */
X		{
X			do_image_size = 0;
X			++argv;
X			--argc;
X		}
X		else if (!strcmp(*argv, "-c"))	/* sample count		 */
X		{
X			++argv;
X			sample_cnt = atoi(*argv);
X			++argv;
X			argc -= 2;
X			if (sample_cnt < 0)
X			{
X				fprintf(stderr, "%s: sample count must be > 0\n", my_name);
X				exit(1);
X			}
X		}
X		else if (!strcmp(*argv, "-y"))	/* y start and inc */
X		{
X			++argv;
X			y_start = atoi(*argv);
X			++argv;
X			y_inc = atoi(*argv);
X			++argv;
X			argc -= 3;
X			if (y_start < 0 || y_inc < 1)
X			{
X				fprintf(stderr, "%s: bad y_start and y_inc\n", my_name);
X				exit(1);
X			}
X		}
X		else
X		{
X			Usage();
X		}
X	}
X
X	if (argc == 0)
X	{
X		strcpy(input_file, "STDIN");
X		strcpy(output_file, "STDOUT");
X	}
X	else if (argc == 2)
X	{
X		strcpy(input_file, argv[0]);
X		strcpy(output_file, argv[1]);
X	}
X	else
X		Usage();
X
X	/*
X	 * Read the input file. Will exit on error.
X	 */
X
X	if (argc == 0)
X		Read_input_file(NULL);
X	else
X		Read_input_file(input_file);
X
X	/*
X	 * Check to make sure that there was at least one object and one
X	 * light source specified.
X	 */
X
X	if (nlights == 0)
X	{
X		fprintf(stderr, "%s: no light sources were specified.\n", my_name);
X		exit(1);
X	}
X
X	if (nobjects == 0)
X	{
X		fprintf(stderr, "%s: no objects were specified.\n", my_name);
X		exit(1);
X	}
X
X	/*
X	 * Adjust the intensity of each light
X	 */
X
X	for (i = 0; i < nlights; i++)
X	{
X		lights[i]->intensity = sqrt((double) nlights) / (double) nlights;
X	}
X
X	/*
X	 * Open the output file.
X	 */
X
X	if (argc == 0)
X		Init_output_file(NULL);
X	else
X		Init_output_file(output_file);
X
X	/*
X	 * If verbose flag is on, print some info.
X	 */
X
X	if (verbose)
X	{
X		fprintf(stderr, "%s: input file = %s\n", my_name, input_file);
X		fprintf(stderr, "%s: output file = %s\n", my_name, output_file);
X		fprintf(stderr, "%s: %d objects were specified\n", my_name, nobjects);
X		fprintf(stderr, "%s: %d lights were specified\n", my_name, nlights);
X		fprintf(stderr, "%s: output image is %d x %d\n", my_name,
X			view.x_res, view.y_res);
X	}
X
X	/*
X	 * Build the bounding box structures.
X	 */
X
X	Build_bounding_slabs();
X
X	if (verbose)
X	{
X		fprintf(stderr, "%s: %d objects after adding bounding volumes\n", my_name,
X			nobjects);
X	}
X
X	/*
X	 * Raytrace the picture.
X	 */
X
X	Raytrace();
X
X	/*
X	 * Close output file and exit
X	 */
X
X	if(argc == 0)
X		Close_output_file(NULL);
X	else
X		Close_output_file(output_file);
X
X	if(verbose)
X		fprintf(stderr, "\n");
X
X	/*
X	 * If verbose mode is on, then print some stats.
X	 * 
X	 */
X
X	if (verbose)
X	{
X		time(&timeend);
X		fprintf(stderr, "%s: total execution time: %d:%02d\n", my_name,
X			(timeend - timest) / 60, (timeend - timest) % 60);
X		fprintf(stderr, "%s: number of rays traced: %d\n", my_name, n_rays);
X		fprintf(stderr, "%s: number of non-shadow intersections: %d\n", my_name,
X			n_intersects);
X		fprintf(stderr, "%s: number of shadow rays: %d\n", my_name, n_shadows);
X		fprintf(stderr, "%s: number of shadow hits: %d\n", my_name, n_shadinter);
X		fprintf(stderr, "%s: number of reflected rays: %d\n", my_name, n_reflect);
X		fprintf(stderr, "%s: number of refracted rays: %d\n", my_name, n_refract);
X	}
X
X	exit(0);
X}
X
X/*
X * Usage() - Print usage and exit.
X */
X
XUsage()
X{
X	fprintf(stderr, 
X		"Usage: %s: [-v] [-s] [-l] [-r] [-d] [-z] [-c sample_count]\n", my_name);
X	fprintf(stderr, 
X		"           [-y y_start y_inc]  [input-file output-file]\n");
X	exit(1);
X}
END_OF_FILE
if test 4291 -ne `wc -c <'main.c'`; then
    echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'output.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'output.c'\"
else
echo shar: Extracting \"'output.c'\" \(1442 characters\)
sed "s/^X//" >'output.c' <<'END_OF_FILE'
X
X/*
X * output.c - This files contains all of the output image related functions.
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include "rt.h"
X#include "externs.h"
X
X#define CLAMPING	FALSE
X
XFILE           *out_fp;
X
X/*
X * Init_output_file()
X * 
X * Create and initialize the output image file.
X */
X
XInit_output_file(filename)
Xchar           *filename;
X{
X	long            xx;
X
X	if (filename)
X	{
X		if ((out_fp = fopen(output_file, "w")) == NULL)
X		{
X			fprintf(stderr, "%s: unable to create output file '%s'\n",
X				my_name, output_file);
X			exit(1);
X		}
X	}
X	else
X	{
X		out_fp = stdout;
X	}
X
X	if(do_image_size)
X	{
X		fprintf(out_fp, "%d %d\n", view.x_res, view.y_res);
X	}
X}
X
X/*
X * Close_output_file()
X * 
X * Do just like it sez.
X */
X
XClose_output_file(filename)
Xchar           *filename;
X{
X	if (filename)
X		fclose(out_fp);
X}
X
X/*
X * Write_pixel()
X * 
X * Write the given RGB color pixel to the output file. Apply clamping if
X * necessary.
X */
X
XWrite_pixel(c)
XCOLOR          *c;
X{
X	unsigned char   rr, gg, bb;
X	double          mc;
X
X#if CLAMPING
X	if (c->r > 1.0)
X		c->r = 1.0;
X	if (c->g > 1.0)
X		c->g = 1.0;
X	if (c->b == 1.0)
X		c->b = 1.0;
X#endif
X
X	mc = c->r;
X	if (c->g > mc)
X		mc = c->g;
X	if (c->b > mc)
X		mc = c->b;
X
X	if (mc > 1)
X	{
X		c->r /= mc;
X		c->g /= mc;
X		c->b /= mc;
X	}
X
X	rr = 255.0 * c->r;
X	gg = 255.0 * c->g;
X	bb = 255.0 * c->b;
X
X	putc(rr, out_fp);
X	putc(gg, out_fp);
X	putc(bb, out_fp);
X}
X
XFlush_output_file()
X{
X	return ;
X}
X
END_OF_FILE
if test 1442 -ne `wc -c <'output.c'`; then
    echo shar: \"'output.c'\" unpacked with wrong size!
fi
# end of 'output.c'
fi
if test -f 'poly.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'poly.c'\"
else
echo shar: Extracting \"'poly.c'\" \(4608 characters\)
sed "s/^X//" >'poly.c' <<'END_OF_FILE'
X
X/*
X * poly.c - This module conatins all of the code that relates to polygons.
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <malloc.h>
X#include <math.h>
X
X#include "rt.h"
X#include "externs.h"
X
X
Xint             Poly_intersect(), Poly_normal();
Xextern int      line;
X
X/*
X * Build_poly()
X * 
X * Given some info on a polygon, build the entire object structure.
X */
X
XBuild_poly(p)
XPOLYGON        *p;
X{
X	OBJECT         *o;
X	VECTOR          pt1, pt2;
X	int             i;
X
X	if (nobjects == MAX_PRIMS)
X	{
X		fprintf(stderr, "%s: too many objects specified\n", my_name);
X		exit(1);
X	}
X
X	if ((o = (OBJECT *) malloc(sizeof(OBJECT))) == NULL)
X	{
X		fprintf(stderr, "%s: malloc failed\n", my_name);
X		exit(1);
X	}
X
X	o->type = T_POLYGON;
X	o->obj = p;
X	o->surf = cur_surface;
X	o->inter = Poly_intersect;
X	o->normal = Poly_normal;
X
X	objects[nobjects++] = o;
X
X	/*
X	 * Calculate the normals and the D coefficient by various cross
X	 * products.
X	 */
X
X	VecSub(p->points[1], p->points[0], pt1);
X	VecSub(p->points[2], p->points[0], pt2);
X	VecCross(pt1, pt2, p->normal);
X	VecNormalize(&p->normal);
X
X	p->d = -VecDot(p->normal, p->points[0]);
X
X	for (i = 0; i < p->npoints; i++)
X	{
X		if (fabs(VecDot(p->points[i], p->normal) + p->d) > MIN_T)
X		{
X#ifdef CHECK_COORD_ORDER
X			fprintf(stderr, "%s: coordinate given in wrong order on line %d\n",
X				my_name, line - p->npoints);
X#endif
X		}
X	}
X
X	/*
X	 * Figure out the most dominant normal.
X	 */
X
X	if (fabs(p->normal.x) > fabs(p->normal.y) &&
X	    fabs(p->normal.x) > fabs(p->normal.z))
X	{
X		p->p1 = 1;
X		p->p2 = 2;
X	}
X	else if (fabs(p->normal.y) > fabs(p->normal.x) &&
X		 fabs(p->normal.y) > fabs(p->normal.z))
X	{
X		p->p1 = 0;
X		p->p2 = 2;
X	}
X	else
X	{
X		p->p1 = 0;
X		p->p2 = 1;
X	}
X
X	/*
X	 * Setup the min and the max values for the bouding box.
X	 */
X
X	o->b_min.x = o->b_min.y = o->b_min.z = HUGE;
X	o->b_max.x = o->b_max.y = o->b_max.z = -HUGE;
X
X	for (i = 0; i < p->npoints; i++)
X	{
X		o->b_min.x = MIN(p->points[i].x, o->b_min.x);
X		o->b_min.y = MIN(p->points[i].y, o->b_min.y);
X		o->b_min.z = MIN(p->points[i].z, o->b_min.z);
X
X		o->b_max.x = MAX(p->points[i].x, o->b_max.x);
X		o->b_max.y = MAX(p->points[i].y, o->b_max.y);
X		o->b_max.z = MAX(p->points[i].z, o->b_max.z);
X	}
X}
X
X
X
X/*
X * Poly_intersect()
X * 
X * Check given ploy for intersection with given ray. Return TRUE if an
X * intersection takes place.
X */
X
XPoly_intersect(obj, ray, inter)
XOBJECT         *obj;
XRAY            *ray;
XINTERSECT      *inter;
X{
X	POLYGON        *p;
X	VECTOR          ipoint;
X	double          vo, vd;
X	double          t, b, m;
X	double          pi[3], pj[3], ip[3];
X	int             qi, qj, ri, rj, i, j;
X	int             n1, n2, l;
X
X
X	p = obj->obj;
X
X	/*
X	 * First check to see if this ray hit the plane which this polygon
X	 * resides on.
X	 */
X
X	vd = VecDot(ray->dir, p->normal);
X
X	if (fabs(vd) < MIN_T)
X		return (0);
X
X	vo = VecDot(ray->pos, p->normal) + p->d;
X
X	t = -vo / vd;
X	if (t < MIN_T)
X		return (0);
X
X	/*
X	 * OK. We now know that this ray hit the plane in which this polygon
X	 * resides on. Now we need to check to see if it hits the polygon. We
X	 * use the Jordon Curve Theorem to do this.
X	 */
X
X	/* get the point of intersection on the plane */
X	VecAddS(t, ray->dir, ray->pos, ipoint);
X	ip[0] = ipoint.x;
X	ip[1] = ipoint.y;
X	ip[2] = ipoint.z;
X
X	/* get the dominant normals */
X	n1 = p->p1;
X	n2 = p->p2;
X
X	/* ok, do it */
X
X	l = 0;
X	for (i = 0; i < p->npoints; i++)
X	{
X		j = (i + 1) % p->npoints;
X		qi = qj = ri = rj = 0;
X
X		pi[0] = p->points[i].x;
X		pi[1] = p->points[i].y;
X		pi[2] = p->points[i].z;
X
X		pj[0] = p->points[j].x;
X		pj[1] = p->points[j].y;
X		pj[2] = p->points[j].z;
X
X		/* check for horizontal line and ignore them */
X		if (pi[n2] == pj[n2])
X			continue;
X
X		if (pi[n2] < ip[n2])
X			qi = 1;
X		if (pj[n2] < ip[n2])
X			qj = 1;
X		if (qi == qj)
X			continue;
X
X		if (pi[n1] < ip[n1])
X			ri = 1;
X		if (pj[n1] < ip[n1])
X			rj = 1;
X
X		if (ri & rj)
X		{
X			++l;	/* crossed an edge		 */
X			continue;
X		}
X
X		if (!(rj | ri))
X			continue;
X
X		m = (pj[n2] - pi[n2]) / (pj[n1] - pi[n1]);
X		b = (pj[n2] - ip[n2]) - (m * (pj[n1] - ip[n1]));
X
X		if ((-b / m) < MIN_T)
X			++l;
X	}
X
X	if ((l % 2) == 0)
X		return (0);
X
X	/*
X	 * We have crossed an odd number of edges, that means that we have a
X	 * hit!!!
X	 */
X
X	inter->t = t;
X	inter->obj = obj;
X	inter->inside = 0;
X
X	return (1);
X}
X
X
X/*
X * Poly_normal()
X * 
X * Return the normal to a polygon at a given point along the surface.
X */
X
XPoly_normal(poly, ray, ip, normal)
XPOLYGON        *poly;
XRAY            *ray;
XVECTOR         *ip;
XVECTOR         *normal;
X{
X	VecCopy(poly->normal, *normal);
X	if (VecDot(ray->dir, *normal) >= 0)
X		VecNegate(*normal);
X}
END_OF_FILE
if test 4608 -ne `wc -c <'poly.c'`; then
    echo shar: \"'poly.c'\" unpacked with wrong size!
fi
# end of 'poly.c'
fi
if test -f 'quadric.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'quadric.c'\"
else
echo shar: Extracting \"'quadric.c'\" \(3152 characters\)
sed "s/^X//" >'quadric.c' <<'END_OF_FILE'
X
X/*
X * quadric.c - This module conatins all of the code that relates to
X * quadratics.
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <malloc.h>
X#include <math.h>
X
X#include "rt.h"
X#include "externs.h"
X
X
Xint             Quadric_intersect(), Quadric_normal();
X
X/*
X * Build_quadric()
X * 
X * Given some info on a quadric, build the entire object structure.
X */
X
XBuild_quadric(q)
XQUADRIC        *q;
X{
X	OBJECT         *o;
X
X	if (nobjects == MAX_PRIMS)
X	{
X		fprintf(stderr, "%s: too many objects specified\n", my_name);
X		exit(1);
X	}
X
X	if ((o = (OBJECT *) malloc(sizeof(OBJECT))) == NULL)
X	{
X		fprintf(stderr, "%s: malloc failed\n", my_name);
X		exit(1);
X	}
X
X
X	o->type = T_QUADRIC;
X	o->obj = q;
X	o->surf = cur_surface;
X	o->inter = Quadric_intersect;
X	o->normal = Quadric_normal;
X
X	objects[nobjects++] = o;
X
X	/*
X	 * Calculate some constants that we will need in the intersect
X	 * routine.
X	 */
X
X	q->a2 = q->a * 2.0;
X	q->b2 = q->b * 2.0;
X	q->c2 = q->c * 2.0;
X	q->d2 = q->d * 2.0;
X	q->f2 = q->f * 2.0;
X	q->g2 = q->g * 2.0;
X	q->i2 = q->i * 2.0;
X
X	/*
X	 * Setup the min and the max values for the bouding box. For now,
X	 * just use what the user specifies.
X	 */
X
X	o->b_min = q->min;
X	o->b_max = q->max;
X
X}
X
X
X
X/*
X * Quadric_intersect()
X * 
X * Check given quadratic for intersection with given ray. Return TRUE if an
X * intersection takes place.
X */
X
XQuadric_intersect(obj, ray, inter)
XOBJECT         *obj;
XRAY            *ray;
XINTERSECT      *inter;
X{
X	QUADRIC        *q;
X	VECTOR          rd, rp;
X	double          aq, nbq, cq;
X	double          t, disc;
X	double          ka, kb;
X
X	q = (QUADRIC *) obj->obj;
X
X	rd = ray->dir;
X	rp = ray->pos;
X
X	/*
X	 * Compute Aq, Bq, Cq.
X	 */
X
X	aq = rd.x * (q->a * rd.x + q->b2 * rd.y + q->c2 * rd.z) +
X		rd.y * (q->e * rd.y + q->f2 * rd.z) +
X		q->h * rd.z * rd.z;
X
X	nbq = rd.x * (q->a * rp.x + q->b * rp.y + q->c * rp.z + q->d) +
X		rd.y * (q->b * rp.x + q->e * rp.y + q->f * rp.z + q->g) +
X		rd.z * (q->c * rp.x + q->f * rp.y + q->h * rp.z + q->i);
X
X	cq = rp.x * (q->a * rp.x + q->b2 * rp.y + q->c2 * rp.z + q->d2) +
X		rp.y * (q->e * rp.y + q->f2 * rp.z + q->g2) +
X		rp.z * (q->h * rp.z + q->i2) + q->j;
X
X	if (fabs(aq) < MIN_T)
X	{
X		t = -cq / (2 * nbq);
X		if (t < MIN_T)
X			return (0);	/* no hit */
X
X		inter->obj = obj;
X		inter->t = t;
X		inter->inside = 0;
X		return (1);
X	}
X
X	/*
X	 * Compute the discriminator.
X	 */
X
X	ka = -nbq / aq;
X	kb = cq / aq;
X
X	disc = (ka * ka) - (kb);
X	if (disc < MIN_T)
X		return (0);
X
X	t = ka - sqrt(disc);
X
X	if (t < MIN_T)
X	{
X		t = ka + sqrt(disc);
X		if (t < MIN_T)
X			return (0);
X		inter->inside = 1;
X	}
X	else
X		inter->inside = 0;
X
X	inter->t = t;
X	inter->obj = obj;
X
X	return (1);
X}
X
X
X/*
X * Quadric_normal()
X * 
X * Return the normal to a quadric at a given point along the surface.
X */
X
XQuadric_normal(q, ray, ip, normal)
XQUADRIC        *q;
XRAY            *ray;
XVECTOR         *ip;
XVECTOR         *normal;
X{
X
X	normal->x = q->a * ip->x + q->b * ip->y + q->c * ip->z + q->d;
X	normal->y = q->b * ip->x + q->e * ip->y + q->f * ip->z + q->g;
X	normal->z = q->c * ip->x + q->f * ip->y + q->h * ip->z + q->i;
X
X	VecNormalize(normal);
X
X	if (VecDot(ray->dir, *normal) >= 0)
X		VecNegate(*normal);
X}
END_OF_FILE
if test 3152 -ne `wc -c <'quadric.c'`; then
    echo shar: \"'quadric.c'\" unpacked with wrong size!
fi
# end of 'quadric.c'
fi
if test -f 'ring.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ring.c'\"
else
echo shar: Extracting \"'ring.c'\" \(2928 characters\)
sed "s/^X//" >'ring.c' <<'END_OF_FILE'
X
X/*
X * ring.c - This module conatins all of the code that relates to the ring
X * primitive.
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <malloc.h>
X#include <math.h>
X
X#include "rt.h"
X#include "externs.h"
X
X
Xint             Ring_intersect(), Ring_normal();
Xextern int      line;
X
X/*
X * Build_ring()
X * 
X * Given some info on a ring, build the entire object structure.
X */
X
XBuild_ring(r)
XRING           *r;
X{
X	OBJECT         *o;
X	VECTOR          pt1, pt2;
X	int             i;
X
X	if (nobjects == MAX_PRIMS)
X	{
X		fprintf(stderr, "%s: too many objects specified\n", my_name);
X		exit(1);
X	}
X
X	if ((o = (OBJECT *) malloc(sizeof(OBJECT))) == NULL)
X	{
X		fprintf(stderr, "%s: malloc failed\n", my_name);
X		exit(1);
X	}
X
X
X	o->type = T_RING;
X	o->obj = r;
X	o->surf = cur_surface;
X	o->inter = Ring_intersect;
X	o->normal = Ring_normal;
X
X	objects[nobjects++] = o;
X
X	/*
X	 * Calculate the normals and the D coefficient by various cross
X	 * products.
X	 */
X
X	VecSub(r->point1, r->center, pt1);
X	VecSub(r->point2, r->center, pt2);
X	VecCross(pt1, pt2, r->normal);
X	VecNormalize(&r->normal);
X
X
X	r->d = -VecDot(r->normal, r->center);
X
X	if (fabs(VecDot(r->center, r->normal) + r->d) > MIN_T)
X	{
X		fprintf(stderr, "%s: coordinate given in wrong order on line %d\n",
X			my_name, line);
X	}
X
X	/*
X	 * Do some other precomp for the sake of speed.
X	 */
X
X	r->o_radius2 = r->o_radius * r->o_radius;
X	r->i_radius2 = r->i_radius * r->i_radius;
X
X	/*
X	 * Setup the min and the max values for the bouding box.
X	 */
X
X	pt1.x = pt1.y = pt1.z = r->o_radius;
X
X	VecSub(r->center, pt1, o->b_min);
X	VecAdd(r->center, pt1, o->b_max);
X}
X
X
X
X/*
X * ring_intersect()
X * 
X * Check given ring for intersection with given ray. Return TRUE if an
X * intersection takes place.
X */
X
XRing_intersect(obj, ray, inter)
XOBJECT         *obj;
XRAY            *ray;
XINTERSECT      *inter;
X{
X	RING           *r;
X	VECTOR          ip, tp;
X	double          vo, vd;
X	double          t, t2;
X
X	r = obj->obj;
X
X	/*
X	 * First check to see if this ray hit the plane which this ring
X	 * resides on.
X	 */
X
X	vd = VecDot(ray->dir, r->normal);
X
X	if (fabs(vd) < MIN_T)
X		return (0);
X
X	vo = VecDot(ray->pos, r->normal) + r->d;
X
X	t = -vo / vd;
X	if (t < MIN_T)
X		return (0);
X
X	/*
X	 * Calculate the point of intersection.
X	 */
X
X	VecAddS(t, ray->dir, ray->pos, ip);
X
X	/*
X	 * If the point of intersection lies between the inner and outer
X	 * radius, the have have a hit.
X	 */
X
X	VecSub(r->center, ip, tp);
X	t2 = VecDot(tp, tp);
X
X	if (t2 < r->i_radius2 || t2 > r->o_radius2)
X		return (0);
X
X	/* we have a hit */
X
X	inter->t = t;
X	inter->obj = obj;
X	inter->inside = 0;
X
X	return (1);
X}
X
X
X/*
X * Ring_normal()
X * 
X * Return the normal to a ring at a given point along the surface.
X */
X
XRing_normal(ring, ray, ip, normal)
XRING           *ring;
XRAY            *ray;
XVECTOR         *ip;
XVECTOR         *normal;
X{
X	VecCopy(ring->normal, *normal);
X	if (VecDot(ray->dir, *normal) >= 0)
X		VecNegate(*normal);
X}
END_OF_FILE
if test 2928 -ne `wc -c <'ring.c'`; then
    echo shar: \"'ring.c'\" unpacked with wrong size!
fi
# end of 'ring.c'
fi
if test -f 'sphere.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sphere.c'\"
else
echo shar: Extracting \"'sphere.c'\" \(2458 characters\)
sed "s/^X//" >'sphere.c' <<'END_OF_FILE'
X
X/*
X * sphere.c - This module contain all of the code that relates to spheres.
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <malloc.h>
X#include <math.h>
X
X#include "rt.h"
X#include "externs.h"
X
X
Xint             Sphere_intersect(), Sphere_normal();
X
X
X/*
X * Build_sphere()
X * 
X * Given some info on a sphere object, build a complete object stucture.
X */
X
XBuild_sphere(s)
XSPHERE         *s;
X{
X	OBJECT         *o;
X
X	if (nobjects == MAX_PRIMS)
X	{
X		fprintf(stderr, "%s: too many objects specified\n", my_name);
X		exit(1);
X	}
X
X	if ((o = (OBJECT *) malloc(sizeof(OBJECT))) == NULL)
X	{
X		fprintf(stderr, "%s: malloc failed\n", my_name);
X		exit(1);
X	}
X
X	s->radius2 = s->radius * s->radius;
X
X	o->type = T_SPHERE;
X	o->obj = s;
X	o->surf = cur_surface;
X	o->inter = Sphere_intersect;
X	o->normal = Sphere_normal;
X
X	objects[nobjects++] = o;
X
X	/*
X	 * Setup of bounding box for this puppy.
X	 */
X
X	o->b_min.x = s->center.x - s->radius;
X	o->b_min.y = s->center.y - s->radius;
X	o->b_min.z = s->center.z - s->radius;
X
X	o->b_max.x = s->center.x + s->radius;
X	o->b_max.y = s->center.y + s->radius;
X	o->b_max.z = s->center.z + s->radius;
X
X}
X
X
X/*
X * Sphere_intersect()
X * 
X * Check given sphere for intersection with given ray. Return TRUE if an
X * intersection takes place.
X */
X
XSphere_intersect(obj, ray, inter)
XOBJECT         *obj;
XRAY            *ray;
XINTERSECT      *inter;
X{
X	SPHERE         *s;
X	VECTOR          oc;
X	double          l2oc, tca, t2hc, disc;
X	double          t;
X
X	s = obj->obj;
X
X	/* calculate the origin to center vector */
X
X	VecSub(s->center, ray->pos, oc);
X	l2oc = VecDot(oc, oc);
X
X	/* find out the closest approach along the ray */
X	tca = VecDot(oc, ray->dir);
X	t2hc = s->radius2 - l2oc + (tca * tca);
X
X	/* if the discriminator < 0, then the ray will not hit */
X	if (t2hc < MIN_T)
X		return (0);
X
X	disc = sqrt(t2hc);
X
X	/* if ray is inside object, set the inside flag */
X	if (l2oc > s->radius2 + MIN_T)
X	{
X		inter->inside = 0;
X		t = tca - disc;
X	}
X	else
X	{
X		inter->inside = 1;
X		t = tca + disc;
X	}
X
X	if (t < MIN_T)
X		return (0);
X
X	inter->obj = obj;
X	inter->t = t;
X
X	return (1);
X
X}
X
X
X/*
X * Sphere_normal()
X * 
X * Return the normal to a sphere at a given point along the surface.
X */
X
XSphere_normal(sphere, ray, ip, normal)
XSPHERE         *sphere;
XRAY            *ray;
XVECTOR         *ip;
XVECTOR         *normal;
X{
X
X	VecSub(*ip, sphere->center, *normal);
X	VecNormalize(normal);
X	if (VecDot(ray->dir, *normal) >= 0)
X		VecNegate(*normal);
X}
END_OF_FILE
if test 2458 -ne `wc -c <'sphere.c'`; then
    echo shar: \"'sphere.c'\" unpacked with wrong size!
fi
# end of 'sphere.c'
fi
if test -f 'stack.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stack.c'\"
else
echo shar: Extracting \"'stack.c'\" \(824 characters\)
sed "s/^X//" >'stack.c' <<'END_OF_FILE'
X
X/*
X * stack.c
X * 
X * This module conatains all of the code for the object intersect test stack.
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <math.h>
X
X#include "rt.h"
X#include "externs.h"
X
X/*
X * Push_object()
X * 
X * Push the object onto the stack. Die of stack overflows.
X */
X
XPush_object(obj)
XOBJECT         *obj;
X{
X
X	/* check to stack overflow */
X	if (stack_cnt == STACK_SIZE)
X	{
X		fprintf(stderr, "%s: object stack overflow\n", my_name);
X		exit(1);
X	}
X
X	/* push it !! */
X	object_stack[stack_cnt++] = obj;
X}
X
X/*
X * Pop_object()
X * 
X * Pop an object from the stack. If none exist, die.
X */
X
XOBJECT         *
XPop_object()
X{
X
X	/* check for stack undeflow */
X	if (stack_cnt == 0)
X	{
X		fprintf(stderr, "%s: object stack underflow\n", my_name);
X		exit(1);
X	}
X
X	return (object_stack[--stack_cnt]);
X
X}
END_OF_FILE
if test 824 -ne `wc -c <'stack.c'`; then
    echo shar: \"'stack.c'\" unpacked with wrong size!
fi
# end of 'stack.c'
fi
if test -f 'tokens.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tokens.l'\"
else
echo shar: Extracting \"'tokens.l'\" \(839 characters\)
sed "s/^X//" >'tokens.l' <<'END_OF_FILE'
X%{
X#include <stdio.h>
X
Xtypedef double Flt ;
Xtypedef Flt Vec[3] ;
Xtypedef Vec Point ;
Xtypedef Vec Color ;
X
Xextern int yylinecount;
X
X#include "y.tab.h"
X%}
X
X%%
X[ \t]			;
X\#.*$			;
X\n			yylinecount ++ ;
Xv			return VIEWPOINT ;
Xviewpoint		return VIEWPOINT ;
Xfrom			return FROM ;
Xat			return AT ;
Xup			return UP ;
Xangle			return ANGLE ;
Xhither			return HITHER ;
Xresolution		return RESOLUTION ;
Xl			return LIGHT ;
Xlight			return LIGHT ;
Xb			return BACKGROUND ;
Xbackground		return BACKGROUND ;
Xf			return SURFACE ;
Xsurface			return SURFACE ;
Xc			return CONE ;
Xcone			return CONE ;
Xs			return SPHERE ;
Xsphere			return SPHERE ;
Xp			return POLYGON ;
Xpolygon			return POLYGON ;
Xpp			return PATCH ;
Xpatch			return PATCH ;
X\-?[0-9]*(\.[0-9]*(e\-?[0-9]+)?)? 	return NUM ;
X[A-Za-z0-9_]+		return TOKEN ;
X.			return yytext[0] ;
X
X%%
X
Xyywrap()
X{
X	return 1 ;
X}
END_OF_FILE
if test 839 -ne `wc -c <'tokens.l'`; then
    echo shar: \"'tokens.l'\" unpacked with wrong size!
fi
# end of 'tokens.l'
fi
if test -f 'trace.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'trace.c'\"
else
echo shar: Extracting \"'trace.c'\" \(3737 characters\)
sed "s/^X//" >'trace.c' <<'END_OF_FILE'
X/*
X * trace.c - This files contains the code which does the actuall raytracing.
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <math.h>
X
X#include "rt.h"
X#include "externs.h"
X
X
XCOLOR           Trace_a_ray(), Background_color(), Illuminate();
X
X
X/*
X * Raytrace()
X * 
X * Raytrace the entire picture.
X */
X
XRaytrace()
X{
X	RAY             ray;
X	double          xr, yr, x_step, y_step, x_pw, y_pw;
X	double          x_rand, y_rand;
X	int             x, y;
X	VECTOR          hor, ver;
X	COLOR           col, lcol, scol;
X	long            ts, te;
X	int             l_pr, l_int, l_shad, l_refl, l_refr, s;
X
X	/* calculate the viewing frustrum. */
X	VecSub(view.look_at, view.from, view.look_at);
X	VecNormalize(&view.look_at);
X	VecNormalize(&view.up);
X	VecCross(view.up, view.look_at, hor);
X	VecNormalize(&hor);	/* horizontal screen vector */
X	VecCross(view.look_at, hor, ver);
X	VecNormalize(&ver);	/* vertical screen vector	 */
X
X
X	x_pw = x_step = 2.0 / view.x_res;
X	y_pw = y_step = 2.0 / view.y_res;
X
X	VecCopy(view.from, ray.pos);
X
X	view.angle = tan(view.angle * M_PI / 180) / sqrt(2.0);
X
X	l_pr = l_int = l_shad = l_refl = l_refr = 0;
X	time(&ts);
X
X	/* OK, start tracing */
X	yr = 1 - (y_step * (double) y_start);
X	y_step = y_step * (double) y_inc;
X
X	for (y = y_start; y < view.y_res; y += y_inc)
X	{
X		xr = 1;
X		for (x = 0; x < view.x_res; x++)
X		{
X			/*
X			 * Setup the ray
X			 */
X			if (sample_cnt == 1)
X			{
X				VecComb(xr * view.angle, hor, yr * view.angle, ver, ray.dir);
X				VecAdd(ray.dir, view.look_at, ray.dir);
X				VecNormalize(&ray.dir);
X
X				/*
X				 * Trace that Ray!!
X				 */
X
X				col = Trace_a_ray(&ray, 0);
X			}
X			else
X			{
X				col.r = col.g = col.b = 0.0;
X				for (s = 1; s < sample_cnt; s++)
X				{
X					x_rand = (xr * view.angle) + (x_pw * RAND());
X					y_rand = (yr * view.angle) + (y_pw * RAND());
X
X					VecComb(x_rand, hor, y_rand, ver, ray.dir);
X					VecAdd(ray.dir, view.look_at, ray.dir);
X					VecNormalize(&ray.dir);
X
X					/*
X					 * printf("ray.dir = (%lg %lg
X					 * %lg)\n", ray.dir.x, ray.dir.y,
X					 * ray.dir.z);
X					 */
X
X					scol = Trace_a_ray(&ray, 0);
X
X					col.r += scol.r;
X					col.g += scol.g;
X					col.b += scol.b;
X				}
X
X				col.r /= sample_cnt;
X				col.g /= sample_cnt;
X				col.b /= sample_cnt;
X			}
X
X			/*
X			 * Write pixel to output file
X			 */
X
X			Write_pixel(&col);
X
X			xr -= x_step;
X		}
X
X		Flush_output_file();
X
X		yr -= y_step;
X
X		if (verbose)
X		{
X			time(&te);
X			fprintf(stderr, "\r%s: scan %d -- %d:%02d  i:%d  s:%d   rl:%d  rr:%d ",
X				my_name, y, (te - ts) / 60, (te - ts) % 60,
X				n_intersects - l_int, n_shadinter - l_shad,
X				n_reflect - l_refl, n_refract - l_refr);
X
X			l_int = n_intersects;
X			l_shad = n_shadinter;
X			l_refl = n_reflect;
X			l_refr = n_refract;
X
X			ts = te;
X		}
X	}
X
X}
X
X
X/*
X * Trace_a_ray()
X * 
X * Trace the given ray and return the resulting color.
X */
X
XCOLOR 
XTrace_a_ray(ray, n)
XRAY            *ray;
Xint             n;
X{
X	OBJECT         *obj;
X	INTERSECT       inter;
X	COLOR           col;
X	VECTOR          ip;
X	double          mc, t;
X
X	++n_rays;
X
X	/*
X	 * Check to see if this ray will intersect anything. If not, then
X	 * return a proper background color. Else, apply the proper
X	 * illumination model to get the color of the object.
X	 */
X
X	if (!Intersect(ray, &inter))
X		return (Background_color(ray));
X
X	++n_intersects;
X
X	/*
X	 * calculate the point of intersection and pass it to the shad
X	 * function
X	 */
X
X	t = inter.t;
X	VecAddS(t, ray->dir, ray->pos, ip);
X
X	col = Illuminate(&inter, ray, &ip, n);
X
X	/*
X	 * If colors have overflown, normalize it.
X	 */
X
X	return (col);
X
X}
X
X
X/*
X * Background_color()
X * 
X * Determin what color the background should be at the given point.
X */
X
XCOLOR 
XBackground_color(ray)
XRAY            *ray;
X{
X	return (bkgnd.col);
X}
END_OF_FILE
if test 3737 -ne `wc -c <'trace.c'`; then
    echo shar: \"'trace.c'\" unpacked with wrong size!
fi
# end of 'trace.c'
fi
if test -f 'vector.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'vector.c'\"
else
echo shar: Extracting \"'vector.c'\" \(327 characters\)
sed "s/^X//" >'vector.c' <<'END_OF_FILE'
X
X/*
X * vector.c - This module contains all of the vector math related functions.
X * 
X * Copyright (C) 1990, Kory Hamzeh
X */
X
X#include <stdio.h>
X#include <math.h>
X
X#include "rt.h"
X
Xdouble 
XVecNormalize(v)
XVECTOR         *v;
X{
X	double          len;
X
X	len = VecLen(*v);
X	v->x /= len;
X	v->y /= len;
X	v->z /= len;
X
X	return (len);
X}
END_OF_FILE
if test 327 -ne `wc -c <'vector.c'`; then
    echo shar: \"'vector.c'\" unpacked with wrong size!
fi
# end of 'vector.c'
fi
echo shar: End of archive 1 \(of 3\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 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
-- 
-------------------------------------------------------------------------------
Kory Hamzeh             UUCP: avatar!kory or ..!uunet!avatar!kory
                    INTERNET: kory at avatar.com 



More information about the Alt.sources mailing list