Advertisment

Develop Games with OpenGL 

author-image
PCQ Bureau
New Update

Ever found yourself asking, “How do they do that” when you look at the latest computer games? If you would like to get into the exciting world of game development, then read on. To write a game you need to know graphics/sound programming and apply a lot of logic. This article focuses on the graphics part, introducing you to the basics of 3D graphics using the OpenGL API. Creating 3D graphics involves a lot of mathematics and matrices, and is quite complex. OpenGL takes away these complexities so that you can focus on the graphics. Plus, it takes advantage of hardware acceleration from the graphics card. Starting this month, we're going to build ourselves a simple 3D game. 

Advertisment

The first step in graphics programming is to open a window using OpenGL. There are two ways to go about this. One, which we'll talk about, is to use an API called GLUT to handle all WIN32 specific parts so that the programmer need only concentrate on what he is drawing. GLUT stands for OpenGL Utility Toolkit, and is a window system independent toolkit for writing OpenGL programs (see box titled Set up the openGL Toolkit). The other way is to actually get a device context using WIN32 and open the window using system calls. The latter being pretty unfriendly, we go the GLUT way, although we warn you that eventually we will have to start coding in WIN32 because of the sheer power over the system it gives us. The coding is done in C for convenience and can be compiled in either Visual C or Borland C. You'll find the code on this month's PCQ Essential CD. We'll explain parts of it in this article, and refer to code in the main.c file on the CD. To start off, create a new 32-bit console application by placing the following statements in your main() function:





#include


int main()


{


glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);


glutInitWindowSize(640,480); 


glutCreateWindow(“My first opengl program”);


.


.


return 0


}












We've included the header glut.h, and created a double-buffered window of size 640x480 with a color depth of 32 bits, and also requested for a depth buffer. The string parameter denotes the caption of the window. 

Advertisment

Next, we declare two more functions, namely void Init() and void Draw() to handle the initialization and drawing parts of the scene respectively. We then tell OpenGL that Draw() has to be called repetitively to render each and every frame by the following statement. Also, we define a function void Resize(GLsizei, GLsizei)that is called whenever the window is resized. Finally we call the glutMainLoop() function to tell OpenGL to go off into an infinite loop until otherwise terminated by the program. The statements that achieve this are:






...


glutDisplayFunc(Draw);


glutReshapeFunc(Resize);


.


.


glutCreateWindow(“My first opengl program”);


f main()





The code of the Resize function would look like:





void Resize(GLsizei w,GLsizei h)


{


if(h==0) h=1;


.


.


glLoadIdentity();


}























This function gets the window width and height every time the window is moved or resized and resets the projection. glViewport() is used to tell OpenGL how much of the window it can draw to. The other statements load the projection matrix and set up a view volume (the world we see in simple terms) with a field of view of 60 degrees and near and far planes at 1.0 and 500.0 in world coordinates. The difference between screen coordinates and world coordinates should be noted here. Screen coordinates are bound by your desktop resolution; world coordinates are the imaginary coordinate system that your 3d world exists in. Finally, the modelview matrix is loaded so that we can begin drawing. Next function to handle before we actually get drawing is the Init() function. Here we perform the following initializations.





void Init()


{


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


.


.


glFrontFace(GL_CCW);//Anticlockwise polygons face front


}








Here we first set the screen-clearing colour to black, with full opacity. All colours in OpenGL are expressed as RGB values each holding a floating-point value between 0.0 and 1.0. The other statements clear various buffers and are self-explanatory.

Drawing in OpenGL



Let's start Draw()ing! Since it's a fairly long piece of code, we'll only delve into the explanation here. Refer to the file main.c file in the dev labs section under game development. Here we can actually insert the drawing primitives and perform a few transformations. As promised, we will introduce a few theory terms that are unavoidable in this context. All geometric transformations can be decomposed into three basic transformations: Translation, Rotation and Scaling. While the last two are self explanatory, translation is a term used to refer to moving an object along one or many axes by a certain distance. (Think of it as picking up something and putting it somewhere.) The other important concept to grasp here is the one of matrices.

Advertisment
My

first opengl program
OpenGL lets programmers focus on only graphics

Each computer-generated image can be represented by a matrix. OpenGL gives us a matrix stack to perform operations upon and all transformations affect only the matrix on the top of the stack. This enables us to transform individual objects without affecting the rest of the scene. The rest just makes a color triangle on the screen that shows you every possible color that you could think of.

In the code, the glBegin .. glEnd can be used with GL_QUADS for drawing quadrilaterals and GL_POLYGON for drawing polygons, although care should be taken that polygons defined should be on one plane and be convex polygons. Finally we put a standard primitive, the teapot, on to the scene, just to demonstrate the next addition we are going to make, which is lighting. 

Advertisment

Adding lights



As you may have noticed, if compiled with the lighting disabled, the teapot hardly looks 3D. That's because of the absence of lighting in the scene. To enable lighting, we need to define a light source, the color of the light source and its position. Then we tell OpenGL to switch it on so that we can see the scene. The light source is defined by declaring the following arrays globally.






GLfloat ambient<>={0.1f,0.1f,0.1f,1.0f};//dim white light


GLfloat diffuse<>={1.0f,1.0f,1.0f,1.0f};//bright white 


GLfloat light<>={0.0f,10.0f,10.0f};//light at {(0,10,10)}


And also by adding the following code to Init()


glEnable(GL_LIGHTING);


.


.


glEnable(GL_LIGHT0);














This should give us a dim ambient light (light from all around) and a strong diffuse component (directional light). If you compile and run this, all of a sudden you will see the teapot come to life, in its entire 3 dimensional splendor. The last topic left to cover in lighting is specular lighting or simply put shiny lights. These are defined like ambient or diffuse lights, but take a few additional parameters such as spot cutoff and direction. This can be accomplished by adding the following properties to GL_LIGHT0:





GLfloat specular<>={1.0f,1.0f,1.0f};


GLfloat reflectance<>={1.0f,1.0f,1.0f};


And by adding the following code to Init()


glLightfv(GL_LIGHT0,GL_SPECULAR,specular);


glLightfv(GL_FRONT,GL_SPECULAR,reflectance);


glLighti(GL_FRONT,GL_SHININESS,128);// shininess range: 0-128 







Making your first game



Okay, so a color triangle and rotating teapot don't make a game. But, in the process you have learned how to move lit up 3D objects about the scene. So, let's get to the core of the game we are trying to write. Let's try and write a small little game, in 3D, something in the likeness of 'Sky Roads'. Simple rules: Take your craft, floor the accelerator and reach the finish line by jumping over the obstacles. No turns to be made, no curves to be negotiated, just speed along. 

Direct Hit!
Applies to:

3D game developers
USP:

Takes away the complexities of mathematics and matrices involved in creating 3D graphics and lets you focus on graphics
Links:

opengl.org/documentation/red-book-1.0/
Code on CD:

system\cdrom\openGl programming
Advertisment

To do that, though, we need input from the keyboard, which we will handle a little later, because keyboard input is best taken asynchronously, which calls for the implementation of threads. For now we shall set a variable speed, which stays constant so when we implement the keyboard thread, it can just adjust the value of speed. 

For the source code of this game, refer to main2.c in the PCQEssential CD in the dev labs section. Here, the Draw ( ) function would be different, and would start as follows: 






void Draw()


{


static int speed=2,x=0,z=-100;


glClear(GL_COLOR_BUFFER_BIT);


glClear(GL_DEPTH_BUFFER_BIT);


.


.


.


z+=speed;


if(z==1000)


exit(0);


}


















Right now it might not look like much, but once the scene gets texture mapped, as we will demonstrate in later articles, the big quad in the centre will turn into a road and the blank sides can be replaced by something more interesting like a starscape or something that's simply more aesthetic! For now, play around with the code and get a feel of 3D transformations. 

A good resource for OpenGL primitives would be the 'OpenGL Redbook', which is the official OpenGL documentation. Other than that, many tutorials are present on the Internet that should help you get off the starting block and get drawing, although a friendly reminder would be Start Simple.

Advertisment

Rakesh Iyer

Set up the opengl toolkit

Advertisment

We've given GLUT files along with the source code for the game we've developed in this article, on this month's PCQ Essential CD. You can use the files to set up GLUT either in Visual C or Borland C. 

GLUT for Visual C: Setting up glut for VC is simple. Copy the .h file to the include/gl directory and the .lib file into the folder that contains all other libraries. Finally, glut32.dll should be copied into the windows/system or windows/system32 directory.

GLUT for Borland C: This being a free compiler is useful. Copy the .h into the include/gl directory and the .dll into the windows/system(32) directory. The .lib has to be converted to Borland C format and can be done with the tools that come with the compiler. An already converted version is included.

Advertisment