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(×t);
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