For this project we define a rudimentary scene graph language. Each command should be placed on its own line, and CR/LF should only occur at the end of the command. If a CR/LF appears before the end, the results may be unpredicatable, but whitespace can be present anywhere, in any quantity. All color values are floating point values between 0.0 and 1.0, and all other numeric expressions are assumed to be floating point, also, unless otherwise noted. Angles are given in radians.

Commands:

**#camera** **px py pz dx dy dz
ux uy uz ha**

This defines a perspective camera in the scene. *(px,py,pz)* is
the position of the camera in world coordinates, *(dx,dy,dz)* is a
unit vector describing the direction of the camera, and *(ux,uy,uz)*
is a unit vector in the up direction. The half-height angle of the
viewing frustum is given by *ha*, such that the half-width angle can
be found by *ha*ar, *where *ar* is the width-over-height aspect
ratio of the output image (given on the command line). The *camera*
command must appear before of any *group* directives. The first
*camera*
found in the file will be used, and subsequent *camera* definitions
are ignored.

**#background r g b**

The background color defines the color to assign to rays which fail
to intersect any object, and leave the scene. Only the first *background*
definition encountered is used, and subsequent instances are ignored.
It must appear before any *group* directives. If not defined,
a value of black is assumed.

**#ambient r g b**

Sets the global ambient light level. The first *ambient* definition
is used, and subsequent instances are ignored. It must appear before
any *group* directives. If not defined, a value of black is assumed.

**#light_num n**

The total number of lights in the scene is given by this command.
This command must appear before any *light_** definitions. Only
the first incidence of this command is used, while subsequent instances
are ignored. It must appear before any *group* directives. If
there are no lights in the scene (only global ambient light), *light_num
0* need not be declared.

**#light_point r g b px py pz ca la qa**

This defines a point light in the scene. *(r,g,b)* gives
the color of the light. Note that we depart from the OpenGL convention
of defining three colors for a light (one for each of ambient, diffuse,
and specular properties.) In this ray tracer, use this single light
color for diffuse and specular contributions at each surface. Do
not compute ambient contributions from each light, but rather use the global
ambient light defined by the *ambient* directive. Each instance
must appear before any *group* directives.

*(px,py,pz) *gives the position of the light in world coordinates.
The attenuation of the light with distance from its position is given by
*ca,
la, *and *qa *which define the constant, linear and quadratic components
of the attenuation factor. If d is the distance from the light to
the surface, then the light's color at the surface is given by (r,g,b)
* (ca + la*d + qa*d^2)^-1. Each coeficient must be positive or equal
to zero. Note: to achieve no attenuation use a *(ca,la,qa)* of (1,0,0).

**#light_spot r g b px py pz dx dy dz
ca la qa sc sd**

This defines a spot point light in the scene. *(r,g,b)* gives
the color of the light. Note that we depart from the OpenGL convention
of defining three colors for a light (one for each of ambient, diffuse,
and specular properties.) In this ray tracer, use this single light
color for diffuse and specular contributions at each surface. Do
not compute ambient contributions from each light, but rather use the global
ambient light defined by the *ambient* directive. Each instance must
appear before any *group* directives.

*(px,py,pz) *gives the position of the light in world coordinates,
and *(dx,dy,dz)* is a unit vector describing the direction of the
light. The attenuation of the light with distance from its
position is given by *ca, la, *and *qa *which define the constant,
linear and quadratic components of the attenuation factor. If d is
the distance from the light to the surface, then the light's color at the
surface is given by (r,g,b) * (ca + la*d + qa*d^2)^-1. Each cooeficient
must be positive or equal to zero. Note: to achieve no attenuation use
a *(ca,la,qa)* of (1,0,0).

The spot light cutoff is given by *cs* and defines the half angle
of divergence of the light cone. It can be measured as the angle
from the center axis to the edge of the spot cone. It should be less
than pi/2 radians. The fall off in intensity from the center axis
to the cone edge is given by the spot drop-off factor, *sd*.
It can take values from 0.0 to 1.0, where 0.0 indicated constant intensity
across the cone, and 1.0 yields a sharp fall-off. The cosine of the
angle between light direction and the direction of a ray from *(px,py,pz)*
to the point being lit, raised to the power of 128**sd* will yield
the correct result.

**#light_dir r g b dx dy dz**

This defines a directional light in the scene. *(r,g,b)*
gives the color of the light. Note that we depart from the OpenGL
convention of defining three colors for a light (one for each of ambient,
diffuse, and specular properties.) In this ray tracer, use this single
light color for diffuse and specular contributions at each surface.
Do not compute ambient contributions from each light, but rather use the
global ambient light defined by the *ambient* directive. Each instance
must appear before any *group* directives.

*(dx,dy,dz) *is a unit vector giving the direction of the light
in the scene. Note that attenuation makes no sense for directional lights,
and so is not a parameter of this directive.

**#texture_num n**

The total number of textures used in the scene is given by this command.
The command must appear before any *texture* AND/OR *material*
definitions. Only the first incidence of this command is used, while
subsequent instances are ignored. It must appear before any *group*
directives. If there are no textures used, *texture_num 0* need
not be declared.

**#texture filename**

Each texture used in the scene is declared by the *texture* directive
using the filename of the texture. The first texture declared will
take the interger identifier 0, and subsequent textures will follow in
order (i.e. 1, 2, 3, ...). This integer handle is used in *material *definitions
to indicate that the material includes the respective texture. Textures
need not be declared before materials, however *texture_num* must
be called before any *material* declaration. This declaration must
appear before any *group* directives.

**#material_num n**

The total number of materials used in the scene is given by this command.
The command must appear before any *material* definitions. Only
the first incidence of this command is used, while subsequent instances
are ignored. This declaration must appear before any *group*
directives.

**#material ar ag ab dr dg db sr
sg sb er eg eb ks kt ir tn !string!**

Each material used in the scene is declared by the *material* directive.
The first material declared will take the interger identifier 0, and subsequent
materials will follow in order (i.e. 1, 2, 3, ...). This integer handle
is used in *shape *definitions to indicate that the rendering should
occur with the appropriate material. This declaration must appear
before any *group* directives.

The colors (*ar,ag,ab), (dr,dg,db), (sr,sg,sb), and
(er,eg,eb)* are the ambient, diffuse, specular, and emmisive colors
of the material, respectively. The ambient material color is used
in ambient light calculation with the global ambient light color, the diffuse
and specular material colors are used in diffuse and specular lighting
computations with the color of each light in the scene, and the emmisive
material color acts independently of any light source.

*ks* defines the specular 'shininess' of the material, and takes
values from 0.0 to 1.0. The cosine of the angle between the ray direction
and the specular reflection direction raised to the power of 128*ks gives
the OpenGL specular highlight factor. *ks* also defines the
reflection coefficient for recursive reflection rays. *kt* is
the transmission coefficient for recursive transmission rays, and ranges
from 0.0 to 1.0. *ks* + *kt *need not total to 1.0. The
index of refraction is given by *ir* and is used in Snell's Law computations
for refraction direction. For non-closed surfaces, such as triangles,
it is assumed that *ir* is the index of refraction on the backside
of the surface. For closed surfaces, such as cones, it is assumed
that *ir* is the index of refraction on the inside of the surface.

To assign a texture to this material, *tn* should be the integer
handle of the appropriate texture declared in the file. At rending
time, it is assumed that the color of the appropriate texture pixel will
modulate the color computed by the lighting equation. If no texture
is to be associated with the material, then a value of -1 must be
indicated.

The final parameter is a string delimited by exclaimation marks. The string must not contain any control characters, or unpredicatable behaviour could occur. This field is provided for the users to assign material properties not defined by this file format. For instance, the numeric constants describing a Perlin Noise 3-D solid texture could be put in this field to instruct the rendered to how to texture shapes which are drawn with this material. If no unsupported parameters are required, empty exclamation marks must conclude the material declaration as follows: !!

**#group_begin m11 m12 m13 m14 m21 m22 m23 m24
m31 m32 m33 m34 m41 m42 m43 m44**
**#group_end**

This pair of directives defines a transformation context in which it
is valid to specify *shape_** objects to draw. All objects within
the *group_begin* .. and associated *group_end* directive are
subject to the 4x4 transformation matrix given in the *group_begin*
declaration. Groups may be nested, permitting the specification of
a transformation heirarchy. Shapes within nested groups are subject,
in order, to the transformation contexts of all their enclosing groups.
The total transformation context of a given shape is determined, then,
by starting with the matrix of the root enclosing group, and concatenating
additional matrices on the right as we decend into nested groups, until
we reach the shape. The transformation context of a group is applicable
only to its shapes and sub groups, so we must remove matrices from the
right as we ascend back up the heirarchy. From an OpenGL stand point
this is analagous to pushing the matrix state onto the stack and multiplying
in a group's matrix as we enter it, and then poping the statck when we
exit the group.

The matrix elements appear as follows and are intended to operate on column vectors:

`|m11 m12 m13 m14|`
`|m21 m22 m23 m24|`
`|m31 m32 m33 m34|`
`|m41 m42 m43 m44|`

`Note: shape_* declarations can only occur within groups.
Thus, even if no transformations are desired, a root group must still be
defined to hold all the shapes. A group_begin 1 0 0 0 0 1
0 0 0 0 1 0 0 0 0 1 directive can be issued to define the root context
with the identity transformation.`

**#shape_* m ...**

All shapes that can be defined are prefixed by *shape_* and take
a common first parameter *m* which indicates the integer handle of
the material to use when rendering the object. Subsequent descriptions
of the supported shapes will omit explanations of the *m* parameter...

**#shape_sphere m cx cy cz r**

This defines a sphere, situated at the point (cx,cy,cz) with a radius
given by *r*.

**#shape_box m cx cy cz lx ly lz**

This defines an axis aligned box, centered at the point (cx,cy,cz).
The length of the x, y, and z axis aligned sides is given by *lx, ly,
*and*
lz,* respectively. The box extends from x=cx-lx/2 to x=cx+lx/2, y=cy-ly/2
to y=cy+ly/2, and z=cz-lz/2 to z=cz+lz/2.

**#shape_cylinder m cx cy cz r h**

This defines a cylinder, with a central axis parallel to the y-axis,
and centered at the point (cx,cy,cz). The radius and height are given
by *r* and *h*, respectively. The cylinder is a closed
surface (i.e. it has end caps.) The ends lie at y=cy-h/2 and y=cy+h/2.

**#shape_cone m cx cy cz r h**

This defines a cone, with a central axis parallel to the y-axis, and
centered at the point (cx,cy,cz). The radius and height are given
by *r* and *h*, respectively. The cone is a closed surface
(i.e. it's base is capped) The base and apex of the cone lie at y=cy-h/2
and y=cy+h/2, respectively.

**#shape_triangle m v1x v1y v1z v2x v2y v2z
v3x v3y v3z n1x n1y n1z n2x n2y n2z n3x n3y
n3z t1s t1t t2s t2t t3s t3t**

This defines a triangle with vertices (*v1x,v1y,v1z), (v2x,v2y,v2z),
*and*
(v3x,v3y,v3z)*. Associated, respectively, with each vertex are

are the normals (n*1x,n1y,n1z), (n2x,n2y,n2z), *and*
(n3x,n3y,n3z).* It is assumed that normals are of unit length.
Also associated, respectively, with each vertex are the texture coordinates
(*t1s,t1t), (t2s,t2t), *and* (t3s,t3t). *It
is assumed that the texture coordinate (0,0) maps to the lower left of
the associate texture map image, and that the positive s and t texture
coordinates axis extend in right and upward image directions, respectively.
Even if no texturing is desired for a given triangle, it is mandatory that
the 6 texture coordinate fields be present (so, add 0 0 0 0 0 0 after the
*n3z
*coordinate,
for instance.)