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.