216 CHAPTER 7: Well-Rendered Miscellany^
Line 2 converts the pixel locations to relative values based on the
width and height of the frame. The values are scaled by 2 because our
viewport will be 2 units wide and high, going from -1 to 1 in each
direction. These are the values eventually passed on to
glTranslatef().
Next, turn off the any depth testing, just to be safe, along with the
lighting, because the flares have to be calculated apart from the actual
lighting in the scene.
Since we’re going to use orthographic projection, let’s reset the
GL_PROJECTION to the identity in line 4. Remember that any time to
want to touch a specific matrix, you need to specify which one ahead
of time. The glPushMatrix() method lets us tinker with the projection
matrix without messing up anything prior in the chain of events.
Line 5 is the heart of this routine. glOrthof() is a new call and sets up
the orthographic matrix. In effect, it specifies a box. In this case, the
box’s width and depth go all from -1 to 1, while the height is scaled a
little extra using the aspect ratio to compensate for it being a
nonsquare display. This is why the scaledX and scaledY values were
multiplied by 2.
Next, set the identify matrix of the modelview, in lines 6f, followed by
the call to glTranslatef() in line 7.
Line 8 determines how to scale the collection of flares based on the
field of view for our scene, followed by line 9 that performs the actual
scaling. This is relative and depends on the magnification ranges you
want to deal with. Right now, pinch-to-zoom is not implemented, so
this stays constant. The zoomBias affects all the elements, which
makes it easy to scale everything at once.
Lines 10ff set up the blending function using the most common of the
choices. This causes each of the reflections to blend in a very
believable way, especially when they start stacking up in the center.
Now set the color and draw the object.
And again, be a good neighbor and pop the matrices so they won’t
affect anything else.
I created a flare object for the individual flares, and I created a LensFlare parent object
to handle setting up the vector, contain each of the individual images, and place them
when ready. The main loop from LensFlare.mm in Listing 7-7 should need very little
explanation at this point. It merely calculates the start of the flare vector and then
enumerates through the array to execute each entity.