Using The OpenGL Utility Toolkit (GLUT) with Dev-C++

Using The OpenGL Utility Toolkit (GLUT) with Dev-C++

NOTE: This article was originally written a long time ago. I no longer use Dev-C++ as I have found Code::Blocks to be all-around better (in my opinion.) This information is provided for those who do wish to use Dev-C++. If you have not installed Dev-C++, I would recommend looking at Code::Blocks, or even Visual C++ Express (which is also free.) Of course, if you have the money, the professional version of Visual Studio is about as good as it gets. (It's not often I recommend a Microsoft product.)

You've installed Dev-C++ and experimented with the OpenGL template, or, following NeHe's examples, written your own code for OpenGL. If you're a hard-core Windows programmer, then you're all set. However, if you are a novice programmer, or if you are doing cross-platform development and don't want to be burdened with OS-specific calls, then you may be looking at GLUT. Originally written by Mark Kilgard, the OpenGL Utility Toolkit (GLUT) provides functions for such tasks as window creation, reading mouse and keyboard input, and generating some basic objects. With ports to different operating systems, code written with GLUT can be easily ported to a wide variety of systems. I will take you through developing your first GLUT-enabled program with Dev-C++, then I'll give you a template so you can automatically generate a GLUT project.

Setup

Setting up glut for Dev-C++ is fairly straightforward. However, if you try to use Nate Robins' files directly, you will probably have some trouble, so I will attempt to guide you through the setup. First, go ahead and download the package from the GLUT website http://www.xmission.com/~nate/glut.html. Unpack the zip file and copy the 'glut32.dll' to your windows/system folder. Copy the 'glut.h' file to your Dev-C++ include/gl folder (there should already be the OpenGL header files in this folder.) Now before you can begin, you will need to have a MinGW compatible version of GLUT. There are places on the Internet where you can find GLUT converted to MinGW, but I wasn't able to find the current version (3.7.6) so I converted the glut32.lib file from the GLUT website to a MinGW file using the 'reimp' tool. Download my package of GLUT 3.7.6 for MinGW compilers and copy 'libglut32.a' to the Dev-C++ lib folder (replacing the old version). To link, go into 'Project→Project Options' and add '-lglut32' to the list of linker options under the 'Parameters' tab.

Create a Blank Project

The easiest way to get started is to create a blank project. Go to 'File→New→Project…' and choose 'Empty Project' from the 'Basic' tab. Enter a project name and click enter.

Add a Blank Document

The template will have generated a project with no files, so we'll need to add one now. Right-click on the project name at the left side of the screen and choose 'New File' to add a blank document to the project. You can go ahead and save this as 'main.cpp.'


OK, so the point of GLUT is to get rid of any OS dependent functions. However, OpenGL on the Windows platform requires the Windows header to be included. We need to check if we are compiling under Windows, and if so, include the windows.h file at the start of your code:

#ifdef _WIN32
#define WIN32_EXTRALEAN // Only include the basics
#include // exit, virtual key codes
#endif

Include the OpenGL and GLUT Headers

Now we need to include the header files for OpenGL and GLUT:

#include <GL\GL.h>
#include <GL\Glut.h>

GLUT Handler Functions

We need to define some callback functions, which will be given to GLUT to handle some common tasks. When we initialize GLUT, we will give it the names of these functions. It doesn't matter what you call these functions, but you will need to make sure the parameter list matches what GLUT is expecting.

The first handler function we will define is the keyboard callback. The parameter uKey is the code for the key that was pressed. x and y define the position of the mouse at the time of the key press.

void Keyboard( unsigned char uKey, int x, int y )
{
    switch ( uKey )
    {
        // If the escape key was pressed, we need to exit
        // the program:
        case VK_ESCAPE:
            exit( 0 );
            break;
    }
}

Next, we will define the function to handle resizing the display. The parameter iWidth is the new width of the window, and iHeight is the window's new height.

void    Resize( int iWidth, int iHeight )
{
    // Set the dimensions of the viewport:
    glViewport( 0, 0, (GLsizei)iWidth, (GLsizei)iHeight );
 
    // Switch to the projection matrix:
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
 
    // Define the projection transformation matrix.  Notice that this is using
    // glFrustum instead of gluPerspective:
    glFrustum( -1.0f, 1.0f, -1.0f, 1.0f, 1.5f, 20.0f );

That may have been a little different than you're used to. The idea is to reduce/eliminate dependency on the GLu library. Basically, gluPerspective is calling glFrustum anyway, so we are just saving it the trouble! The first two parameters are the min/max x-range, the second pair is the min/max y-range, and the third pair are the near/far values (min/max z-range).

    // Switch back to the modelview matrix:
    glMatrixMode( GL_MODELVIEW );
}

We need a callback to handle redrawing the scene. This won't need any parameters.

void	Redraw()
{
	// Clear the screen and depth buffer:
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 
 
	// Enable the default back-face removal:
	glEnable( GL_CULL_FACE );
 
 
	// Translate the cube into view:
	glLoadIdentity();
	glTranslatef( 0.0f, 0.0f, -5.0f );
 
 
	// Rotate the cube:
	static float	fRotAngle = 0.0f;
	glRotatef( fRotAngle, 0.0f, 1.0f, 0.0f );
	fRotAngle	+= 0.5f;

That static variable might be a bit confusing to some. Basically, it means that the variable fRotAngle can be initialized only once. The first time this function is called, the variable is initialized to 0.0, but the second time the function is called, it will contain the last value that it was set. In this case, it would be 0.0 + 0.5 = 0.5. Therefore, we can just keep adding 0.5 and it will keep incrementing the value of 'fRotAngle.'

	// Render a wireframe cube:
	glutWireCube( 1.0 );

'glutWireCube' will use GLUT to generate a wireframe cube. 1.0 indicates the size of each side of the cube.

	// Swap buffers:
	glutSwapBuffers();
}

We are going to make our cube rotate, so we will need a timer to keep calling the redraw function. The timer function takes a single argument, which is the ID of the timer currently being triggered (it is possible to have multiple timers in a single application.)

void	Timer( int iValue )
{
	// Tell glut to redisplay the scene:
	glutPostRedisplay();
 
	// Need to call this method again after the desired amount of time has passed:
	glutTimerFunc( 1, Timer, iValue );
}

A quick rundown on the timer. glutPostRedisplay() simply tells glut that it is time to redraw the display. Once the timer is triggered, glut puts it out of its memory. In order to have the timer go off again, we need to reset the timer function, hence the glutTimerFunc.

Main Entry Loop

Every application needs an entry point. This example will use the typical int main( int argc, char *argv[] ) function to handle initialization.

int		main( int argc, char *argv[] )
{
	// Initialize the display mode:
	glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );

This initializes the OpenGL window mode. In this case, we are using RGB color, Depth Buffering, and Double Buffering.

	// Set the window size and position:
	glutInitWindowPosition( 0, 0 );
	glutInitWindowSize( 256, 256 );

The above methods take care of setting the size and position of the application window (for those that are windowed.) In our case, the window will be 256×256 (excluding frame and title bar) and be positioned at the top-right corner.

	// Perform command-line initialization:
	glutInit( &argc, argv );
 
	// Create the window:
	glutCreateWindow( "MyFirstGlut" );

glutInit handles any command-line parameters that GLUT might recognize, and glutCreateWindow will create the window, using (in this case) 'MyFirstGlut' as the title.

	// Set the GLUT callbacks:
	glutKeyboardFunc( Keyboard );
	glutReshapeFunc( Resize );
	glutDisplayFunc( Redraw );
 
	// Setup the timer:
	glutTimerFunc( 1, Timer, 1 );
 
	// Enter the program loop:
	glutMainLoop();

glutMainLoop starts our continues loop, checking for input, updating the display, etc. It will be exited when the user closes the application window or presses 'Esc.'

	return 0;
}

That is all we need for our first GLUT example. If you do not want to type all that in (although it is highly recommended) you can download the sample program for Dev-C++ 4.9.8 (probably works in other versions) as well as a template which will generate this project for you.