0% found this document useful (0 votes)
73 views

Debugging OpenGL With GLUT

1) The document introduces the 2D OpenGL and GLUT graphics library. GLUT makes it easy to create an OpenGL window and handle events. 2) It provides instructions for installing GLUT on Windows, including downloading files and placing them in the proper directories. 3) A simple example program is given that uses GLUT to create a window and OpenGL to clear it to blue, demonstrating the basic structure for OpenGL programs.

Uploaded by

silly_rabbitz
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
73 views

Debugging OpenGL With GLUT

1) The document introduces the 2D OpenGL and GLUT graphics library. GLUT makes it easy to create an OpenGL window and handle events. 2) It provides instructions for installing GLUT on Windows, including downloading files and placing them in the proper directories. 3) A simple example program is given that uses GLUT to create a window and OpenGL to clear it to blue, demonstrating the basic structure for OpenGL programs.

Uploaded by

silly_rabbitz
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

2D OpenGL and GLUT Tutorial

2D OpenGL and GLUT Tutorial


Frank Luna

Because C++ is designed to be portable, it does not provide a graphics library; indeed, some
platforms C++ is implemented on may not even have a hardware device capable of graphics
output. And even if they all did, the graphical hardware capabilities from one platform to the
other will vary so much that it would be a useless attempt to try and create a standard graphical
interface. Thus graphics are left to 3rd party libraries specific to the platform. OpenGL (Open
Graphics Library) is one such library that has been implemented on a variety of platforms
capable of interactive polygonal based computer graphics, such as Windows, Mac, Linux, and
Playstation. The goal of this tutorial is to provide the reader with the opportunity to practice
C++ programming by doing some basic 2D graphics programming in OpenGL. The only
prerequisites correspond to Chapters 1-5 of C++ Module I.

§1 GLUT Installation and Setup


GLUT (OpenGL Utility Toolkit) is another 3rd party library which makes it easy to get started
using OpenGL. With GLUT, we can create a window for an OpenGL application to draw onto
very easily with only a few function calls from the GLUT library. GLUT also provides a simple
interface for working with the keyboard and mouse. We will use GLUT in these tutorials
because, presumably, our intended audience does not have the background to setup a window
without it. (For example, you need to know some intermediate Win32 programming, if you are
working on a Win32 platform. Moreover, GLUT is implemented on several platforms, so the
code can be easily ported to another platform GLUT is implemented on.) In this section, we
show how to obtain and install GLUT. We will assume you are working on a Windows platform
using Visual Studio 2005 (VS05), but the steps should be analogous for other platforms and
other IDEs.
First, you need to download GLUT for Windows (glut-3.7.6-bin.zip), which can be
obtained in the download section of the course website. Unzip the archive to the place on your
hard drive you want to store the glut folder (e.g., C:\glut-3.7.6-bin). In particular, you should
have the files glut.h, glut32.lib and glut32.dll contained in the glut-3.7.6-bin folder. Now you
will need to move these three files to other directories like so:

1. Move glut.h to the OpenGL folder of VS05: for example, C:\Program Files\Microsoft
Visual Studio 8\VC\PlatformSDK\Include\gl. Now VS05 will be able to find glut.h when
we write #include <GL/glut.h>.

2. Move the GLUT library file glut32.lib to the VS05 library folder, for example,
C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Lib. Now VS05 will be
able to find glut32.lib when we link it.

www.gameinstitute.com Page 1
2D OpenGL and GLUT Tutorial

3. Move glut32.dll over to C:\WINDOWS\system32, which is one of the folders applications


search DLLs for.

After completing these three steps, your system should now be ready to write and build OpenGL
and GLUT applications.

Note: It is not explicitly necessary to link opengl32.lib, glu32.lib, glut32.lib, since glut.h does this with #pragma:
#pragma comment (lib, "opengl32.lib") /* link with Microsoft OpenGL lib */
#pragma comment (lib, "glu32.lib") /* link with Microsoft OpenGL Utility lib */
#pragma comment (lib, "glut32.lib") /* link with Win32 GLUT lib */

§2 Initializing OpenGL
The following code creates a window using GLUT and clears its area to the color blue. We
recommend that you create a new console application and enter in this code yourself, after
completing the steps in §1.

Program 1: InitGL

#include <GL/glut.h>

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

glutSwapBuffers();
}

int main(int argc, char **argv)


{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(640, 480);
glutCreateWindow("InitGL");

glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

glutDisplayFunc(Display);
glutMainLoop();
}

This program does not do much, but it demonstrates how to create a window using GLUT which
we can draw onto using OpenGL. Every OpenGL program we make in these tutorials will
contain these lines of code; so in some sense, this is the simplest OpenGL program.
We summarize the functions used in Program 1, starting in the main function:

glutInit: This function initializes GLUT and processes command line arguments; it
should be called before any other GLUT functions.

www.gameinstitute.com Page 2
2D OpenGL and GLUT Tutorial

glutInitDisplayMode: This function allows us to specify some properties of the


display system. In the code above, we specify GLUT_DOUBLE and GLUT_RGB:

o GLUT_DOUBLE: This means the display system will use a technique called
double buffering for smooth flicker free animation. In double buffering, there are
two surfaces (essentially a rectangular array of pixels) used for drawing: a front
buffer and a back buffer. The front buffer corresponds to the pixels currently
visible on the screen. The back buffer is an off screen surface that just exists in
memory. The idea of hardware double buffering is to draw the next frame of
animation to the back buffer while the front buffer is being displayed. Once the
frame is completely drawn to the back buffer, the front buffer and back buffer are
swapped between monitor refreshes (the old back buffer becomes the new front
buffer and the old front buffer becomes the new back buffer). In this way, we do
not modify the front buffer while the monitor is in the middle of displaying it,
which could cause tearing; additionally, it means that we do not watch the frame
as it gets drawn, which can cause flickering due to overdraw. Note that even
though we always draw to the back buffer, we will sometimes say “draw to the
screen” because that is the essential result in the end.
o GLUT_RGB: This means a pixel‟s color is specified as a combination of red,
green, and blue.

glutInitWindowPosition: This function is used to specify the position of


the window‟s upper-left corner relative to the screen coordinate system. (Note that the
origin of the screen is in the upper-left corner of the screen, the positive x-axis goes to the
right and the positive y-axis goes down. This is the typical screen coordinate system.)
The first parameter is the x-coordinate and the second parameter is the y-coordinate, and
units are measured in pixels. Try experimenting with different window positions.

glutInitWindowSize: This function is used to specify the width and height of the
window we are going to create. The first parameter is the width and the second
parameter is the height, and units are measured in pixels. Try experimenting with
different window dimensions.

glutCreateWindow: This function actually creates the window with position and
dimensions specified by glutInitWindowPosition and
glutInitWindowSize; it takes a string parameter which will be displayed in the
window‟s title bar. This function creates a window, but it is not displayed until
glutMainLoop is invoked.

glClearColor: This OpenGL function only sets the color to use for clearing the back
buffer; it does not actually clear it. A color consists of four components: red, green, blue,
and alpha. The alpha component is used to control transparency, something we will not
use in these tutorials. By combining different intensities of red, green, and blue, we can
represent just about every practical color. The first, second, third, and fourth parameters
of this function specify the intensities of the red, green, blue, and alpha components,

www.gameinstitute.com Page 3
2D OpenGL and GLUT Tutorial

respectively. The intensity of a color component is described by a floating-point number


from 0.0 to 1.0; for example, a value of 0.5 for red means to use 50% of the brightest red,
a value of 0.25 for blue means to use 25% of the brightest blue. You should experiment
and try out different combinations of red, green, and blue to get a feel for the final colors
they generate. Examples:

o glClearColor(1.0f, 0.0f, 0.0f, 1.0f) // red


o glClearColor(0.0f, 1.0f, 0.0f, 1.0f) // green
o glClearColor(1.0f, 0.0f, 1.0f, 1.0f) // blue
o glClearColor(0.0f, 0.0f, 0.0f, 1.0f) // black
o glClearColor(1.0f, 1.0f, 1.0f, 1.0f) // white
o glClearColor(0.5f, 0.5f, 0.5f, 1.0f) // gray
o glClearColor(1.0f, 1.0f, 0.0f, 1.0f) // yellow
o glClearColor(0.0f, 0.0f, 0.5f, 1.0f) // dark blue

glutDisplayFunc: For this function, we pass a pointer to a display function we


define, which contains the drawing code we want executed. GLUT will then invoke this
display function as needed when the window needs repainting (e.g., when the window is
resized, when the window becomes visible).

glClear: This function, with argument GL_COLOR_BUFFER_BIT, clears the back


buffer to the color set by the glClearColor function. We always clear the back
buffer before drawing our scene to erase the contents of the previous scene. This
function also takes other arguments that instruct the function to clear other buffers, but
we will not discuss them since we do not need them for these tutorials.

glutSwapBuffers: This function instructs the system to swap the front and back
buffers. We must call this function so that the scene we just drew to the back buffer
eventually gets displayed.

glutMainLoop: This function displays the window created with


glutCreateWindow and enters into an application message loop. The message loop
will constantly scan for user input and respond (e.g., you may have noticed we can resize
the window created in Program 1), and it will constantly update the window so that we
can render animations.

Note: GLUT functions are prefixed with “glut” (e.g., glutSwapBuffers). OpenGL functions are prefixed with
“gl” (e.g., glClear). There is another related library, called GLU (OpenGL Utility), and their functions are
prefixed with “glu” (e.g., gluPerspective).

§3 Drawing Basic Shapes


This next program clears the window to black, and then draws an „X‟ shape by drawing two
lines. The new code, different from the previous program, has been bolded.

www.gameinstitute.com Page 4
2D OpenGL and GLUT Tutorial

Program 2: GLLines

#include <GL/glut.h>

float VIEW_HEIGHT = 20.0f;


float VIEW_WIDTH = -1.0f; // to be set in the Reshape function.

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_LINES);

// Line 1 specified by two endpoints.


glVertex2f(-5.0f, -5.0f);
glVertex2f( 5.0f, 5.0f);

// Line 2 specified by two endpoints.


glVertex2f(-5.0f, 5.0f);
glVertex2f( 5.0f, -5.0f);

glEnd();

glutSwapBuffers();
}

void Reshape(int w, int h)


{
float aspectRatio = float(w)/h;
VIEW_WIDTH = aspectRatio*VIEW_HEIGHT;

glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-VIEW_WIDTH/2, VIEW_WIDTH/2,
-VIEW_HEIGHT/2, VIEW_HEIGHT/2,
-10.0, 10.0);
}

int main(int argc, char **argv)


{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(640, 480);
glutCreateWindow("GLLines");

glutReshapeFunc(Reshape);

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

glutDisplayFunc(Display);
glutMainLoop();
}

www.gameinstitute.com Page 5
2D OpenGL and GLUT Tutorial

You will need to type this program into your code editor and build the program, in order to do
the exercises of this section. Now let us review the new code Program 2 introduces, starting in
the Display function.
OpenGL only has built-in support for drawing simple geometric objects like points, lines,
and triangles (complex objects that you see in games are modeled by a mesh of many small
triangles). Before we can specify the vertices of any geometric primitives, we need to call
glBegin. The single parameter of glBegin is used to specify the type of primitives we will
be drawing; in the example above, we specify GL_LINES indicating that we are drawing a line
list. With a line list, every two specified vertices form a line segment; a vertex is specified by
the glVertex2f function, which takes two floating-point parameters: the x- and y-coordinates
of the vertex, respectively. On the other hand, specifying GL_TRIANGLES for glBegin
would indicate a triangle list, in which every three vertices specified by glVertex2f would
define a triangle. When we are finished drawing the primitives of a particular type, we must call
glEnd. Note that all glVertex2f function calls must take place between a
glBegin/glEnd pair.
The Reshape function is a function we define and pass to GLUT via the
glutReshapeFunc (i.e., we pass a pointer to the function Reshape as an argument to the
function glutReshapeFunc). GLUT will then invoke this function whenever the window is
resized, passing in the new width and height of the resized window. Inside the Reshape
function, we update some OpenGL display properties based on the new window dimensions.
The way we call glViewport ensures that OpenGL will draw to the entire newly resized
window (rather than a sub-rectangle of the window). The glOrtho function, together with
glMatrixMode and glLoadIdentity, define a “viewing box,” centered at the origin.
Geometry that intersects this box can be seen by the virtual eye, and will be displayed on the
screen. Geometry outside this box is not seen and is discarded. The first two parameters specify
the left and right bounds of the box (where the x-axis corresponds with left and right); the third
and fourth parameters specify the bottom and top bounds of the box (where the y-axis
corresponds with bottom and top); and the fifth and sixth parameters specify the near and far
bounds of the box (where the z-axis corresponds with near and far). Because we are only
drawing in 2D for these tutorials, the fifth and sixth parameters, controlling the depth of the box,
are not of particular importance. The aspect ratio code is used to scale the view box so that its
width and height ratio matches the width and height ratio of the output window; if the ratios do
not match, a scaling distortion occurs (e.g., a circle becomes an ellipse or a square becomes a
rectangle). In the code, we specify the height of the view box with the global variable
VIEW_HEIGHT and then compute the width of the view box, VIEW_WIDTH, in the Reshape
function based on the aspect ratio.

Exercise: Try replacing the Display code in Program 2 with the following code to draw the
lines with color.

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_LINES);

www.gameinstitute.com Page 6
2D OpenGL and GLUT Tutorial

// Line 1 specified by two endpoints and colored red.


glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(-5.0f, -5.0f);
glVertex2f( 5.0f, 5.0f);

// Line 2 specified by two endpoints and colored blue.


glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(-5.0f, 5.0f);
glVertex2f( 5.0f, -5.0f);

glEnd();

glutSwapBuffers();
}

The new glColor3f function has three floating-point parameters (the ranges of which should
be in the interval [0, 1], just like glClearColor) which specify the red, green, and blue
intensities of the color to use, respectively. Subsequently drawn vertices will be drawn with the
color specified by this function.

Exercise: Try replacing the Display code in Program 2 with the following code to draw a grid
of points.

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_POINTS);

// Draw a grid of points.


for(float y = -9.0f; y <= 9.0f; y+=1.0f)
for(float x = -9.0f; x <= 9.0f; x+=1.0f)
glVertex2f(x, y);

glEnd();

glutSwapBuffers();
}

Exercise: Try replacing the Display code in Program 2 with the following code to draw a
triangle.

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_TRIANGLES);

// Three vertices make a triangle.

glColor3f(1.0f, 0.0f, 0.0f);


glVertex2f(0.0f, 5.0f);

glColor3f(0.0f, 1.0f, 0.0f);

www.gameinstitute.com Page 7
2D OpenGL and GLUT Tutorial

glVertex2f(-5.0f, -5.0f);

glColor3f(0.0f, 0.0f, 1.0f);


glVertex2f(5.0f, -5.0f);

glEnd();

glutSwapBuffers();
}

Notice how we draw each vertex with a different color. The colors of triangle‟s interior points
are formed by a weighted average of these three vertex colors to create a smooth transition. We
recommend you experiment with different colors at each vertex and examine the output until you
develop some intuition of how the interior colors are related to the vertex colors.

Exercise: Try replacing the Display code in Program 2 with the following code to draw a
quad (rectangle).

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_QUADS);

// Four vertices make a quad.

glColor3f(1.0f, 0.0f, 0.0f);


glVertex2f(5.0f, -3.0f);
glVertex2f(5.0f, 3.0f);

glColor3f(0.0f, 0.0f, 1.0f);


glVertex2f(-5.0f, 3.0f);
glVertex2f(-5.0f, -3.0f);

glEnd();

glutSwapBuffers();
}

Exercise: The following two functions draw a circle and solid disk, respectively. We will not go
into the details of how these functions work (for understanding the math, try the Game Math
course). However, we will make use of these functions in later demos, so you ought to try and
use these functions to draw a few circles and disks, in order to make sure you know how to use
them.

#include <cmath>

// DrawCircle
// cx: x-coordinate of the center of the circle.
// cy: y-coordinate of the center of the circle.
// r: radius of the circle.
// RGB: Color components of the circle's color.

www.gameinstitute.com Page 8
2D OpenGL and GLUT Tutorial

void DrawCircle(float cx, float cy, float r, float R, float G, float B)


{
glBegin(GL_LINE_LOOP);

glColor3f(R, G, B);

const float PI = 3.14159;


float stepSize = 2*PI/32;
for(float t = 0.0f; t < 2*PI; t+=stepSize)
{
float x = r*cosf(t) + cx;
float y = r*sinf(t) + cy;

glVertex2f(x,y);
}

glEnd();
}

// DrawDisk
// cx: x-coordinate of the center of the disk.
// cy: y-coordinate of the center of the disk.
// RGB: Color components of the disk's color.
void DrawDisk(float cx, float cy, float r, float R, float G, float B)
{
glBegin(GL_TRIANGLE_FAN);

glColor3f(R, G, B);

const float PI = 3.14159;


float stepSize = 2*PI/32;
glVertex2f(cx, cy);
for(float t = 0.0f; t <= 2*PI; t+=stepSize)
{
float x = r*cosf(t) + cx;
float y = r*sinf(t) + cy;

glVertex2f(x,y);
}

glEnd();
}

§4 Using the Keyboard and Mouse


In this section, we will write a program which translates a disk based on user input.
To handle key presses, we implement a function like the following:

void OnKeyPress(unsigned char key, int x, int y)


{
switch( key )
{
case 'a':
// Respond to ‘a’ key press.
break;

www.gameinstitute.com Page 9
2D OpenGL and GLUT Tutorial

case 'd':
// Respond to ‘d’ key press.
break;
case 'w':
// Respond to ‘w’ key press.
break;
case 's':
// Respond to ‘s’ key press.
break;
}

// Force the window to be repainted so the disk is drawn


// in the new position.
glutPostRedisplay();
}

The first parameter specifies the key pressed, and the second and third parameters specify the
position of the mouse cursor when the key was pressed, relative to the top-left corner of the
window. So essentially our key handling function will just be a case statement which does
different things based on which key was pressed. Often, and in the case of our demo for this
section, we will use key presses to update the position of an object we are drawing. Therefore,
after updating the position based on keyboard input, we call glutPostRedisplay to instruct
GLUT to repaint the window, so that the object is drawn in its updated position. After defining a
key handling function like the one above, we need to register it with GLUT, so that GLUT can
invoke it, with the appropriate arguments, when it detects that a key is pressed; to do this, call the
glutKeyboardFunc and pass a pointer to the key handing function you want to use:

glutKeyboardFunc(OnKeyPress);

To handle mouse presses, we implement a function like the following:

void OnMouseClick(int button, int state, int x, int y)


{
if( button == GLUT_LEFT_BUTTON )
{
// Respond to left mouse button click.
}

if( button == GLUT_MIDDLE_BUTTON )


{
// Respond to middle mouse button click.
}

if( button == GLUT_RIGHT_BUTTON )


{
// Respond to right mouse button click.
}
}

The first parameter identifies the button pressed; as you can see from the code, there are three
predefined identifiers GLUT uses to identify the three mouse buttons. The state parameter is
GLUT_UP if the mouse event was due to a mouse button being released or GLUT_DOWN if the

www.gameinstitute.com Page 10
2D OpenGL and GLUT Tutorial

mouse event was due to a mouse button being pressed (this flexibility is for if you want to do
different things for mouse presses and mouse releases). The third and fourth parameters specify
the position of the mouse cursor when the mouse button was pressed/released, relative to the top-
left corner of the window. After defining a mouse handling function like the one above, we need
to register it with GLUT, so that GLUT can invoke it, with the appropriate arguments, when it
detects that a mouse button is pressed; to do this, call the glutMouseFunc and pass a pointer
to the mouse handing function you want to use:

glutMouseFunc(OnMouseClick);

The following program draws a disk, where the user can press the „a‟, „d‟, „w‟, and „s‟
keys to move the disk to the left, right, up, and down, respectively; in addition, the user can left
mouse click a point in the window and the disk will be moved to the clicked point. The code
relevant to input handling and updating the disk has been bolded.

Program 3: GLInput

#include <GL/glut.h>
#include <cmath>

//************************************************************************
// Globals

float VIEW_HEIGHT = 200.0f;


float VIEW_WIDTH = -1.0f; // to be set below.

// Disk's center position.


float gCenterPosX = 0.0f;
float gCenterPosY = 0.0f;

//************************************************************************
// Function prototypes

// DrawDisk
// cx: x-coordinate of the center of the disk.
// cy: y-coordinate of the center of the disk.
// RGB: Color components of the disk's color.
void DrawDisk(float cx, float cy, float r, float R, float G, float B);

// ScreenToView: Converts point from window coordinates to the OpenGL view


space.
// sx: x-coordinate of point relative to screen window.
// sy: y-coordinate of point relative to screen window.
// vx: x-coordinate of point relative to view space.
// vy: y-coordinate of point relative to view space.
void ScreenToView(int sx, int sy, float& vx, float& vy);

//************************************************************************
// Function implementations.

www.gameinstitute.com Page 11
2D OpenGL and GLUT Tutorial

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

DrawDisk(gCenterPosX, gCenterPosY, 10.0f, 0.0f, 0.0f, 1.0f);

glEnd();
glutSwapBuffers();
}

void Reshape(int w, int h)


{
float aspectRatio = float(w)/h;
VIEW_WIDTH = aspectRatio*VIEW_HEIGHT;

glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-VIEW_WIDTH/2, VIEW_WIDTH/2,
-VIEW_HEIGHT/2, VIEW_HEIGHT/2,
-10.0, 10.0);
}

void OnKeyPress(unsigned char key, int x, int y)


{
switch( key )
{
case 'a':
gCenterPosX -= 2.0f;
break;
case 'd':
gCenterPosX += 2.0f;
break;
case 'w':
gCenterPosY += 2.0f;
break;
case 's':
gCenterPosY -= 2.0f;
break;
}

// Force the window to be repainted so the disk is drawn


// in the new position.
glutPostRedisplay();
}

void OnMouseClick(int button, int state, int x, int y)


{
// Move the center of the circle to the clicked point.
if( button == GLUT_LEFT_BUTTON )
{
ScreenToView(x, y, gCenterPosX, gCenterPosY);

// Force the window to be repainted so the disk is drawn


// in the new position.
glutPostRedisplay();

www.gameinstitute.com Page 12
2D OpenGL and GLUT Tutorial

}
}

int main(int argc, char **argv)


{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(640, 480);
glutCreateWindow("GLInput");

glutReshapeFunc(Reshape);
glutKeyboardFunc(OnKeyPress);
glutMouseFunc(OnMouseClick);

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

glutDisplayFunc(Display);
glutMainLoop();
}

void DrawDisk(float cx, float cy, float r, float R, float G, float B)


{
glBegin(GL_TRIANGLE_FAN);

glColor3f(R, G, B);

const float PI = 3.14159;


float stepSize = 2*PI/32;
glVertex2f(cx, cy);
for(float t = 0.0f; t <= 2*PI; t+=stepSize)
{
float x = r*cosf(t) + cx;
float y = r*sinf(t) + cy;

glVertex2f(x,y);
}

glEnd();
}

void ScreenToView(int sx, int sy, float& vx, float& vy)


{
int screenWidth = glutGet(GLUT_WINDOW_WIDTH);
int screenHeight = glutGet(GLUT_WINDOW_HEIGHT);

vx = +float(sx)*VIEW_WIDTH/screenWidth - VIEW_WIDTH/2;
vy = -float(sy)*VIEW_HEIGHT/screenHeight + VIEW_HEIGHT/2;
}

Remark: The ScreenToView function deserves some explanation. When a mouse button is pressed, we are given
the coordinates of the clicked point, relative to the upper-left corner of the window. These coordinates, however, are
not directly useful for updating the position of the disk because we describe the position of the disk relative to the
view box coordinate system, not the window coordinate system. So what the ScreenToView function does is
convert the window coordinates to the corresponding view coordinates, much like meters can be

www.gameinstitute.com Page 13
2D OpenGL and GLUT Tutorial

converted to centimeters, for example. However, for the purposes of this tutorial, we will omit the mathematical
derivation. Just know that the function inputs a point in window coordinates (sx and sy) and outputs the
corresponding point in view coordinates (vx and vy).

§5 Timing and Animation


We begin by reviewing a little mathematics which will be employed in the demo for this section.
Consider the pair of equations:

If we think of x and y as the coordinates of a point, then this pair of equations generates different
points as we vary t in the range 0 to 1. For example, the following table shows the
different points generated for different values of t:

If we plot these functions using graphing software, we see that these equations generate points on
a circle, centered at the origin with radius 10, starting at the point . If we think of as
time, and the position of an object, then we can think of these equations as defining the
motion of the object over time; in the example above, the object would move around a circle
over a period of one time unit (say, seconds).
In the above equations, we kept the radius of the circle fixed at 10, but we could also
make the radius vary as t varies. For example, we could make the radius oscillate to get a spiral
like effect:

In this section, we animate a disk by changing its position and radius over time using
equations like the ones described above. There are two key GLUT functions we need to add
animation:

glutIdleFunc: This function is used to register a function for GLUT to call when the
application is idle. Our application will be idle most of the time since, once the window

www.gameinstitute.com Page 14
2D OpenGL and GLUT Tutorial

is created and we draw our scene, the application will just sit there idling. In the demo
below, we register the Display function as the idle function, so that the image will be
redrawn at frequent intervals. Thus, if we change the image over time, we will
continuously be redisplaying the new updated image, thereby creating a smooth
animation.

glutGet(GLUT_ELAPSED_TIME): This function, with this particular argument,


returns the time that has elapsed, in milliseconds, since the glutInit function was
called. Loosely speaking, this tells us how long the application has been running for. We
can use this value as our for the parametric equations to update quantities over time.

The following program presents the complete code for animating the disk; as usual, the code
relevant to this section has been bolded.

Program 4: GLTiming

#include <GL/glut.h>
#include <cmath>

//************************************************************************
// Globals

float VIEW_HEIGHT = 200.0f;


float VIEW_WIDTH = -1.0f; // to be set below.

//************************************************************************
// Function prototypes

// DrawDisk
// cx: x-coordinate of the center of the disk.
// cy: y-coordinate of the center of the disk.
// RGB: Color components of the disk's color.
void DrawDisk(float cx, float cy, float r, float R, float G, float B);

//************************************************************************
// Function implementations.

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

// Get time since glutInit called, and convert from


// milliseconds to seconds.
float t = glutGet(GLUT_ELAPSED_TIME)*0.001f;

// Animate position and radius of disk as function of time.


const float PI = 3.14159;
float r = 50.0f + 50.0f*sinf(t);
float x = r*cosf(2*PI*t);

www.gameinstitute.com Page 15
2D OpenGL and GLUT Tutorial

float y = r*sinf(2*PI*t);

// Draw the disk with its new position and radius.


DrawDisk(x, y, 1.0f+r/3, 0.0f, 0.0f, 1.0f);

glEnd();
glutSwapBuffers();
}

void Reshape(int w, int h)


{
float aspectRatio = float(w)/h;
VIEW_WIDTH = aspectRatio*VIEW_HEIGHT;

glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-VIEW_WIDTH/2, VIEW_WIDTH/2,
-VIEW_HEIGHT/2, VIEW_HEIGHT/2,
-10.0, 10.0);
}

int main(int argc, char **argv)


{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(640, 480);
glutCreateWindow("GLTiming");
glutReshapeFunc(Reshape);

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);


glutDisplayFunc(Display);
glutIdleFunc(Display);

glutMainLoop();
}

void DrawDisk(float cx, float cy, float r, float R, float G, float B)


{
glBegin(GL_TRIANGLE_FAN);

glColor3f(R, G, B);

const float PI = 3.14159;


float stepSize = 2*PI/32;
glVertex2f(cx, cy);
for(float t = 0.0f; t <= 2*PI; t+=stepSize)
{
float x = r*cosf(t) + cx;
float y = r*sinf(t) + cy;

glVertex2f(x,y);
}

glEnd();

www.gameinstitute.com Page 16
2D OpenGL and GLUT Tutorial

Depending on your mathematical background, the following exercises may be difficult to


understand. However, all that is asked is that you type the code in and watch the results.
Hopefully they will at least illustrate to you that it is difficult to do anything interesting in
graphics without mathematics, and provide you with motivation to study mathematics.

Exercise: Try replacing the Display function in Program 4 with this new one:

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

glColor3f(1.0f, 1.0f, 0.0f);

// Get time since glutInit called, and convert from


// milliseconds to seconds.
float t = glutGet(GLUT_ELAPSED_TIME)*0.001f;

// Keep t in the range 0 to 2*PI:


const float PI = 3.14159;
int cycle = t / (2.0f*PI);
t -= cycle*2.0f*PI;

// Draw a complex curve over time.


glBegin(GL_LINE_STRIP);

// As time passes draw more of the curve. I.e., at any


// time t, draw the curve from time 0 to t. The full
// curve is drawn when t = 2*PI.
float t_k = 0.0f;
while(t_k < t)
{
// The curve is approximated by drawing small line segments
// between generated points on the curve.

float x = cosf(t_k) + 0.5f*cosf(7.0f*t_k) +


(1.0f/3.0f)*sinf(17.0f*t_k);
float y = sinf(t_k) + 0.5f*sinf(7.0f*t_k) +
(1.0f/3.0f)*cosf(17.0f*t_k);

glVertex2f(75.0f*x, 75.0f*y);

// Next time to generate a point on the curve.


t_k += 0.01f;
}

glEnd();

glutSwapBuffers();
}

Figure 1 shows a snapshot of the curve this code generates.

www.gameinstitute.com Page 17
2D OpenGL and GLUT Tutorial

Figure 1

Exercise: Try replacing the Display function in Program 4 with this new one:

void Display()
{
glClear(GL_COLOR_BUFFER_BIT);

glColor3f(0.0f, 0.0f, 1.0f);

// Get time since glutInit called, and convert from


// milliseconds to seconds.
float t = glutGet(GLUT_ELAPSED_TIME)*0.001f;

// Keep t in the range 0 to 14*PI:


const float PI = 3.14159;
int cycle = t / (14.0f*PI);
t -= cycle*14.0f*PI;

// Draw a complex curve over time.


glBegin(GL_LINE_STRIP);

// As time passes draw more of the curve. I.e., at any


// time t, draw the curve from time 0 to t. The full
// curve is drawn when t = 14*PI.
float t_k = 0.0f;
while(t_k < t)
{
// The curve is approximated by drawing small line segments

www.gameinstitute.com Page 18
2D OpenGL and GLUT Tutorial

// between generated points on the curve.

float x = 17.0f*cosf(t_k) + 7.0f*cosf(17.0f/7.0f*t_k);


float y = 17.0f*sinf(t_k) - 7.0f*sinf(17.0f/7.0f*t_k);

glVertex2f(4.0f*x, 4.0f*y);

// Next time to generate a point on the curve.


t_k += 0.01f;
}

glEnd();

glutSwapBuffers();
}

Note: Given a list of n + 1 vertices , GL_LINE_STRIPS draws a line between each vertex and its
subsequent vertex . More explicitly, a line segment is drawn between and , between and , …,
between and . Observe how the line segments are connected. Contrast this to GL_LINES where the line
segments need not be connected.

Figure 2 shows a snapshot of the curve this code generates.

Figure 2

www.gameinstitute.com Page 19
2D OpenGL and GLUT Tutorial

§6 Missile Strike Game


We conclude by showing a screenshot (Figure 3) of a simple game, reminiscent of the early PC
days, which was developed using the techniques of this tutorial. The idea of the game is simple:
Enemy missiles will be shot down from the sky and it is the player‟s job to fire missiles back in
order to intercept and destroy the incoming missiles before they strike the ground. As you can
see, we use a quad with different colored vertices to model the ground; the incoming and
outgoing missiles are modeled as lines; explosions are modeled by concentric rings that spread
out over time; and we use glutBitmapCharacter to output characters so that we can
display textual information, such as the game stats. For those who wish to study it, the full
source code for the game is available for download.

Figure 3

www.gameinstitute.com Page 20

You might also like