Chapter 11
Textures
With the glMaterial commands embedded in the TMaterial component you have 
considerable power over the appearance of objects in your scenes. Not only do you control 
the basic color of your polygons, but combined with lighting, you can control shading and 
shininess.
Complicated Surfaces
However, many surfaces have more detail than you may want to tackle. For a simple 
example, consider an ordinary brick. A brick is not just a simple rectangular solid; it has a 
bumpy, irregular surface and numerous color variations. You could draw a polygon for each 
variation, with different material properties for each polygon.
The Problem
Thus, a simple brick that might be represented with a few primitives becomes a major task 
for the programmer and quite computationally intensive. Imagine the impossible task of 
creating a scene with bricks and rocks and grass and dirt and trees with leaves. Even if you 
could program it, the computer would probably take a very long time to render each frame. 
Even with massive simplification and approximation, fairly simple scenes would be 
prohibitive. There has to be a better way.
The Solution
Fortunately there is a standard way to represent complicated surfaces more efficiently. You 
can prepare or obtain flat graphics patterns and wrap them around simple graphics objects 
to simulate complicated surfaces. OpenGL knows how to perform transformations 
(translation, rotation, scaling) on the patterns along with the polygons to which they are 
attached. The name for these graphics patterns is textures. The technique of applying such 

PAGE 245
 patterns to your polygons is texture mapping. The subject of textures in OpenGL covers a 
huge territory; this book deals with a reasonable subset only.
Texture Structure
A texture is a rectangular graphic image, and as you might expect, OpenGL treats it as an 
array. 
Layout, Limits, and a Command
OpenGL commands will be quite satisfied receiving a simple linear array to represent a 
texture; in the command identifying a texture you must tell OpenGL the width and height of 
the graphic, since all the command sees is a pointer to a linear region of memory.

procedure glTexImage2D(target:GLenum; level,components:GLint; width,	
height:GLsizei; border:GLint; format,_type:GLenum; pixels:Pointer); stdcall;	
For the target parameter, only one value is permissible:

  GL_TEXTURE_2D = $DE1;	
The level parameter should be 0 for now. You would use a higher number for mipmapped 
textures, which involve multiple images.
The components parameter tells how many color components are in the texture. Use 1, 2, 3, 
or 4, depending on the format parameter.
The width and height parameters tell how many units wide and tall the texture is. You must 
explicitly tell OpenGL this information because it cannot determine the structure from the 
memory region. These values cannot be just anything; they are limited to powers of two. 
Your textures could be, among others, 512x512, 128x128, or 8x8. You are not limited to 
square textures; they could be 256x64, 128x32, 16x8, and many others.
The border parameter specifies the width of the texture’s border. Border issues can become 
quite complex and will not be considered here; use 0.
The format parameter describes the structure of each unit of texture information. These 
values are below:

  GL_COLOR_INDEX = $1900; 	
Each value in the texture is an index into a color palette. Use 1 as the number of color 
components.


PAGE 246
   GL_RED = $1903; 	
Each value in the texture is an intensity of red.

  GL_GREEN = $1904; 	
Each value in the texture is an intensity of green.

  GL_BLUE = $1905; 	
Each value in the texture is an intensity of blue.

  GL_ALPHA = $1906; 	
Each value in the texture is an alpha value.

  GL_RGB = $1907; 	
Each value in the texture is a structure with three color components—red green, and blue. 
Use 3 for the components parameter.

  GL_RGBA = $1908;	
Each value in the texture is a structure with four color components—red green, blue, and 
alpha. Use 4 for the components parameter.

  GL_LUMINANCE = $1909; 	
Each value in the texture is a grayscale intensity.

  GL_LUMINANCE_ALPHA = $190A; 	
Each value in the texture has a grayscale intensity and an alpha value.
The _type parameter specifies the underlying data type in the texture element structure. The 
symbolic constants have obvious meanings:

  GL_BYTE           = $1400;	
  GL_UNSIGNED_BYTE  = $1401;	
  GL_SHORT          = $1402;	
  GL_UNSIGNED_SHORT = $1403;	
  GL_INT            = $1404;	
  GL_UNSIGNED_INT   = $1405;	
  GL_FLOAT          = $1406;	
Here are some corresponding OpenGL data types not covered yet:

  GLbyte   = shortint;	
  GLshort  = smallInt;	
  GLubyte  = byte;	
  GLushort = word;	

PAGE 247
 Finally, the pixels parameter points to the region of memory containing the texture. The 
fundamental piece of information within the array is the texel, or texture element, which 
corresponds to the pixel, or picture element.
Make a Brick
The first example program will use a texture representing a brick. You could use a linear 
array, but the richness of Delphi certainly provides a more meaningful way to represent the 
layout. Define TTexel3 for GL_RGB and TTexel4 for GL_RGBA as follows:

type	
  TTexel3=packed record	
    red,	
    green,	
    blue: GLubyte;	
  end;	
  TTexel4=packed record	
    red,	
    green,	
    blue,	
    alpha: GLubyte;	
  end;	
As the names indicate, the types have three and four color components, respectively, one of 
which will be the appropriate value of the components parameter in the glTexImage2D 
command. In this example program, use 4 in the FormCreate method:

glTexImage2D(GL_TEXTURE_2D,Level,4,wBrick,hBrick,Border,GL_RGBA,	 
GL_UNSIGNED_BYTE,@Brick); 	
The width and height parameters are symbolic constants. Other symbolic constants also 
appear in this code to help identify the parameters in a rather bulky API call:

const	
  wBrick=16;	
  hBrick=8; 	
  Level=0;	
  Border=0;	
  ColorComps=4;	


PAGE 248
 The Brick variable is of type TBrick, which is a two-dimensional array of TTexel4:

type	
  TBrickLine=array[0..wBrick-1] of TTexel4;	
  TBrick=array[0..hBrick-1] of TBrickLine;	
	
var	
  Brick: TBrick;	
Use a MakeBrick procedure to fill in the Brick structure. Randomize initializes the random 
seed and Random adjusts the red value of each texel slightly to give the brick texture a 
mottled appearance. Notice the loop control variables. For dealing with textures the 
convention is to refer to S and T coordinates instead of X and Y coordinates.

procedure MakeBrick;	
var	
  sTex, {x}	
  tTex: {y} integer;	
begin	
  Randomize;	
  for tTex := 0 to hBrick-1 do	
    for sTex := 0 to wBrick-1 do	
    with Brick[tTex][sTex] do	
    begin	
      alpha := 255;	
      if (tTex=hBrick-1) or (sTex=wBrick-1) then	
      begin	
        red := 220;	
        green := 220;	
        blue := 220;	
      end else begin	
        red := 150+Random(60);	
        green := 60;	
        blue := 0;	
      end;	
    end; {for with}	
end;	
Remember that OpenGL coordinates proceed from bottom to top, so as the tTex coordinate 
advances, the procedure builds the brick from the bottom up. The special condition makes 
the top row and right column of texels an off-white to represent mortar. Figure 11-1 shows 
the randomly mottled brick texture.


PAGE 249
 Simple Texture, Simple Surface
Now, with several pages of explanation out of the way, you can start building an example 
program. Create a new directory under the OpenGL directory and name it Chapter.11. 
Under that directory create one called Simple. Create a new project and save its files into the 
Simple directory. Name the main unit Simple1.Pas and the project Simple0.Dpr. Listing 11-1 
shows the components and properties.

object Form1: TForm1
  Left = 311
  Top = 102
  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
  object OpenGL1: TOpenGL
    pfdFlags = [Draw_To_Window, Support_OpenGL]
    PixelType = RGBA
    Projection = Perspective
    Enable = [depthTest]


PAGE 250
     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
    TranZ = -2.2
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform1Paint
    Left = 4
    Top = 36
  end
end
Listing 11-1. Simple texture project properties.
Set Up Texturing
You need some commands in the FormCreate method to set up texturing. FormCreate also 
calls MakeBrick to create a simple texture. Be sure to place the MakeBrick procedure 
described earlier just before FormCreate.

procedure TForm1.FormCreate(Sender: TObject);	
begin	
  glPixelStorei(GL_UNPACK_ALIGNMENT,1);	
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);	
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);	
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);	
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 	
  MakeBrick;	
  glTexImage2D(GL_TEXTURE_2D,Level,ColorComps,wBrick,hBrick,Border,	
    GL_RGBA,GL_UNSIGNED_BYTE,@Brick);	
  glEnable(GL_TEXTURE_2D);	
  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);	
end;	


PAGE 251
 Here are the pertinent constant declarations:

  GL_UNPACK_ALIGNMENT       = $0CF5;	
  GL_TEXTURE_2D             = $0DE1; 	
  GL_TEXTURE_ENV_MODE       = $2200; 	
  GL_TEXTURE_ENV            = $2300; 	
  GL_NEAREST                = $2600;	
  GL_NEAREST_MIPMAP_NEAREST = $2700; 	
  GL_TEXTURE_MAG_FILTER     = $2800;	
  GL_TEXTURE_MIN_FILTER     = $2801;	
  GL_TEXTURE_WRAP_S         = $2802; 	
  GL_TEXTURE_WRAP_T         = $2803;	
  GL_CLAMP                  = $2900;	
  GL_REPEAT                 = $2901;	
Here are the declarations of the new commands:

procedure glPixelStorei(pname:GLenum;param:GLint); stdcall;	
procedure glTexParameteri(target,pname:GLenum;param:GLint); stdcall;	
procedure glTexEnvf(target,pname:GLenum;param:GLfloat); stdcall;	
In FormCreate you first tell OpenGL about the pixel storage mode with the glPixelStorei 
command. It affects several different operations, including the unpacking of texture patterns. 
The first parameter, GL_UNPACK_ ALIGNMENT, tells OpenGL the alignment 
requirements for the start of each pixel row in memory. The second value is 1, which means 
byte alignment. Larger values would mean alignment on 2-, 4-, or 8-byte boundaries, but 
byte alignment is the current need.
A lot of different parameters control texture mapping; the glTexParameteri command allows 
you to specify a target (one- or two-dimensional textures), name a parameter, and assign a 
value to that parameter. The target parameter for each glTexParameteri command is 
GL_TEXTURE_2D, telling OpenGL that the parameters being set are for two-dimensional 
textures rather than for one-dimensional textures. One-dimensional textures have their uses, 
but the scope of this book does not include them. FormCreate calls the command several 
times, each with a different pname.
GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T tell OpenGL what the wrapping 
parameters will be, either GL_CLAMP or GL_REPEAT. GL_REPEAT enables multiple copies 
of the texture to appear in the S or T direction when dimensions warrant. You could use 
GL_REPEAT even when wrapping would not occur, but GL_CLAMP would prevent 
possible wrapping artifacts.
GL_TEXTURE_MAG_FILTER and GL_TEXTURE_MIN_FILTER tell OpenGL what to do 
when the pixel being textured is larger or smaller than the texel. The third parameter set to 
GL_NEAREST tells OpenGL to use the 

PAGE 252
 color of the texel nearest the center of the pixel being textured. Other possible values would 
require OpenGL to calculate a color after selecting from multiple images in mipmaps.
The glTexImage2D command uses Level 0 for the base image level and also uses 0 for the 
border width. The format is GL_RGBA (red, green, blue, and alpha), so the number of color 
components is four. The texture is 16 texels wide and 8 texels tall. The data type in the 
structure is GLubyte, which is the equivalent of a Delphi byte. The texture is contained in the 
Brick variable, to which the call to the command passes a pointer.
The glEnable command is self explanatory, but glTexEnvf needs a little more description. 
The first two parameters are inflexible, but for the third you have several choices; however, 
this book only uses two of them:

  GL_MODULATE = $2100; 	
  GL_DECAL    = $2101;	
The command tells OpenGL how to interpret texture values when texturing a fragment. For 
now, use GL_DECAL, which basically tells OpenGL to paste an opaque or possibly an alpha 
blended texture over the surface.
More Methods
The following methods illustrate how simple and straightforward this project is:

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;	
Applying the Texture
The final piece of this texture puzzle is tacking the texture to the surface. Where you specify 
the vertices, also specify texture coordinates with glTexCoord2f commands:


PAGE 253
 procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  glBegin(GL_POLYGON);	
    glTexCoord2f(0.0,0.0); glVertex3f(-1.0,-0.5,+0.0);	
    glTexCoord2f(1.0,0.0); glVertex3f(+1.0,-0.5,+0.0);	
    glTexCoord2f(1.0,1.0); glVertex3f(+1.0,+0.5,+0.0);	
    glTexCoord2f(0.0,1.0); glVertex3f(-1.0,+0.5,+0.0);	
  glEnd;	
end;	
Run
Save, compile, and run. Figure 11-3 shows the polygon is completely covered by the texture.
So what has this accomplished? How is this better than drawing a picture in Windows 
Paint? The answer is once a texture is mapped to an object, transformations on the object also 
transform the texture. Exit from the running Simple0.Exe, select the TTransform component 
on the form designer, and change a few properties in the Object Inspector. 

PAGE 254
 Set Angle to 65, AxisX to 0.3, and AxisY to 1.0.

Again save, compile, and run. Figure 11-4 shows the polygon and texture together rotated 
and clipped by the zNear clipping plane.




       Figure 11-4. A texture transformed 
       with its polygon.

Stretch
The texture fit very nicely on the polygon and moved around perfectly with the polygon. 
What more is there? Well, there is the fact that the texture and the polygon were custom 
designed to fit each other. What if the texture and the polygon do not have the same 
proportional dimensions?
Mapping Manner
The answer lies in these two statements:

  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);	
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);	
The manner in which OpenGL performs its texture mapping proceeds from the various 
parameters set in the glTexParameteri commands. These particular command instances set 
the wrapping parameters to GL_CLAMP, so the texture image has a one-to-one exact fit to 
the polygon; it tacks to the appropriate vertices, shrinking or stretching as needed.
The best way to explain that effect is by means of an example in which the coordinates of the 
polygon are not proportional to the texture dimensions.


PAGE 255
 Coordinates
Create a new directory under the Chapter.11 directory and name it Stretch. Create a new 
project and save it into the new directory, naming the unit Stretch1.Pas and the project 
Stretch0.Dpr. Make this project identical to the previous one except for the vertex 
coordinates in the Transform1Paint method. Also use the original zero values for Angle, 
AxisX, and AxisY in the Object Inspector for the Transform1 component.

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  glBegin(GL_POLYGON);	
    glTexCoord2f(0.0,0.0); glVertex3f(-1.0,-1.0,+0.0);	
    glTexCoord2f(1.0,0.0); glVertex3f(+1.0,-1.0,+0.0);	
    glTexCoord2f(1.0,1.0); glVertex3f(+1.0,+1.0,+0.0);	
    glTexCoord2f(0.0,1.0); glVertex3f(-1.0,+1.0,+0.0);	
  glEnd;	
end;	
Run
Save, compile, and run. Figure 11-5 shows the result. The texture image is stretched 
vertically by a factor of two, or compressed horizontally; take your preference. Figure 11-6 
diagrams the mapping process. The point is that texture mapping has much more flexibility 
than the first example program alone would indicate. The Stretch0 application shows that a 
texture image can deform to fit its surface.



PAGE 256
 Replication
These examples of texture mapping suggest great possibilities for effective rendering, but 
they are very far from exhausting the available varieties. Suppose you want to render a brick 
wall twenty bricks tall and a hundred bricks wide. Do you apply 2,000 separate textures? 
That is certainly a dreadful thought!
Two for One
Create another directory and project under Chapter.11; name the directory Double, the unit 
Double1.Pas, and the project Double0.Dpr. The names were chosen because this application 
will make two bricks out of one. Make this project just like the Stretch0 project except for a 
couple of changes.

PAGE 257
 Parameters
In the FormCreate method, replace the GL_CLAMP values with GL_REPEAT:

  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);	
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);	
By setting the wrap parameters to GL_REPEAT you allow OpenGL to repeat the texture 
image over the surface. This value allows but does not require repetition. The final 
distribution of image copies depends on the S and T texture coordinates.
Coordinates
Change the texture coordinates in the Transform1Paint method. Rather than running the T 
values from 0.0 to 1.0, replace the higher value with 2.0. By making the T coordinates run 
from 0.0 to 2.0 you provide for two copies of the texture image in the vertical direction.

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  glBegin(GL_POLYGON);	
    glTexCoord2f(0.0,0.0); glVertex3f(-1.0,-1.0,+0.0);	
    glTexCoord2f(1.0,0.0); glVertex3f(+1.0,-1.0,+0.0);	
    glTexCoord2f(1.0,2.0); glVertex3f(+1.0,+1.0,+0.0);	
    glTexCoord2f(0.0,2.0); glVertex3f(-1.0,+1.0,+0.0);	
  glEnd;	
end;	
Run
Save, compile, and run. Behold the magic of two bricks as in Figure 11-7, enlarged for your 
viewing pleasure. Notice how well the image copies fit together at the mortar seams.
Figure 11-8 diagrams the image copy layout.

PAGE 258
 
PAGE 259
 
A Brick Wall
Admittedly the two-brick example is a bit lame for most situations, but it does introduce a 
technique which you can easily expand. To illustrate, the next example program builds a 
brick wall.
Make another directory under Chapter.11 named Wall. Create and save a project in it named 
(surprise!) Wall0.Dpr with a unit named Wall1.Pas. Make this project just like the Double0 
project except for the texture coordinates:

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  glBegin(GL_POLYGON);	
    glTexCoord2f(0.0,00.0); glVertex3f(-1.0,-1.0,+0.0);	
    glTexCoord2f(8.0,00.0); glVertex3f(+1.0,-1.0,+0.0);	
    glTexCoord2f(8.0,16.0); glVertex3f(+1.0,+1.0,+0.0);	
    glTexCoord2f(0.0,16.0); glVertex3f(-1.0,+1.0,+0.0);	
  glEnd;	
end;	
These texture coordinates result in eight bricks across and sixteen bricks up. (Remember that 
OpenGL y window coordinates increase from bottom to top.) Save, compile, and run. You 
will see a brick wall like that in Figure 11-9.

PAGE 260
 Multiple Polygons
So far you have mapped one or more copies of a texture image to a single polygon, which is 
great, but few OpenGL scenes depend solely on such simple surfaces. 
Triangle Strip Square
The first example of texturing multiple polygons will be just one step up from texturing a 
single polygon. In this exercise you will create a square of the same size as before out of a 
triangle strip. You advance from texturing one polygon to two.
Create a new directory under Chapter.11 and call it Strip. Save a new project in it named 
Strip0.Dpr with a unit named Strip1.Pas. Make it just like the Wall0 project except for your 
rendering code.
Here is the code to make a square out of a strip of two triangles:

  glBegin(GL_TRIANGLE_STRIP);	
    glVertex3f(-1.0,+1.0,+0.0);	
    glVertex3f(-1.0,-1.0,+0.0);	
    glVertex3f(+1.0,+1.0,+0.0);	
    glVertex3f(+1.0,-1.0,+0.0); 	
  glEnd;	
You have four vertices, just like before. They even have the same values. On the other hand 
they are not in the same order and are not used the same way. So how do you map your 
texture to these vertices? The basic idea is that you match parts of the texture image to 
specific vertices. Although the vertices are not specified in the same order, you still tack a 
particular texture coordinate to a particular vertex. Here is the rendering code:

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  glBegin(GL_TRIANGLE_STRIP); 	
    glTexCoord2f(00.0,16.0); glVertex3f(-1.0,+1.0,+0.0);	
    glTexCoord2f(00.0,00.0); glVertex3f(-1.0,-1.0,+0.0);	
    glTexCoord2f(08.0,16.0); glVertex3f(+1.0,+1.0,+0.0);	
    glTexCoord2f(08.0,00.0); glVertex3f(+1.0,-1.0,+0.0);	
  glEnd;	
end;	
Save, compile, and run. It should look just like the Wall0 project, as shown in Figure 11-9.

PAGE 261
 Still More Polygons
With that experience under your belt, you can go all out, mapping a repeating texture image 
to a strip of 36 triangles. As if that were not daring enough, you will apply your flat texture 
map to a curved surface! By combining a cylinder with a brick texture you can build a brick 
silo. Unlike an ordinary silo, this one will go spinning through space.
Create another directory under Chapter.11 and name it Silo. Save a new project in it named 
Silo0.Dpr with a unit named Silo1.Pas. Although the Shapes unit does not yet contain a 
textured cylinder, you will still need it in the project because you will use the CylinderBase 
procedure.
On the form place a TOpenGL component and a TTransform component. Listing 11-2 shows 
the properties:

object Form1: TForm1
  Left = 314
  Top = 108
  Width = 328
  Height = 347
  Caption = 'Form1'
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  Position = poScreenCenter
  OnCreate = FormCreate
  OnPaint = FormPaint
  OnResize = FormResize
  PixelsPerInch = 96
  TextHeight = 13
  object OpenGL1: TOpenGL
    pfdFlags = [DoubleBuffer, Draw_To_Window, Support_OpenGL]
    PixelType = RGBA
    Projection = Perspective
    Enable = [depthTest]
    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


PAGE 262
     Left = 8
    Top = 8
  end
  object Transform1: TTransform
    TranZ = -2.55
    AxisX = 0.2
    AxisY = 1
    Angle = -65
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform1Paint
    Left = 8
    Top = 40
  end
end
Listing 11-2. Silo0 properties.
In the form type declaration you need some private fields for the cylinder translation and an 
Idle method:

  private	
    deltaX,	
    deltaY,	
    deltaZ: GLfloat;	
    procedure Idle(Sender:TObject;var Done:boolean);	
  public	
In the implementation section you need the constants, types, variables, and the MakeBrick 
procedure you have seen before in the last several projects. Also, in the Shapes unit, you will 
need to move the circleX, circleY, and circleZ variables from the implementation section to 
the interface section so the Silo1 unit can use them after they have been initialized by the 
CylinderBase procedure.
The FormCreate method is also the same as before, except for a little extra initialization at the 
end, just after the glTexEnvf command:

  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);	
  Application.OnIdle := Idle;	
  deltaX := 0.01;	
  deltaY := 0.01;	
  deltaZ := 0.01;	
  CylinderBase;	
end;	

Put the code for a texture-capable cylinder after the FormCreate method. Call it CylinderT, 
and give it parameters for the ranges of texture coordinates. The range of the S texture 
coordinates (the sTex parameter) will be 

PAGE 263
 tacked to 36 evenly spaced vertices, so divide the range by 36 and store it in the s36 variable.

procedure CylinderT(sTex,tTex:glFloat);	
var	
  around: integer;	
  s36: GLfloat;	
begin	
  S36 := sTex/36.0;	
  glBegin(GL_TRIANGLE_STRIP);	
    for around := 0 to 35 do	
    begin	
      glTexCoord2f(around*s36,tTex);	
      glVertex3f(circleX[around],circleY[around],-0.4);	
      glTexCoord2f(around*s36,0.0);	
      glVertex3f(circleX[around],circleY[around],+0.4);	
    end; {for}	
    glTexCoord2f(sTex,tTex);	
    glVertex3f(circleX[0],circleY[0],-0.4);	
    glTexCoord2f(sTex,0.0);	
    glVertex3f(circleX[0],circleY[0],+0.4);	
  glEnd;	
end;	
The FormResize method is the same as always, but the FormPaint method needs adjustment 
for double buffering:

procedure TForm1.FormPaint(Sender: TObject);	
begin	
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);	
  Transform1.Apply;	
  OpenGL1.Swap;	
  OpenGL1.ErrorCheck('FormPaint');	
end;	
For rendering code, just call CylinderT in the Transform1Paint method:

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  CylinderT(16.0,8.0);	
end;	
Finally, here is the Idle method that moves the cylinder around, keeping it within some 
boundaries by changing the sign of the delta variables. (So that this example stays focused 
on the current purpose, no extra code for machine-independent speed is present.) You may 
want to adjust the delta values in this code for the most appropriate speed for your 
computer:

procedure TForm1.Idle(Sender:TObject;var Done:boolean);	
begin	


PAGE 264
   Done := false;	
  with Transform1 do	
  begin	
    if Angle<360.0 then	
      Angle := Angle+0.1	
    else	
      Angle := 0.0;	
	
    if TranX<-0.7 then	
      deltaX := 0.001;	
    if TranX>0.7 then	
      deltaX := -0.001;	
    TranX := TranX+deltaX;	
	
    if TranY<-0.8 then	
      deltaY := 0.001;	
    if TranY>0.8 then	
      deltaY := -0.001;	
    TranY := TranY+deltaY;	
	
    if TranZ>-2.22 then	
      deltaZ := -0.001;	
    if TranZ<-9.00 then	
      deltaZ := 0.001;	
    TranZ := TranZ+deltaZ;	
  end; {with}	
  FormPaint(nil);	
end;	
Save, compile, and run to see a flying brick silo like in Figure 11-10.







         Figure 11-10. A flying brick silo.


PAGE 265
 Windows Bitmaps as Textures
Obviously many texture images are more complicated than the little memory brick used so 
far, and they require more sophisticated tools to draw. In the world of Microsoft Windows, 
the dominant image format is the Windows bitmap. The typical file extension is .BMP. (Since 
OpenGL has its own concept called “bitmap,” the term must be qualified with “Windows” 
or “OpenGL” for clarity.) Windows bitmap structures and OpenGL texture structures 
developed completely independently of each other, so they are not necessarily compatible.
A Close One
Fortunately, one Windows bitmap format is very close to one OpenGL texture image format, 
so that about the only conversion required is skipping the header. The selected Windows 
bitmap format is 24-bit true color, and the selected OpenGL texture format is GL_RGB. 
In both formats, each element takes three bytes, one for red, one for green, and one for blue. 
Not only that, but Windows bitmaps run their vertical coordinates from bottom to top, just 
like OpenGL.
Remember the power-of-two requirement for OpenGL texture dimensions. In order for a 
Windows bitmap to be useful as an OpenGL texture image, it must abide by the same 
restrictions. The forthcoming example program will use a 256x256 image as the label of a 
fanciful beverage called Zap, which appears in Figure 11-11. The file is available on the 
companion CD as Fig11-11.bmp, created by means of Windows Paint.
The Project
Create a new directory under Chapter.11 called Zap and save a new project in it called 
Zap0.Dpr, with a unit called Zap1.Pas. Copy Fig11-11.bmp from 

PAGE 266
 the CD into the new directory. Make the project just like the Silo0 project with a few 
exceptions, which follow.
The Differences
Near the top of the implementation section, remove the wBrick and hBrick constants and 
change ColorComps from 4 to 3 because the 24-bit Windows bmp file has no alpha 
component:

const	
  Level=0;	
  Border=0;	
  ColorComps=3;	
Just below the constants, replace the type and variable definitions completely:

type	
  TRGB=packed record	
    r,g,b: byte;	
  end;	
  TWrap=array[0..0] of TRGB;	
	
var	
  Wrapper: pointer;	
Remove the MakeBrick procedure and replace it with a ReadBitmap function that opens the 
designated file, gets the file size, and subtracts the header sizes to obtain the size of the 
actual bitmap. Then it reads the file header and checks for a valid bitmap signature. Next the 
function reads the info header and extracts the width and height in pixels, which it 
communicates to the caller via the var parameters. Finally, it allocates the required memory 
and reads the bitmap into that memory. The function returns a pointer to the memory 
containing the raw true-color bitmap.

function ReadBitmap(const FilePath:string;var sWidth,tHeight:GLsizei):	 pointer;	
const	
  szh=SizeOf(TBitmapFileHeader);	
  szi=SizeOf(TBitmapInfoHeader);	
var	
  bmpfile: file;	
  bfh: TBitmapFileHeader;	
  bmi: TBitmapInfoHeader;	
  t: byte;	
  x,	
  fpos,	
  size: integer;	
begin	


PAGE 267
   assignFile(bmpfile,FilePath);	
  reset(bmpfile,1);	
  size := FileSize(bmpfile)-szh-szi;	
  blockread(bmpfile,bfh,szh);	
  if Bfh.bfType<>$4D42 then	
    raise EInvalidGraphic.Create('Invalid Bitmap');	
  blockread(bmpfile,bmi,szi);	
  with bmi do	
  begin	
    sWidth := biWidth;	
    tHeight := biHeight;	
  end;	
  getmem(result,size);	
  blockread(bmpfile,result^,size);	
end;	
Add a couple of local variables to the FormCreate method, which will receive the width and 
height information from the ReadBitmap function:

procedure TForm1.FormCreate(Sender: TObject);	
var	
  sWidth,	
  tHeight: GLsizei;	
Replace the call to MakeBrick and the parameters to glTexImage2D. Free the Wrapper 
memory after passing it to the OpenGL command. Do not be alarmed by this; when you pass 
a structure to OpenGL, it makes its own copy, so you can do anything you want with the 
original any time there- after without affecting OpenGL’s copy. Actually, you should replace 
the filename with a fully qualified path to the file so that the program will work even if you 
have changed your current directory before starting.

  Wrapper := ReadBitmap(‘Fig11-11.bmp’,sWidth,tHeight);	
  glTexImage2D(GL_TEXTURE_2D,Level,ColorComps,sWidth,tHeight,Border,	
    GL_RGB,GL_UNSIGNED_BYTE,Wrapper);	
  Freemem(Wrapper);	
Change the parameters in the call to CylinderT because instead of eight bricks across by 
sixteen bricks tall, you only need two beverage labels wrapped around, and only one label 
tall:

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  CylinderT(2.0,1.0);	
end;	
Finally, change some properties of the TTransform component. Change Angle from –65.0 to 
90.0, AxisX from 0.2 to 1.0, AxisY from 1.0 to 0.0, and AxisZ from 0.0 to 1.0.

PAGE 268
 Run
Save, compile, and run. Watch the deadly beverage can tumble around with a dazzling 
green label. Figure 11-12 captures one frame:
Close, But No Cigar
If you opened the bitmap with Windows Paint you may have noticed a color difference 
between it and the OpenGL rendering. The blue “ZAP” should have been a red “ZAP.” The 
cyan lightning bolts were originally yellow. The reason is that OpenGL is using RGB and 
Windows stored BGR, so red and blue are switched. Therefore, the program will have to do 
some conversion after all.
Go back to the ReadBitmap function and add a pixel-flipping loop at the end. The types and 
variables are already in place:

  blockread(bmpfile,result^,size);	
  for x := 0 to sWidth*tHeight-1 do	
  with TWrap(result^)[x] do	
  begin	
    t := r;	


PAGE 269
     r := b;	
    b := t;	
  end;	
end;	
Now save your changes, compile, and run again. Now you will have red lettering and 
yellow lightning bolts.
Mipmapping
Have you ever seen one of those first-person games where you wander around and shoot 
everything that moves? If you have, you have probably noticed that if you approach too 
closely to one of those nicely textured stone walls, the illusion is spoiled by an extremely 
blocky close-up. You may have wondered why the games did not have finer detail in those 
textures so that you would not be disappointed by the proximity. The issue, of course, was 
memory. A texture image can take up precious memory in the video card. A high-detail 
texture image would possibly have taken too much of a scarce resource, and most of the time 
the detail would have remained unappreciated, except by those folks who perversely decide 
to bump into walls.
OpenGL provides a mechanism by which you can avoid the worst of such artifacts. An 
earlier part of the chapter introduced the term “mipmap” involving multiple images for a 
texture. With mipmapping, basically you start with your largest and best texture image. 
Then you make various shrunken, lower-detail images from it. OpenGL picks which image 
is the most appropriate to use as the texture in a given frame. As an object becomes larger 
(closer), OpenGL replaces the texture with a larger one with more detail. As the object 
becomes smaller, OpenGL can use a texture image that requires less memory.
To illustrate the technique, first illustrate the problem. Create a new directory named Mip 
under the Chapter.11 directory. In it save a new project named Mip0.Dpr with a unit named 
Mip1.Pas. Make it just like the Zap0 project. Naturally, differences will follow. Copy from 
the CD a series of bitmap files named GW0.BMP, GW1.BMP...GW8.BMP to the new 
directory.
To the FormCreate method, add a string to hold a potentially variable filename:

procedure TForm1.FormCreate(Sender: TObject);	
var	
  sWidth,	
  tHeight: GLsizei;	
  fn: string;	
begin  	

PAGE 270
 Change the lines around the call to glTexImage2D. Instead of the assignment to fn shown 
below, use a fully qualified path to the file. Remove the call to CylinderBase and the 
assignments to deltaX and deltaY. While you are at it, remove their declarations as well:

  fn := 'GW3.BMP';	
  Wrapper := ReadBitmap(fn,sWidth,tHeight);	
  glTexImage2D(GL_TEXTURE_2D,0,ColorComps,sWidth,tHeight,Border,GL_RGB,	
    GL_UNSIGNED_BYTE,Wrapper);	
  freemem(Wrapper); 	
  glEnable(GL_TEXTURE_2D);	
  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);	
  Application.OnIdle := Idle;	
  deltaZ := 0.01;	
  OpenGL1.ErrorCheck(‘FormCreate’);	
end;	
This time draw a square rather than a cylinder. Since you are no longer using the CylinderT 
procdure, go ahead and remove it:

procedure TForm1.Transform1Paint(Sender: TObject);	
begin	
  glBegin(GL_POLYGON);	
    glTexCoord2f(0.0,0.0); glVertex3f(-1.0,-1.0,+0.0);	
    glTexCoord2f(1.0,0.0); glVertex3f(+1.0,-1.0,+0.0);	
    glTexCoord2f(1.0,1.0); glVertex3f(+1.0,+1.0,+0.0);	
    glTexCoord2f(0.0,1.0); glVertex3f(-1.0,+1.0,+0.0);	
  glEnd;	
end;	
For the TOpenGL component, change the pxFar property to 32.0 in the Object Inspector. 
Correspondingly change the TranZ property of the TTransform to –32.0; change its Angle 
and Axis properties to zero. Trim the Idle method to manipulate only deltaZ:

procedure TForm1.Idle(Sender:TObject;var Done:boolean);	
begin	
  Done := false;	
  with Transform1 do	
  begin	
    if TranZ>-2.01 then	
      deltaZ := -0.001;	
    if TranZ<-31.99 then	
      deltaZ := 0.001;	
    TranZ := TranZ+deltaZ;	
  end; {with}	
  FormPaint(nil);	
end; {Idle}	

PAGE 271
 Save, compile, and run. The program uses a single 32x32 texture image representing some 
gold foil. Notice what happens to the texture as the image gets close. Ugly! You can even see 
a sparkling effect as OpenGL keeps recalculating the size of the texture from perspective 
adjustment. See Figure 11-13 for the closest (and ugliest) view.
Now, change the FormCreate method to accommodate mipmapping, as in Listing 11-3. 
Notice the new parameter to go with GL_TEXTURE_MIN_FILTER. 
GL_NEAREST_MIPMAP_ NEAREST tells OpenGL you will be using multiple texture 
images and, for a given image, tells OpenGL to use the color of the texel nearest the center of 
the pixel being textured.
The base image is 256x256, so there are a total of nine images for sizes down to 1x1. Each 
successive image must be one-half the size of the previous one in each direction (so it will 
usually be one-fourth the “area” of the previous one). For example, the second image is 
128x128. Even if the base image were not square, the number of images is determined by the 
larger dimension. Once the smaller dimension has been cut down to one pixel, successive 
images continue to cut down the longer dimension until it too reaches one pixel. The nine 
bitmap files beginning with GW0.BMP are the nine images for the mipmap.

procedure TForm1.FormCreate(Sender: TObject);
var
  sWidth,
  tHeight: GLsizei;
  fn: string;
begin
  glPixelStorei(GL_UNPACK_ALIGNMENT,1);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,  
    GL_NEAREST_MIPMAP_NEAREST);

  fn := 'GW0.BMP';


PAGE 272
   Wrapper := ReadBitmap(fn,sWidth,tHeight);
  glTexImage2D(GL_TEXTURE_2D,0,ColorComps,sWidth,tHeight,Border,GL_RGB,
    GL_UNSIGNED_BYTE,Wrapper);
  freemem(Wrapper);

  inc(fn[3]);
  Wrapper := ReadBitmap(fn,sWidth,tHeight);
  glTexImage2D(GL_TEXTURE_2D,1,ColorComps,sWidth,tHeight,Border,GL_RGB,
    GL_UNSIGNED_BYTE,Wrapper);
  freemem(Wrapper);

  inc(fn[3]);
  Wrapper := ReadBitmap(fn,sWidth,tHeight);
  glTexImage2D(GL_TEXTURE_2D,2,ColorComps,sWidth,tHeight,Border,GL_RGB,
    GL_UNSIGNED_BYTE,Wrapper);
  freemem(Wrapper);

  inc(fn[3]);
  Wrapper := ReadBitmap(fn,sWidth,tHeight);
  glTexImage2D(GL_TEXTURE_2D,3,ColorComps,sWidth,tHeight,Border,GL_RGB,
    GL_UNSIGNED_BYTE,Wrapper);
  freemem(Wrapper);

  inc(fn[3]);
  Wrapper := ReadBitmap(fn,sWidth,tHeight);
  glTexImage2D(GL_TEXTURE_2D,4,ColorComps,sWidth,tHeight,Border,GL_RGB,
    GL_UNSIGNED_BYTE,Wrapper);
  freemem(Wrapper);

  inc(fn[3]);
  Wrapper := ReadBitmap(fn,sWidth,tHeight);
  glTexImage2D(GL_TEXTURE_2D,5,ColorComps,sWidth,tHeight,Border,GL_RGB,
    GL_UNSIGNED_BYTE,Wrapper);
  freemem(Wrapper);

  inc(fn[3]);
  Wrapper := ReadBitmap(fn,sWidth,tHeight);
  glTexImage2D(GL_TEXTURE_2D,6,ColorComps,sWidth,tHeight,Border,GL_RGB,
    GL_UNSIGNED_BYTE,Wrapper);
  freemem(Wrapper);

  inc(fn[3]);
  Wrapper := ReadBitmap(fn,sWidth,tHeight);
  glTexImage2D(GL_TEXTURE_2D,7,ColorComps,sWidth,tHeight,Border,GL_RGB,
    GL_UNSIGNED_BYTE,Wrapper);
  freemem(Wrapper);

  inc(fn[3]);
  Wrapper := ReadBitmap(fn,sWidth,tHeight);


PAGE 273
   glTexImage2D(GL_TEXTURE_2D,8,ColorComps,sWidth,tHeight,Border,GL_RGB,
    GL_UNSIGNED_BYTE,Wrapper);
  freemem(Wrapper);

  glEnable(GL_TEXTURE_2D);
  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
  Application.OnIdle := Idle;
  deltaZ := 0.01;
  OpenGL1.ErrorCheck('FormCreate');
end;
Listing 11-3. FormCreate sets up mipmapping.

Again, you should replace the filename with a fully qualified path to the file so that the 
program will work even if you have changed your current directory before starting. Replace 
fn[3] with the proper resulting position in the fn string for the numeric digit part of the 
filename.
Save, compile, and run. Behold a mipmap in operation. Figure 11-14 shows the closest view 
of the gold foil. 
If you watch closely while the program is running, you may notice when OpenGL switches 
to the next size texture. The somewhat clumsy transitions and the coarseness of the smaller 
images are due to the fact that the tool (Windows Paint) uses a relatively crude method of 
image reduction from the base image. While this serves quite well to demonstrate the 
mipmap process, you will need to use better tools to create mipmaps for real applications.


PAGE 274
 Lighting
One really big thing that has been missing from these demonstrations is lighting. In the next 
illustrative program, you will add the lighting that makes OpenGL so powerful.
Add Components
Under Chapter.11 create a new directory named Light, a project named Light0.Dpr, and a 
unit named Light1.Pas. Naturally you should save the project and its unit in the new 
directory. Make the project just like the Wall0 project, but add another TTransfer component 
and a TLight component. Listing 11-4 shows the added components and their properties, 
along with a few changes in Transform1:

object Form1: TForm1
  Left = 308
  Top = 100
  Width = 328
  Height = 347
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = True
  OnCreate = FormCreate
  OnPaint = FormPaint
  OnResize = FormResize
  PixelsPerInch = 96
  TextHeight = 13
  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


PAGE 275
     ColorBits = 24
    DepthBits = 32
    StencilBits = 0
    Left = 8
    Top = 4
  end
  object Transform1: TTransform
    TranZ = -2.2
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform1Paint
    Left = 8
    Top = 40
  end
  object Light2: TLight
    Which = 0
    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 = 44
    Top = 76
  end
  object Transform2: TTransform
    TranX = -4
    TranY = 1
    ScaleX = 1
    ScaleY = 1
    ScaleZ = 1
    OnPaint = Transform2Paint
    Left = 8
    Top = 76
  end
  object Material1: TMaterial
    ambRed = 1
    ambGreen = 1
    ambBlue = 1
    ambAlpha = 1
    difRed = 1
    difGreen = 1
    difBlue = 1


PAGE 276
     difAlpha = 1
    aFace = faFront
    dFace = faFront
    sFace = faFront
    Left = 44
    Top = 40
  end
  object Material2: TMaterial
    ambRed = 1
    ambGreen = 1
    ambBlue = 1
    ambAlpha = 1
    difRed = 1
    difGreen = 1
    difBlue = 1
    difAlpha = 1
    aFace = faBack
    dFace = faBack
    sFace = faBack
    Left = 84
    Top = 40
  end
end
Listing 11-4. Light0 project properties.
The OnPaint event handler for Transform2 applies the lighting:

procedure TForm1.Transform2Paint(Sender: TObject);	
begin	
  Light2.Apply;	
end;	
The FormPaint method should call Transform2.Apply first since it carries the lighting:

procedure TForm1.FormPaint(Sender: TObject);	
begin	
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);	
  Transform2.Apply;	
  Transform1.Apply;	
  glFlush;	
  OpenGL1.ErrorCheck(‘FormPaint’);	
end;	
Save, compile, and run. Because of the angles and positions of the brick wall and the light, 
the near part of the wall should be dark and the more distant part should be fairly well 
illuminated. Instead, as Figure 11-15 shows, the wall is uniformly bright.


PAGE 277
 Alpha
Well, that did not work, so try something else. Under Chapter.11, make an Alpha directory 
containing an Alpha0.Dpr project and an Alpha1.Pas unit, which you make just like the 
Light0 project, with a slight change, of course.
The brick has an alpha component, so put it to use. In the MakeBrick procedure, make your 
texture halfway transparent:

    with Brick[tTex][sTex] do	
    begin	
      alpha := 222;	
Now you need material color that can respond to the lighting and blend with the texture. 
Change the properties of the Material1 component according to its text representation in 
Listing 11-5:

  object Material1: TMaterial
    ambRed = 0.5
    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


PAGE 278
     Left = 40
    Top = 40
  end
Listing 11-5. Material to blend with texture.
Save, compile, and run. Now the texture shows little, if any, shading. This may be an 
improvement, but not anything to brag about or even notice. The real use of alpha is to allow 
texture color to combine with material color, not shading. Maybe OpenGL has a suitable 
constant to pass as a parameter to facilitate light and shade.
Modulate
Indeed it does. Instead of GL_DECAL, pass GL_MODULATE. GL_DECAL tells OpenGL to 
apply the texture like a decal that covers a surface but does not partake of the properties of 
the surface, other than the shape and possibly some alpha blending. GL_MODULATE 
passed to the texture environment command allows the lit material color to attenuate the 
texture color. While it does facilitate lighting effects, it does not provide for shininess. For 
that you would have to render twice, once with the texture and once with only the shiny 
material properties. Such a technique is not covered here.
Create a new directory under the Chapter.11 directory and name it Modulate. Create a new 
project and save it in the new directory as Mod0.Dpr, with a unit named Mod1.Pas. Make 
the project like the Alpha0 project, but leave the alpha value for the brick at the original 255. 
In the FormCreate method, change the parameter passed to the texture environment 
command from GL_DECAL to GL_MODULATE:

  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);	
Save, compile, run, and behold shading, as shown in Figure 11-16.

PAGE 279
 
Identifier Reference
Identifier			Description
GLbyte
An OpenGL data type equivalent to Delphi shortint.
glPixelStorei
An OpenGL command that specifies the pixel storage mode.
GLshort
An OpenGL data type equivalent to Delphi smallint.
glTexCoord2f
An OpenGL command that gives the texture coordinate to go with the next vertex 
coordinate.
glTexEnvf
An OpenGL command that tells OpenGL how to interpret texture values when texturing a 
fragment.
glTexImage2D
An OpenGL command that tells OpenGL important information about the two-dimensional 
texture image and points to the texture image.
glTexParameteri
An OpenGL command that allows you to set the parameters that control texture mapping.
GLubyte
An OpenGL data type equivalent to Delphi byte.
GLushort
An OpenGL data type equivalent to Delphi word.
GL_ALPHA
An OpenGL constant that informs OpenGL that each value in the texture is an alpha value 
so that it represents an RGBA value in which the red, green, and blue values are 0 and the 
alpha value is the specified amount.
GL_BLUE
An OpenGL constant that informs OpenGL that each value in the texture is an intensity of 
blue.
GL_BYTE
An OpenGL constant that informs OpenGL that an underlying data type is GLbyte.
GL_CLAMP
An OpenGL constant, used as a texture wrapping parameter, that tells OpenGL not to repeat 
the texture image in the given direction.

PAGE 280
 
Identifier			Description
GL_COLOR_INDEX
An OpenGL constant that informs OpenGL that each value in the texture is an index into a 
color palette. 
GL_DECAL
An OpenGL constant that tells OpenGL to paste the texture image over the surface using the 
shape as the only property of the surface, with some account of the material color if the 
texture alpha is less than the maximum.
GL_GREEN
An OpenGL constant that informs OpenGL that each value in the texture is an intensity of 
green.
GL_FLOAT
An OpenGL constant that informs OpenGL that an underlying data type is GLfloat.
GL_INT
An OpenGL constant that informs OpenGL that an underlying data type is GLint.
GL_LINEAR
An OpenGL constant which, when passed to glTexParameteri, tells OpenGL to use the color 
of the four texels nearest the center of the pixel being textured.
GL_LUMINANCE
An OpenGL constant that informs OpenGL that each value in the texture is a grayscale 
intensity.
GL_LUMINANCE_
ALPHA
An OpenGL constant that informs OpenGL that each value in the texture has a grayscale 
intensity and an alpha value.
GL_MODULATE
An OpenGL constant that allows modulation between the lit material color and the texture 
color.
GL_NEAREST
An OpenGL constant which, when passed to glTexParameteri, tells OpenGL to use the color 
of the texel nearest the center of the pixel being textured.
GL_NEAREST_MIPMAP_
NEAREST
An OpenGL constant which, when passed to the glTexParameteri command, tells OpenGL 
you will be using multiple texture images and, for a given image, tells OpenGL to use the 
color of the texel nearest the center of the pixel being textured.

PAGE 281
 
Identifier			Description
GL_RED
An OpenGL constant that informs OpenGL that each value in the texture is an intensity of 
red.
GL_REPEAT
An OpenGL constant that enables multiple copies of the texture to appear in the S or T 
direction when dimensions warrant.
GL_RGB
An OpenGL constant that informs OpenGL that each value in the texture is a structure with 
three color components—red, green, and blue.
GL_RGBA
An OpenGL constant that informs OpenGL that each value in the texture is a structure with 
four color components—red, green, blue, and alpha.
GL_SHORT
An OpenGL constant that informs OpenGL that an underlying data type is GLshort.
GL_TEXTURE_2D
An OpenGL constant that informs OpenGL that the OpenGL command applies to a two-
dimensional texture, rather than to a one-dimensional texture.
GL_TEXTURE_ENV
The obligatory OpenGL constant that serves as the target for the glTexEnvf command.
GL_TEXTURE_ENV_
MODE
An OpenGL constant to pass to the glTexEnvf command. When you pass this constant you 
can tell OpenGL with the next parameter how texture values should combine with color 
values from the fragment being textured.
GL_TEXTURE_MAG_
FILTER
An OpenGL constant to pass to glTexParameteri to tell OpenGL what to do when the pixel 
being textured is larger than the texel.
GL_TEXTURE_MIN_
FILTER
An OpenGL constant to pass to glTexParameteri to tell OpenGL what to do when the pixel 
being textured is smaller than the texel.
GL_TEXTURE_WRAP_S
An OpenGL constant to pass to glTexParameteri to tell OpenGL what the wrapping 
parameters will be in the S direction.
GL_TEXTURE_WRAP_T
An OpenGL constant to pass to glTexParameteri to tell OpenGL what the wrapping 
parameters will be in the T direction.

PAGE 282
 
Identifier			Description
GL_UNPACK_
ALIGNMENT
An OpenGL constant which, when passed to the GlPixelStorei command, tells OpenGL the 
alignment requirements for the start of each pixel row in memory. 
GL_UNSIGNED_BYTE
An OpenGL constant that informs OpenGL that an underlying data type is GLubyte.
GL_UNSIGNED_INT
An OpenGL constant that informs OpenGL that an underlying data type is GLuint.
GL_UNSIGNED_SHORT
An OpenGL constant that informs OpenGL that an underlying data type is GLushort.
Summary
OpenGL has a method to add realistic detail to scenes without a massive increase in the 
number of polygons. With texture mapping you can apply a flat image to a polygon or 
group of polygons. Various OpenGL commands and constants allow you to set up a 
multitude of possible texture mapping criteria. Use the GL_DECAL constant to paste a 
texture on a surface or GL_MODULATE to allow lighting effects in combination with 
material properties.
A key factor in successful texture mapping is properly matching up texture coordinates, 
using glTexCoord2f, with vertex coordinates, which you specify just after the texture 
coordinates. A very useful texture mapping feature allows you to multiply a small texture 
image many times over a surface. For example, you could represent an entire brick wall 
when you only draw one brick. The constant you use for this is GL_REPEAT in conjunction 
with texture coordinates greater than 1.0. Another, rather advanced, feature  comes in handy 
when different levels of detail are needed for a texture seen from a wide range of distances. 
With mipmapping, OpenGL can automatically select the most appropriate image from a 
group of images.
Texture mapping is one more example of the tremendous power OpenGL brings to the 
world of three-dimensional graphics. Indeed, although this chapter unlocks fascinating and 
versatile texturing techniques, it only touches the “surface” of OpenGL’s texturing 
capabilities.


PAGE 283
 

PAGE 284

