Chapter 10
Effects
Well, have you been wondering about things mentioned in passing and put off until later, 
such as the alpha parameter of material properties and the w parameter of glVertex4f? Good! 
Later has arrived.
Transparency
The alpha parameter pertains to a concept called blending. Imagine two surfaces, one behind 
the other. Leave the material alpha properties as the usual 1.0 for the farther surface. Set the 
alpha properties for the nearer surface to some fraction, such as 0.3. Typically for such a 
value the alpha blending will result in a color made 30 percent from the source (front) 
surface and 70 percent from the destination (rear) surface. Naturally, an alpha value of 1.0 
(the usual) means the color comes 100 percent from the source.
The Project
Create a new directory under OpenGL and name it Chapter.10. Create another directory 
under Chapter.10 and name it Alpha. Create a new project and save it as Alpha0.Dpr in the 
Alpha directory, naming the unit Alpha1.Pas on the way.
Units
Add the Shapes unit to the project and be sure to add OpenGL and Shapes to the interface 
uses clause of the main unit. From now on you can take for granted that the OpenGL unit 
must be included in the uses clause of any unit that makes OpenGL API calls. Again, always 
be sure to include Shapes in the project and in the uses clause of any unit that calls its 
routines. This is the last mention of such conditions.

PAGE 219
 Within the Shapes unit you need to center the cylinder about the origin for easier placement. 
Inside the Cylinder procedure, replace the 0.0 z values with –0.4, and replace the 1.0 z values 
with +0.4.
Components
Drop on a TOpenGL component, three TTransform components, a TLight component, and 
four TMaterial components, as shown in Figure 10-1.
Properties
Listing 10-1, which is the form as text, shows the property settings for the form and its 
components:

object Form1: TForm1
  Left = 309
  Top = 104
  Width = 328
  Height = 347
  Caption = ‘Form1’
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = ‘MS Sans Serif’
  Font.Style = []
  OnCreate = FormCreate
  OnPaint = FormPaint
  OnResize = FormResize
  PixelsPerInch = 96
  TextHeight = 13


PAGE 220
   object OpenGL1: TOpenGL
    pfdFlags = [Draw_To_Window, Support_OpenGL]
    PixelType = RGBA
    Projection = Perspective
    Enable = [depthTest, Lighting]
    ClearRed = 0.6
    ClearGreen = 0.8
    ClearBlue = 0.8
    prxLeft = -1
    prxRight = 1
    prxBottom = -1
    prxTop = 1
    prxNear = 2
    prxFar = 9
    ColorBits = 24
    DepthBits = 32
    Left = 4
    Top = 4
  end
  object Transform1: TTransform
    TranY = 1
    TranZ = -3
    AxisX = 1
    Angle = -90
    ScaleX = 0.4
    ScaleY = 0.4
    ScaleZ = 0.4
    OnPaint = Transform1Paint
    Left = 4
    Top = 36
  end
  object Light1: TLight
    Which = 1
    Cutoff = 65
    AmbientRed = 0.2
    AmbientGreen = 0.2
    AmbientBlue = 0.2
    DiffuseRed = 1
    DiffuseGreen = 1
    DiffuseBlue = 1
    Direction = True
    Position = True
    Spotlight = True
    Enabled = True
    Left = 36
    Top = 36
  end
  object Material1: TMaterial
    ambRed = 0.5


PAGE 221
     ambGreen = 0.5
    ambBlue = 0.5
    ambAlpha = 1
    difRed = 0.5
    difGreen = 0.5
    difBlue = 0.5
    difAlpha = 1
    aFace = faFront
    dFace = faFront
    sFace = faFront
    Left = 68
    Top = 36
  end
  object Transform2: TTransform
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform2Paint
    Left = 4
    Top = 68
  end
  object Material2: TMaterial
    ambRed = 0.8
    ambGreen = 0.6
    ambBlue = 0.4
    ambAlpha = 1
    difRed = 0.8
    difGreen = 0.6
    difBlue = 0.4
    difAlpha = 1
    aFace = faFront
    dFace = faFront
    sFace = faFront
    Left = 36
    Top = 68
  end
  object Transform3: TTransform
    TranX = 0.6
    TranY = -0.6
    TranZ = -3
    AxisX = 1
    Angle = 90
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform3Paint
    Left = 4
    Top = 100
  end


PAGE 222
   object Material3: TMaterial
    ambRed = 1
    ambGreen = 1
    ambBlue = 1
    ambAlpha = 0.5
    difRed = 1
    difGreen = 1
    difBlue = 1
    difAlpha = 0.5
    aFace = faFront
    dFace = faFront
    sFace = faFront
    mShine = 128
    Left = 36
    Top = 100
  end
  object Material4: TMaterial
    ambRed = 1
    ambGreen = 1
    ambBlue = 1
    ambAlpha = 0.2
    difRed = 1
    difGreen = 1
    difBlue = 1
    difAlpha = 0.2
    aFace = faBack
    dFace = faBack
    sFace = faBack
    mShine = 128
    Left = 68
    Top = 100
  end
end
Listing 10-1. Alpha project properties.
Methods
This project needs FormCreate, FormResize, FormPaint, Transform1Paint, Transform2Paint, 
and Transform3Paint methods.
The FormCreate method prepares for drawing circular objects and sets up the two-sided 
light model:

procedure TForm1.FormCreate(Sender: TObject);	
begin	
  CylinderBase;	
  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);	
end;	

PAGE 223
 The FormResize method has the usual contents:

procedure TForm1.FormResize(Sender: TObject);	
begin	
  if OpenGL1.Smaller then	
    FormPaint(Sender);	
end;	
The FormPaint method is also typical: clearing, applying, flushing, and checking for errors:

procedure TForm1.FormPaint(Sender: TObject);	
begin	
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);	
  Transform1.Apply;	
  Transform2.Apply;	
  Transform3.Apply;	
  glFlush;	
  OpenGL1.ErrorCheck(‘FormPaint’);	
end;	
The Transform1Paint method applies the lighting and material property, then calls the Cube 
method. Transform1 positions the light near the top of the viewing volume and points it 
down. The cube serves to show the light’s position and aim. The TMaterial component gives 
the cube a gray color.

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  Light1.Apply;	
  Material1.Apply;	
  Cube;	
end;	
The Transform2Paint method draws a square floor for the scene. The Material2 component 
gives it a wood-like color.

procedure TForm1.Transform2Paint(Sender: TObject);	
begin	
  Material2.Apply;	
  glBegin(GL_POLYGON);	
    glVertex3f(-1.0,-1.0,-2.0);	
    glVertex3f(+1.0,-1.0,-2.0);	
    glVertex3f(+1.0,-1.0,-4.0);	
    glVertex3f(-1.0,-1.0,-4.0);	
  glEnd;	
end;	
The Transform3 component and its Transform3Paint method place a cylinder on the floor 
and color it white inside and out. The TMaterial 

PAGE 224
 components referenced here are the ones that do the magic with alpha blending.

procedure TForm1.Transform3Paint(Sender: TObject);	
begin	
  Material3.Apply;	
  Material4.Apply;	
  Cylinder;	
end;	
Action
Save, compile, and run. Figure 10-2 shows the result:
Enable
So, why is there no difference? If you guessed that something needs enabling, give yourself a 
gold star. Here are some OpenGL constant declarations:

  GL_BLEND               = $BE2;	
  GL_SRC_ALPHA           = $302;	
  GL_ONE_MINUS_SRC_ALPHA = $303;	
  GL_DST_ALPHA           = $304;	
  GL_ONE_MINUS_DST_ALPHA = $305;	
GL_BLEND is the constant to pass to glEnable. By this means you enable alpha blending. 
Are you surprised? You should pass the next two constants to a procedure that specifies how 
to perform the blending. GL_SRC_ALPHA as the first parameter instructs OpenGL to use 
the source alpha value as 

PAGE 225
 the multiplier to determine the source contribution to the result color. 
GL_ONE_MINUS_SRC_ALPHA as the second parameter tells OpenGL to use one minus the 
source alpha value as the multiplier to determine the destination contribution to the result 
color. The last two constants, GL_DST_ALPHA and GL_ONE_MINUS_DST_ ALPHA, are 
not supported by the Microsoft OpenGL implementations, but you will probably not have 
occasion to shed tears over that fact. Here is the OpenGL procedure declaration:

procedure glBlendFunc(sfactor,dfactor:GLenum); stdcall;	
Glass
Add code to the FormCreate method to enable alpha blending and specify how to do it:

procedure TForm1.FormCreate(Sender: TObject);	
begin	
  CylinderBase;	
  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);	
  glEnable(GL_BLEND);	
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);	
end;	
Save, compile, and run. Figure 10-3 shows the very different result. It illustrates one of the 
primary uses of alpha blending: transparency. The cylinder looks like it is made of glass.


PAGE 226
 Fight the Jaggies
Something you may have noticed in some scenes is that some supposedly straight lines or 
straight sides look more like zigzags. The reason, of course, is that pixels on the screen have 
specific grid locations as in Figure 10-4. This is not a problem for horizontal and vertical 
lines, but lines (or edges) on a slant must affect pixels that come closest to approximating the 
mathematically calculated positions.
Antialiasing
When a line has a jagged appearance because of the necessity of approximating the pixel 
positions, the line is said to be aliased. Making such lines and edges appear smoother is 
certainly a desirable goal, and fortunately there are ways to fight the jaggies in OpenGL. 
Accomplishing this task is called antialiasing, and OpenGL utilizes alpha blending for it.
Draw the Line
To illustrate the technique, set your screen resolution to 640x480 if you are currently using a 
higher resolution. The coarser display serves to emphasize the alias problem and makes the 
correction more evident. Under Chapter.10 create a directory called Line. Create a new 
project in the new directory, saving its unit as Alias1.Pas and the project file as Anti.Dpr.
Drop on a TOpenGL component and a TTransform component. Create event handlers and 
set properties for the form and the components on it according to Listing 10-2:

object Form1: TForm1
  Left = 217
  Top = 97
  Width = 328
  Height = 347
  Caption = 'Form1'
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'


PAGE 227
   Font.Style = []
  OnCreate = FormCreate
  OnPaint = FormPaint
  OnResize = FormResize
  PixelsPerInch = 96
  TextHeight = 13
  object OpenGL1: TOpenGL
    pfdFlags = [Draw_To_Window, Support_OpenGL]
    PixelType = RGBA
    Projection = Perspective
    Enable = []
    ClearRed = 0.6
    ClearGreen = 0.8
    ClearBlue = 0.8
    prxLeft = -1
    prxRight = 1
    prxBottom = -1
    prxTop = 1
    prxNear = 2
    prxFar = 9
    ColorBits = 24
    DepthBits = 32
    Left = 4
    Top = 4
  end
  object Transform1: TTransform
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform1Paint
    Left = 4
    Top = 40
  end
end
Listing 10-2. Aliased lines project properties.
The FormCreate method sets the line width and the drawing color. This very simple project 
does not have lighting or material properties. The remaining lines in the method set up 
antialiasing for lines, but are commented out in order to demonstrate the problem before 
demonstrating the solution.

procedure TForm1.FormCreate(Sender: TObject);	
begin	
  glLineWidth(2.0);	
  glColor3f(0.0,0.0,0.0);	
  {	
  glEnable(GL_LINE_SMOOTH);	
  glEnable(GL_BLEND);	


PAGE 228
   glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);	
  }	
end;	
FormPaint is just what you would expect and FormResize is the same as always:

procedure TForm1.FormResize(Sender: TObject);	
begin	
  if OpenGL1.Smaller then	
    FormPaint(Sender);	
end;	
	
procedure TForm1.FormPaint(Sender: TObject);	
begin	
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);	
  Transform1.Apply;	
  glFlush;	
  OpenGL1.ErrorCheck('FormPaint');	
end;	
The Transform1Paint method draws a nearly vertical line:

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  glBegin(GL_LINES);	
    glVertex3f(0.0,1.0,-2.2);	
    glVertex3f(0.2,0.0,-2.2);	
  glEnd;	
end;	
Save, compile, run, and behold a line with a bad case of the jaggies. You have probably seen 
many other such lines on computer screens. Perhaps you stopped noticing long ago, just 
accepting it as a necessary part of computer graphics.
Smooth the Jagged Line
Now, remove the curly braces from the FormCreate method so Delphi can compile the lines 
of code between them. Those lines enable line smoothing and alpha blending, which work 
together, and specify the appropriate method of blending. Here is the new constant you 
need and its relatives:

  GL_POINT_SMOOTH   = $B10;	
  GL_LINE_SMOOTH    = $B20;	
  GL_POLYGON_SMOOTH = $B41;	
Save, compile, and run again. You should see an amazing difference.

PAGE 229
 How Did it Do That?
OpenGL antialiasing fools the eye into seeing a smooth line by placing blended color pixels 
at the jagged places so that the eye sees a more gradual transition from one line segment to 
the next. Basically, the color of a pixel depends on how much of the pixel would be covered 
if the line (of the given width) could color a partial pixel. OpenGL accomplishes this by 
setting appropriate alpha values. Figure 10-5 shows a simplified magnification of the pixels.
Antialiasing Polygons
The edges of polygons have the same aliasing problem that lines possess and need a similar 
solution. To illustrate, create a directory named Edge under Chapter.10, then create a project 
in it named Poly.Dpr. Save its unit as Edge1.Pas. Add components, create methods, and set 
properties just like those in the Anti project. Make the contents of the FormCreate method 
slightly different:

procedure TForm1.FormCreate(Sender: TObject);	
begin	
  glColor3f(0.0,0.0,0.0);	
  {	
  glEnable(GL_POLYGON_SMOOTH);	
  glEnable(GL_BLEND);	
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);	
  }	
end;	
In Transform1Paint, draw a triangle instead of a line:

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  glBegin(GL_TRIANGLES);	
    glVertex3f(+0.0,1.0,-2.2);	
    glVertex3f(-0.2,0.0,-2.2);	
    glVertex3f(+0.2,0.0,-2.2);	
  glEnd;	
end;	
Save, compile, and run. You will see a skinny black triangle with noticeably aliased edges. 
Now remove the curly braces and do it again. This time you should see a significantly 
smoother triangle, although the difference may not be as dramatic as the difference in lines. 
Also note that some 

PAGE 230
 implementations of OpenGL for certain video cards may not show any improvement at all.
Points Also
As you can see from the “smooth” constants, you can also apply antialiasing to points. Of 
course that is only meaningful for “points” larger than one pixel. The technique for 
antialiasing points, if you happen to need it, should be evident from the examples for lines 
and polygons.
Scaling
You have been using glVertex3f to give three-dimensional coordinates. That should be 
enough, right? Well, there is such a thing as glVertex4f. You may remember from Chapter 2 
that the parameters for glVertex4f are x, y, z, and w. The fourth coordinate is not some 
mysterious fourth dimension, but a divider. If you do not specify it (as with glVertex3f), it 
defaults to one.
Homogeneous Coordinates
Even if you only specify two or three dimensions, OpenGL represents coordinates as four 
numbers, with defaults for the unspecified values. Coordinates become a 1x4 array to which 
OpenGL can apply a matrix. OpenGL uses homogeneous coordinates wherein (x,y,z,w) 
represent the three-dimensional point in space (x/w,y/w,z/w). If you multiply the 
coordinates by factor m, the resulting coordinates (mx,my,mz,mw) produce the same point 
in space. The point (mx/mw,my/mw,mz/mw) is exactly the same as the point 
(x/w,y/w,z/w). This ability to multiply homogeneous coordinates without changing the 
point they represent makes them useful for a matrix-based graphics system such as OpenGL.
Opportunity
OpenGL’s use of homogeneous coordinates provides an interesting opportunity for scaling. 
If you use glVertex4f and use a variable for the fourth parameter, you can change the size of 
an object just by changing the value of a single variable. This is certainly not the standard 
way to scale a part of a scene, but it does serve to illustrate what the w parameter does.
Blow up a Pyramid
Create a new directory under Chapter.10 and call it W. Create a new Delphi project and save 
its files into the W directory. Name the unit W1.Pas and 

PAGE 231
 the project file W0.Dpr. Drop some of the usual components on the form, as shown in Figure 
10-6. Listing 10-3 shows the property values.

object Form1: TForm1
  Left = 200
  Top = 104
  Width = 328
  Height = 347
  Caption = 'Form1'
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  KeyPreview = True
  OnCreate = FormCreate
  OnKeyPress = FormKeyPress
  OnPaint = FormPaint
  OnResize = FormResize
  PixelsPerInch = 96
  TextHeight = 13
  object OpenGL1: TOpenGL
    pfdFlags = [Draw_To_Window, Support_OpenGL]
    PixelType = RGBA
    Projection = Perspective
    Enable = [depthTest, cullFace, Lighting]
    ClearRed = 0.6
    ClearGreen = 0.8
    ClearBlue = 0.8
    prxLeft = -1


PAGE 232
     prxRight = 1
    prxBottom = -1
    prxTop = 1
    prxNear = 2
    prxFar = 9
    ColorBits = 24
    DepthBits = 32
    Left = 4
    Top = 4
  end
  object Transform1: TTransform
    TranX = 0.6
    TranY = -0.6
    TranZ = -2.2
    AxisX = 0.2
    AxisY = 1
    Angle = 15
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform1Paint
    Left = 4
    Top = 36
  end
  object Light1: TLight
    Which = 1
    Cutoff = 65
    AmbientRed = 0.2
    AmbientGreen = 0.2
    AmbientBlue = 0.2
    DiffuseRed = 1
    DiffuseGreen = 1
    DiffuseBlue = 1
    Direction = True
    Position = True
    Spotlight = True
    Enabled = True
    Left = 40
    Top = 36
  end
  object Transform2: TTransform
    TranZ = -3
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform2Paint
    Left = 4
    Top = 72
  end


PAGE 233
   object Material1: TMaterial
    ambRed = 1
    ambAlpha = 1
    difRed = 1
    difAlpha = 1
    aFace = faFront
    dFace = faFront
    sFace = faFront
    Left = 40
    Top = 72
  end
end
Listing 10-3. Property settings for the W pyramid.
In the private section of the form type declaration, provide a private field to be the fourth 
parameter in the homogeneous coordinates:

  private	
    hom: GLfloat;	
  public	
In the FormCreate method, initialize hom and set the front face winding direction clockwise 
since this program draws a pyramid from a triangle fan:

procedure TForm1.FormCreate(Sender: TObject);	
begin	
  hom := 1.0;	
  glFrontFace(GL_CW);	
end;	
The FormResize, FormPaint, and Transform1Paint methods are what you would expect:

procedure TForm1.FormResize(Sender: TObject);	
begin	
  if OpenGL1.Smaller then	
    FormPaint(Sender);	
end;	
	
procedure TForm1.FormPaint(Sender: TObject);	
begin	
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);	
  Transform1.Apply;	
  Transform2.Apply;	
  glFlush;	
  OpenGL1.ErrorCheck('FormPaint');	
end;	
	
procedure TForm1.Transform1Paint(Sender: TObject);	


PAGE 234
 begin	
  Light1.Apply;	
end;	
In the Transform2Paint method, draw the pyramid, using hom as the fourth parameter in 
gVertex4f. Note that the properties of the TTransform2 and Material1 components will result 
in the display of a red triangle.

procedure TForm1.Transform2Paint(Sender: TObject);	
begin	
  Material1.Apply;	
  glBegin(GL_TRIANGLE_FAN);	
    glVertex4f(+0.0,+0.0,+0.0,hom);	
    glVertex4f(-0.3,+0.3,-0.4,hom);	
    glVertex4f(+0.3,+0.3,-0.4,hom);	
    glVertex4f(+0.0,-0.3,-0.4,hom);	
    glVertex4f(-0.3,+0.3,-0.4,hom);	
  glEnd;	
end;	
In the FormKeyPress method, use a case statement to assign values to the hom field. Since 
the KeyPreview property of the form is true, your key presses will pass through this event 
handler. Lowercase “a” through “n” will affect the size of the pyramid. Pressing “n” will 
reduce the pyramid size by 40 percent, and “a” will blow it up to ten times its normal size.

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);	
begin	
  case Key of	
    'a': hom := 0.1;	
    'b': hom := 0.2;	
    'c': hom := 0.3;	
    'd': hom := 0.4;	
    'e': hom := 0.5;	
    'f': hom := 0.6;	
    'g': hom := 0.7;	
    'h': hom := 0.8;	
    'i': hom := 0.9;	
    'j': hom := 1.0;	
    'k': hom := 1.1;	
    'l': hom := 1.2;	
    'm': hom := 1.3;	
    'n': hom := 1.4;	
    else Key := #0;	
  end; {case}	
  if Key<>#0 then	
    Invalidate;	
end;	
Save, compile, and run. Have fun.

PAGE 235
 Fog
When you look at scenes on Earth, you may have noticed that not only do objects appear 
smaller in the distance (perspective), but they also become less distinct. The OpenGL scenes 
you have rendered up to this point in the book retain perfect clarity as they retreat into the 
distance, but that is not the natural appearance unless you are floating in outer space. 
OpenGL provides fog effects to bring more realism to its scenes. In OpenGL fog is a general 
term for atmospheric effects; OpenGL supports three kinds, embodied in three OpenGL fog 
mode constants.
Declarations
Even on a clear day, distant objects are less distinct than nearby objects when viewed 
through an atmosphere. We have all learned to use haziness as a clue to an object’s distance, 
in addition to the apparent size of an object. Here is the OpenGL fog mode constant used to 
command this effect:

  GL_LINEAR = $2601;	
For heavy fog or clouds, use:

  GL_EXP = $800;	
For smoke and weather haze, use:

  GL_EXP2 = $801;	
To tell OpenGL you are setting the fog mode, you need this constant:

  GL_FOG_MODE = $B65;	
As you probably guessed, you must enable fog effects; you need a constant to pass to 
glEnable:

  GL_FOG = $B60;	
Obviously, since there is more to fog than just turning it on and off, there must be a set of 
glFog commands:

procedure glFogf(pname: GLenum; param: GLfloat); stdcall;	
procedure glFogfv(pname: GLenum; params: PGLfloat); stdcall;	
procedure glFogi(pname: GLenum; param: GLint); stdcall;	
procedure glFogiv(pname: GLenum; params: PGLint); stdcall;	
Here are other fog declarations, which will be explained in an example program. The 
exception is GL_FOG_INDEX, which is used with color index mode (corresponding to a 
Windows 256-color palette mode), and is listed here only for completeness:

PAGE 236
 
  GL_FOG_INDEX = $B61;	
  GL_FOG_DENSITY = $B62;	
  GL_FOG_START = $B63;	
  GL_FOG_END = $B64;	
  GL_FOG_COLOR = $B66;	
Project
Create a new directory under Chapter.10 and name it Fog. In that directory create a project 
named Foggy.Dpr with a main unit named Fog1.Pas. Place a TOpenGL component, five 
TTransform components, a TLight component, and four TMaterial components on the form. 
Create event handlers and set the properties according to Listing 10-4. Note the 
DoubleBuffer flag and the KeyPreview property.

object Form1: TForm1
  Left = 204
  Top = 99
  Width = 328
  Height = 347
  Caption = 'Form1'
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  KeyPreview = True
  OnCreate = FormCreate
  OnKeyPress = FormKeyPress
  OnPaint = FormPaint
  OnResize = FormResize
  PixelsPerInch = 96
  TextHeight = 13
  object OpenGL1: TOpenGL
    pfdFlags = [DoubleBuffer, Draw_To_Window, Support_OpenGL]
    PixelType = RGBA
    Projection = Perspective
    Enable = [depthTest, Lighting]
    ClearRed = 0.6
    ClearGreen = 0.8
    ClearBlue = 0.8
    prxLeft = -1
    prxRight = 1
    prxBottom = -1
    prxTop = 1
    prxNear = 2
    prxFar = 9
    ColorBits = 24


PAGE 237
     DepthBits = 32
    Left = 4
    Top = 4
  end
  object Transform1: TTransform
    TranX = 0.6
    TranY = -0.6
    TranZ = -2.2
    AxisX = 0.2
    AxisY = 1
    Angle = 15
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform1Paint
    Left = 4
    Top = 36
  end
  object Light1: TLight
    Which = 1
    Cutoff = 65
    AmbientRed = 0.4
    AmbientGreen = 0.4
    AmbientBlue = 0.4
    DiffuseRed = 1
    DiffuseGreen = 1
    DiffuseBlue = 1
    Direction = True
    Position = True
    Spotlight = True
    Enabled = True
    Left = 40
    Top = 36
  end
  object Transform2: TTransform
    TranX = 1
    TranZ = -3.0
    AxisX = 1
    Angle = 75
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform2Paint
    Left = 4
    Top = 72
  end
  object Material1: TMaterial
    ambRed = 1
    ambAlpha = 1


PAGE 238
     difRed = 1
    difAlpha = 1
    aFace = faFrontAndBack
    dFace = faFrontAndBack
    sFace = faFrontAndBack
    Left = 40
    Top = 72
  end
  object Transform3: TTransform
    TranY = 0.6
    TranZ = -3.6
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform3Paint
    Left = 4
    Top = 108
  end
  object Material2: TMaterial
    ambBlue = 1
    ambAlpha = 1
    difBlue = 1
    difAlpha = 1
    aFace = faFrontAndBack
    dFace = faFrontAndBack
    sFace = faFrontAndBack
    Left = 40
    Top = 108
  end
  object Transform4: TTransform
    TranX = -1.3
    TranZ = -4
    AxisX = 1
    AxisY = 1
    Angle = 65
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform4Paint
    Left = 4
    Top = 144
  end
  object Material3: TMaterial
    ambGreen = 1
    ambAlpha = 1
    difGreen = 1
    difAlpha = 1
    aFace = faFrontAndBack
    dFace = faFrontAndBack


PAGE 239
     sFace = faFrontAndBack
    Left = 40
    Top = 144
  end
  object Transform5: TTransform
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform5Paint
    Left = 4
    Top = 176
  end
  object Material4: TMaterial
    ambRed = 0.8
    ambGreen = 0.6
    ambBlue = 0.4
    ambAlpha = 1
    difRed = 0.8
    difGreen = 0.6
    difBlue = 0.4
    difAlpha = 1
    aFace = faFront
    dFace = faFront
    sFace = faFront
    Left = 40
    Top = 176
  end
end
Listing 10-4. Properties for the Foggy project.
In the form type declaration, set up a couple of private fields that the GL_LINEAR fog mode 
will need:

  private	
    fogStart,	
    fogEnd: GLfloat;	
  public	
In the FormCreate method, prepare for drawing round things and set up conditions for a 
fog. You need the FogColor variable to pass to a glFog command to set the (you guessed it) 
fog color. OpenGL fog works by mixing the fog color with the color of each part of a scene. 
Although this is still another kind of blending, fog effects do not require enabling 
GL_BLEND because fog has its own special constant. In this event handler, enable fog, set 
up one of the fog modes, establish the fog color, and specify the density of the fog.

procedure TForm1.FormCreate(Sender: TObject);	
var	


PAGE 240
   FogColor: packed record	
    red,	
    green,	
    blue,	
    alpha: GLfloat;	
  end;	
begin	
  CylinderBase;	
  glEnable(GL_FOG);	
  glFogi(GL_FOG_MODE,GL_EXP2);	
  with FogColor do	
  begin	
    red := 0.5;	
    green := 0.5;	
    blue := 0.5;	
    alpha := 1.0;	
  end;	
  glFogfv(GL_FOG_COLOR,@FogColor);	
  glFogf(GL_FOG_DENSITY,0.3);	
end;	
The FormResize and FormPaint methods are about what you would expect. Note the use of 
Swap instead of glFlush. This example needs non-flickering transitions from one fog state to 
another so you can detect some of the more subtle changes.

procedure TForm1.FormResize(Sender: TObject);	
begin	
  if OpenGL1.Smaller then	
    FormPaint(Sender);	
end;	
	
procedure TForm1.FormPaint(Sender: TObject);	
begin	
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);	
  Transform1.Apply;	
  Transform2.Apply;	
  Transform3.Apply;	
  Transform4.Apply;	
  Transform5.Apply;	
  OpenGL1.Swap;	
  OpenGL1.ErrorCheck('FormPaint');	
end;	
The TTransform OnPaint event handlers are also typical. In them you apply lighting and 
draw a red cylinder, a blue cube, a green cone, and a brown rectangular floor at varying 
distances.

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	


PAGE 241
   Light1.Apply;	
end;	
	
procedure TForm1.Transform2Paint(Sender: TObject);	
begin	
  Material1.Apply;	
  Cylinder;	
end;	
	
procedure TForm1.Transform3Paint(Sender: TObject);	
begin	
  Material2.Apply;	
  Cube;	
end;	
	
procedure TForm1.Transform4Paint(Sender: TObject);	
begin	
  Material3.Apply;	
  Cone;	
end;	
	
procedure TForm1.Transform5Paint(Sender: TObject);	
begin	
  Material4.Apply;	
  glBegin(GL_POLYGON);	
    glVertex3f(-1.0,-1.0,-2.0);	
    glVertex3f(+1.0,-1.0,-2.0);	
    glVertex3f(+1.0,-1.0,-7.0);	
    glVertex3f(-1.0,-1.0,-7.0);	
  glEnd;	
end;	
To allow yourself to explore various fog settings by pressing keys, fill in a FormKeyPress 
event handler. A small “a” disables fog, and “b,” “c,” and “d” enable fog with various fog 
modes. The fog mode for “d” is GL_LINEAR, which needs start and end information. Use 
“0” through “9” to set the fog start value from 0.0 to 9.0. Use “e” through “z” to set the fog 
end value from 1.0 to 22.0 greater than the current start value. Note that the start and end 
values have no effect on the other two fog modes.
How thick is the fog? Is it clear, the faintest wisp, or as thick as pea soup? Of course OpenGL 
cannot use those descriptions, but it can take a floating-point number from 0.0 to 1.0. Use 
capital letters “A” through “Z” to set GL_FOG_DENSITY.

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);	
var	
  density: GLfloat;	
begin	


PAGE 242
   case Key of	
    '0'..'9': begin	
      fogStart := ord(key)-48;	
      glFogf(GL_FOG_START,fogStart);	
    end;	
    'A'..'Z': begin	
      density := (ord(Key)-65)/25.0;	
      glFogf(GL_FOG_DENSITY,density);	
    end;	
    'a': glDisable(GL_FOG);	
    'b': begin	
      glEnable(GL_FOG);	
      glFogi(GL_FOG_MODE,GL_EXP);	
    end;	
    'c': begin	
      glEnable(GL_FOG);	
      glFogi(GL_FOG_MODE,GL_EXP2);	
    end;	
    'd': begin	
      glEnable(GL_FOG);	
      glFogi(GL_FOG_MODE,GL_LINEAR);	
    end;	
    'e'..'z': begin	
      fogEnd := ord(Key)-ord('d')+fogStart;	
      glFogf(GL_FOG_END,fogEnd);	
    end;	
  end; {case}	
  FormPaint(nil);	
end;	
Save, compile, run, and enjoy.
Identifier Reference
Identifier			Description
glBlendFunc
OpenGL command that specifies rules for blending.
GL_BLEND
OpenGL constant to pass to glEnable for enabling 
blending.
GL_DST_ALPHA
OpenGL constant for specifying rules for blending.
GL_EXP
OpenGL constant that tells OpenGL to use an 
exponential fog equation.
GL_EXP2
OpenGL constant that tells OpenGL to use a higher 
order exponential fog equation.

PAGE 243
 
Identifier			Description
glFog
An OpenGL command to set parameters for fog.
GL_FOG
An OpenGL constant to pass to glEnable or glDisable to enable or disable atmospheric 
effects.
GL_FOG_COLOR
OpenGL constant that specifies RGBA fog color.
GL_FOG_DENSITY
An OpenGL constant that tells OpenGL what density to use with the exponential equations.
GL_FOG_END
An OpenGL constant that tells OpenGL the far distance in the linear fog equation.
GL_FOG_INDEX
An OpenGL constant that tells OpenGL the palette entry to use for fog color in color index 
mode.
GL_FOG_MODE
An OpenGL constant that introduces a parameter telling OpenGL what fog equation to use.
GL_FOG_START
An OpenGL constant that tells OpenGL the near distance in the linear fog equation.
GL_LINE_SMOOTH
The OpenGL constant to pass to glEnable for antialiasing lines.
GL_LINEAR
OpenGL constant for use of linear fog equation.
GL_ONE_MINUS_
DST_ALPHA
An OpenGL constant for specifying rules for blending.
GL_ONE_MINUS_
SRC_ALPHA
An OpenGL constant for specifying rules for blending.
GL_POINT_SMOOTH
The OpenGL constant to pass to glEnable for antialiasing points.
GL_POLYGON_
SMOOTH
The OpenGL constant to pass to glEnable for antialiasing polygons.
GL_SRC_ALPHA
OpenGL constant for specifying rules for blending.
Summary
In this chapter you learned the meaning of the mysterious fourth coordinate in 
homogeneous coordinate systems and how to use it in a scaling effect. You also learned 
some helpful visual effects with blending. In particular, you learned how to smooth out lines 
and polygon edges, how to simulate transparency, and how to simulate atmospheric effects.

PAGE 244

