Programming Assignment 1
CS 45500
Computer Graphics
Fall, 2021

This assignment makes use of the files contained in this zip file. This assignment is due Thursday, September 9.

This assignment and your next assignment are about the data structures used at the two ends of the 3D graphics rendering pipeline; what goes into the beginning of the pipeline and what comes out of the end of the pipeline. Roughly, what goes into the pipeline is the Scene data structure which describes the geometry of what the renderer should draw. What comes out of the pipeline is the FrameBuffer data structure which holds the image of the scene drawn by the renderer. This assignment is about what comes out of the graphics pipeline, the FrameBuffer data structure. Assignment 2 will be about what goes into the rendering pipeline, the Scene data structure.

A FrameBuffer object holds an array of pixel data that represents an image that can be displayed on a computer's screen. For each pixel in the image, the FrameBuffer's array holds three bytes, one byte that represents the red component of the pixel's color, one byte that represents the green component, and one byte that represents the blue component of the pixel's color. Each of these three bytes is only eight bits in size, so each of the three colors has only 256 shades (but there are 256^3 = 16,777,216 distinct colors). If a framebuffer has dimensions of n rows of pixels by m columns of pixels, then the framebuffer's array holds n*m integers and each integer holds the three bytes for one pixel (with one unused byte in each integer). The pixel data is NOT stored as a "two-dimensional" (or "three-dimensional") array. It is stored as a one-dimensional integer array of length n*m. This one-dimensional array is in row major form, meaning that the first m integers in the array are the pixels from the image's first (top) row. The next m integers from the array are the pixels from the image's second row, etc. Finally, the last m integers in the array are the pixels from the image's last (bottom) row of pixels as displayed on the computer's screen.

In this assignment you are to write a program that creates a FrameBuffer object and then fills it with pixel data so that the resulting image looks like the file Hw1_demo.ppm from the zip file. In the zip file there is a file Hw1.java that you need to complete. In Hw1.java there is a brief outline of what you need to do. You should make as much use of the FrameBuffer interface as possible when you write your code. To learn about the FrameBuffer class's interface, look at its source code in the framebuffer sub folder of the zip file. You should also create and look at the Javadoc html file for the FrameBuffer class. The FrameBuffer.java class file contains a main() method that tests the code in the class. Read the main() method carefully because it is also a good demonstration of how to write code that uses the FrameBuffer and its Viewport nested class.

Your program should produce a result that looks exactly like Hw1_demo.ppm. There are a number of facts about the image in Hw1_demo.ppm that you need to find out (like, what are the exact colors?). Use tools from pixel-utilities.zip to determine these details about Hw1_demo.ppm.

Notice that the program Hw1.java takes a command-line argument which is the name of the file to imbed into the final picture. This lets you run the program using either the RebelTrooper.ppm file or the Hulk.ppm file. Your final version of Hw1.java must use that command-line argument. I will test your program to make sure it is getting the file name from the command-line, and not hard-coding the file name into the code.

When you copy pixel data from RebelTrooper.ppm (or Hulk.ppm) framebuffer into the main framebuffer, you should only copy a pixel if it is not a background pixel. For the most part, the background pixels are white (the color with (r, g, b) = (255, 255, 255)). But some of the background pixels near the image are not quite exactly white. For example, a background pixel very near the image might be (252, 251, 254). In order to get a good sharp "cutout" of the image, it helps to not copy any pixel that is "nearly" white.

The last step of creating the final image it to add Dumbledore's "ghost". Put the Dumbledore pixel data in its own FrameBuffer object. Then create a viewport the covers the area where Dumbledore should appear. Then use two nested for-loops to simultaneously step through the pixels of the Dumbledore framebuffer and the Dumbledore viewport. For each pixel from the Dumbledore framebuffer, if that pixel is not white (or not almost white) then blend that pixel from the framebuffer with the corresponding pixel from the viewport. Blend them with 70% weight on the framebuffer pixel and 30% weight on the viewport pixel. So if c1 is the pixel color from the framebuffer and c2 is the color from the viewport, then blend them (more or less) like this (for the red component, similarly for the green and blue components),


      new_red = 0.7*c1.getRed() + 0.3*c2.getRed()

After you compute the new blended color components, you write that new color into the viewport's pixel. By averaging Dumbledore's pixels with the pixels already in the framebuffer, you create the effect of a "see-through" ghost of Dumbledore superimposed on the framebuffer's contents.

Turn in a zip file called CS455Hw1Surname.zip (where Surname is your last name) containing your version of Hw1.java.

This assignment is due Thursday, September 9.