Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

The OpenGL and GLUT: A Powerful Graphics Library and Utility Kit

5.00/5 (21 votes)
10 Sep 2010CPOL16 min read 103.9K   4.1K  
An article that explains how to use this library

One Quick Note to Get Started

To use OpenGL and GLUT, download OpenGL from http://www.videotutorialsrock.com/opengl2.exe.

Then download GLUT from http://www.xmission.com/~nate/glut/glut-3.7.6-src.zip.

Simply install OpenGL and unzip the GLUT sources to the locations stated below. This will enable you to compile the code given. Note if your header file causes problems, then delete the GL to make the header file<glut.h>. So what is OpenGL, GLUT, and why would we want to use them? Those questions are the focus of this article.

Introduction

OpenGL is an interface to graphics hardware. GL stands for Graphics Library. As such, it is mainly a low-level graphics library specification. GL provides commands for specifying geometric objects in two or three dimensions, and for controlling how these objects are drawn on the display. Objects, in this case, are points, lines, polygons, images, and bitmaps. OpenGL does provide commands for performing windowing tasks or for obtaining user input. These commands are provided the OpenGL Utility Kit (GLUT). GLUT provides commands to create windows, subwindows, and menus; and to handle input from various devices via a callback function. When installing OpenGL, you must install the most recent version of GLUT, which provides four files: glut.h, glut.lib, glut.def, and glut32.dll. When working with GLUT on visual Studio, the header and library files must be placed in the VC++ include and library directories, respectively. The definition file has a relation to the DLLs, but the gllut32.dll must be placed in the %windir%\system32 directory.

Since OpenGL drawing commands are limited to those that generate simple geometric primitives (points, lines, and polygons), the OpenGL Utility Toolkit (GLUT) has been created to aid in the development of more complicated three-dimensional objects such as a sphere, a torus, and even a teapot. GLUT may not be satisfactory for full-featured OpenGL applications, but it is a useful starting point for learning OpenGL.

GLUT is designed to fill the need for a window system independent programming interface for OpenGL programs. The interface is designed to be simple yet still meet the needs of useful OpenGL programs. Removing window system operations from OpenGL is a sound decision because it allows the OpenGL graphics system to be retargeted to various systems including powerful but expensive graphics workstations as well as mass-production graphics systems like video games, set-top boxes for interactive television, and PCs. GLUT simplifies the implementation of programs using OpenGL rendering. The GLUT application programming interface (API) requires very few routines to display a graphics scene rendered using OpenGL. The GLUT routines also take relatively few parameters.

So Show Me Some Code

While it is early in the article, examine this code and how the code body is structured. Then examine the output, which is a window containing a basic triangle:

C++
#include <glut.h>
void renderScene(void) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBegin(GL_TRIANGLES);
        glVertex3f(-0.5,-0.5,0.0);
        glVertex3f(0.5,0.0,0.0);
        glVertex3f(0.0,0.5,0.0);
    glEnd();
    glFlush();
}

void main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(320,320);
    glutCreateWindow("3D Tech- GLUT Tutorial");
    glutDisplayFunc(renderScene);
    glutMainLoop();
}

When compiled on Visual Studio or on the command line, here is the output. But take care to notice the sequence of the functions that ensue the main body:

Capture.PNG

Initialization

Routines beginning with the glutInit- prefix are used to initialize GLUT state. The primary initialization routine is glutInit that should only be called exactly once in a GLUT program. No non-glutInit- prefixed GLUT or OpenGL routines should be called before glutInit. The other glutInit- routines may be called before glutInit. The reason is these routines can be used to set default window initialization state that might be modified by the command processing done in glutInit. For example, glutInitWindowSize(400, 400) can be called before glutInit to indicate 400 by 400 is the program’s default window size. Setting the initial window size or position before glutInit allows the GLUT program user to specify the initial size or position using command line arguments. glutInit is used to initialize the GLUT library.

C++
void glutInit(int *argcp, char **argv);

An rgcp is a pointer to the program’s unmodified argc variable from main. Upon return, the value pointed to by argcp will be updated, because glutInit extracts any command line options intended for the GLUT library. argv The program’s unmodified argv variable from main. Like argcp, the data for argv will be updated because glutInit extracts any command line options understood by the GLUT library. glutInit will initialize the GLUT library and negotiate a session with the window system. During this process, glutInit may cause the termination of the GLUT program with an error message to the user if GLUT cannot be properly initialized. Examples of this situation include the failure to connect to the window system, the lack of window system support for OpenGL, and invalid command line options. glutInit also processes command line options, but the specific options parse are window system dependent.

glutInitDisplayMode: glutInitDisplayMode sets the initial display mode.

C++
void glutInitDisplayMode(unsigned int mode);

glutInitWindowPosition, glutInitWindowSize: glutInitWindowPosition and glutInitWindowSizeset the initial window position and size respectively.

C++
void glutInitWindowSize(int width, int height);
void glutInitWindowPosition(int x, int y);

width Width in pixels.
height Height in pixels.
x Window X location in pixels.
y Window Y location in pixels.

Windows created by glutCreateWindow will be requested to be created with the current initial window position and size. The initial value of the initial window position GLUT state is -1 and -1. If either the X or Y component to the initial window position is negative, the actual window position is left to the window system to determine. The initial value of the initialwindow size GLUT state is 300 by 300. The initialwindow size components must be greater than zero. The intent of the initial window position and size values is to provide a suggestion to the window system for a window’s initial size and position. The window system is not obligated to use this information. Therefore, GLUT programs should not assume the window was created at the specified size or position. A GLUT program should use the window’s reshape callback to determine the true size of the window.

C++
int glutCreateWindow(char *name);

note: name ASCII character string for use as window name.

glutCreateWindow creates a top-level window. The name will be provided to the window system as the window’s name. The intent is that the window system will label the window with the name. Implicitly, the current window is set to the newly created window. Each created window has a unique associated OpenGL context. State changes to a window’s associated OpenGL context can be done immediately after the window is created. The display state of a window is initially for the window to be shown. But the window’s display state is not actually acted upon until glutMainLoop is entered. This means until glutMainLoop is called, rendering to a created window is ineffective because the window cannot yet be displayed. The value returned is a unique small integer identifier for the window. The range of allocated identifiers starts at one. This window identifier can be used when calling glutSetWindow.

C++
void glutDisplayFunc(void (*func)(void));
func The new display callback function.

glutDisplayFunc sets the display callback for the current window. When GLUT determines that the normal plane for the window needs to be redisplayed, the display callback for the window is called. Before the callback, the current window is set to the window needing to be redisplayed and (if no overlay display callback is registered) the layer in use is set to the normal plane. The display callback is called with no parameters. The entire normal plane region should be redisplayed in response to the callback (this includes ancillary buffers if your program depends on their state). GLUT determines when the display callback should be triggered based on the window’s redisplay state.

The redisplay state for a window can be either set explicitly by calling glutPostRedisplay or implicitly as the result of window damage reported by the window system. Multiple posted redisplays for a window are coalesced by GLUT to minimize the number of display callbacks called. When an overlay is established for a window, but there is no overlay display callback registered, the display callback is used for redisplaying both the overlay and normal plane (that is, it will be called if either the redisplay state or overlay redisplay state is set). In this case, the layer in use is not implicitly changed on entry to the display callback. When a window is created, no display callback exists for the window. It is the responsibility of the programmer to install a display callback for the window before the window is shown. A display callback must be registered for any window that is shown. If a window becomes displayed without a display callback being registered, a fatal error occurs. Passing NULL to glutDisplayFunc is illegal as of GLUT 3.0; there is no way to “deregister” a display callback (though another callback routine can always be registered). Upon return from the display callback, the normal damaged state of the window (returned by calling glutLayerGet(GLUT NORMAL DAMAGED) is cleared. If there is no overlay display callback registered, the overlay damaged state of the window (returned by calling glutLayerGet(GLUT OVERLAY DAMAGED) is also cleared.

Beginning Event Processing

After a GLUT program has done initial setup such as creating windows and menus, GLUT programs enter the GLUT event processing loop by calling glutMainLoop. glutMainLoop enters the GLUT event processing loop. Notice that this is the last API called in the basic program shown above.

C++
void glutMainLoop(void);

glutMainLoop enters the GLUT event processing loop. This routine should be called at most once in a GLUT program. Once called, this routine will never return. It will call as necessary any callbacks that have been registered. GLUT supports two types of windows: top-level windows and subwindows. Both types support OpenGL rendering and GLUT callbacks. There is a single identifier space for both types of windows.

Now Let’s Examine Animation

Here is code written similar to that above. But when you compile it using the cl.exe VC++ compiler driver, that shape rotates and changes size:

C++
#include <math.h><glut.h>
#include <glut.h><math.h>
float angle = 0.0;
float red=1.0, blue=1.0, green=1.0;

void changeSize(int w, int h) {

    // Prevent a divide by zero, when window is too short
    // (you cant make a window of zero width).
    if(h == 0)
        h = 1;

    float ratio = 1.0* w / h;

    // Reset the coordinate system before modifying
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    
    // Set the viewport to be the entire window
    glViewport(0, 0, w, h);

    // Set the correct perspective.
    gluPerspective(45,ratio,1,1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0,0.0,5.0, 
              0.0,0.0,-1.0,
              0.0f,1.0f,0.0f);
}

void renderScene(void) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
    glRotatef(angle,0.0,1.0,0.0);

    glColor3f(red,green,blue);

    glBegin(GL_TRIANGLES);
        glVertex3f(-0.5,-0.5,0.0);
        glVertex3f(0.5,0.0,0.0);
        glVertex3f(0.0,0.5,0.0);
    glEnd();
    glPopMatrix();
    angle++;
    glutSwapBuffers();
}

void processNormalKeys(unsigned char key, int x, int y) {

    if (key == 27) 
        exit(0);
}

void processSpecialKeys(int key, int x, int y) {

    switch(key) {
        case GLUT_KEY_F1 : red = 1.0; green = 0.0; blue = 0.0; break;
        case GLUT_KEY_F2 : red = 0.0; green = 1.0; blue = 0.0; break;
        case GLUT_KEY_F3 : red = 0.0; green = 0.0; blue = 1.0; break;
    }
}

void main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(320,320);
    glutCreateWindow("Lighthouse 3D - GLUT Tutorial");
    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);
    glutReshapeFunc(changeSize);

    //adding here the setting of keyboard processing
    glutKeyboardFunc(processNormalKeys);
    glutSpecialFunc(processSpecialKeys);
    glutMainLoop();
}

The output is as the above description states. Now let’s examine this Graphics Library further by adding some functionality to the code:

C++
#include <math.h><math.h>
#include <glut.h><glut.h>
#include <stdio.h><stdio.h>
#include <string.h><string.h>

float angle=0.0,deltaAngle = 0.0,ratio;
float x=0.0f,y=1.75f,z=5.0f;
float lx=0.0f,ly=0.0f,lz=-1.0f;
int deltaMove = 0,h,w;
int font=(int)GLUT_BITMAP_8_BY_13;
static GLint snowman_display_list;
int bitmapHeight=13;

int frame,time,timebase=0;
char s[30];

void initWindow();

void changeSize(int w1, int h1)
    {    
    if(h1 == 0)
        h1 = 1;

    w = w1;
    h = h1;
    ratio = 1.0f * w / h;
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glViewport(0, 0, w, h);
        gluPerspective(45,ratio,0.1,1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(x, y, z, 
              x + lx,y + ly,z + lz,
              0.0f,1.0f,0.0f);
    }

void drawSnowMan() {

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

    glTranslatef(0.0f ,0.75f, 0.0f);
    glutSolidSphere(0.75f,20,20);

    glTranslatef(0.0f, 1.0f, 0.0f);
    glutSolidSphere(0.25f,20,20);

    glPushMatrix();
    glColor3f(0.0f,0.0f,0.0f);
    glTranslatef(0.05f, 0.10f, 0.18f);
    glutSolidSphere(0.05f,10,10);
    glTranslatef(-0.1f, 0.0f, 0.0f);
    glutSolidSphere(0.05f,10,10);
    glPopMatrix();

    glColor3f(1.0f, 0.5f , 0.5f);
    glRotatef(0.0f,1.0f, 0.0f, 0.0f);
    glutSolidCone(0.08f,0.5f,10,2);
}

GLuint createDL() {
    GLuint snowManDL;
    
    snowManDL = glGenLists(2);

    glNewList(snowManDL+1,GL_COMPILE);
        drawSnowMan();
    glEndList();

    glNewList(snowManDL,GL_COMPILE);

    for(int i = -3; i < 3; i++)
        for(int j=-3; j < 3; j++) {
            glPushMatrix();
            glTranslatef(i*10.0,0,j * 10.0);
            glCallList(snowManDL+1);
            glPopMatrix();
        }

    glEndList();

    return(snowManDL);
}

void initScene() {

    glEnable(GL_DEPTH_TEST);
    snowman_display_list = createDL();

}

void orientMe(float ang) {

    lx = sin(ang);
    lz = -cos(ang);
    glLoadIdentity();
    gluLookAt(x, y, z, 
              x + lx,y + ly,z + lz,
              0.0f,1.0f,0.0f);
}

void moveMeFlat(int i) {
    x = x + i*(lx)*0.1;
    z = z + i*(lz)*0.1;
    glLoadIdentity();
    gluLookAt(x, y, z, 
              x + lx,y + ly,z + lz,
              0.0f,1.0f,0.0f);
}

void setOrthographicProjection() {
    
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
       gluOrtho2D(0, w, 0, h);
    glScalef(1, -1, 1);
    glTranslatef(0, -h, 0);
    glMatrixMode(GL_MODELVIEW);
}

void resetPerspectiveProjection() {
    
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
}

void renderBitmapString(float x, float y, void *font,char *string)
{  
  char *c;
  
  glRasterPos2f(x, y);
  
  for (c=string; *c != '\0'; c++) {
    glutBitmapCharacter(font, *c);
  }
}

void renderScene(void) {

    if (deltaMove)
        moveMeFlat(deltaMove);
    if (deltaAngle) {
        angle += deltaAngle;
        orientMe(angle);
    }

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Draw ground

    glColor3f(0.9f, 0.9f, 0.9f);
    glBegin(GL_QUADS);
        glVertex3f(-100.0f, 0.0f, -100.0f);
        glVertex3f(-100.0f, 0.0f,  100.0f);
        glVertex3f( 100.0f, 0.0f,  100.0f);
        glVertex3f( 100.0f, 0.0f, -100.0f);
    glEnd();

// Draw 36 SnowMen

    glCallList(snowman_display_list);
    
    frame++;
    time=glutGet(GLUT_ELAPSED_TIME);
    if (time - timebase > 1000) {
        sprintf(s,"FPS:%4.2f",frame*1000.0/(time-timebase));
        timebase = time;        
        frame = 0;
    }

    glColor3f(0.0f,1.0f,1.0f);
    setOrthographicProjection();
    glPushMatrix();
    glLoadIdentity();
    renderBitmapString(30,15,(void *)font,"GLUT Tutorial @ 3D Tech"); 
    renderBitmapString(30,35,(void *)font,s);
    renderBitmapString(30,55,(void *)font,"Esc - Quit");
    glPopMatrix();
    resetPerspectiveProjection();

    glutSwapBuffers();
}

void processNormalKeys(unsigned char key, int x, int y) {

    if (key == 27) 

        exit(0);
    
    }

void pressKey(int key, int x, int y) {

    switch (key) {
        case GLUT_KEY_LEFT : deltaAngle = -0.01f;break;
        case GLUT_KEY_RIGHT : deltaAngle = 0.01f;break;
        case GLUT_KEY_UP : deltaMove = 1;break;
        case GLUT_KEY_DOWN : deltaMove = -1;break;
    }
}

void releaseKey(int key, int x, int y) {

    switch (key) {
        case GLUT_KEY_LEFT : if (deltaAngle < 0.0f) 
                                 deltaAngle = 0.0f;
                             break;
        case GLUT_KEY_RIGHT : if (deltaAngle > 0.0f) 
                                 deltaAngle = 0.0f;
                             break;
        case GLUT_KEY_UP :     if (deltaMove > 0) 
                                 deltaMove = 0;
                             break;
        case GLUT_KEY_DOWN : if (deltaMove < 0) 
                                 deltaMove = 0;
                             break;
    }
}

void initWindow() {
    glutIgnoreKeyRepeat(1);
    glutKeyboardFunc(processNormalKeys);
    glutSpecialFunc(pressKey);
    glutSpecialUpFunc(releaseKey);
    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);
    glutReshapeFunc(changeSize);
    initScene();
}

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(640,360);
    glutCreateWindow("SnowMen from Lighthouse3D");

    // register all callbacks
    initWindow();

    glutMainLoop();

    return(0);
} 

This is the result:

Capture2.PNG

The code above contained more functions and a floating point to indicate that we were dealing drawing a geometric shape. But before we get into those types of functions and some 3D applications, we will review the steps taken thus far.

What You Should Know About Windows and GLUT

C++
void glutInit(int *argc, char **argv); 

glutInit() is the first function that should be called, it parses the parameters that are window system specific for example the -display parameter that is used to let X11 begin exported to other screens. Be sure to call this with &argc as first parameter, because the function wants a pointer not the plain argc. So you would call glutInit(&argc, argv);

C++
glutInitDisplayMode(unsigned int mode);

glutInitDisplayMode() sets the initial display mode, you should pass an OR'ed chain of modes, there are various options like GLUT_RGBA, GLUT_RGB, GLUT_INDEX, GLUT_SINGLE, GLUT_DOUBLE, GLUT_ACCUM, GLUT_ALPHA, GLUT_DEPTH, GLUT_STENCIL, GLUT_MULTISAMPLE, GLUT_STEREO, GLUT_LUMINANCE. I will just mention that GLUT_RGBA says you want to use the RGBA color model (default), GLUT_DOUBLE says you want to use double buffering, this means that you create 2 virtual screens one that is visible and one in the background, on this in the background changes are being made and you swap the buffers using the glutSwapBuffers() function. GLUT_SINGLE uses single buffering, which is not really advised for an animation but this is default if you don't specify something else. If you use GLUT_INDEX (color index mode) you should manually take care of the color map using the glutSetColor() function, refer to the manpage for more information.

C++
glutInitWindowSize(int width, int height);
glutInitWindowSize() sets the initial size of the window.
glutInitWindowPosition(int x, int y);

glutInitWindowPosition();

sets the initial position of the window but this is easily overwritten by your window manager.

C++
void glutFullScreen(void);
glutFullScreen();
 requests that the window is made full screen
int glutCreateWindow(char *name)
glutCreateWindow()

creates the window for you, the string you pass will be the title of the window, the window is only displayed when glutMainLoop() is entered (see what you should know about actually starting the program and displaying the window for more information). This returns an integer, this integer is the window identifier, some functions need this identifier to know which window you mean, an example is the following: glutDestroyWindow.

C++
void glutDestroyWindow(int win)

glutDestroyWindow destroys a window, the win parameter is the window identifier mentioned above. The program isn't killed when you destroy the window, only the window is destroyed. (See example below.)

What You Should Know About Events and GLUT

In order to understand the following, I will first explain what a callback is. When a certain event occurs, you want a program to do something. So in case of event E call, method/function/procedure M. A callback just occurred. Within this part, you define which function has to be called when an event happens. (An event is something that happens: you move the mouse, press a key, resize the window,... mostly generated by the user). Now I will define the most commonly used GLUT callbacks.

C++
void glutDisplayFunc(void (*func)(void)); 

This specifies the function that needs to be called when the window is redrawn. This function is called when the window if shown for the first time, when it is popped up, when the contents was damaged (by moving another window over it). It is also possible to force a redraw see glutPostRedisplay() below. An example might look like:

C++
void doMagic(void){
   // put everything on the screen
}

To make doMagic() you display function you would put the following line in your source code:

C++
glutDisplayFunc(doMagic);
          
void glutPostRedisplay(void); 

When you put glutPostRedisplay(); somewhere in your code, this means that the function defined using glutDisplayFunc() will be called at the next opportunity. It marks the current window as needing a redraw.

C++
void glutReshapeFunc(void (*func)(int width, int height));

The callback defined using glutReshapeFunc is called whenever the window is being moved and/or resized. The arguments are the new width and the new height of the window.

C++
void glutTimerFunc(unsigned int msecs,void (*func)(int value), value); 

Defines a callback that is called periodically, you can register multiple callbacks but you can't unregister them, you should ignore these callbacks by setting the value so the method would ignore it. msecs is the number of milliseconds in which the callback will be trigger at least.

C++
void glutKeyboardFunc(void (*func)(unsigned char key,int x, int y)); 

A callback for keyboard events, key is the ASCII value of the key pressed and x and y are the coordinates of the mouse at the moment of the keypress.

C++
void glutMouseFunc(void (*func)(int button, int state, int x, int y)); 

A callback triggered on mouse clicks. Button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON. State defines what you actually did, did you press the button or release the button, these are defined by GLUT_UP or GLUT_DOWN. And x and y are the coordinates of the mouse.

C++
void glutMotionFunc(void (*func)(int x, int y)); 

Callback triggered when the mouse is moved while one or more buttons are pressed. x and y are the coordinates.

C++
void glutIdleFunc(void (*func)(void)); 

As we will see in shortly, the program is started when you enter the main loop which waits for events, this can be compared to something like:

C++
while(true){
   // let the world move
}

But not every time there occurs an event that needs to be handled that where the idling comes in. This is when the glutIdleFunc() comes in. This function is useful when some continuous animation is needed.

Important note: You can undo most callbacks by passing NULL as the function name.

What You Should Know About Creating 3D Objects in GLUT

Another advantage of glut is that glut has some pre defined primitives that you can put on the screen in an easy way. I will list the primitives below, most parameters speak for themselves. Each primitive comes in a solid or in a wireframe taste.

C++
void glutSolidSphere(GLdouble radius, GLint slices, GLint stacks);
void glutWireSphere(GLdouble radius, GLint slices, GLint stacks);

Renders a sphere centered around the origin, slices are the number of subdivision around the Z axis, stacks the number of subdivisions along the Z axis. Note that the double and int parameters are part of OpenGL (see the gl prefix) and not part of glut.

C++
void glutSolidCube(GLdouble size);
void glutWireCube(GLdouble size);

Size is the length of the sides.

C++
void glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks);
void glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks);

base is the radius of the base.

C++
void glutSolidTorus
	(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings); 
void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, 
	GLint nsides, GLint rings);void glutSolidDodecahedron(void); 
void glutWireDodecahedron(void);

Renders a solid or wireframe 12-sided regular solid. Centered around the origin and with a radius equal to the square root of 3.

C++
void glutSolidTetrahedron(void);
void glutWiredTetrahedron(void);

Renders a solid or wireframe 4-sided regular solid. Centered around the origin and with a radius equal to the square root of 3.

C++
void glutSolidIcosahedron(void);
void glutWireIcosahedron(void);

Renders a solid or wireframe 20-sided regular solid. Centered around the origin and with a radius equal to 1.0.

C++
void glutSolidOctahedron(void);
void glutWireOctahedron(void);

Renders a solid or wireframe 8-sided regular solid. Centered around the origin and with a radius equal to 1.0.

C++
void glutSolidTeapot(GLdouble size);
void glutWireTeapot(GLdouble size);

What You Should Know About Menus in GLUT

C++
int glutCreateMenu(void (*func)(int value));

This function defines the callback that has to be called when a menu item was selected. This callback function has one parameter, the value. (The programmer has to define a value for each menu item he defines see blutAddMenuEntry() for more information). This function returns an int, this is the menu identifier. This identifier is needed when you would want to attach this menu as a submenu.

C++
void glutSetMenu(int menu);

You can set the current menu by calling glutSetMenu and passing the menu identifier as parameter, using int glutGetMenu(void); you can query which menu is the current menu.

C++
void glutAddMenuEntry(char *name, int value);

This adds an entry to the menu with the label defined by name and the second parameter is the value that will be passed to the callback function. The menu is being added to the current menu. Each menu entry that is being added is added at the bottom of the current menu.

C++
void glutAddSubMenu(char *name, int menu);

This adds the menu identified by the menu identifier as a submenu with a given name to the current menu. The program won't work if it contains an infinite loop of menus.

C++
void glutAttachMenu(int button);

This attaches the current menu to a certain (mouse) event, you can let a menu listen to a specified mouse button, button can be one of the following: GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, and GLUT_RIGHT_BUTTON. You can also detach the menu using void glutDetachMenu(int button);.

And last but not least, this renders a teapot. Having reiterated these functions and how they are called to render graphics, consider this code. The source code below, opens a window, clears it with a black color and draws a teapot, it listens to keyboard presses and writes out the key that was pressed and the coordinates. The program terminates when the user presses "q". This program only uses 2 OpenGL functions, the first one is glClearColor() that sets the Clearcolor (background) to black and glClear() that actually clears the window. In this example, no idlefunction is defined and I use single buffering (no double buffering) since no animation is needed:

C++
#include <iostream><iostream>
#include <glut.h><glut.h>
#include <cstdlib.h><cstdlib>
using namespace std;
void createMenu(void);
void menu(int value);
void disp(void);
static int win;
static int menid;
static int submenid;
static int primitive = 0;
int main(int argc, char **argv){
 // normal initialisation
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE);
  glutInitWindowSize(500,500);
  glutInitWindowPosition(100,100);
  win = glutCreateWindow("GLUT MENU");
    // put all the menu functions in one nice procedure
  createMenu();
// set the clearcolor and the callback
  glClearColor(0.0,0.0,0.0,0.0);
  glutDisplayFunc(disp);
  // enter the main loop
  glutMainLoop();
}
void createMenu(void){
 submenid = glutCreateMenu(menu);
 // Add sub menu entry
  glutAddMenuEntry("Teapot", 2);
  glutAddMenuEntry("Cube", 3);
  glutAddMenuEntry("Torus", 4);
  // Create the menu, this menu becomes the current menu
 menid = glutCreateMenu(menu);
  // Create an entry
  glutAddMenuEntry("Clear", 1);
  glutAddSubMenu("Draw", submenid);
  // Create an entry
  glutAddMenuEntry("Quit", 0);

  // Let the menu respond on the right mouse button
  glutAttachMenu(GLUT_RIGHT_BUTTON);
}
void disp(void){
  // Just clean the screen
  glClear(GL_COLOR_BUFFER_BIT);
  // draw what the user asked
  if(primitive == 1){
    glutPostRedisplay();
  }else if(primitive == 2){
    glutWireTeapot(0.5);
  }else if(primitive == 3){
    glutWireCube(0.5);
  }else if(primitive == 4){
    glutWireTorus(0.3,0.6,100,100);
  }
  glFlush();
}
void menu(int value){
  if(value == 0){
    glutDestroyWindow(win);
    exit(0);
  }else{
    primitive=value;
  }
    // you would want to redraw now
  glutPostRedisplay();
} 

cl.exe tea.c yields tea.exe!

Capture6.PNG

Build Your Own Terminator

This next example actually builds a robotic figure that can walk towards you when you right-click the surface image and choose one of the options that appears. The motion and transforms are largely trigonometric in nature. The products of the trigonometric components form the angles and the motion. Note that the shape of the robot is the summation of geometric shapes that are joined together: the sum of the parts forms the whole. Since the code is written in ANSI C, there are a lot of macro preprocessor directives. Study this code, as it can be expanded upon and serve as a cursor for actual game programming:

C++
#define SPHERE
#define COLOR
#define LIGHT
#define TORSO
#define HIP
#define SHOULDER
#define UPPER_ARM
#define LOWER_ARM
#define ROCKET_POD
#define UPPER_LEG
#define LOWER_LEG
#define NO_NORM
#define ANIMATION
#define DRAW_MECH
#define DRAW_ENVIRO
#define MOVE_LIGHT
/* end of compilation conditions */

/* start various header files needed */
#include <stdlib.h><stdlib.h>

#include <math.h<math.h>
#define GLUT
#define GLUT_KEY
#define GLUT_SPEC
#include <glut.h><glut.h>

/* end of header files */

/* start of display list definitions */
#define SOLID_MECH_TORSO           1
#define SOLID_MECH_HIP          2
#define SOLID_MECH_SHOULDER     3
#define SOLID_MECH_UPPER_ARM    4
#define SOLID_MECH_FOREARM    5
#define SOLID_MECH_UPPER_LEG       6
#define SOLID_MECH_FOOT            7
#define SOLID_MECH_ROCKET          8
#define SOLID_MECH_VULCAN    9
#define SOLID_ENVIRO        10
/* end of display list definitions */

/* start of motion rate variables */
#define ANKLE_RATE    3
#define HEEL_RATE    3
#define ROTATE_RATE    10
#define TILT_RATE    10
#define ELBOW_RATE    2
#define SHOULDER_RATE    5
#define LAT_RATE    5
#define CANNON_RATE    40
#define UPPER_LEG_RATE    3
#define UPPER_LEG_RATE_GROIN 10
#define LIGHT_TURN_RATE    10
#define VIEW_TURN_RATE    10
/* end of motion rate variables */

/* start of motion  variables */

/* Some <math.h> files do not define M_PI... */
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

GLUquadricObj *qobj;

char leg = 0;

int shoulder1 = 0, shoulder2 = 0, shoulder3 = 0, shoulder4 = 0, lat1 = 20, lat2 = 20,
  elbow1 = 0, elbow2 = 0, pivot = 0, tilt = 10, ankle1 = 0, ankle2 = 0, heel1 = 0,
  heel2 = 0, hip11 = 0, hip12 = 10, hip21 = 0, hip22 = 10, fire = 0, solid_part = 0,
  anim = 0, turn = 0, turn1 = 0, lightturn = 0, lightturn1 = 0;

float elevation = 0.0, distance = 0.0, frame = 3.0
 /* foot1v[] = {} foot2v[] = {} */ ;

/* end of motion variables */

/* start of material definitions */
#ifdef LIGHT
GLfloat mat_specular[] =
{0.628281, 0.555802, 0.366065, 1.0};
GLfloat mat_ambient[] =
{0.24725, 0.1995, 0.0745, 1.0};
GLfloat mat_diffuse[] =
{0.75164, 0.60648, 0.22648, 1.0};
GLfloat mat_shininess[] =
{128.0 * 0.4};

GLfloat mat_specular2[] =
{0.508273, 0.508273, 0.508373};
GLfloat mat_ambient2[] =
{0.19225, 0.19225, 0.19225};
GLfloat mat_diffuse2[] =
{0.50754, 0.50754, 0.50754};
GLfloat mat_shininess2[] =
{128.0 * 0.6};

GLfloat mat_specular3[] =
{0.296648, 0.296648, 0.296648};
GLfloat mat_ambient3[] =
{0.25, 0.20725, 0.20725};
GLfloat mat_diffuse3[] =
{1, 0.829, 0.829};
GLfloat mat_shininess3[] =
{128.0 * 0.088};

GLfloat mat_specular4[] =
{0.633, 0.727811, 0.633};
GLfloat mat_ambient4[] =
{0.0215, 0.1745, 0.0215};
GLfloat mat_diffuse4[] =
{0.07568, 0.61424, 0.07568};
GLfloat mat_shininess4[] =
{128 * 0.6};

GLfloat mat_specular5[] =
{0.60, 0.60, 0.50};
GLfloat mat_ambient5[] =
{0.0, 0.0, 0.0};
GLfloat mat_diffuse5[] =
{0.5, 0.5, 0.0};
GLfloat mat_shininess5[] =
{128.0 * 0.25};

#endif
/* end of material definitions */

/* start of the body motion functions */
void
Heel1Add(void)
{
  heel1 = (heel1 + HEEL_RATE) % 360;
}

void
Heel1Subtract(void)
{
  heel1 = (heel1 - HEEL_RATE) % 360;
}

void
Heel2Add(void)
{
  heel2 = (heel2 + HEEL_RATE) % 360;
}

void
Heel2Subtract(void)
{
  heel2 = (heel2 - HEEL_RATE) % 360;
}

void
Ankle1Add(void)
{
  ankle1 = (ankle1 + ANKLE_RATE) % 360;
}

void
Ankle1Subtract(void)
{
  ankle1 = (ankle1 - ANKLE_RATE) % 360;
}

void
Ankle2Add(void)
{
  ankle2 = (ankle2 + ANKLE_RATE) % 360;
}

void
Ankle2Subtract(void)
{
  ankle2 = (ankle2 - ANKLE_RATE) % 360;
}

void
RotateAdd(void)
{
  pivot = (pivot + ROTATE_RATE) % 360;
}

void
RotateSubtract(void)
{
  pivot = (pivot - ROTATE_RATE) % 360;
}

void
MechTiltSubtract(void)
{
  tilt = (tilt - TILT_RATE) % 360;
}

void
MechTiltAdd(void)
{
  tilt = (tilt + TILT_RATE) % 360;
}

void
elbow1Add(void)
{
  elbow1 = (elbow1 + ELBOW_RATE) % 360;
}

void
elbow1Subtract(void)
{
  elbow1 = (elbow1 - ELBOW_RATE) % 360;
}

void
elbow2Add(void)
{
  elbow2 = (elbow2 + ELBOW_RATE) % 360;
}

void
elbow2Subtract(void)
{
  elbow2 = (elbow2 - ELBOW_RATE) % 360;
}

void
shoulder1Add(void)
{
  shoulder1 = (shoulder1 + SHOULDER_RATE) % 360;
}

void
shoulder1Subtract(void)
{
  shoulder1 = (shoulder1 - SHOULDER_RATE) % 360;
}

void
shoulder2Add(void)
{
  shoulder2 = (shoulder2 + SHOULDER_RATE) % 360;
}

void
shoulder2Subtract(void)
{
  shoulder2 = (shoulder2 - SHOULDER_RATE) % 360;
}

void
shoulder3Add(void)
{
  shoulder3 = (shoulder3 + SHOULDER_RATE) % 360;
}

void
shoulder3Subtract(void)
{
  shoulder3 = (shoulder3 - SHOULDER_RATE) % 360;
}

void
shoulder4Add(void)
{
  shoulder4 = (shoulder4 + SHOULDER_RATE) % 360;
}

void
shoulder4Subtract(void)
{
  shoulder4 = (shoulder4 - SHOULDER_RATE) % 360;
}

void
lat1Raise(void)
{
  lat1 = (lat1 + LAT_RATE) % 360;
}

void
lat1Lower(void)
{
  lat1 = (lat1 - LAT_RATE) % 360;
}

void
lat2Raise(void)
{
  lat2 = (lat2 + LAT_RATE) % 360;
}

void
lat2Lower(void)
{
  lat2 = (lat2 - LAT_RATE) % 360;
}

void
FireCannon(void)
{
  fire = (fire + CANNON_RATE) % 360;
}

void
RaiseLeg1Forward(void)
{
  hip11 = (hip11 + UPPER_LEG_RATE) % 360;
}

void
LowerLeg1Backwards(void)
{
  hip11 = (hip11 - UPPER_LEG_RATE) % 360;
}

void
RaiseLeg1Outwards(void)
{
  hip12 = (hip12 + UPPER_LEG_RATE_GROIN) % 360;
}

void
LowerLeg1Inwards(void)
{
  hip12 = (hip12 - UPPER_LEG_RATE_GROIN) % 360;
}

void
RaiseLeg2Forward(void)
{
  hip21 = (hip21 + UPPER_LEG_RATE) % 360;
}

void
LowerLeg2Backwards(void)
{
  hip21 = (hip21 - UPPER_LEG_RATE) % 360;
}

void
RaiseLeg2Outwards(void)
{
  hip22 = (hip22 + UPPER_LEG_RATE_GROIN) % 360;
}

void
LowerLeg2Inwards(void)
{
  hip22 = (hip22 - UPPER_LEG_RATE_GROIN) % 360;
}

/* end of body motion functions */

/* start of light source position functions */
void
TurnRight(void)
{
  turn = (turn - VIEW_TURN_RATE) % 360;
}

void
TurnLeft(void)
{
  turn = (turn + VIEW_TURN_RATE) % 360;
}

void
TurnForwards(void)
{
  turn1 = (turn1 - VIEW_TURN_RATE) % 360;
}

void
TurnBackwards(void)
{
  turn1 = (turn1 + VIEW_TURN_RATE) % 360;
}

void
LightTurnRight(void)
{
  lightturn = (lightturn + LIGHT_TURN_RATE) % 360;
}

void
LightTurnLeft(void)
{
  lightturn = (lightturn - LIGHT_TURN_RATE) % 360;
}

void
LightForwards(void)
{
  lightturn1 = (lightturn1 + LIGHT_TURN_RATE) % 360;
}

void
LightBackwards(void)
{
  lightturn1 = (lightturn1 - LIGHT_TURN_RATE) % 360;
}

/* end of light source position functions */

/* start of geometric shape functions */
void
Box(float width, float height, float depth, char solid)
{
  char i, j = 0;
  float x = width / 2.0, y = height / 2.0, z = depth / 2.0;

  for (i = 0; i < 4; i++) {
    glRotatef(90.0, 0.0, 0.0, 1.0);
    if (j) {
      if (!solid)
        glBegin(GL_LINE_LOOP);
      else
        glBegin(GL_QUADS);
      glNormal3f(-1.0, 0.0, 0.0);
      glVertex3f(-x, y, z);
      glVertex3f(-x, -y, z);
      glVertex3f(-x, -y, -z);
      glVertex3f(-x, y, -z);
      glEnd();
      if (solid) {
        glBegin(GL_TRIANGLES);
        glNormal3f(0.0, 0.0, 1.0);
        glVertex3f(0.0, 0.0, z);
        glVertex3f(-x, y, z);
        glVertex3f(-x, -y, z);
        glNormal3f(0.0, 0.0, -1.0);
        glVertex3f(0.0, 0.0, -z);
        glVertex3f(-x, -y, -z);
        glVertex3f(-x, y, -z);
        glEnd();
      }
      j = 0;
    } else {
      if (!solid)
        glBegin(GL_LINE_LOOP);
      else
        glBegin(GL_QUADS);
      glNormal3f(-1.0, 0.0, 0.0);
      glVertex3f(-y, x, z);
      glVertex3f(-y, -x, z);
      glVertex3f(-y, -x, -z);
      glVertex3f(-y, x, -z);
      glEnd();
      if (solid) {
        glBegin(GL_TRIANGLES);
        glNormal3f(0.0, 0.0, 1.0);
        glVertex3f(0.0, 0.0, z);
        glVertex3f(-y, x, z);
        glVertex3f(-y, -x, z);
        glNormal3f(0.0, 0.0, -1.0);
        glVertex3f(0.0, 0.0, -z);
        glVertex3f(-y, -x, -z);
        glVertex3f(-y, x, -z);
        glEnd();
      }
      j = 1;
    }
  }
}

void
Octagon(float side, float height, char solid)
{
  char j;
  float x = sin(0.785398163) * side, y = side / 2.0, z = height / 2.0, c;

  c = x + y;
  for (j = 0; j < 8; j++) {
    glTranslatef(-c, 0.0, 0.0);
    if (!solid)
      glBegin(GL_LINE_LOOP);
    else
      glBegin(GL_QUADS);
    glNormal3f(-1.0, 0.0, 0.0);
    glVertex3f(0.0, -y, z);
    glVertex3f(0.0, y, z);
    glVertex3f(0.0, y, -z);
    glVertex3f(0.0, -y, -z);
    glEnd();
    glTranslatef(c, 0.0, 0.0);
    if (solid) {
      glBegin(GL_TRIANGLES);
      glNormal3f(0.0, 0.0, 1.0);
      glVertex3f(0.0, 0.0, z);
      glVertex3f(-c, -y, z);
      glVertex3f(-c, y, z);
      glNormal3f(0.0, 0.0, -1.0);
      glVertex3f(0.0, 0.0, -z);
      glVertex3f(-c, y, -z);
      glVertex3f(-c, -y, -z);
      glEnd();
    }
    glRotatef(45.0, 0.0, 0.0, 1.0);
  }
}

/* end of geometric shape functions */
#ifdef NORM
void
Normalize(float v[3])
{
  GLfloat d = sqrt(v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);

  if (d == 0.0) {
    printf("zero length vector");
    return;
  }
  v[1] /= d;
  v[2] /= d;
  v[3] /= d;
}

void
NormXprod(float v1[3], float v2[3], float v[3], float out[3])
{
  GLint i, j;
  GLfloat length;

  out[0] = v1[1] * v2[2] - v1[2] * v2[1];
  out[1] = v1[2] * v2[0] - v1[0] * v2[2];
  out[2] = v1[0] * v2[1] - v1[1] * v2[0];
  Normalize(out);
}

#endif

void
SetMaterial(GLfloat spec[], GLfloat amb[], GLfloat diff[], GLfloat shin[])
{

  glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
  glMaterialfv(GL_FRONT, GL_SHININESS, shin);
  glMaterialfv(GL_FRONT, GL_AMBIENT, amb);
  glMaterialfv(GL_FRONT, GL_DIFFUSE, diff);
}

void
MechTorso(char solid)
{
  glNewList(SOLID_MECH_TORSO, GL_COMPILE);
#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  Box(1.0, 1.0, 3.0, solid);
  glTranslatef(0.75, 0.0, 0.0);
#ifdef LIGHT
  SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
  glColor3f(0.5, 0.5, 0.5);
  Box(0.5, 0.6, 2.0, solid);
  glTranslatef(-1.5, 0.0, 0.0);
  Box(0.5, 0.6, 2.0, solid);
  glTranslatef(0.75, 0.0, 0.0);
  glEndList();
}

void
MechHip(char solid)
{
  int i;

  glNewList(SOLID_MECH_HIP, GL_COMPILE);
#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  Octagon(0.7, 0.5, solid);
#ifdef SPHERE
  for (i = 0; i < 2; i++) {
    if (i)
      glScalef(-1.0, 1.0, 1.0);
    glTranslatef(1.0, 0.0, 0.0);
#ifdef LIGHT
    SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
    glColor3f(0.5, 0.5, 0.5);
    if (!solid)
      gluQuadricDrawStyle(qobj, GLU_LINE);
    gluSphere(qobj, 0.2, 16, 16);
    glTranslatef(-1.0, 0.0, 0.0);
  }
  glScalef(-1.0, 1.0, 1.0);
#endif
  glEndList();
}

void
Shoulder(char solid)
{
  glNewList(SOLID_MECH_SHOULDER, GL_COMPILE);
#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  Box(1.0, 0.5, 0.5, solid);
  glTranslatef(0.9, 0.0, 0.0);
#ifdef LIGHT
  SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
  glColor3f(0.5, 0.5, 0.5);
#ifdef SPHERE
  if (!solid)
    gluQuadricDrawStyle(qobj, GLU_LINE);
  gluSphere(qobj, 0.6, 16, 16);
#endif
  glTranslatef(-0.9, 0.0, 0.0);
  glEndList();
}

void
UpperArm(char solid)
{
  int i;

  glNewList(SOLID_MECH_UPPER_ARM, GL_COMPILE);
#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  Box(1.0, 2.0, 1.0, solid);
  glTranslatef(0.0, -0.95, 0.0);
  glRotatef(90.0, 1.0, 0.0, 0.0);
#ifdef LIGHT
  SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
  glColor3f(0.5, 0.5, 0.5);
  if (!solid)
    gluQuadricDrawStyle(qobj, GLU_LINE);
  gluCylinder(qobj, 0.4, 0.4, 1.5, 16, 10);
#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  glRotatef(-90.0, 1.0, 0.0, 0.0);
  glTranslatef(-0.4, -1.85, 0.0);
  glRotatef(90.0, 0.0, 1.0, 0.0);
  for (i = 0; i < 2; i++) {
    if (!solid)
      gluQuadricDrawStyle(qobj, GLU_LINE);
    if (i)
      gluCylinder(qobj, 0.5, 0.5, 0.8, 16, 10);
    else
      gluCylinder(qobj, 0.2, 0.2, 0.8, 16, 10);
  }
  for (i = 0; i < 2; i++) {
    if (i)
      glScalef(-1.0, 1.0, 1.0);
    if (!solid)
      gluQuadricDrawStyle(qobj, GLU_LINE);
    if (i)
      glTranslatef(0.0, 0.0, 0.8);
    gluDisk(qobj, 0.2, 0.5, 16, 10);
    if (i)
      glTranslatef(0.0, 0.0, -0.8);
  }
  glScalef(-1.0, 1.0, 1.0);
  glRotatef(-90.0, 0.0, 1.0, 0.0);
  glTranslatef(0.4, 2.9, 0.0);
  glEndList();
}

void
VulcanGun(char solid)
{
  int i;

  glNewList(SOLID_MECH_VULCAN, GL_COMPILE);

#ifdef LIGHT
  SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
  glColor3f(0.5, 0.5, 0.5);

  if (!solid) {
    gluQuadricDrawStyle(qobj, GLU_LINE);
  }
  gluCylinder(qobj, 0.5, 0.5, 0.5, 16, 10);
  glTranslatef(0.0, 0.0, 0.5);
  gluDisk(qobj, 0.0, 0.5, 16, 10);

  for (i = 0; i < 5; i++) {
    glRotatef(72.0, 0.0, 0.0, 1.0);
    glTranslatef(0.0, 0.3, 0.0);
    if (!solid) {
      gluQuadricDrawStyle(qobj, GLU_LINE);
    }
    gluCylinder(qobj, 0.15, 0.15, 2.0, 16, 10);
    gluCylinder(qobj, 0.06, 0.06, 2.0, 16, 10);
    glTranslatef(0.0, 0.0, 2.0);
    gluDisk(qobj, 0.1, 0.15, 16, 10);
    gluCylinder(qobj, 0.1, 0.1, 0.1, 16, 5);
    glTranslatef(0.0, 0.0, 0.1);
    gluDisk(qobj, 0.06, 0.1, 16, 5);
    glTranslatef(0.0, -0.3, -2.1);
  }
  glEndList();
}

void
ForeArm(char solid)
{
  char i;

  glNewList(SOLID_MECH_FOREARM, GL_COMPILE);
#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  for (i = 0; i < 5; i++) {
    glTranslatef(0.0, -0.1, -0.15);
    Box(0.6, 0.8, 0.2, solid);
    glTranslatef(0.0, 0.1, -0.15);
    Box(0.4, 0.6, 0.1, solid);
  }
  glTranslatef(0.0, 0.0, 2.45);
  Box(1.0, 1.0, 2.0, solid);
  glTranslatef(0.0, 0.0, -1.0);
  glEndList();
}

void
UpperLeg(char solid)
{
  int i;

  glNewList(SOLID_MECH_UPPER_LEG, GL_COMPILE);
#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  if (!solid) {
    gluQuadricDrawStyle(qobj, GLU_LINE);
  }
  glTranslatef(0.0, -1.0, 0.0);
  Box(0.4, 1.0, 0.7, solid);
  glTranslatef(0.0, -0.65, 0.0);
  for (i = 0; i < 5; i++) {
    Box(1.2, 0.3, 1.2, solid);
    glTranslatef(0.0, -0.2, 0.0);
    Box(1.0, 0.1, 1.0, solid);
    glTranslatef(0.0, -0.2, 0.0);
  }
  glTranslatef(0.0, -0.15, -0.4);
  Box(2.0, 0.5, 2.0, solid);
  glTranslatef(0.0, -0.3, -0.2);
  glRotatef(90.0, 1.0, 0.0, 0.0);
#ifdef LIGHT
  SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
  glColor3f(0.5, 0.5, 0.5);
  gluCylinder(qobj, 0.6, 0.6, 3.0, 16, 10);
#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  glRotatef(-90.0, 1.0, 0.0, 0.0);
  glTranslatef(0.0, -1.5, 1.0);
  Box(1.5, 3.0, 0.5, solid);
  glTranslatef(0.0, -1.75, -0.8);
  Box(2.0, 0.5, 2.0, solid);
  glTranslatef(0.0, -0.9, -0.85);
#ifdef LIGHT
  SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
  glColor3f(0.5, 0.5, 0.5);
  gluCylinder(qobj, 0.8, 0.8, 1.8, 16, 10);
  for (i = 0; i < 2; i++) {
    if (i)
      glScalef(-1.0, 1.0, 1.0);
    if (!solid)
      gluQuadricDrawStyle(qobj, GLU_LINE);
    if (i)
      glTranslatef(0.0, 0.0, 1.8);
    gluDisk(qobj, 0.0, 0.8, 16, 10);
    if (i)
      glTranslatef(0.0, 0.0, -1.8);
  }
  glScalef(-1.0, 1.0, 1.0);
  glEndList();
}

void
Foot(char solid)
{

  glNewList(SOLID_MECH_FOOT, GL_COMPILE);
#ifdef LIGHT
  SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
  glColor3f(0.5, 0.5, 0.5);
  glRotatef(90.0, 1.0, 0.0, 0.0);
  Octagon(1.5, 0.6, solid);
  glRotatef(-90.0, 1.0, 0.0, 0.0);
  glEndList();
}

void
LowerLeg(char solid)
{
  float k, l;

#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  for (k = 0.0; k < 2.0; k++) {
    for (l = 0.0; l < 2.0; l++) {
      glPushMatrix();
      glTranslatef(k, 0.0, l);
#ifdef LIGHT
      SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
      glColor3f(1.0, 1.0, 0.0);
      Box(1.0, 0.5, 1.0, solid);
      glTranslatef(0.0, -0.45, 0.0);
#ifdef LIGHT
      SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
      glColor3f(0.5, 0.5, 0.5);
#ifdef SPHERE
      if (!solid)
        glutWireSphere(0.2, 16, 10);
      else
        glutSolidSphere(0.2, 16, 10);
#endif
      if (leg)
        glRotatef((GLfloat) heel1, 1.0, 0.0, 0.0);
      else
        glRotatef((GLfloat) heel2, 1.0, 0.0, 0.0);
      /* glTranslatef(0.0, -0.2, 0.0); */
      glTranslatef(0.0, -1.7, 0.0);
#ifdef LIGHT
      SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
      glColor3f(1.0, 1.0, 0.0);
      Box(0.25, 3.0, 0.25, solid);
      glTranslatef(0.0, -1.7, 0.0);
#ifdef LIGHT
      SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
      glColor3f(0.5, 0.5, 0.5);
#ifdef SPHERE
      if (!solid)
        glutWireSphere(0.2, 16, 10);
      else
        glutSolidSphere(0.2, 16, 10);
#endif
      if (leg)
        glRotatef((GLfloat) - heel1, 1.0, 0.0, 0.0);
      else
        glRotatef((GLfloat) - heel2, 1.0, 0.0, 0.0);
      glTranslatef(0.0, -0.45, 0.0);
#ifdef LIGHT
      SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
      glColor3f(1.0, 1.0, 0.0);
      Box(1.0, 0.5, 1.0, solid);
      if (!k && !l) {
        int j;

        glTranslatef(-0.4, -0.8, 0.5);
        if (leg)
          glRotatef((GLfloat) ankle1, 1.0, 0.0, 0.0);
        else
          glRotatef((GLfloat) ankle2, 1.0, 0.0, 0.0);
        glRotatef(90.0, 0.0, 1.0, 0.0);
        if (!solid)
          gluQuadricDrawStyle(qobj, GLU_LINE);
        gluCylinder(qobj, 0.8, 0.8, 1.8, 16, 10);
        for (j = 0; j < 2; j++) {
          if (!solid)
            gluQuadricDrawStyle(qobj, GLU_LINE);
          if (j) {
            glScalef(-1.0, 1.0, 1.0);
            glTranslatef(0.0, 0.0, 1.8);
          }
          gluDisk(qobj, 0.0, 0.8, 16, 10);
          if (j)
            glTranslatef(0.0, 0.0, -1.8);
        }
        glScalef(-1.0, 1.0, 1.0);
        glRotatef(-90.0, 0.0, 1.0, 0.0);
        glTranslatef(0.95, -0.8, 0.0);
        glCallList(SOLID_MECH_FOOT);
      }
      glPopMatrix();
    }
  }
}

void
RocketPod(char solid)
{

  int i, j, k = 0;

  glNewList(SOLID_MECH_ROCKET, GL_COMPILE);
#ifdef LIGHT
  SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
  glColor3f(0.5, 0.5, 0.5);
  glScalef(0.4, 0.4, 0.4);
  glRotatef(45.0, 0.0, 0.0, 1.0);
  glTranslatef(1.0, 0.0, 0.0);
  Box(2.0, 0.5, 3.0, solid);
  glTranslatef(1.0, 0.0, 0.0);
  glRotatef(45.0, 0.0, 0.0, 1.0);
  glTranslatef(0.5, 0.0, 0.0);
  Box(1.2, 0.5, 3.0, solid);
  glTranslatef(2.1, 0.0, 0.0);
  glRotatef(-90.0, 0.0, 0.0, 1.0);
#ifdef LIGHT
  SetMaterial(mat_specular, mat_ambient, mat_diffuse, mat_shininess);
#endif
  glColor3f(1.0, 1.0, 0.0);
  Box(2.0, 3.0, 4.0, solid);
  glTranslatef(-0.5, -1.0, 1.3);
  for (i = 0; i < 2; i++) {
    for (j = 0; j < 3; j++) {
      if (!solid) {
        gluQuadricDrawStyle(qobj, GLU_LINE);
      }
      glTranslatef(i, j, 0.6);
#ifdef LIGHT
      SetMaterial(mat_specular3, mat_ambient3, mat_diffuse3, mat_shininess3);
#endif
      glColor3f(1.0, 1.0, 1.0);
      gluCylinder(qobj, 0.4, 0.4, 0.3, 16, 10);
      glTranslatef(0.0, 0.0, 0.3);
#ifdef LIGHT
      SetMaterial(mat_specular4, mat_ambient4, mat_diffuse4, mat_shininess4);
#endif
      glColor3f(0.0, 1.0, 0.0);
      gluCylinder(qobj, 0.4, 0.0, 0.5, 16, 10);
      k++;
      glTranslatef(-i, -j, -0.9);
    }
  }
  glEndList();
}

void
Enviro(char solid)
{

  int i, j;

  glNewList(SOLID_ENVIRO, GL_COMPILE);
  SetMaterial(mat_specular4, mat_ambient4, mat_diffuse4, mat_shininess4);
  glColor3f(0.0, 1.0, 0.0);
  Box(20.0, 0.5, 30.0, solid);
  SetMaterial(mat_specular4, mat_ambient3, mat_diffuse2, mat_shininess);
  glColor3f(0.6, 0.6, 0.6);
  glTranslatef(0.0, 0.0, -10.0);
  for (j = 0; j < 6; j++) {
    for (i = 0; i < 2; i++) {
      if (i)
        glScalef(-1.0, 1.0, 1.0);
      glTranslatef(10.0, 4.0, 0.0);
      Box(4.0, 8.0, 2.0, solid);
      glTranslatef(0.0, -1.0, -3.0);
      Box(4.0, 6.0, 2.0, solid);
      glTranslatef(-10.0, -3.0, 3.0);
    }
    glScalef(-1.0, 1.0, 1.0);
    glTranslatef(0.0, 0.0, 5.0);
  }
  glEndList();
}

void
Toggle(void)
{
  if (solid_part)
    solid_part = 0;
  else
    solid_part = 1;
}

void
disable(void)
{
  glDisable(GL_LIGHTING);
  glDisable(GL_DEPTH_TEST);
  glDisable(GL_NORMALIZE);
  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}

void
lighting(void)
{

  GLfloat position[] =
  {0.0, 0.0, 2.0, 1.0};

#ifdef MOVE_LIGHT
  glRotatef((GLfloat) lightturn1, 1.0, 0.0, 0.0);
  glRotatef((GLfloat) lightturn, 0.0, 1.0, 0.0);
  glRotatef(0.0, 1.0, 0.0, 0.0);
#endif
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_NORMALIZE);
  glDepthFunc(GL_LESS);
  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

  glLightfv(GL_LIGHT0, GL_POSITION, position);
  glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 80.0);

  glTranslatef(0.0, 0.0, 2.0);
  glDisable(GL_LIGHTING);
  Box(0.1, 0.1, 0.1, 0);
  glEnable(GL_LIGHTING);
}

void
DrawMech(void)
{
  int i, j;

  glScalef(0.5, 0.5, 0.5);
  glPushMatrix();
  glTranslatef(0.0, -0.75, 0.0);
  glRotatef((GLfloat) tilt, 1.0, 0.0, 0.0);

  glRotatef(90.0, 1.0, 0.0, 0.0);
#ifdef HIP
  glCallList(SOLID_MECH_HIP);
#endif
  glRotatef(-90.0, 1.0, 0.0, 0.0);

  glTranslatef(0.0, 0.75, 0.0);
  glPushMatrix();
  glRotatef((GLfloat) pivot, 0.0, 1.0, 0.0);
  glPushMatrix();
#ifdef TORSO
  glCallList(SOLID_MECH_TORSO);
#endif
  glPopMatrix();
  glPushMatrix();
  glTranslatef(0.5, 0.5, 0.0);
#ifdef ROCKET_POD
  glCallList(SOLID_MECH_ROCKET);
#endif
  glPopMatrix();
  for (i = 0; i < 2; i++) {
    glPushMatrix();
    if (i)
      glScalef(-1.0, 1.0, 1.0);
    glTranslatef(1.5, 0.0, 0.0);
#ifdef SHOULDER
    glCallList(SOLID_MECH_SHOULDER);
#endif
    glTranslatef(0.9, 0.0, 0.0);
    if (i) {
      glRotatef((GLfloat) lat1, 0.0, 0.0, 1.0);
      glRotatef((GLfloat) shoulder1, 1.0, 0.0, 0.0);
      glRotatef((GLfloat) shoulder3, 0.0, 1.0, 0.0);
    } else {
      glRotatef((GLfloat) lat2, 0.0, 0.0, 1.0);
      glRotatef((GLfloat) shoulder2, 1.0, 0.0, 0.0);
      glRotatef((GLfloat) shoulder4, 0.0, 1.0, 0.0);
    }
    glTranslatef(0.0, -1.4, 0.0);
#ifdef UPPER_ARM
    glCallList(SOLID_MECH_UPPER_ARM);
#endif
    glTranslatef(0.0, -2.9, 0.0);
    if (i)
      glRotatef((GLfloat) elbow1, 1.0, 0.0, 0.0);
    else
      glRotatef((GLfloat) elbow2, 1.0, 0.0, 0.0);
    glTranslatef(0.0, -0.9, -0.2);
#ifdef LOWER_ARM
    glCallList(SOLID_MECH_FOREARM);
    glPushMatrix();
    glTranslatef(0.0, 0.0, 2.0);
    glRotatef((GLfloat) fire, 0.0, 0.0, 1.0);
    glCallList(SOLID_MECH_VULCAN);
    glPopMatrix();
#endif
    glPopMatrix();
  }
  glPopMatrix();

  glPopMatrix();

  for (j = 0; j < 2; j++) {
    glPushMatrix();
    if (j) {
      glScalef(-0.5, 0.5, 0.5);
      leg = 1;
    } else {
      glScalef(0.5, 0.5, 0.5);
      leg = 0;
    }
    glTranslatef(2.0, -1.5, 0.0);
    if (j) {
      glRotatef((GLfloat) hip11, 1.0, 0.0, 0.0);
      glRotatef((GLfloat) hip12, 0.0, 0.0, 1.0);
    } else {
      glRotatef((GLfloat) hip21, 1.0, 0.0, 0.0);
      glRotatef((GLfloat) hip22, 0.0, 0.0, 1.0);
    }
    glTranslatef(0.0, 0.3, 0.0);
#ifdef UPPER_LEG
    glPushMatrix();
    glCallList(SOLID_MECH_UPPER_LEG);
    glPopMatrix();
#endif
    glTranslatef(0.0, -8.3, -0.4);
    if (j)
      glRotatef((GLfloat) - hip12, 0.0, 0.0, 1.0);
    else
      glRotatef((GLfloat) - hip22, 0.0, 0.0, 1.0);
    glTranslatef(-0.5, -0.85, -0.5);
#ifdef LOWER_LEG
    LowerLeg(1);
#endif
    glPopMatrix();
  }
}

void
display(void)
{
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glEnable(GL_DEPTH_TEST);

  glPushMatrix();
  glRotatef((GLfloat) turn, 0.0, 1.0, 0.0);
  glRotatef((GLfloat) turn1, 1.0, 0.0, 0.0);
#ifdef LIGHT
  if (solid_part) {
    glPushMatrix();
    lighting();
    glPopMatrix();
  } else
    disable();
#endif
#ifdef DRAW_MECH
  glPushMatrix();
  glTranslatef(0.0, elevation, 0.0);
  DrawMech();
  glPopMatrix();
#endif
#ifdef DRAW_ENVIRO
  glPushMatrix();
  if (distance >= 20.136)
    distance = 0.0;
  glTranslatef(0.0, -5.0, -distance);
  glCallList(SOLID_ENVIRO);
  glTranslatef(0.0, 0.0, 10.0);
  glCallList(SOLID_ENVIRO);
  glPopMatrix();
#endif
  glPopMatrix();
  glFlush();
  glutSwapBuffers();
}

void
myinit(void)
{
  char i = 1;

  qobj = gluNewQuadric();
#ifdef LIGHT
  SetMaterial(mat_specular2, mat_ambient2, mat_diffuse2, mat_shininess2);
#endif
  glEnable(GL_DEPTH_TEST);
  MechTorso(i);
  MechHip(i);
  Shoulder(i);
  RocketPod(i);
  UpperArm(i);
  ForeArm(i);
  UpperLeg(i);
  Foot(i);
  VulcanGun(i);
  Enviro(i);
}

void
myReshape(int w, int h)
{
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(65.0, (GLfloat) w / (GLfloat) h, 1.0, 20.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef(0.0, 1.2, -5.5);  /* viewing transform  */
}

#ifdef ANIMATION
void
animation_walk(void)
{
  float angle;
  static int step;

  if (step == 0 || step == 2) {
    /* for(frame=3.0; frame<=21.0; frame=frame+3.0){ */
    if (frame >= 0.0 && frame <= 21.0) {
      if (frame == 0.0)
        frame = 3.0;
      angle = (180 / M_PI) * 
	(acos(((cos((M_PI / 180) * frame) * 2.043) + 1.1625) / 3.2059));
      if (frame > 0) {
        elevation = -(3.2055 - (cos((M_PI / 180) * angle) * 3.2055));
      } else
        elevation = 0.0;
      if (step == 0) {
        hip11 = -(frame * 1.7);
        if (1.7 * frame > 15)
          heel1 = frame * 1.7;
        heel2 = 0;
        ankle1 = frame * 1.7;
        if (frame > 0)
          hip21 = angle;
        else
          hip21 = 0;
        ankle2 = -hip21;
        shoulder1 = frame * 1.5;
        shoulder2 = -frame * 1.5;
        elbow1 = frame;
        elbow2 = -frame;
      } else {
        hip21 = -(frame * 1.7);
        if (1.7 * frame > 15)
          heel2 = frame * 1.7;
        heel1 = 0;
        ankle2 = frame * 1.7;
        if (frame > 0)
          hip11 = angle;
        else
          hip11 = 0;
        ankle1 = -hip11;
        shoulder1 = -frame * 1.5;
        shoulder2 = frame * 1.5;
        elbow1 = -frame;
        elbow2 = frame;
      }
      if (frame == 21)
        step++;
      if (frame < 21)
        frame = frame + 3.0;
    }
  }
  if (step == 1 || step == 3) {
    /* for(x=21.0; x>=0.0; x=x-3.0){ */
    if (frame <= 21.0 && frame >= 0.0) {
      angle = (180 / M_PI) * 
	(acos(((cos((M_PI / 180) * frame) * 2.043) + 1.1625) / 3.2029));
      if (frame > 0)
        elevation = -(3.2055 - (cos((M_PI / 180) * angle) * 3.2055));
      else
        elevation = 0.0;
      if (step == 1) {
        elbow2 = hip11 = -frame;
        elbow1 = heel1 = frame;
        heel2 = 15;
        ankle1 = frame;
        if (frame > 0)
          hip21 = angle;
        else
          hip21 = 0;
        ankle2 = -hip21;
        shoulder1 = 1.5 * frame;
        shoulder2 = -frame * 1.5;
      } else {
        elbow1 = hip21 = -frame;
        elbow2 = heel2 = frame;
        heel1 = 15;
        ankle2 = frame;
        if (frame > 0)
          hip11 = angle;
        else
          hip11 = 0;
        ankle1 = -hip11;
        shoulder1 = -frame * 1.5;
        shoulder2 = frame * 1.5;
      }
      if (frame == 0.0)
        step++;
      if (frame > 0)
        frame = frame - 3.0;
    }
  }
  if (step == 4)
    step = 0;
  distance += 0.1678;
  glutPostRedisplay();
}

void
animation(void)
{
  animation_walk();
}

#endif

#ifdef GLUT
#ifdef GLUT_KEY
/* ARGSUSED1 */
void
keyboard(unsigned char key, int x, int y)
{

  int i = 0;

  switch (key) {
    /* start arm control functions */
  case 'q':{
      shoulder2Subtract();
      i++;
    }
    break;
  case 'a':{
      shoulder2Add();
      i++;
    }
    break;
  case 'w':{
      shoulder1Subtract();
      i++;
    }
    break;
  case 's':{
      shoulder1Add();
      i++;
    }
    break;
  case '2':{
      shoulder3Add();
      i++;
    }
    break;
  case '1':{
      shoulder4Add();
      i++;
    }
    break;
  case '4':{
      shoulder3Subtract();
      i++;
    }
    break;
  case '3':{
      shoulder4Subtract();
      i++;
    }
    break;

  case 'z':{
      lat2Raise();
      i++;
    }
    break;
  case 'Z':{
      lat2Lower();
      i++;
    }
    break;
  case 'x':{
      lat1Raise();
      i++;
    }
    break;
  case 'X':{
      lat1Lower();
      i++;
    }
    break;

  case 'A':{
      elbow2Add();
      i++;
    }
    break;
  case 'Q':{
      elbow2Subtract();
      i++;
    }
    break;
  case 'S':{
      elbow1Add();
      i++;
    }
    break;
  case 'W':{
      elbow1Subtract();
      i++;
    }
    break;
    /* end of arm control functions */

    /* start of torso control functions */
  case 'd':{
      RotateAdd();
      i++;
    }
    break;
  case 'g':{
      RotateSubtract();
      i++;
    }
    break;
  case 'r':{
      MechTiltAdd();
      i++;
    }
    break;
  case 'f':{
      MechTiltSubtract();
      i++;
    }
    break;
    /* end of torso control functions */

    /* start of leg control functions */
  case 'h':{
      RaiseLeg2Forward();
      i++;
    }
    break;
  case 'y':{
      LowerLeg2Backwards();
      i++;
    }
    break;
  case 'Y':{
      RaiseLeg2Outwards();
      i++;
    }
    break;
  case 'H':{
      LowerLeg2Inwards();
      i++;
    }
    break;

  case 'j':{
      RaiseLeg1Forward();
      i++;
    }
    break;
  case 'u':{
      LowerLeg1Backwards();
      i++;
    }
    break;
  case 'U':{
      RaiseLeg1Outwards();
      i++;
    }
    break;
  case 'J':{
      LowerLeg1Inwards();
      i++;
    }
    break;

  case 'N':{
      Heel2Add();
      i++;
    }
    break;
  case 'n':{
      Heel2Subtract();
      i++;
    }
    break;
  case 'M':{
      Heel1Add();
      i++;
    }
    break;
  case 'm':{
      Heel1Subtract();
      i++;
    }
    break;

  case 'k':{
      Ankle2Add();
      i++;
    }
    break;
  case 'K':{
      Ankle2Subtract();
      i++;
    }
    break;
  case 'l':{
      Ankle1Add();
      i++;
    }
    break;
  case 'L':{
      Ankle1Subtract();
      i++;
    }
    break;
    /* end of leg control functions */

    /* start of light source position functions */
  case 'p':{
      LightTurnRight();
      i++;
    }
    break;
  case 'i':{
      LightTurnLeft();
      i++;
    }
    break;
  case 'o':{
      LightForwards();
      i++;
    }
    break;
  case '9':{
      LightBackwards();
      i++;
    }
    break;
    /* end of light source position functions */
  }
  if (i)
    glutPostRedisplay();
}

#endif

#ifdef GLUT_SPEC
/* ARGSUSED1 */
void
special(int key, int x, int y)
{

  int i = 0;

  switch (key) {
    /* start of view position functions */
  case GLUT_KEY_RIGHT:{
      TurnRight();
      i++;
    }
    break;
  case GLUT_KEY_LEFT:{
      TurnLeft();
      i++;
    }
    break;
  case GLUT_KEY_DOWN:{
      TurnForwards();
      i++;
    }
    break;
  case GLUT_KEY_UP:{
      TurnBackwards();
      i++;
    }
    break;
    /* end of view positions functions */
    /* start of miscellaneous functions */
  case GLUT_KEY_PAGE_UP:{
      FireCannon();
      i++;
    }
    break;
    /* end of miscellaneous functions */
  }
  if (i)
    glutPostRedisplay();
}

#endif
#endif
void
menu_select(int mode)
{
  switch (mode) {
#ifdef ANIMATION
  case 1:
    glutIdleFunc(animation);
    break;
#endif
  case 2:
    glutIdleFunc(NULL);
    break;
  case 3:
    Toggle();
    glutPostRedisplay();
    break;
  case 4:
    exit(EXIT_SUCCESS);
  }
}

/* ARGSUSED */
void
null_select(int mode)
{
}

void
glutMenu(void)
{

  int glut_menu[13];

  glut_menu[5] = glutCreateMenu(null_select);
  glutAddMenuEntry("forward       : q,w", 0);
  glutAddMenuEntry("backwards     : a,s", 0);
  glutAddMenuEntry("outwards      : z,x", 0);
  glutAddMenuEntry("inwards       : Z,X", 0);

  glut_menu[6] = glutCreateMenu(null_select);
  glutAddMenuEntry("upwards       : Q,W", 0);
  glutAddMenuEntry("downwards     : A,S", 0);
  glutAddMenuEntry("outwards      : 1,2", 0);
  glutAddMenuEntry("inwards       : 3,4", 0);

  glut_menu[1] = glutCreateMenu(null_select);
  glutAddMenuEntry(" : Page_up", 0);

  glut_menu[8] = glutCreateMenu(null_select);
  glutAddMenuEntry("forward       : y,u", 0);
  glutAddMenuEntry("backwards     : h.j", 0);
  glutAddMenuEntry("outwards      : Y,U", 0);
  glutAddMenuEntry("inwards       : H,J", 0);

  glut_menu[9] = glutCreateMenu(null_select);
  glutAddMenuEntry("forward       : n,m", 0);
  glutAddMenuEntry("backwards     : N,M", 0);

  glut_menu[9] = glutCreateMenu(null_select);
  glutAddMenuEntry("forward       : n,m", 0);
  glutAddMenuEntry("backwards     : N,M", 0);

  glut_menu[10] = glutCreateMenu(null_select);
  glutAddMenuEntry("toes up       : K,L", 0);
  glutAddMenuEntry("toes down     : k,l", 0);

  glut_menu[11] = glutCreateMenu(null_select);
  glutAddMenuEntry("right         : right arrow", 0);
  glutAddMenuEntry("left          : left arrow", 0);
  glutAddMenuEntry("down          : up arrow", 0);
  glutAddMenuEntry("up            : down arrow", 0);

  glut_menu[12] = glutCreateMenu(null_select);
  glutAddMenuEntry("right         : p", 0);
  glutAddMenuEntry("left          : i", 0);
  glutAddMenuEntry("up            : 9", 0);
  glutAddMenuEntry("down          : o", 0);

  glut_menu[4] = glutCreateMenu(NULL);
  glutAddSubMenu("at the shoulders? ", glut_menu[5]);
  glutAddSubMenu("at the elbows?", glut_menu[6]);

  glut_menu[7] = glutCreateMenu(NULL);
  glutAddSubMenu("at the hip? ", glut_menu[8]);
  glutAddSubMenu("at the knees?", glut_menu[9]);
  glutAddSubMenu("at the ankles? ", glut_menu[10]);

  glut_menu[2] = glutCreateMenu(null_select);
  glutAddMenuEntry("turn left    : d", 0);
  glutAddMenuEntry("turn right    : g", 0);

  glut_menu[3] = glutCreateMenu(null_select);
  glutAddMenuEntry("tilt backwards : f", 0);
  glutAddMenuEntry("tilt forwards  : r", 0);

  glut_menu[0] = glutCreateMenu(NULL);
  glutAddSubMenu("move the arms.. ", glut_menu[4]);
  glutAddSubMenu("fire the vulcan guns?", glut_menu[1]);
  glutAddSubMenu("move the legs.. ", glut_menu[7]);
  glutAddSubMenu("move the torso?", glut_menu[2]);
  glutAddSubMenu("move the hip?", glut_menu[3]);
  glutAddSubMenu("rotate the scene..", glut_menu[11]);
#ifdef MOVE_LIGHT
  glutAddSubMenu("rotate the light source..", glut_menu[12]);
#endif

  glutCreateMenu(menu_select);
#ifdef ANIMATION
  glutAddMenuEntry("Start Walk", 1);
  glutAddMenuEntry("Stop Walk", 2);
#endif
  glutAddMenuEntry("Toggle Wireframe", 3);
  glutAddSubMenu("How do I ..", glut_menu[0]);
  glutAddMenuEntry("Quit", 4);
  glutAttachMenu(GLUT_LEFT_BUTTON);
  glutAttachMenu(GLUT_RIGHT_BUTTON);
}

int
main(int argc, char **argv)
{
#ifdef GLUT
  /* start of glut windowing and control functions */
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
  glutInitWindowSize(800, 600);
  glutCreateWindow("glutmech: Vulcan Gunner");
  myinit();
  glutDisplayFunc(display);
  glutReshapeFunc(myReshape);
#ifdef GLUT_KEY
  glutKeyboardFunc(keyboard);
#endif
#ifdef GLUT_SPEC
  glutSpecialFunc(special);
#endif
  glutMenu();
  glutMainLoop();
  /* end of glut windowing and control functions */
#endif
  return 0;             
}

Compile this code as an empty C++ Console Application where you add a new item (i.e., a code file) and paste this code in. I had no problem compiling it on the VC++ command line. Recall that you are in the bin directory, you must type vcvars32.bat to set the environment. Type ‘type con > robot.c’ and your cursor will drop down one line and go to the far left with no prompt. Paste the code in this console space, and compile it with the cl.exe compiler:

Capture5.PNG

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)