Here are some of the more interesting design choices:
I went ahead and implemented the more robust Lambertian lighting where you take the dot product instead of abs so that you don't see shadows bleeding through to the backside.
I decided not to make a normal class and instead to just use the vector class. I am assuming that this shouldn't make a differance even though some people do create normal classes (pbrt for instance). Hopefully there's no problem with my lazy approach...
I created all the base classes specified in the notes including a primitive class.
I created an intersect method for lights so that as soon as an occluder is found it can stop intersecting the rest of the objects against the light.
I print out \a (bell sound) so that I can hear when it's done rendering :)
The camera class (and derived classes) do not keep track of which pixel needs to be drawn. I do that (the two nested for loops that iterate over the pixels)in another class which I call driver. If we ever start to do fancy sampling, then I'll create a class to handle this kind of stuff...
Images!
The final image from above the plane
The final image from below the plane (note no shadows bleeding through).
My creative image: 20,000 randomly placed spheres, done without any acceleration structures -- oh the humanity!