A good place to start with this project is just by adding the new box geometry. The intersect_box routine should follow our discussion in class; the calls to this function are placed similarly to intersect_sphere and intersect_plane. The box shown above is at ll = (0.3, -0.6, 2.3) and ur = (0.7, -0.2, 3.0).
While you're at it, you may want to add the SCENE_T data structure to store your object and light arrays (among other data).
Now we can add some color! Simply replace all of your grayscale computations with three-component (RGB) computations. Of course, you'll also need to create a COLOR_T type and add that to your OBJ_T structure. You can make COLOR_T an array of three elements or a structure with three fields (all of type unsigned char, of course). The colors of the objects above are top sphere: (0.8, 0.0, 0.0), lower sphere: (0.0, 0.8, 0.0), and box: (0.0, 0.0, 0.7). Experiment with the colors to create interesting images.
Since you're dealing with a new file type, this step may also include migration to file processing (rather than redirecting stdout). Check argc near the start of main. If it's < 2, go with the default output file name (image.ppm); otherwise, the user has specified an output file name in argv [1]. Initially, you can use this file name in main for opening and writing. Later, you'll want to pass this name to a function (perhaps called write_ppm) to handle all the ppm-specific processing. Note that you may want to use the IMG_T structure for this processing.
Add light attenuation for diffuse and specular lighting.
This may also be a good time to divide your code into multiple source files. Each of these .c files should have a corresponding header (.h) file containing the prototypes of those functions which can be called by other functions in other .c files. For instance, intersect_sphere should be placed in its own source file named sphere.c. Its prototype should be listed in sphere.h and those source files that contain calls to intersect_sphere (e.g., main in ray.c), must include sphere.h.
Also write an appropriate makefile in this step.
(optional) Add antialiasing to eliminate jaggies. Compare the image above with the previous image -- note the changes, especially on the shadow edges.
Use a small 3x3 array, as we discussed in class to hold the 9 samples that you'll compute for each pixel. For the computation, add two additional nested loops per pixel. Before moving on to the next pixel, find the weighted average of the 9 values and store it in the image structure.
The above image shows the image with a different aspect ratio. (This code could have been added at any point above.) Keep in mind that the goal here is to keep the pixels square (width of pixel = height of pixel).
The image above now has two lights: one at (2.5, 5.0, -1.0) with color (0.6, 0.6, 0.6), and the other at (0.0, 4.0, -1.0) with color (0.7, 0.7, 0.7). Note the overlapping shadows from the lights.
Try to get reflection working before adding the other code modifications. That way,
if errors arise, you'll know they're from the reflection code rather than the linked
list/file operations.
Here's another sample image, but with two reflective objects.
For the code enhancements, start with reading the file. Once you get that done,
then you can perform the dynamic memory allocation and linked lists.