The sample program presented in this section will show you how
to create the viewport, set up matrix modes, and draw some simple
2-D images.
Start by creating a new project named GLSample2 and setting it
up for OpenGL like you did with the first program, or use the
first program as your starting point.
Use ClassWizard to add an OnSize function to CGLSample2View in
response to a WM_SIZE message. Edit OnSize to look like this:
void CGLSample2View::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
GLsizei width, height;
GLdouble aspect;
width = cx;
height = cy;
if (cy==0)
aspect = (GLdouble)width;
else
aspect = (GLdouble)width/(GLdouble)height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 500.0*aspect, 0.0, 500.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
Now use ClassWizard to an OnPaint function to CGLSample2View in
response to a WM_PAINT message. Edit OnPaint to look like this:
void CGLSample2View::OnPaint()
{
CPaintDC dc(this); // device context for painting (added by ClassWizard)
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POLYGON);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glVertex2f(100.0f, 50.0f);
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
glVertex2f(450.0f, 400.0f);
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glVertex2f(450.0f, 50.0f);
glEnd();
glFlush();
}
Compile and run the program. You should see a black window with
a large multicolored triangle in it. Try resizing the window and
watch the triangle resize along with it. OnSize defines the viewport
and the viewing coordinates. The viewport is the area of the window
that the OpenGL commands can draw into. It is set in this program
by calling
glViewport(0, 0, width, height);
This sets the lower left hand corner of the viewport to the lower
left hand corner of the window and sets the height and width to
that of the window. The parameters passed into the function are
in screen coordinates. Try changing the glViewport command in
OnSize to the following. Then compile and run the program to see
what happens.
glViewport(width/4, height/4, width/2, height/2);
Make the window taller than it is wide. Because the viewport is
smaller than the screen, part of the triangle will be clipped.
Change the code back to the way it was originally
The next command called in OnSize is glMatrixMode(GL_PROJECTION).
OpenGL maintains three internal matrices to control various transformations.
These matrices are name Projection, ModelView, and
Texture. The Projection matrix handles transformations
from the eye coordinates to clip coordinates. The ModelView matrix
converts object coordinates to eye coordinates. The Texture matrix
converts textures from the coordinates they are defined in to
the coordinates need to map them onto a surface. glMatrixMode
sets which of these matrices will be affected by matrix operations.
Don't worry if you don't understand these right now, I'll explain
them as needed.
We call glLoadIdentity to initialize the project matrix. gluOrtho2D
sets the project matrix to display a two dimension orthogonal
image. The numbers passed into this function define the space
within which you may draw. This space is known as the world coordinates.
We now initialize the ModelView matrix and leave OpenGL in this
matrix mode. Matrix operations (which include transformations)
carried out while in the ModelView mode will affect the location
and shape of any object drawn. For example if we called "glRotated(30,
0, 0, 1)" just before out glBegin call in OnPaint, our triangle
would be rotated 30 degrees around the lower left corner of the
screen. We will look at this more a little later. (For those of
you who have used IRIS GL, we have just set up the equivalent
of calling mmode(MSINGLE). There is an entire section in the VC++
online documentation detailing the differences between IRIS GL
and OpenGL for those who are interested.)
OnPaint is the beast that actually draws our triangle. First we
clear our ModelView matrix. This isn't really necessary since
we aren't doing any transformations, but I added it just in case
we decide to do any. Next we clear the color buffer (which in
this case happens to be the screen, but could be a print buffer
or bitmap depending on the type of device context you used to
create rendering context ). The next call is glBegin(GL_POLYGON).
This function changes the state of the rendering context. From
an object oriented perspective, it creates an internal object
of type GL_POLYGON, which is defined by all commands issued until
glEnd() is called. We make three glColor4f and three glVertex2f
calls to define our triangle.
Let me take a moment at this point to discuss the naming conventions
OpenGL uses. All OpenGLcommands use the prefix "gl".
There are also a number of "glu" commands which are
considered "GL Utilities". These "glu" commands
are simply combinations of "gl" commands that perform
commonly useful tasks - like setting up 2-D orthographic matrices.
Most "gl" commands have a number of variants that each
take different data types. The glVertex2f command, for instance,
defines a vertex using two floats. There are other variants ranging
from four doubles to an array of two shorts. Read the list of
glVertex calls in the online documentation and you will feel like
you are counting off an eternal list. glVertex2d, glVertex2f,
glVertex3i, glVertex3s, glVertex2sv, glVertex3dv...
The definition for our triangle uses the following technique.
We call glColor4f(1.0f, 0.0f, 0.0f, 1.0f). This sets the current
color to Red by specifying the Red component to 1 and the Green
and Blue components to 0. We then define a vertex at point (100,50)
in our world coordinates by calling glVertex2f(100.0f, 50.0f).
We now have a red vertex at point (100,50). We repeat this process,
setting the color to Green and Blue respectively, for the next
two vertices. The call to glEnd ends the definition of this polygon.
At this point there should still be nothing on the screen. OpenGL
will save the list of commands in a buffer until you call glFlush.
glFlush causes these commands to be executes. OpenGL automatically
interpolates the colors between each of the points to give you
the multihued triangle you see on the screen.
Play with some of the different shapes you can create with glBegin.
There is a list of modes and valid commands to create shapes below.
In the next version of this program, we will move our drawing
routines into the document class. I will also show you how to
use the basic transforms and the importance of pushing and popping
matrices onto and off of the matrix stack.
glBegin(GLenum mode) parameters:
GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES,
GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, GL_POLYGON
Functions that are valid between glBegin and glEnd:
glVertex, glColor, glIndex, glNormal, glTexCoord, glEvalCoord,
glEvalPoint, glMaterial, and glEdgeFlag
Download Example Source
Source code for GLSample2
Place the file in the parent directory for the project and type "pkunzip -d GLSamp2.zip".
Then choose File - OpenWorkspace and open the glsample1.mak file unzipped into the GLSample2 directory.
You must have a version on PKZip that supports long file names.
Click here to get the latest version of PKZip.