OpenGL is one of the interactive 3D graphics standards used in the computer gaming industry. Another one is
Microsoft's DirectX. Most of the graphics on the cronodon.com are rendered on Pov-Ray.
Pov-ray is excellent for
doing non-interactive graphics, such as still snapshots or animations

In this section Bot will show you some of the basics of OpenGL and maybe we will even produce a simple 3D
game, wait and see!



Bot has been using OpenGL in MS Visual Studio .NET 2003. For information on obtaining and installing the
OpenGL library files click below:

                                                        External link:
OpenGL in .NET 2003

This link also shows you how to initialise empty projects and remove the command prompt window, if you don't
need it for input/output (as it can be quite annoying). The OpenGL libraries are for use with C++ (though
versions are available for C#, but Bot has not used these). A typical OpenGL program is a C++ app with calls to
OpenGL library functions which have their own format.

The listing below shows you how to rotate a camera or viewer's eye around a stationary cube in 3D space. The
cube is illuminated by a point light_source off to one side. It allows the user to move the camera along the x, y
and z axes by pressing the cursor, page up and page down keys, or by clicking the mouse.

You can download an executable of the program (written for Windows XP)
here. Note that this file is an
executable (program) so your security will warn you and ask permission before allowing you to download it
(executables can be malicious software, but rest assured that this is a simple graphics demo).

Good sources for basic OpenGL code are numeroud web sites / forums and the following books:

  • Computer Graphics with OpenGL, D. Hearn & M.P. Baker, Pearson (3rd Edition, a newer ed is probably
    now available).
  • Interactive Computer graphics, A top-down approach using OpenGL, Edward Angel (3rd Edition, a newer
    ed is probably now available).

Some of the demo code presented here has been adapted from these sources.
Programming 3D Interactive graphics with OpenGL
//Rotating View around a cube with lighting

#include <cstdio>
using namespace std;
#include <GL/glut.h>

//Global variables

GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},
{1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},
{1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};

GLfloat normals[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},
{1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},
{1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};

GLfloat colors[][4] = {{0.0,0.0,0.0,1.0},{1.0,0.0,0.0,1.0},
{1.0,1.0,0.0,1.0}, {0.0,1.0,0.0,1.0}, {0.0,0.0,1.0,1.0},
{1.0,0.0,1.0,1.0}, {1.0,1.0,1.0,1.0}, {0.0,1.0,1.0,1.0}};

GLfloat eyeX = 0.0, eyeY = 0.0, eyeZ = 5.0; //Viewing coord origin
GLfloat atX = 0.0, atY = 0.0, atZ = 0.0; //Look-at point
GLfloat upX = 0.0, upY = 1.0, upZ = 0.0; //View-up vector

//Near and far clipping planes
GLfloat dnear = 2, dfar = 50.0;

void polygon(int a, int b, int c , int d , int e)
{
GLfloat specularCoeff[] = { 1.0, 1.0, 1.0, 1.0 };

glBegin(GL_POLYGON);
        //glColor3fv(colors[a]);
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, colors[e]);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularCoeff);
        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 25.0);
        glNormal3fv(normals[a]);
   glVertex3fv(vertices[a]);
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, colors[e]);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularCoeff);
        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 25.0);
        glNormal3fv(normals[b]);
   glVertex3fv(vertices[b]);
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, colors[e]);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularCoeff);
        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 25.0);
        glNormal3fv(normals[c]);
   glVertex3fv(vertices[c]);
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, colors[e]);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularCoeff);
        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 25.0);
        glNormal3fv(normals[d]);
   glVertex3fv(vertices[d]);
glEnd();
}

void colorcube()
{
polygon(0,3,2,1,1);
polygon(2,3,7,6,2);
polygon(0,4,7,3,3);
polygon(1,2,6,5,4);
polygon(4,5,6,7,5);
polygon(0,1,5,4,6);
}

static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 0;
static GLdouble viewer[]= {eyeX, eyeY, eyeZ}; // initial viewer location

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//Update viewer position in modelview matrix
glLoadIdentity();
gluLookAt(viewer[0],viewer[1],viewer[2], atX, atY, atZ, upX, upY, upZ);

//Rotate Cube
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);      
//Display Cube        
colorcube();

glFlush();
glutSwapBuffers();
}

//Uses mouse to rotate cube
void mouse(int btn, int state, int x, int y)
{
if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0;
if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1;
if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2;
theta[axis] += 2.0;
if( theta[axis] > 360.0 ) theta[axis] -= 360.0;
display();
}

//Uses cursor, page up and page down keys to move camera
void specialKeys(int specialkey, int x, int y)
{
if(specialkey == GLUT_KEY_LEFT) viewer[0]-= 1.0;
if(specialkey == GLUT_KEY_RIGHT) viewer[0]+= 1.0;
if(specialkey == GLUT_KEY_UP) viewer[1]+= 1.0;
if(specialkey == GLUT_KEY_DOWN) viewer[1]-= 1.0;
if(specialkey == GLUT_KEY_PAGE_UP) viewer[2]+= 1.0;
if(specialkey == GLUT_KEY_PAGE_DOWN) viewer[2]-= 1.0;
display();
}

void myReshape(int w, int h)
{
 glViewport(0, 0, w, h);
//Use a perspective view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
{
        glFrustum(-2.0, 2.0, -2.0 * (GLfloat) h/ (GLfloat) w, 2.0* (GLfloat) h / (GLfloat) w, dnear, dfar);
}
else
{
        glFrustum(-2.0, 2.0, -2.0 * (GLfloat) w/ (GLfloat) h, 2.0* (GLfloat) w / (GLfloat) h, dnear, dfar);
}
glMatrixMode(GL_MODELVIEW);
}

void Lights(void)
{
//Light source
GLfloat light1PosType[] = { 100.0, 0.0, 0.0, 1.0 };
GLfloat ambientColor[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat diffuseColor[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat specularColor[] = { 1.0, 1.0, 1.0, 1.0 };
//Light colours
glLightfv(GL_LIGHT1, GL_AMBIENT, ambientColor);
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuseColor);
glLightfv(GL_LIGHT1, GL_SPECULAR, specularColor);
//Light attenuation
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5-1);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.75-0.75);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.4+0.6);
//Switch light on!
glEnable(GL_LIGHT1);
glEnable(GL_LIGHTING);
}

void main(int argc, char **argv)        //Entry point for program
{
//Initialise OpenGL Window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("colorcube");

//Reshape Window if Requested without too much distortion!
 glutReshapeFunc(myReshape);

//Switch one lights
 Lights();

//Display Graphic
 glutDisplayFunc(display);
 display();

//Get input from user
 glutMouseFunc(mouse);
 glutSpecialFunc(specialKeys);

 glEnable(GL_DEPTH_TEST);

//Main program loop - wait for input and maintain display
 glutMainLoop();
}
Typical Anatomy of an OpenGL C++ Program

#include is a preprocessor directive, it tells the compiler to add files to the code, for example cstdio is the
standard C library input/output file, which contains code for handling I/O. This file used to be called stdio.h, but
in Visual studio (VS) the modern standard of naming C/C++ library files is generally adopted, which means
dropping the .h for 'header' file.

#include <GL/glut.h>
Tells the compiler preprocessor to add a header file that contains the basic code needed for the OpenGL
functions. The preprocessor adds in the necessary code at the #include directives and then the compiler is
able to read the convert and convert it into the machine-code which the executable file is written in. Without
this header instructions like GLfloat would make no sense to the compiler as this is the OpenGL designation
for a float variable (which is just float in C++).

Global Variables
These are variables that sit outside any of the functions or classes in a C++ program and are usually placed
near the start of the program before any functions that may need them. These variables can be accessed by
any of the functions, since they are global. Local variables are declared inside functions and can only be used
inside those functions as they cease to exist outside their enclosing braces {} (e.g. GLfloat light1PosType[] = {
100.0, 0.0, 0.0, 1.0 }; an array holding the position coordinates of light1 inside the Lights() function body).

The main function main()
This is the central part of the program where execution starts and it is easier to read programs by starting
here. Sometimes the main() function is near the start of a C++ program, in which case it must be proceeded by
the function names (prototypes) but when placing it at the end the proceeding functions have already been
defined so the compiler will know what they are. For example, the main() calls the function Lights() to initialise
and switch-on the lights. If this function followed main() then the compiler would not understand the function
call Lights(), in which case we would need to include the function prototype: void Lights(); before main()
(without the function body enclosed in the braces {}).

The main function displays a window, which will contain our graphics, using its own glut functions, rather than
the MS Windows functions which achieve this (though these are no doubt called by glut). This makes it easier
for us to set the window how we want it - its size and position and title. The glutReshapeWindow() function is
needed to reset the graphics display should the user resize the window. It is set to call our own reshape
function, myReshape(int w, int h) which receives two integers, one for the width (w) of the window and the
other for the height (h) of the window in pixels.

Next the main() function switches on the lights by calling the Light() function. The display() function is called to
draw the graphics. The main() function then uses OpenGL functions that wait for user input from keyboard
special keys (like the cursor keys) or from the mouse.

The glutMainLoop() function is always called last and this tells the computer to maintain a window-loop,
meaning that the display is maintained whilst the computer waits for user input and this loop is only terminated
when the window is closed.