[comp.sources.unix] v18i071: A ray-tracing package, Part02/03

rsalz@uunet.uu.net (Rich Salz) (03/28/89)

Submitted-by: Mark VandeWettering <markv@drizzle.cs.uoregon.edu>
Posting-number: Volume 18, Issue 71
Archive-name: mtvraytrace/part02

#! /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 2 (of 3)."
# Contents:  NFF color.c cone.c intersect.c poly.c screen.c shade.c
#   tri.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'NFF' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'NFF'\"
else
echo shar: Extracting \"'NFF'\" \(8711 characters\)
sed "s/^X//" >'NFF' <<'END_OF_FILE'
XFrom uoregon!uw-beaver!cornell!batcomputer!saponara Mon Oct  3 13:30:35 PDT 1988
XArticle 3096 of comp.graphics:
XPath: uoregon!uw-beaver!cornell!batcomputer!saponara
X>From: saponara@batcomputer.tn.cornell.edu (John Saponara)
XNewsgroups: comp.graphics
XSubject: A description of NFF (Neutral File Format)
XSummary: here you go...
XKeywords: NFF, benchmark
XMessage-ID: <6443@batcomputer.tn.cornell.edu>
XDate: 3 Oct 88 19:57:58 GMT
XReply-To: saponara@tcgould.tn.cornell.edu (Eric Haines, in truth)
XOrganization: 3D/Eye Inc
XLines: 235
XReferences:
XStatus: OR
X
XHere's my first draft, hot off the disk.
X
X    Eric Haines (not John Saponara)
X
XNote: don't reply to me here, as this account disappears soon.  Instead,
X	write me at hpfcla!hpfcrs!eye!erich@hplabs.hp.com
X
X-----------------------------------------------------------------------------
X
XNeutral File Format (NFF),
X    by Eric Haines, 3D/Eye Inc, 410 E Upland Rd, Ithaca, NY 14850
X    (607)-257-1381
X    email: hpfcla!hpfcrs!eye!erich@hplabs.hp.com
X
X
X[This is a description of the format used in the SPD package.  Any comments
Xon how to expand this format are appreciated.  Some extensions seem obvious
Xto me (e.g. adding directional lights, circles, and tori), but I want to take
Xmy time, gather opinions, and get it more-or-less right the first go round.
XAlso, I'm ridiculously busy right now. -EAH]
X
XDraft document #1, 10/3/88
X
XThe NFF (Neutral File Format) is designed as a minimal scene description
Xlanguage.  The language was designed in order to test various rendering
Xalgorithms and efficiency schemes.  It is meant to describe the geometry and
Xbasic surface characteristics of objects, the placement of lights, and the
Xviewing frustum for the eye.  Some additional information is provided for
Xesthetic reasons (such as the color of the objects, which is not strictly
Xnecessary for testing rendering algorithms).
X
XFuture enhancements include:  circle and torus objects, spline surfaces
Xwith trimming curves, directional lights, characteristics for positional
Xlights, CSG descriptions, and probably more by the time you read this.
XComments, suggestions, and criticisms are all welcome.
X
XAt present the NFF file format is used in conjunction with the SPD (Standard
XProcedural Database) software, a package designed to create a variety of
Xdatabases for testing rendering schemes.  The SPD package is available
Xfrom Netlib and via ftp from drizzle.cs.uoregon.edu.  For more information
Xabout SPD see "A Proposal for Standard Graphics Environments," IEEE Computer
XGraphics and Applications, vol. 7, no. 11, November 1987, pp. 3-5.
X
XBy providing a minimal interface, NFF is meant to act as a simple format to
Xallow the programmer to quickly write filters to move from NFF to the
Xlocal file format.  Presently the following entities are supported:
X     A simple perspective frustum
X     A positional (vs. directional) light source description
X     A background color description
X     A surface properties description
X     Polygon, polygonal patch, cylinder/cone, and sphere descriptions
X
XFiles are output as lines of text.  For each entity, the first line
Xdefines its type.  The rest of the first line and possibly other lines
Xcontain further information about the entity.  Entities include:
X
X"v"  - viewing vectors and angles
X"l"  - positional light location
X"b"  - background color
X"f"  - object material properties
X"c"  - cone or cylinder primitive
X"s"  - sphere primitive
X"p"  - polygon primitive
X"pp" - polygonal patch primitive
X
X
XThese are explained in depth below:
X
XViewpoint location.  Description:
X    "v"
X    "from" Fx Fy Fz
X    "at" Ax Ay Az
X    "up" Ux Uy Uz
X    "angle" angle
X    "hither" hither
X    "resolution" xres yres
X
XFormat:
X
X    v
X    from %g %g %g
X    at %g %g %g
X    up %g %g %g
X    angle %g
X    hither %g
X    resolution %d %d
X
XThe parameters are:
X
X    From:  the eye location in XYZ.
X    At:    a position to be at the center of the image, in XYZ world
X	   coordinates.  A.k.a. "lookat".
X    Up:    a vector defining which direction is up, as an XYZ vector.
X    Angle: in degrees, defined as from the center of top pixel row to
X	   bottom pixel row and left column to right column.
X    Resolution: in pixels, in x and in y.
X
X  Note that no assumptions are made about normalizing the data (e.g. the
X  from-at distance does not have to be 1).  Also, vectors are not
X  required to be perpendicular to each other.
X
X  For all databases some viewing parameters are always the same:
X    Yon is "at infinity."
X    Aspect ratio is 1.0.
X
X  A view entity must be defined before any objects are defined (this
X  requirement is so that NFF files can be used by hidden surface machines).
X
X--------
X
XPositional light.  A light is defined by XYZ position.  Description:
X    "b" X Y Z
X
XFormat:
X    l %g %g %g
X
X    All light entities must be defined before any objects are defined (this
X    requirement is so that NFF files can be used by hidden surface machines).
X    Lights have a non-zero intensity of no particular value [this definition
X    may change soon, with the addition of an intensity and/or color].
X
X--------
X
XBackground color.  A color is simply RGB with values between 0 and 1:
X    "b" R G B
X
XFormat:
X    b %g %g %g
X
X    If no background color is set, assume RGB = {0,0,0}.
X
X--------
X
XFill color and shading parameters.  Description:
X     "f" red green blue Kd Ks Shine T index_of_refraction
X
XFormat:
X    f %g %g %g %g %g %g %g %g
X
X    RGB is in terms of 0.0 to 1.0.
X
X    Kd is the diffuse component, Ks the specular, Shine is the Phong cosine
X    power for highlights, T is transmittance (fraction of light passed per
X    unit).  Usually, 0 <= Kd <= 1 and 0 <= Ks <= 1, though it is not required
X    that Kd + Ks == 1.  Note that transmitting objects ( T > 0 ) are considered
X    to have two sides for algorithms that need these (normally objects have
X    one side).
X  
X    The fill color is used to color the objects following it until a new color
X    is assigned.
X
X--------
X
XObjects:  all objects are considered one-sided, unless the second side is
Xneeded for transmittance calculations (e.g. you cannot throw out the second
Xintersection of a transparent sphere in ray tracing).
X
XCylinder or cone.  A cylinder is defined as having a radius and an axis
X    defined by two points, which also define the top and bottom edge of the
X    cylinder.  A cone is defined similarly, the difference being that the apex
X    and base radii are different.  The apex radius is defined as being smaller
X    than the base radius.  Note that the surface exists without endcaps.  The
X    cone or cylinder description:
X
X    "c"
X    base.x base.y base.z base_radius
X    apex.x apex.y apex.z apex_radius
X
XFormat:
X    c
X    %g %g %g %g
X    %g %g %g %g
X
X    A negative value for both radii means that only the inside of the object is
X    visible (objects are normally considered one sided, with the outside
X    visible).  Note that the base and apex cannot be coincident for a cylinder
X    or cone.
X
X--------
X
XSphere.  A sphere is defined by a radius and center position:
X    "s" center.x center.y center.z radius
X
XFormat:
X    s %g %g %g %g
X
X    If the radius is negative, then only the sphere's inside is visible
X    (objects are normally considered one sided, with the outside visible).
X
X--------
X
XPolygon.  A polygon is defined by a set of vertices.  With these databases,
X    a polygon is defined to have all points coplanar.  A polygon has only
X    one side, with the order of the vertices being counterclockwise as you
X    face the polygon (right-handed coordinate system).  The first two edges
X    must form a non-zero convex angle, so that the normal and side visibility
X    can be determined.  Description:
X
X    "p" total_vertices
X    vert1.x vert1.y vert1.z
X    [etc. for total_vertices vertices]
X
XFormat:
X    p %d
X    [ %g %g %g ] <-- for total_vertices vertices
X
X--------
X
XPolygonal patch.  A patch is defined by a set of vertices and their normals.
X    With these databases, a patch is defined to have all points coplanar.
X    A patch has only one side, with the order of the vertices being
X    counterclockwise as you face the patch (right-handed coordinate system).
X    The first two edges must form a non-zero convex angle, so that the normal
X    and side visibility can be determined.  Description:
X
X    "pp" total_vertices
X    vert1.x vert1.y vert1.z norm1.x norm1.y norm1.z
X    [etc. for total_vertices vertices]
X
XFormat:
X    pp %d
X    [ %g %g %g %g %g %g ] <-- for total_vertices vertices
X
X--------
X
XComment.  Description:
X    "#" [ string ]
X
XFormat:
X    # [ string ]
X
X    As soon as a "#" character is detected, the rest of the line is considered
X    a comment.
X
X-------------------------------------------------------------------------------
X
X
END_OF_FILE
if test 8711 -ne `wc -c <'NFF'`; then
    echo shar: \"'NFF'\" unpacked with wrong size!
fi
# end of 'NFF'
fi
if test -f 'color.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'color.c'\"
else
echo shar: Extracting \"'color.c'\" \(6975 characters\)
sed "s/^X//" >'color.c' <<'END_OF_FILE'
X/***********************************************************************
X * $Author: markv $
X * $Revision: 1.2 $
X * $Date: 88/09/12 12:53:47 $
X * $Log:	color.c,v $
X * Revision 1.2  88/09/12  12:53:47  markv
X * Fixed problem in LookupColorbyName, had return ; and return(0).
X * [ Thank you lint! ]
X * 
X * Revision 1.1  88/09/11  11:00:37  markv
X * Initial revision
X * 
X ***********************************************************************/
X
X#include <stdio.h>
X#include "defs.h"
X
X#define		NCOLORS		(142)
X
Xtypedef struct t_color_entry {
X	char *	ce_name ;
X	Vec 	ce_color ;
X} ColorEntry ;
X
X#define LESS_THAN -1
X#define GREATER_THAN 1
X#define EQUAL_TO 0
X
X/*
X * Note: These colors must be in sorted order, because we binary search
X * for them.
X *
X * They were swiped from the X-11 distribution.  Sorry....
X */
X
XColorEntry Colors[] = {
X	"Aquamarine", {.439216, .858824, .576471},
X	"Black", {0, 0, 0},
X	"Blue", {0, 0, 1},
X	"BlueViolet", {.623529, .372549, .623529},
X	"Brown", {.647059, .164706, .164706},
X	"CadetBlue", {.372549, .623529, .623529},
X	"Coral", {1, .498039, 0},
X	"CornflowerBlue", {.258824, .258824, .435294},
X	"Cyan", {0, 1, 1},
X	"DarkGreen", {.184314, .309804, .184314},
X	"DarkOliveGreen", {.309804, .309804, .184314},
X	"DarkOrchid", {.6, .196078, .8},
X	"DarkSlateBlue", {.419608, .137255, .556863},
X	"DarkSlateGray", {.184314, .309804, .309804},
X	"DarkSlateGrey", {.184314, .309804, .309804},
X	"DarkTurquoise", {.439216, .576471, .858824},
X	"DimGray", {.329412, .329412, .329412},
X	"DimGrey", {.329412, .329412, .329412},
X	"Firebrick", {.556863, .137255, .137255},
X	"ForestGreen", {.137255, .556863, .137255},
X	"Gold", {.8, .498039, .196078},
X	"Goldenrod", {.858824, .858824, .439216},
X	"Gray", {.752941, .752941, .752941},
X	"Green", {0, 1, 0},
X	"GreenYellow", {.576471, .858824, .439216},
X	"Grey", {.752941, .752941, .752941},
X	"IndianRed", {.309804, .184314, .184314},
X	"Khaki", {.623529, .623529, .372549},
X	"LightBlue", {.74902, .847059, .847059},
X	"LightGray", {.658824, .658824, .658824},
X	"LightGrey", {.658824, .658824, .658824},
X	"LightSteelBlue", {.560784, .560784, .737255},
X	"LimeGreen", {.196078, .8, .196078},
X	"Magenta", {1, 0, 1},
X	"Maroon", {.556863, .137255, .419608},
X	"MediumAquamarine", {.196078, .8, .6},
X	"MediumBlue", {.196078, .196078, .8},
X	"MediumForestGreen", {.419608, .556863, .137255},
X	"MediumGoldenrod", {.917647, .917647, .678431},
X	"MediumOrchid", {.576471, .439216, .858824},
X	"MediumSeaGreen", {.258824, .435294, .258824},
X	"MediumSlateBlue", {.498039, 0, 1},
X	"MediumSpringGreen", {.498039, 1, 0},
X	"MediumTurquoise", {.439216, .858824, .858824},
X	"MediumVioletRed", {.858824, .439216, .576471},
X	"MidnightBlue", {.184314, .184314, .309804},
X	"Navy", {.137255, .137255, .556863},
X	"NavyBlue", {.137255, .137255, .556863},
X	"Orange", {.8, .196078, .196078},
X	"OrangeRed", {1, 0, .498039},
X	"Orchid", {.858824, .439216, .858824},
X	"PaleGreen", {.560784, .737255, .560784},
X	"Pink", {.737255, .560784, .560784},
X	"Plum", {.917647, .678431, .917647},
X	"Red", {1, 0, 0},
X	"Salmon", {.435294, .258824, .258824},
X	"SeaGreen", {.137255, .556863, .419608},
X	"Sienna", {.556863, .419608, .137255},
X	"SkyBlue", {.196078, .6, .8},
X	"SlateBlue", {0, .498039, 1},
X	"SpringGreen", {0, 1, .498039},
X	"SteelBlue", {.137255, .419608, .556863},
X	"Tan", {.858824, .576471, .439216},
X	"Thistle", {.847059, .74902, .847059},
X	"Turquoise", {.678431, .917647, .917647},
X	"Violet", {.309804, .184314, .309804},
X	"VioletRed", {.8, .196078, .6},
X	"Wheat", {.847059, .847059, .74902},
X	"White", {.988235, .988235, .988235},
X	"Yellow", {1, 1, 0},
X	"YellowGreen", {.6, .8, .196078},
X	"aquamarine", {.439216, .858824, .576471},
X	"black", {0, 0, 0},
X	"blue", {0, 0, 1},
X	"blue_violet", {.623529, .372549, .623529},
X	"brown", {.647059, .164706, .164706},
X	"cadet_blue", {.372549, .623529, .623529},
X	"coral", {1, .498039, 0},
X	"cornflower_blue", {.258824, .258824, .435294},
X	"cyan", {0, 1, 1},
X	"dark_green", {.184314, .309804, .184314},
X	"dark_olive_green", {.309804, .309804, .184314},
X	"dark_orchid", {.6, .196078, .8},
X	"dark_slate_blue", {.419608, .137255, .556863},
X	"dark_slate_gray", {.184314, .309804, .309804},
X	"dark_slate_grey", {.184314, .309804, .309804},
X	"dark_turquoise", {.439216, .576471, .858824},
X	"dim_gray", {.329412, .329412, .329412},
X	"dim_grey", {.329412, .329412, .329412},
X	"firebrick", {.556863, .137255, .137255},
X	"forest_green", {.137255, .556863, .137255},
X	"gold", {.8, .498039, .196078},
X	"goldenrod", {.858824, .858824, .439216},
X	"gray", {.752941, .752941, .752941},
X	"green", {0, 1, 0},
X	"green_yellow", {.576471, .858824, .439216},
X	"grey", {.752941, .752941, .752941},
X	"indian_red", {.309804, .184314, .184314},
X	"khaki", {.623529, .623529, .372549},
X	"light_blue", {.74902, .847059, .847059},
X	"light_gray", {.658824, .658824, .658824},
X	"light_grey", {.658824, .658824, .658824},
X	"light_steel_blue", {.560784, .560784, .737255},
X	"lime_green", {.196078, .8, .196078},
X	"magenta", {1, 0, 1},
X	"maroon", {.556863, .137255, .419608},
X	"medium_aquamarine", {.196078, .8, .6},
X	"medium_blue", {.196078, .196078, .8},
X	"medium_forest_green", {.419608, .556863, .137255},
X	"medium_goldenrod", {.917647, .917647, .678431},
X	"medium_orchid", {.576471, .439216, .858824},
X	"medium_sea_green", {.258824, .435294, .258824},
X	"medium_slate_blue", {.498039, 0, 1},
X	"medium_spring_green", {.498039, 1, 0},
X	"medium_turquoise", {.439216, .858824, .858824},
X	"medium_violet_red", {.858824, .439216, .576471},
X	"midnight_blue", {.184314, .184314, .309804},
X	"navy", {.137255, .137255, .556863},
X	"navy_blue", {.137255, .137255, .556863},
X	"orange", {.8, .196078, .196078},
X	"orange_red", {1, 0, .498039},
X	"orchid", {.858824, .439216, .858824},
X	"pale_green", {.560784, .737255, .560784},
X	"pink", {.737255, .560784, .560784},
X	"plum", {.917647, .678431, .917647},
X	"red", {1, 0, 0},
X	"salmon", {.435294, .258824, .258824},
X	"sea_green", {.137255, .556863, .419608},
X	"sienna", {.556863, .419608, .137255},
X	"sky_blue", {.196078, .6, .8},
X	"slate_blue", {0, .498039, 1},
X	"spring_green", {0, 1, .498039},
X	"steel_blue", {.137255, .419608, .556863},
X	"tan", {.858824, .576471, .439216},
X	"thistle", {.847059, .74902, .847059},
X	"turquoise", {.678431, .917647, .917647},
X	"violet", {.309804, .184314, .309804},
X	"violet_red", {.8, .196078, .6},
X	"wheat", {.847059, .847059, .74902},
X	"white", {.988235, .988235, .988235},
X	"yellow", {1, 1, 0},
X	"yellow_green", {.6, .8, .196078}
X} ;
X
Xint
XLookupColorByName(name, color)
X char * name ;
X Vec color ;
X{
X	int rc ;
X	rc = BinarySearch(name, 0, NCOLORS - 1 , Colors) ;
X	if (rc < 0) {
X		return(0) ;
X	}
X
X	VecCopy(Colors[rc].ce_color, color) ;
X	return 1 ;
X}
X
X
Xint 
XBinarySearch(name, l, h, array)
X char * name ;
X int l, h ;
X ColorEntry array[] ;
X{
X	int m, rc ;
X	if (l > h)
X		return(-1) ;
X	
X	m = (l + h) / 2 ;
X
X	rc = strcmp(name, array[m].ce_name) ;
X	if (rc == 0)
X		return m ;
X	else if (rc < 0)
X		return BinarySearch(name, l, m-1, array) ;
X	else
X		return BinarySearch(name, m + 1, h, array) ;
X}
END_OF_FILE
if test 6975 -ne `wc -c <'color.c'`; then
    echo shar: \"'color.c'\" unpacked with wrong size!
fi
# end of 'color.c'
fi
if test -f 'cone.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cone.c'\"
else
echo shar: Extracting \"'cone.c'\" \(6358 characters\)
sed "s/^X//" >'cone.c' <<'END_OF_FILE'
X/***********************************************************************
X * $Author: markv $
X * $Revision: 1.3 $
X * $Date: 88/10/04 14:30:02 $
X * $Log:	cone.c,v $
X * Revision 1.3  88/10/04  14:30:02  markv
X * Fixed bug reported by koblas@mips.
X * 
X * Revision 1.2  88/09/15  09:33:02  markv
X * Fixed bug reported by koblas@mips.  Cones which were specified with
X * axis coincident with -y axis had problems.  Caused by incorrect 
X * handling when finding orthogonal axes for the local coordinate system.
X * 
X * Revision 1.1  88/09/11  11:00:38  markv
X * Initial revision
X * 
X ***********************************************************************/
X#include <stdio.h>
X#include <math.h>
X#include "defs.h"
X#include "extern.h"
X
Xtypedef struct t_conedata {
X	Vec 		cone_base ;
X	Flt		cone_base_radius ;
X	Flt		cone_base_d ;
X	Vec		cone_apex ;
X	Flt		cone_apex_radius ;
X	Vec		cone_u ;
X	Vec		cone_v ;
X	Vec		cone_w ;
X	Flt		cone_height ;
X	Flt		cone_slope ;
X	Flt		cone_min_d ;
X	Flt		cone_max_d ;
X} ConeData ;
X
Xint ConePrint ();
Xint ConeIntersect ();
Xint ConeNormal ();
X
XObjectProcs ConeProcs = {
X	ConePrint,
X	ConeIntersect,
X	ConeNormal,
X} ;
X
Xint 
XConePrint(obj)
X Object *obj ;
X{
X	ConeData * cp ;
X
X	cp = (ConeData *) obj -> o_data ;
X
X	printf("c %g %g %g %g %g %g %g %g\n", cp -> cone_base[0], 
X				  cp -> cone_base[1],
X				  cp -> cone_base[2],
X				  cp -> cone_base_radius,
X				  cp -> cone_apex[0],
X				  cp -> cone_apex[1],
X				  cp -> cone_apex[2],
X				  cp -> cone_apex_radius) ;
X}
X
XConeIntersect(obj, ray, hit)
X Object * obj ;
X Ray * ray ;
X Isect * hit ;
X{
X	Ray tray ;
X	ConeData * cd ;
X	Vec V, P ;
X	Flt a, b, c, d, disc ;
X	Flt t1, t2 ;
X	int nroots ;
X
X	cd = (ConeData *) (obj -> o_data) ;
X
X	/*
X	 * First, we get the coordinates of the ray origin in 
X	 * the objects space....
X	 */
X	
X	VecSub(ray -> P, cd -> cone_base, V) ;
X
X	tray.P[0] = VecDot(V, cd -> cone_u) ;
X	tray.P[1] = VecDot(V, cd -> cone_v) ;
X	tray.P[2] = VecDot(V, cd -> cone_w) ;
X
X	/*
X	VecAdd(ray -> P, ray -> D, V) ;
X	VecSub(V, cd -> cone_base, V) ;
X	*/
X
X	tray.D[0] = VecDot(ray -> D, cd -> cone_u) ;
X	tray.D[1] = VecDot(ray -> D, cd -> cone_v) ;
X	tray.D[2] = VecDot(ray -> D, cd -> cone_w) ;
X
X	/*
X	VecSub(tray.D, tray.P, tray.D) ;
X	*/
X
X	a = tray.D[0] * tray.D[0] 
X	    + tray.D[1] * tray.D[1] 
X	    - cd -> cone_slope * cd -> cone_slope * tray.D[2] * tray.D[2] ;
X
X	b = 2.0 * (tray.P[0] * tray.D[0] + tray.P[1] * tray.D[1] - 
X		cd -> cone_slope * cd -> cone_slope * tray.P[2] * tray.D[2]
X		- cd -> cone_base_radius * cd -> cone_slope * tray.D[2]) ;
X
X	c = cd -> cone_slope * tray.P[2] + cd -> cone_base_radius ;
X	c = tray.P[0] * tray.P[0] + tray.P[1] * tray.P[1] - (c * c) ;
X
X	disc = b * b - 4.0 * a * c ;
X
X	if (disc < 0.0)
X		return (0) ;
X	
X	disc = (Flt) sqrt(disc) ;
X	t1 = (-b - disc) / (2.0 * a) ;
X	t2 = (-b + disc) / (2.0 * a) ;
X
X	if (t2 < rayeps)
X		return (0) ;
X	if (t1 < rayeps) {
X		nroots = 1 ;
X		t1 = t2 ;
X	} else {
X		nroots = 2 ;
X	}
X		
X	/*
X	 * ensure that the points are between the two bounding planes...
X	 */
X	
X	switch(nroots) {
X	case 1:
X		RayPoint(ray, t1, P) ;
X		d = VecDot(cd -> cone_w, P) ;
X		if (d >= cd -> cone_min_d && d <= cd -> cone_max_d) {
X			hit -> isect_t = t1 ;	
X			hit -> isect_prim = obj ;
X			hit -> isect_surf = obj -> o_surf ;
X			hit -> isect_enter = 0 ;
X			return(1) ;
X		} else {
X			return(0) ;
X		}
X		break ;
X	case 2:
X		RayPoint(ray, t1, P) ;
X		d = VecDot(cd -> cone_w, P) ;
X		if (d >= cd -> cone_min_d && d <= cd -> cone_max_d) {
X			hit -> isect_t = t1 ;	
X			hit -> isect_prim = obj ;
X			hit -> isect_surf = obj -> o_surf ;
X			hit -> isect_enter = 1 ;
X			return(1) ;
X		} else {
X			RayPoint(ray, t2, P) ;
X			d = VecDot(cd -> cone_w, P) ;
X			if (d >= cd -> cone_min_d && d <= cd -> cone_max_d) {
X				hit -> isect_t = t2 ;	
X				hit -> isect_prim = obj ;
X				hit -> isect_surf = obj -> o_surf ;
X				hit -> isect_enter = 0 ;
X				return(1) ;
X			}
X		}
X		return(0) ;
X	}
X	return(0) ;
X}
X
Xint
XConeNormal(obj, hit, P, N)
X Object * obj ;
X Isect * hit ;
X Point P, N ;
X{
X	Flt t ;
X	Vec V ;
X	ConeData * cd ;
X
X	cd = (ConeData *) obj -> o_data ;
X
X	/*
X	 * fill in the real normal...
X	 * Project the point onto the base plane.  The normal is
X	 * a vector from the basepoint through this point, plus the slope
X	 * times the cone_w vector...
X	 */
X
X	t = - (VecDot(P, cd -> cone_w) + cd -> cone_base_d) ;
X	VecAddS(t, cd -> cone_w, P, V) ;
X	VecSub(V, cd -> cone_base, N) ;
X	VecNormalize(N) ;
X	VecAddS(- cd -> cone_slope, cd -> cone_w, N, N) ;
X	VecNormalize(N) ;
X}
X
XObject *
XMakeCone(basepoint, baseradius, apexpoint, apexradius) 
X Vec basepoint, apexpoint ;
X Flt baseradius, apexradius ;
X{
X	Object * obj ;
X	ConeData * cd ;
X	Flt dmin, dmax, d , ftmp;
X	Vec tmp ;
X	int i ;
X
X	obj = (Object *) malloc (sizeof (Object)) ;
X	obj -> o_type = T_CONE ;
X	obj -> o_procs = & ConeProcs ;
X	obj -> o_surf = CurrentSurface ;
X
X	cd = (ConeData *) malloc (sizeof(ConeData)) ;
X
X	VecCopy(basepoint, cd -> cone_base) ;
X	VecCopy(apexpoint, cd -> cone_apex) ;
X
X	cd -> cone_base_radius = baseradius ;
X	cd -> cone_apex_radius = apexradius ;
X
X
X	VecSub(apexpoint, basepoint, cd -> cone_w) ;
X	cd -> cone_height = VecNormalize(cd -> cone_w) ;
X	cd -> cone_slope =  (cd -> cone_apex_radius - cd -> cone_base_radius) /
X				(cd -> cone_height) ;
X	cd -> cone_base_d = - VecDot(basepoint, cd -> cone_w) ;
X
X	MakeVector(0.0, 0.0, 1.0, tmp) ;
X
X	if (1.0 - fabs(VecDot(tmp, cd ->  cone_w)) < rayeps) {
X		MakeVector(0.0, 1.0, 0.0, tmp) ;
X	}
X
X	/* find two axes which are at right angles to cone_w
X	 */
X
X	VecCross(cd -> cone_w, tmp, cd -> cone_u) ;
X	VecCross(cd -> cone_u, cd -> cone_w, cd -> cone_v) ;
X
X	cd -> cone_min_d = VecDot(cd -> cone_w, cd -> cone_base) ;
X	cd -> cone_max_d = VecDot(cd -> cone_w, cd -> cone_apex) ;
X
X	if (cd -> cone_max_d < cd -> cone_min_d) {
X		ftmp = cd -> cone_max_d ;
X		cd -> cone_max_d = cd -> cone_min_d ;
X		cd -> cone_min_d = ftmp ;
X	}
X
X	obj -> o_data = (void *) cd ;
X
X	for (i = 0 ; i < NSLABS ; i ++) {
X		dmin = HUGE ;
X		dmax = -HUGE ;
X		d = VecDot(basepoint, Slab[i]) - baseradius ;
X		if (d < dmin) dmin = d ; if (d > dmax) dmax = d ;
X		d = VecDot(basepoint, Slab[i]) + baseradius ;
X		if (d < dmin) dmin = d ; if (d > dmax) dmax = d ;
X		d = VecDot(apexpoint, Slab[i]) - apexradius ;
X		if (d < dmin) dmin = d ; if (d > dmax) dmax = d ;
X		d = VecDot(apexpoint, Slab[i]) + apexradius ;
X		if (d < dmin) dmin = d ; if (d > dmax) dmax = d ;
X
X		obj -> o_dmin[i] = dmin ;
X		obj -> o_dmax[i] = dmax ;
X	}
X
X	return(obj) ;
X}
END_OF_FILE
if test 6358 -ne `wc -c <'cone.c'`; then
    echo shar: \"'cone.c'\" unpacked with wrong size!
fi
# end of 'cone.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'\" \(4725 characters\)
sed "s/^X//" >'intersect.c' <<'END_OF_FILE'
X/***********************************************************************
X * $Author: markv $
X * $Revision: 1.2 $
X * $Date: 88/09/12 12:54:48 $
X * $Log:	intersect.c,v $
X * Revision 1.2  88/09/12  12:54:48  markv
X * Added early cutoffs, as suggested by Haines in the RT-News, and 
X * independantly discovered by myself during our correspondence.
X * Now, Intersect takes a max distance, and will not search for 
X * any intersections beyond the max distance.
X * Also, to enable shadow caching, Shadow now returns the object
X * that it found on its way to the light source.
X * 
X * These optimizations speed up shadow testing considerably, and 
X * normal rays some small amount.
X * 
X * Revision 1.1  88/09/11  11:00:40  markv
X * Initial revision
X * 
X ***********************************************************************/
X
X#include <stdio.h>
X#include <math.h>
X#include <assert.h>
X#include "defs.h"
X#include "extern.h"
X
X/*
X * intersect.c
X * Much nicer now, uses the nifty priority queue search
X * as suggested by Kajiya...
X */
X
XFlt		num[NSLABS] ;
XFlt		den[NSLABS] ;
X
X/***********************************************************************
X * CheckAndEnqueue(obj, maxdist)
X * Check the current ray (as paramaterized with the num and den 
X * arrays above) against the bounding volume of obj.
X * If we intersect the bounding volume, then insert it into the 
X * priority queue.
X *
X * Note: should be broken into two separate procedures...
X ***********************************************************************/
X
XINLINE
XCheckAndEnqueue(obj, maxdist)
X Object * obj ;
X Flt maxdist ;
X{
X	int i ;
X	Flt tmp ;
X	Flt tmin, tmax ;
X	Flt dmin = -HUGE ;
X	Flt dmax = maxdist ;
X
X	nChecked ++ ;
X
X	for (i = 0 ; i < NSLABS ; i ++) {
X
X		/* enters the slab here...	*/
X		tmin = (obj -> o_dmin[i] - num[i]) * den[i] ;
X		/* and exits here...		*/
X		tmax = (obj -> o_dmax[i] - num[i]) * den[i] ;
X
X		/* but we may have to swap...	*/
X		if (tmin > tmax) {
X			tmp = tmin ; tmin = tmax ; tmax = tmp ;
X		}
X
X		/* if exited closer than we thought, update 	*/
X		if (tmax < dmax)
X			dmax = tmax ;
X		/* if entered farther than we thought, update 	*/
X		if (tmin > dmin)
X			dmin = tmin ;
X
X		if (dmin > dmax || dmax < rayeps)
X			return ;
X	}
X	PriorityQueueInsert(dmin, obj) ;
X	nEnqueued ++ ;
X}
X
X/***********************************************************************
X * Intersect(ray, hit, maxdist)
X * 
X * Returns true if we hit something in the root model closer than maxdist.  
X * Returns the closest hit in the "hit" buffer.
X ***********************************************************************/
X
XIntersect(ray, hit, maxdist)
X Ray * ray ;
X Isect * hit ;
X Flt maxdist ;
X{
X	Isect		nhit ;
X	int		i ;
X	Flt		min_dist = maxdist ;
X	Object *	cobj ;
X	Object * 	pobj = NULL ;
X	CompositeData 	* cdp ;
X	Flt		key ;
X
X	/* If the object is simple, then return the hit that it gives you */
X
X	if (Root -> o_type != T_COMPOSITE)
X		return (Root -> o_procs -> intersect) (Root, ray, hit) ;
X
X	for (i = 0 ; i < NSLABS ; i ++) {
X		num[i] = VecDot(ray -> P, Slab[i]) ;
X		den[i] = 1.0 / VecDot(ray -> D, Slab[i]) ;
X	}
X
X	/* start with an empty priority queue */
X	PriorityQueueNull() ;
X
X	CheckAndEnqueue(Root, maxdist) ;
X
X	for (;;) {
X
X		if (PriorityQueueEmpty())
X			break ;
X
X		PriorityQueueDelete(&key, &cobj) ;
X
X		if (key > min_dist) {
X
X			/*
X			 * we have already found a primitive
X			 * that was closer, we need look no further...
X			 */
X			 break ;
X
X		} else if (cobj -> o_type == T_COMPOSITE) {
X			/* 
X			 * if it is in the queue, it got hit.
X			 * check each of its children to see if their
X			 * bounding volumes get hit.
X			 * if so, then push them into the priority
X			 * queue...
X			 */
X			
X			cdp = (CompositeData *) cobj -> o_data ;
X
X			for (i = 0 ; i < cdp -> c_size ; i ++ ) {
X				CheckAndEnqueue(cdp -> c_object[i], maxdist) ;
X			}
X
X		} else {
X
X			/*
X			 * we have a primitive 
X			 * intersect with the primitive, and possibly
X			 * update the nearest hit if it is indeed closer
X			 * than the one we currently have...
X			 */
X			
X			if ((cobj -> o_procs -> intersect) (cobj, ray, &nhit)) {
X				if (nhit.isect_t < min_dist) {
X					pobj = cobj ;
X					*hit = nhit ;
X					min_dist = nhit.isect_t ;
X				}
X			}
X		}
X	}
X
X	if (pobj)
X		return 1 ;
X	else
X		return 0 ;
X}
X
X/***********************************************************************
X * Shadow(ray, hit, tmax)
X * 
X * Returns true if we are unshadowed.  Returns the primitive in 
X * the "hit" buffer.
X *
X * Note: the return value of this procedure is a bit strange, as well 
X * as the name.  Should probably be changed.
X ***********************************************************************/
X
Xint 
XShadow(ray, hit, tmax) 
X Ray * ray ;
X Isect * hit ;
X Flt tmax ;
X{
X	if (Intersect(ray, hit, tmax))
X		return 0 ;
X	else
X		return 1 ;
X}
END_OF_FILE
if test 4725 -ne `wc -c <'intersect.c'`; then
    echo shar: \"'intersect.c'\" unpacked with wrong size!
fi
# end of 'intersect.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'\" \(5428 characters\)
sed "s/^X//" >'poly.c' <<'END_OF_FILE'
X/***********************************************************************
X * $Author: markv $
X * $Revision: 1.2 $
X * $Date: 88/10/04 14:32:25 $
X * $Log:	poly.c,v $
X * Revision 1.2  88/10/04  14:32:25  markv
X * Renamed p1 and p2 to be poly_u and poly_v, which are better names.
X * Also may have solved problems having to do with floating point roundoff
X * when planes are parallel to bounding slabs.
X * 
X * Revision 1.1  88/09/11  11:00:42  markv
X * Initial revision
X * 
X ***********************************************************************/
X
X#include <stdio.h>
X#include <math.h>
X#include "defs.h"
X#include "extern.h"
X
Xtypedef struct t_polydata {
X	int 	poly_npoints ;
X	Vec	* poly_point ;
X	Vec	poly_normal ;
X	Flt 	poly_d ;
X	Flt	poly_u, poly_v ;
X} PolyData ;
X
Xint PolyPrint ();
Xint PolyIntersect ();
Xint PolyNormal ();
X
XObjectProcs PolyProcs = {
X	PolyPrint,
X	PolyIntersect,
X	PolyNormal,
X} ;
X
Xint 
XPolyPrint(obj)
X Object * obj ;
X{
X	int i ;
X	PolyData * pd ;
X
X	pd = (PolyData *) obj -> o_data ;
X	printf("p %d\n", pd -> poly_npoints) ;
X	for (i = 0 ; i < pd -> poly_npoints ; i++) {
X		printf("%g %g %g\n", pd -> poly_point[i][0],
X					pd -> poly_point[i][1],
X					pd -> poly_point[i][2]) ;
X	}
X}
X
X/***********************************************************************
X * PolyIntersect(obj, ray, hit)
X * 
X * returns 1 if we hit the polygon, with the hit information in hit.
X * Uses a version of Jordan's theorem to determine whether the point 
X * is inside the polygon.
X * The variable "crosses" will count the number of times that we
X * cross the boundary of the curve.  If it is odd, we are inside.
X *
X ***********************************************************************/
X
XPolyIntersect(obj, ray, hit)
X Object * obj ;
X Ray * ray ;
X Isect * hit ;
X{
X	Flt n,d,t,m,b ;
X	Point V ;
X	int i, j, crosses = 0 ;
X	int qi, qj ;
X	int ri, rj ;
X	int u, v ;
X	PolyData * pd ;
X
X	pd = (PolyData *) obj -> o_data ;
X	n = VecDot(ray -> P, pd -> poly_normal) + pd -> poly_d ;
X	d = VecDot(ray -> D, pd -> poly_normal) ;
X
X	if ((Flt) fabs(d) < rayeps) {
X		return (0) ;
X	}
X
X	t = - n / d ;
X	if (t < rayeps)
X		return 0 ;
X
X	RayPoint(ray,t,V);
X
X	u = pd -> poly_u ;
X	v = pd -> poly_v ;
X
X	for (i = 0 ; i < pd -> poly_npoints ; i++) {
X
X		j = (i + 1) % pd -> poly_npoints ;
X
X		qi = 0 ; qj = 0 ;
X		ri = 0 ; rj = 0 ;
X
X		if (pd -> poly_point[i][v] == pd -> poly_point[j][v])
X			continue ;		/*ignore horizontal lines */
X
X		/*
X		 * If we are both above, or both below the intersection point,
X		 * go onto the next one.
X		 */
X
X		if (pd -> poly_point[i][v] < V[v])
X			qi = 1 ;
X		if (pd -> poly_point[j][v] < V[v])
X			qj = 1 ;
X		if (qi == qj)
X			continue ;
X
X		/*
X		 * We know one end point was above, and one was below.
X		 * If theyare both to the left, then we crossed the line 
X		 * to negative infinity, and we continue.
X		 */
X		if (pd -> poly_point[i][u] < V[u])
X			ri = 1 ;
X 		if (pd -> poly_point[j][u] < V[u])
X			rj = 1 ;
X
X		if (ri & rj) {
X			crosses ++ ;
X			continue ;
X		}
X
X		/*
X		 * Otherwise, if we are both to the right, 
X		 * we can continue without a cross.
X		 */
X
X		if ((ri|rj) == 0)
X			continue ;
X
X
X		/* 
X		 * more difficult acceptance...
X		 * We have a line segment which occurs with endpoints
X		 * in diagonally opposite quadrants.  We must solve
X		 * for the intersection, ie, where v = 0.
X		 */
X
X		m = (pd -> poly_point[j][v] - pd -> poly_point[i][v]) /
X			(pd -> poly_point[j][u] - pd -> poly_point[i][u]) ;
X		
X		b = (pd -> poly_point[j][v] - V[v]) - 
X			m * (pd -> poly_point[j][u] - V[u]);
X
X		if ((-b/m) < rayeps)
X			crosses ++ ;
X	}
X
X	if (crosses & 1) {
X		hit -> isect_t = t ;
X		hit -> isect_surf = obj -> o_surf ;
X		hit -> isect_prim = obj ;
X		hit -> isect_enter = 0 ;
X		return(1);
X	} else {
X		return(0);
X	}
X}
X
XPolyNormal(obj, hit, P, N)
X Object * obj ;
X Isect * hit ;
X Point P, N ;
X{
X
X	PolyData * pd ;
X	pd = (PolyData *) obj -> o_data ;
X	VecCopy(pd -> poly_normal, N);
X}
X
XObject *
XMakePoly(npoints, points)
X int npoints ;
X Vec * points ;
X{
X	Object * obj ;
X	PolyData * pd ;
X	Vec P1, P2 ;
X	Flt d, dmax, dmin ;
X	int i, j ;
X
X	obj = (Object *) malloc (sizeof(Object)) ;
X	obj -> o_type = T_POLY ;
X	obj -> o_procs = & PolyProcs ;
X	obj -> o_surf = CurrentSurface ;
X
X	pd = (PolyData *) malloc (sizeof(PolyData)) ;
X	pd -> poly_npoints = npoints ;
X	pd -> poly_point = points ;
X
X	/*
X	 * calculate the normal by giving various cross products...
X	 */
X	
X	VecSub(pd -> poly_point[0], pd -> poly_point[1], P1) ;
X	VecSub(pd -> poly_point[2], pd -> poly_point[1], P2) ;
X
X	VecCross(P1, P2, pd -> poly_normal) ;
X	VecNormalize(pd -> poly_normal) ;
X
X	if (fabs(pd -> poly_normal[0]) > fabs(pd -> poly_normal[1])
X		&& fabs(pd -> poly_normal[0]) > fabs(pd -> poly_normal[2])) {
X		pd -> poly_u = 1 ;
X		pd -> poly_v = 2 ;
X	} else if (fabs(pd -> poly_normal[1]) > fabs(pd -> poly_normal[0]) 
X		&& fabs(pd -> poly_normal[1]) > fabs(pd -> poly_normal[2])) {
X		pd -> poly_u = 0 ;
X		pd -> poly_v = 2 ;
X	} else {
X		pd -> poly_u = 0 ;
X		pd -> poly_v = 1 ;
X	}
X
X	pd -> poly_d = - VecDot(pd -> poly_normal, pd -> poly_point[0]) ;
X
X	obj -> o_data = (void *) pd ;
X
X	/*
X	 * now, calculate the values of 
X	 * the dmin and dmax 'es for the globally defined slabs...
X	 */
X	
X	for (i = 0 ; i < NSLABS ; i ++) {
X		dmin = HUGE ;
X		dmax = - HUGE ;
X
X		for (j = 0 ; j < pd -> poly_npoints ; j ++) {
X			d = VecDot(Slab[i], pd -> poly_point[j]) ;
X			if (d < dmin) dmin = d ;
X			if (d > dmax) dmax = d ;
X		}
X		obj -> o_dmin[i] = dmin - rayeps ;
X		obj -> o_dmax[i] = dmax + rayeps ;
X	}
X	return(obj) ;
X}
END_OF_FILE
if test 5428 -ne `wc -c <'poly.c'`; then
    echo shar: \"'poly.c'\" unpacked with wrong size!
fi
# end of 'poly.c'
fi
if test -f 'screen.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'screen.c'\"
else
echo shar: Extracting \"'screen.c'\" \(5370 characters\)
sed "s/^X//" >'screen.c' <<'END_OF_FILE'
X/***********************************************************************
X * $Author: markv $
X * $Revision: 1.3 $
X * $Date: 88/10/04 14:33:37 $
X * $Log:	screen.c,v $
X * Revision 1.3  88/10/04  14:33:37  markv
X * Revamped most of this code.  Added code for no antialiasing, jittering, 
X * filtered, and statistically optimized antialiasing.   Statistically
X * optimized anti aliasing still doesn't work properly.
X * 
X * Revision 1.2  88/09/12  10:00:54  markv
X * Fixed lingering (possible) bug with curbuf memory allocation.  
X * Size returned by malloc is now correct in both spots.
X * Thanks tim@ben.
X * 
X * Revision 1.1  88/09/11  11:00:43  markv
X * Initial revision
X * 
X ***********************************************************************/
X
X#include <stdio.h>
X#include <math.h>
X#include <assert.h>
X#include "defs.h"
X#include "pic.h"
X#include "extern.h"
X
XScreen(view, picfile, xres, yres)
X Viewpoint *view ;
X char *picfile ;
X int xres, yres ;
X{
X	Pixel 	*buf, *oldbuf, *curbuf, *tmp ;
X	Pic  	*pic, *PicOpen();
X	Point 	viewvec, leftvec, upvec ;
X	int red, green, blue ;
X	Point	dir ;
X	Ray 	ray ;
X	Color	color;
X	Flt	frustrumwidth ;
X	int 	x, y ;
X
X	pic = PicOpen(picfile, xres, yres) ;
X
X	/*
X	 * calculate the "up" vector...
X	 */
X
X	VecCopy(view -> view_up, upvec) ;
X	VecNormalize(upvec) ;
X
X	/*
X	 * and the "view" vector....
X	 */
X
X	VecSub(view -> view_at, view-> view_from, viewvec);
X	VecNormalize(viewvec);
X
X	/*
X	 * And the "left" vector...
X	 */
X
X	VecCross(view -> view_up, viewvec, leftvec);
X	VecNormalize(leftvec);
X
X	/*
X	 * Calculate the width of the view frustrum in world coordinates.
X	 * and then scale the left and up vectors appropriately.
X	 */
X
X	frustrumwidth = (view -> view_dist) * ((Flt) tan(view -> view_angle)) ;
X	VecScale(-frustrumwidth, upvec) ;
X	VecScale(-frustrumwidth, leftvec) ;
X
X	if (filtflag) {
X		FilterScan( pic,
X			view -> view_from,
X			viewvec,
X			upvec,
X			leftvec, 
X			xres, yres) ;
X	} else if (jitterflag) {
X		JitterScan(   pic,
X			view -> view_from,
X			viewvec,
X			upvec,
X			leftvec, 
X		 	xres, yres) ;
X	} else {
X		Scan(   pic,
X			view -> view_from,
X			viewvec,
X			upvec,
X			leftvec, 
X		 	xres, yres) ;
X	}
X
X	PicClose(pic) ;
X}
X
X
X
X
XScan(pic, eye, viewvec, upvec, leftvec, xres, yres)
X Pic * pic ;
X Vec eye ;
X Vec viewvec ;
X Vec upvec ;
X Vec leftvec ;
X int xres, yres ;
X{
X	Ray ray ;
X	int x, y ;
X	Flt xlen, ylen ;
X	Color color ;
X
X	/*
X	 * Generate the image...
X	 */
X
X	VecCopy(eye, ray.P) ;
X	for (y = 0 ; y < yres ; y++) {
X		for (x = 0 ; x < xres ; x++) {
X			xlen = ((Flt) (2 * x) / (Flt) xres) - 1.0 ;
X			ylen = ((Flt) (2 * y) / (Flt) yres) - 1.0 ;
X			VecComb(xlen, leftvec, ylen, upvec, ray.D) ;
X			VecAdd(ray.D, viewvec, ray.D) ;
X			VecNormalize(ray.D);
X			Trace(0, 1.0, &ray, color);
X			color[0] = min(1.0, color[0]) ;
X			color[1] = min(1.0, color[1]) ;
X			color[2] = min(1.0, color[2]) ;
X			PicWritePixel(pic, color) ;
X		}
X		if (tickflag)
X			fprintf(stderr, ".") ;
X	}
X	if (tickflag)
X		fprintf(stderr, "\n") ;
X}
X
XFilterScan(pic, eye, viewvec, upvec, leftvec, xres, yres)
X Pic * pic ;
X Vec eye ;
X Vec viewvec ;
X Vec upvec ;
X Vec leftvec ;
X int xres, yres ;
X{
X	Ray ray ;
X	int x, y, i ;
X	Flt xlen, ylen ;
X	Color color ;
X	Color * nbuf, *obuf, *tmp  ;	/* new and old buffers, resp.	*/
X	Color avg ;
X
X	/*
X	 * allocate enough memory for the filter buffer
X	 */
X
X	nbuf = (Color *) calloc ((xres + 1), sizeof(Color)) ;
X	obuf = NULL ;
X
X	VecCopy(eye, ray.P) ;
X
X	for (y = 0 ; y <= yres ; y++) {
X		for (x = 0 ; x <= xres ; x++) {
X			xlen = ((Flt) (2 * x) / (Flt) xres) - 1.0 ;
X			ylen = ((Flt) (2 * y) / (Flt) yres) - 1.0 ;
X			VecComb(xlen, leftvec, ylen, upvec, ray.D) ;
X			VecAdd(ray.D, viewvec, ray.D) ;
X			VecNormalize(ray.D);
X			Trace(0, 1.0, &ray, color);
X			color[0] = min(1.0, color[0]) ;
X			color[1] = min(1.0, color[1]) ;
X			color[2] = min(1.0, color[2]) ;
X			VecCopy(color, nbuf[x]) ;
X		}
X		if (obuf) {
X			for (i = 0 ; i < xres ; i++) {
X				VecAdd(nbuf[i], nbuf[i+1], avg) ;
X				VecAdd(obuf[i], avg, avg) ;
X				VecAdd(obuf[i+1], avg, avg) ;
X				VecScale(0.25, avg) ;
X				PicWritePixel(pic, avg) ;
X			}
X			tmp = obuf ;
X			obuf = nbuf ;
X			nbuf = tmp ;
X		} else {
X			/* 
X			 * first scan line, set it up wierdly...
X			 */
X			obuf = nbuf ;
X			nbuf = (Color *) calloc ((xres + 1), sizeof(Color)) ;
X		}
X		if (tickflag)
X			fprintf(stderr, ".") ;
X	}
X	if (tickflag)
X		fprintf(stderr, "\n") ;
X}
X
XJitterScan(pic, eye, viewvec, upvec, leftvec, xres, yres)
X Pic * pic ;
X Vec eye ; 
X Vec viewvec ; 
X Vec upvec ; 
X Vec leftvec ;
X int xres, yres ;
X{
X	Ray ray ;
X	int x, y, i ;
X	Flt xlen, ylen ;
X	Flt xwidth, ywidth ;
X	Color color, avg ;
X
X	/*
X	 * Generate the image...
X	 */
X
X	xwidth = 2.0 / (Flt) xres ;
X	ywidth = 2.0 / (Flt) xres ;
X
X	VecCopy(eye, ray.P) ;
X	for (y = 0 ; y < yres ; y++) {
X		ylen = ((Flt) (2 * y) / (Flt) yres) - 1.0 ;
X		for (x = 0 ; x < xres ; x++) {
X			xlen = ((Flt) (2 * x) / (Flt) xres) - 1.0 ;
X
X			avg[0] = avg[1] = avg[2] = 0.0 ;
X
X			for (i = 0 ; i < maxsamples ; i++) {
X				VecComb(xlen + rnd() * xwidth, leftvec, 
X					ylen + rnd() * ywidth, upvec, ray.D) ;
X				VecAdd(ray.D, viewvec, ray.D) ;
X				VecNormalize(ray.D);
X				Trace(0, 1.0, &ray, color);
X				VecAdd(color, avg, avg) ;
X			}
X
X			VecScale(1.0 / (Flt) maxsamples, avg) ;
X			avg[0] = min(1.0, avg[0]) ;
X			avg[1] = min(1.0, avg[1]) ;
X			avg[2] = min(1.0, avg[2]) ;
X			PicWritePixel(pic, avg) ;
X		}
X		if (tickflag)
X			fprintf(stderr, ".") ;
X	}
X	if (tickflag)
X		fprintf(stderr, "\n") ;
X}
END_OF_FILE
if test 5370 -ne `wc -c <'screen.c'`; then
    echo shar: \"'screen.c'\" unpacked with wrong size!
fi
# end of 'screen.c'
fi
if test -f 'shade.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shade.c'\"
else
echo shar: Extracting \"'shade.c'\" \(4575 characters\)
sed "s/^X//" >'shade.c' <<'END_OF_FILE'
X/***********************************************************************
X * $Author: markv $
X * $Revision: 1.2 $
X * $Date: 88/09/12 12:58:01 $
X * $Log:	shade.c,v $
X * Revision 1.2  88/09/12  12:58:01  markv
X * Added specular reflections and shadow caching.  When a object
X * is found between a light source and the current point we are trying
X * to shade, that object is cached (indexed by recursion level) in the
X * lightsource.  Next time we test a shadow against the light source,
X * we test this object first.  If it is between us and the light source,
X * we can correctly shadow the object without calling Intersect().
X * 
X * Note: specular highlights call the unix pow() function, which seems
X * to be REALLY expensive.  Optimizations could be made here.
X * 
X * Revision 1.1  88/09/11  11:00:44  markv
X * Initial revision
X *  
X ***********************************************************************/
X
X#include <stdio.h>
X#include <math.h>
X#include "defs.h"
X#include "extern.h"
X
X/***********************************************************************
X * Shade(level, weight, P, N, I, hit, col)
X *
X * Wow! Too many parameters!
X *
X * Shade is the driving force of the raytracer.  It calculates the actual
X * luminance at point P, given N, the normal, and I the incident vector.
X * We also pass in the hit, because the normal generating code might need it.
X * The color is returned in col.
X ***********************************************************************/
X
XShade(level, weight, P, N, I, hit, col) 
X int level ;
X Flt weight ;
X Vec P, N, I ;
X Isect * hit;
X Color col ;
X{
X	Ray 	tray ;
X	Color 	tcol ;
X	Vec 	L, H, R ;
X	Flt 	t ;
X	Flt	diff ;
X	Flt 	spec ;
X#ifdef SHADOW_CACHING
X	Object	* cached ;
X#endif /* SHADOW_CACHING */
X	Isect nhit ;
X	Surface	* surf ;
X	int l ;
X
X	col[0] = col[1] = col[2] = 0.0 ;
X	surf = hit -> isect_prim -> o_surf ;
X
X	for (l = 0; l < nLights; l++) {
X		VecSub(Lights[l].light_pos, P, L);
X		if (VecDot(N,L) >= 0.0) {
X			t = VecNormalize(L);
X			VecCopy(P, tray.P);
X			VecCopy(L, tray.D);
X			nShadows ++ ;
X#ifdef SHADOW_CACHING
X			cached = Lights[l].light_obj_cache[level] ;
X			if (cached 
X				&& (cached -> o_procs -> intersect) 
X					(cached, &tray, &nhit) 
X				&& nhit.isect_t < t) {
X				/* 
X				 * we are in shadow, continue...
X				 */
X				nShadowCacheHits ++ ;
X				continue ;
X			}
X#endif /* SHADOW_CACHING */
X			if (Shadow(&tray, &nhit, t)) {
X				diff = VecDot(N,L) * surf -> surf_kd 
X					* Lights[l].light_brightness ;
X#ifdef SHADOW_CACHING
X				Lights[l].light_obj_cache[level] = NULL ;
X#endif /* SHADOW_CACHING */
X				VecAddS(diff, surf -> surf_color, col, col) ;
X				SpecularDirection(I, N, R) ;
X				VecNormalize(R) ;
X				if (surf -> surf_shine > rayeps) {
X					spec = VecDot(R,L) ;
X					if (spec > rayeps) {
X						spec = pow(spec, surf -> surf_shine ) * Lights[l].light_brightness ;
X						col[0] += spec ; 
X						col[1] += spec ; 
X						col[2] += spec ;
X					}
X				}
X			} else {
X#ifdef SHADOW_CACHING
X				Lights[l].light_obj_cache[level] = 
X					nhit.isect_prim ;
X#endif /* SHADOW_CACHING */
X			}
X				
X		}
X	}
X
X	VecCopy(P, tray.P);
X
X	if(surf -> surf_ks * weight > minweight) {
X		nReflected ++ ;
X		SpecularDirection(I, N, tray.D);
X		VecNormalize(tray.D);
X		Trace(level + 1, surf -> surf_ks * weight, &tray, tcol);
X		VecAddS(surf -> surf_ks, tcol, col, col);
X	}
X
X	if (surf -> surf_kt * weight > minweight) { 
X		nRefracted ++ ;
X		if (hit -> isect_enter) 
X			TransmissionDirection(NULL, surf, I, N, tray.D) ;
X		else	
X			TransmissionDirection(surf, NULL, I, N, tray.D) ;
X		Trace(level + 1, surf -> surf_kt * weight, &tray, tcol) ;
X		VecAddS(surf -> surf_kt, tcol, col, col) ;
X	}
X}
X
X/***********************************************************************
X * SpecularDirection(I, N, R)
X * 
X * Given an incident vector I, and the normal N, calculate the 
X * direction of the reflected ray R.
X ***********************************************************************/
X
XSpecularDirection(I, N, R)
X Vec I, N, R;
X{
X	VecComb(1.0/fabs(VecDot(I,N)), I, 2.0, N, R);
X	VecNormalize(R);
X}
X
X/***********************************************************************
X * TransmissionDirection(m1, m2, I, N, T)
X *
X * calculates the direction of the transmitted ray
X ***********************************************************************/
X
XTransmissionDirection(m1, m2, I, N, T)
X Surface *m1, *m2;
X Vec I, N, T ;
X{
X	Flt n1, n2, eta, c1, cs2 ;
X	n1 = m1 ? m1 -> surf_ior : 1.0 ;
X	n2 = m2 ? m2 -> surf_ior : 1.0 ;
X	eta = n1/n2 ;
X
X	c1 = -VecDot(I,N);
X	cs2 = 1.0 - eta * eta*(1.0 - c1*c1);
X	if (cs2 < 0.0)
X		return 0;
X	VecComb(eta, I, eta*c1-sqrt(cs2), N, T);
X	return(1);
X}
END_OF_FILE
if test 4575 -ne `wc -c <'shade.c'`; then
    echo shar: \"'shade.c'\" unpacked with wrong size!
fi
# end of 'shade.c'
fi
if test -f 'tri.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tri.c'\"
else
echo shar: Extracting \"'tri.c'\" \(6022 characters\)
sed "s/^X//" >'tri.c' <<'END_OF_FILE'
X/***********************************************************************
X * $Author: markv $
X * $Revision: 1.1 $
X * $Date: 88/11/12 16:23:13 $
X * $Log:	tri.c,v $
X * Revision 1.1  88/11/12  16:23:13  markv
X * Initial revision
X * 
X * TRIs are triangular patches with normals defined at the vertices.
X * When an intersection is found, it interpolates the normal to the 
X * surface at that point.
X *
X * Algorithm is due to Jeff Arenburg, (arenburg@trwrb.uucp) and was 
X * posted to USENET.
X *
X * Basically, for each triangle we calculate an inverse transformation
X * matrix, and use it to determine the point of intersection in the plane
X * of the triangle relative to the "base point" of the triangle.  We then
X * figure its coordinates relative to that base point.  These base points
X * are used to find the barycentric coordinates, and then in normal 
X * interpolation...
X ***********************************************************************/
X
X#include <stdio.h>
X#include <math.h>
X#include "defs.h"
X#include "extern.h"
X
Xtypedef struct t_spheredata {
X	Vec	tri_P[3] ;
X	Vec	tri_N[3] ;
X	Vec	tri_bb[3] ;
X} TriData ;
X
Xint TriPrint ();
Xint TriIntersect ();
Xint TriNormal ();
X
XObjectProcs TriProcs = {
X	TriPrint,
X	TriIntersect,
X	TriNormal,
X} ;
X
Xint 
XTriPrint(obj)
X Object *obj ;
X{
X	TriData *td ;
X	int i ;
X
X	td = (TriData *) obj -> o_data ;
X	printf("pp 3\n") ;
X	for (i = 0 ; i < 3 ; i ++) {
X		VecPrint("\t", td -> tri_P[i]) ;
X		VecPrint("\t", td -> tri_N[i]) ;
X	}
X}
X
XTriIntersect(obj, ray, hit)
X Object * obj ;
X Ray * ray ;
X Isect * hit ;
X{
X	TriData *td ;
X	Flt n, d, dist ;
X	Flt r, s, t ;
X	Flt a, b ;
X	Vec P, Q ;
X
X	td = (TriData *) obj -> o_data ;
X
X	/*
X	 * The matrix td -> tri_bb transforms vectors in the world 
X	 * space into a space with the following properties.
X	 *
X	 * 1.  The sides of the triangle are coincident with the
X	 *     x and y axis, and have unit length.
X	 * 2.  The normal to the triangle is coincident with the 
X	 *     z axis.
X	 *
X	 */
X
X	/*
X	 * d is the slope with respect to the z axis.  If d is zero, then
X	 * the ray is parallel to the plane of the polygon, and we count 
X	 * it as a miss...
X	 */
X
X	d = VecDot(ray -> D, td -> tri_bb[2]) ;
X	if (fabs(d) < rayeps)
X		return 0 ;
X
X	/*
X	 * Q is a vector from the eye to the triangles "origin" vertex.
X	 * n is then set to be the distance of the tranformed eyepoint
X	 * to the plane in the polygon.
X	 * Together, n and d allow you to find the distance to the polygon, 
X	 * which is merely n / d.
X	 */
X
X	VecSub(td -> tri_P[0], ray -> P, Q) ;
X
X	n = VecDot(Q, td -> tri_bb[2]) ;
X
X	dist = n / d ;
X
X	if (dist < rayeps) 
X		return 0 ;
X	
X	/* 
X	 * Q is the point we hit.  Find its position relative to the
X	 * origin of the triangle.
X	 */
X
X	RayPoint(ray, dist, Q) ;
X	VecSub(Q, td -> tri_P[0], Q) ;
X
X	a = VecDot(Q, td -> tri_bb[0]) ;
X	b = VecDot(Q, td -> tri_bb[1]) ;
X
X	if (a < 0.0 || b < 0.0 || a + b > 1.0) 
X		return 0 ;
X	
X	r = 1.0 - a - b ;
X	s = a ;
X	t = b ;
X
X	hit -> isect_t = dist ;
X	hit -> isect_enter = 0 ;
X	hit -> isect_prim = obj ;
X	hit -> isect_surf = obj -> o_surf ;
X
X	VecZero(hit->isect_normal) ;
X	VecAddS(r, td -> tri_N[0], hit -> isect_normal, hit -> isect_normal) ;
X	VecAddS(s, td -> tri_N[1], hit -> isect_normal, hit -> isect_normal) ;
X	VecAddS(t, td -> tri_N[2], hit -> isect_normal, hit -> isect_normal) ;
X	VecNormalize(hit -> isect_normal) ;
X
X	return(1) ;
X}
X
Xint
XTriNormal(obj, hit, P, N)
X Object * obj ;
X Isect * hit ;
X Point P, N ;
X{
X	VecCopy(hit -> isect_normal, N) ;
X}
X
XObject *
XMakeTri(point)
X Vec *point ;
X{
X	Object * o ;
X	TriData * td ;
X	Vec 	N, P, Q;
X	int i, j ;
X	Flt dmin, dmax, d ;
X	Vec B[3] ;
X
X	o = (Object *) malloc (sizeof(Object)) ;
X	o -> o_type = T_TRI ;
X	o -> o_procs = & TriProcs ;
X	o -> o_surf = CurrentSurface ;
X
X	td = (TriData *) malloc (sizeof(TriData)) ;
X
X	/* 
X	 * copy in the points....
X	 */
X	VecCopy(point[0], td -> tri_P[0]) ;
X	VecCopy(point[2], td -> tri_P[1]) ;
X	VecCopy(point[4], td -> tri_P[2]) ;
X
X	/*
X	 * and the normals, then normalize them...
X	 */
X	VecCopy(point[1], td -> tri_N[0]) ;
X	VecCopy(point[3], td -> tri_N[1]) ;
X	VecCopy(point[5], td -> tri_N[2]) ;
X	VecNormalize(td -> tri_N[0]) ;
X	VecNormalize(td -> tri_N[1]) ;
X	VecNormalize(td -> tri_N[2]) ;
X
X	/*
X	 * construct the inverse of the matrix...
X	 * | P1 |
X	 * | P2 |
X	 * | N  |
X	 * and store it in td -> tri_bb[]
X	 */
X	
X	VecSub(td -> tri_P[1], td -> tri_P[0], B[0]) ;
X	VecSub(td -> tri_P[2], td -> tri_P[0], B[1]) ;
X	VecCross(B[0], B[1], B[2]) ;
X	VecNormalize(B[2]) ;
X
X	InvertMatrix(B, td -> tri_bb) ;
X
X	for (i = 0 ; i < NSLABS ; i ++) {
X		dmin = HUGE ;
X		dmax = - HUGE ;
X
X		for (j = 0 ; j < 3 ; j ++) {
X			d = VecDot(Slab[i], td -> tri_P[j]) ;
X			if (d < dmin) dmin = d ;
X			if (d > dmax) dmax = d ;
X		}
X		o -> o_dmin[i] = dmin - rayeps ;
X		o -> o_dmax[i] = dmax + rayeps ;
X	}
X
X	o -> o_data = (void *) td ;
X
X	return o ;
X}
X
XInvertMatrix(in, out)
X Vec in[3] ;
X Vec out[3] ;
X{
X	int i, j, k ;
X	Flt tmp, det, sum ;
X
X	out[0][0] = (in[1][1] * in[2][2] - in[1][2] * in[2][1]) ;
X	out[1][0] = -(in[0][1] * in[2][2] - in[0][2] * in[2][1]) ;
X	out[2][0] = (in[0][1] * in[1][2] - in[0][2] * in[1][1]) ;
X
X	out[0][1] = -(in[1][0] * in[2][2] - in[1][2] * in[2][0]) ;
X	out[1][1] = (in[0][0] * in[2][2] - in[0][2] * in[2][0]) ;
X	out[2][1] = -(in[0][0] * in[1][2] - in[0][2] * in[1][0]) ;
X
X	out[0][2] = (in[1][0] * in[2][1] - in[1][1] * in[2][0]) ;
X	out[1][2] = -(in[0][0] * in[2][1] - in[0][1] * in[2][0]) ;
X	out[2][2] = (in[0][0] * in[1][1] - in[0][1] * in[1][0]) ;
X	
X	det = 
X	in[0][0] * in[1][1] * in[2][2] +
X	in[0][1] * in[1][2] * in[2][0] +
X	in[0][2] * in[1][0] * in[2][1] -
X	in[0][2] * in[1][1] * in[2][0] -
X	in[0][0] * in[1][2] * in[2][1] -
X	in[0][1] * in[1][0] * in[2][2] ;
X
X	det = 1 / det ;
X
X	for (i = 0 ; i < 3 ; i ++) {
X		for (j = 0 ; j < 3 ; j++) {
X			out[i][j] *= det ;
X		}
X	}
X	
X#ifdef DEBUG
X	for (i = 0 ; i < 3 ; i++) {
X		for (j = 0 ; j < 3 ; j++) {
X			sum = 0.0 ;
X			for (k = 0 ; k < 3 ; k++) {
X				sum += in[i][k] * out[k][j] ;
X			}
X			if (fabs(sum) < rayeps) {
X				sum = 0.0 ;
X			}
X			printf(" %g") ;
X		} 
X		printf("\n") ;
X	}
X	printf("\n") ;
X#endif /* DEBUG */
X}
END_OF_FILE
if test 6022 -ne `wc -c <'tri.c'`; then
    echo shar: \"'tri.c'\" unpacked with wrong size!
fi
# end of 'tri.c'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
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

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.