Search code examples
c++openglglutfreeglut

GLUT program only works for a few frames


I have a program I wrote just over 6 months ago that uses the GLUT library. It worked absolutely fine 6 months ago when I wrote it. I have not used it or edited the code in any way since then.

The program has some cubes floating around with some random velocities and they bounce off walls of an environment they are in. The camera can be moved around using the arrow keys and panned/tilted with the mouse. More walls can be added to the environment by clicking, and the position of these can then be adjusted with the arrow keys.

However, although this was working 6 months ago, now the camera only pans/tilts with the mouse for the first few frames of the program, as does the movement of the camera with the arrow keys. However the program is not frozen, I can still see the cubes floating around and the walls that can be added and their position adjusted can still be moved.

Is there any common reason that causes previously working GLUT programs to only properly function for the first few frames?

#include <iostream>
#include <GL/glut.h>
#include <Windows.h> //FOR CURSOR
#include <tgmath.h> //FOR MATHS
#include <fstream>
#include <string>
#include <time.h>  //FOR THE TIME FOR RANDOM GENERATOR SEED


const int   MAXMOLECULES = 1000000, MAXCUBOIDS = 10000, NUMBER_OF_PRESSURE_SENSORS = 3, MAX_RECORDING_TIME = 1000000;

int         widthOfMonitor = glutGet( GLUT_SCREEN_WIDTH ), heightOfMonitor = glutGet( GLUT_SCREEN_HEIGHT ),
            cuboidBuilding = 0;//IS A CUBE CURRENTLY BEING BUILT? 0 FOR NO, 1 FOR YES.

const float ORIGINAL_CAMERA_LOCATION[3] = { 0, 0, 0 }, //ORIGINAL CAMERA LOCATION
            ORIGINAL_CAMERA_DIRECTION[3] = { 2.001, 0, 0 },
            PI = 3.14159265359, //PI
            MAPSIZE = 20.0, //SIZE OF THE CUBE SURROUNDING THE CENTER
            SIZESCALE = 100.0; //SCALE THE SIZE OF BOXES

float       cameraInformation[3][3], //(CAMERA TRANSLATION FROM ORIGINAL CAMERA LOCATION, CAMERA DIRECTION, CAMERA LOCATION) in (x,y,z)
            cursorAngle[2], //POSITION OF CURSOR CONVERTED TO AN ANGLE, in (y,z)
            cubeInitialOrigin[3], //ORIGIN OF CUBE WHEN STARTING BUILDING, in (x,y,z)
            movementSpeed = 0.0125;
char s[30];

std::string str1 = "FILLINGUPTHESTRING";    //TAKES USERS INPUT OF FILENAME

const char *FILENAME = str1.c_str( );

void window_size( int w, int h ); //TAKE CURRENT SIZE OF WINDOW
void rotate_camera( );
void move_forward( float forwardsOrBackwards );
void move_left( float forwardsOrBackwards );
void move_up( float forwardsOrBackwards );
void keyboard( unsigned char key, int x, int y );
void cuboid   ( float   OCX,     float OCY,     float OCZ,
                float   xsize,   float ysize,   float zsize,
                float   TR,      float TG,      float TB,
                float   BR,      float BG,      float BB,
                float   FR,      float FG,      float FB,
                float   BWR,     float BWG,     float BWB,
                float   LR,      float LG,      float LB,
                float   RR,      float RG,      float RB ); //PRODUCE CUBOIDS
void display ( );   //RENDERS CUBOIDS, TEXT AND MOLECULES
int main ( int argc, char **argv )
{
    ShowCursor( FALSE );
    void glutInit( int *argc, char **argv );
    glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA );
    //CREATE WINDOW, SET RESOLUTION AND POSITION
    glutInitWindowSize( widthOfMonitor, heightOfMonitor );
    glutCreateWindow( "SQUARE" );
    glutInitWindowPosition( 0, 0 );
    glutFullScreen( );
    glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
    glEnable ( GL_COLOR_MATERIAL ) ;
    glutReshapeFunc( window_size ); //SET WINDOW CORRECT SIZE
    glutKeyboardFunc( keyboard );//DETECT IF KEYBOARD IS PRESSED AND RESPOND
    //CONSTANTLY UPDATE DISPLAY AT FRAME rate OF MONITOR (OR LOWER IF CPU/GPU CANNOT PROCESS FAST ENOUGH)
    glutDisplayFunc( display );
    glutIdleFunc( display );
    glEnable( GL_DEPTH_TEST ); //RENDER OBJECTS CLOSEST TO CAMERA INFRONT OF OBJECTS FURTHER AWAY
    glutMainLoop( );
}

/*window_size TAKES INPUT OF SIZE OF WINDOW THEN GENERATES THE ORIGINAL CAMERA VIEW*/
void window_size( int widthOfMonitor, int heightOfMonitor ) //TAKE CURRENT SIZE OF WINDOW
{
    glMatrixMode( GL_PROJECTION ); //EDIT THE CAMERA SETTINGS
    glViewport( 0, 0, widthOfMonitor, heightOfMonitor ); //SET THE RENDERING TO COVER ENTIRE WINDOW
    //SET THE PERSPECTIVE
    gluPerspective( 90,     //FOV
                    widthOfMonitor / heightOfMonitor,    //DISPLAY ASPECT
                    0.01,   //NEAR CLIP
                    20000.0 ); //FAR CLIP
    glMatrixMode( GL_MODELVIEW ); //CHANGE BACK TO EDITING THE WOLRD
    gluLookAt(  ORIGINAL_CAMERA_LOCATION[0], ORIGINAL_CAMERA_LOCATION[1], ORIGINAL_CAMERA_LOCATION[2], //CAMERA LOCATION
                ORIGINAL_CAMERA_LOCATION[0] + ORIGINAL_CAMERA_DIRECTION[0], ORIGINAL_CAMERA_LOCATION[1] + ORIGINAL_CAMERA_LOCATION[1], ORIGINAL_CAMERA_LOCATION[2] + ORIGINAL_CAMERA_LOCATION[2], //LOOK AT
                0.0, 1.0, 0.0 ); //VERTICAL DEFINITION
}
/*rotate_camera DETECTS LOCATION OF CURSOR, ADJUSTING THE DIRECTION LOOKED DEPENDING ON WHAT DIRECTION THE MOUSE IS MOVED*/
void rotate_camera( )
{
    POINT m1;
    GetCursorPos( &m1 );//EXTRACT MOUSE COORDINATES
    //DISPLACEMENT FROM CENTRE OF SCREEN IN X&Y
    int xmpos = ( m1.x - widthOfMonitor  / 2 );
    int ympos = ( m1.y - heightOfMonitor / 2 );
    //TAKE MOUSE COORDS AND SET WHOLE WINDOW TO BE LENGTH 2PI IN X AND Y
    cursorAngle[0] += - ( ( xmpos * 180 / (widthOfMonitor  / 2) ) * PI / 180 );
    cursorAngle[1] +=   ( ( ympos * 180 / (heightOfMonitor / 2) ) * PI / 180 );
    //DON'T ALLOW ROTATING UP PAST CEILING OR BELOW FLOOR, CAN BE DONE BUT MAKES PERSPECTIVE CONFUSING
    if ( cursorAngle[1] > 0 )
        cursorAngle[1] = - 1E-5;
    else if ( cursorAngle[1] < -PI )
        cursorAngle[1] = -( PI - 1E-5 );
    //CONVERT FROM SPHERICAL POLARS INTO CARTESIANS
    cameraInformation[1][0] =  cos( cursorAngle[0] ) * sin( cursorAngle[1] );
    cameraInformation[1][1] =  sin( cursorAngle[0] ) * sin( cursorAngle[1] );
    cameraInformation[1][2] = -cos( cursorAngle[1] );
    //KEEP CURSOR CENTERED TO PREVENT SCREEN GETTING STUCK WHEN ROTATING PAST 2PI.
    SetCursorPos( widthOfMonitor / 2, heightOfMonitor / 2 );
}
/*MoveForwards TRIGGERS IF W OR S IS PRESSED AND MOVES FORWARD OR BACKWARDS IN THE DIRECTION FACED IF A CUBE IS NOT BEING BUILT, OR MOVES CUBE FORWARD OR BACKWARDS IN THE DIRECTION FACED IF CUBE IS BEING BUILT*/
void move_forward( float forwardsOrBackwards )
{
    float changeInX, changeInY, changeInZ, length;
    if ( cuboidBuilding == 0 )
    {
        //GO FORWARD/BACK RELATIVE TO CAMERA VIEW
        changeInX = ( forwardsOrBackwards * cameraInformation[1][0] );
        changeInY = ( forwardsOrBackwards * cameraInformation[1][1] );
        changeInZ = ( forwardsOrBackwards * cameraInformation[1][2] );
        //NORMALIZE MOVEMENT
        length = sqrt ( pow ( changeInX, 2.0 ) + pow ( changeInY, 2.0 ) + pow ( changeInZ, 2.0 ) );
        changeInX = changeInX / length;
        changeInY = changeInY / length;
        changeInZ = changeInZ / length;
        //SET SENSITIVITY AND ADD CHANGE FROM STARTING POSITION TO STARTING POSITION TO GET CURRENT POSITION
        cameraInformation[0][0] += changeInX * movementSpeed;
        cameraInformation[0][1] += changeInY * movementSpeed;
        cameraInformation[0][2] += changeInZ * movementSpeed;
    }

}
/*move_left TRIGGERS IF A OR D IS PRESSED AND MOVES LEFT OR RIGHT TO THE DIRECTION FACED IF A CUBE IS NOT BEING BUILT, OR MOVES CUBE LEFT OR RIGHT OF THE DIRECTION FACED IF CUBE IS BEING BUILT*/
void move_left( float forwardsOrBackwards )
{
    float changeInX, changeInY, length;
    if ( cuboidBuilding == 0 )
    {
        //GO LEFT/RIGHT RELATIVE TO CAMERA VIEW
        changeInX = ( -forwardsOrBackwards * cameraInformation[1][1] );
        changeInY = ( forwardsOrBackwards * cameraInformation[1][0] );
        //NORMALIZE MOVEMENT
        length = sqrt ( pow ( changeInX, 2.0 ) + pow ( changeInY, 2.0 ) );
        changeInX = changeInX / length;
        changeInY = changeInY / length;
        //SET SENSITIVITY AND ADD CHANGE FROM STARTING POSITION TO STARTING POSITION TO GET CURRENT POSITION
        cameraInformation[0][0] += changeInX * movementSpeed;
        cameraInformation[0][1] += changeInY * movementSpeed;
    }
}
/*move_up TRIGGERS IF Q OR E IS PRESSED AND MOVES VERTICALLY UP OR DOWN IF A CUBE IS NOT BEING BUILT, OR MOVES CUBE VERTICALLY UP OR DOWN IF CUBE IS BEING BUILT*/
void move_up( float forwardsOrBackwards )
{
    //MOVEMENT AND MAKING CUBE AS THE DIRECTION MOVED IS ALWAYS PARRALEL TO Z COORDS, SO NO CONVERSION FROM CAMERA TO BOX IS REQUIRED
    float changeInZ, length;
    //GO UP/DOWN RELATIVE TO CAMERA VIEW
    changeInZ = ( forwardsOrBackwards );
    //NORMALIZE MOVEMENT
    length = sqrt( pow ( changeInZ, 2.0 ) );
    changeInZ = changeInZ / length;
    //SET SENSITIVITY
    if ( cuboidBuilding == 0 )
        cameraInformation[0][2] += changeInZ * movementSpeed;
    //ADD CHANGE FROM STARTING POSITION TO STARTING POSITION TO GET CURRENT POSITION
}
/*keyboard TRIGGERS IF A KEY ON THE KEYBOARD IS PRESSED, THEN PASSES TO A FUNCTION THAT PROCESSES THE KEY PRESSED, ALSO UPDATES THE LOCATION OF CAMERA IF MOVEMENT KEYS ARE PRESSED */
void keyboard( unsigned char key, int x, int y )
{
    int forwardsOrBackwards; //FORWARD OR BACKWORDS.
    //PREVENT A POTENTIAL DIVIDE BY 0 ERROR BY SETTING 0 DIRECTIONS TO VERY SMALL DIRECTIONS.
    for ( int i = 0; i <= 2; i++ )
    {
    if ( cameraInformation[1][i] > -1E-5 && cameraInformation[1][i] < 1E-5 )
        cameraInformation[1][i] = 1E-4;
    }
    switch ( key )
    {
        case 122: case 90: //z
        if ( movementSpeed < 0.5 )
            movementSpeed = 1.0;
        else
            movementSpeed = 0.025;
        break;
        case 119: case 52: forwardsOrBackwards = 1; move_forward ( forwardsOrBackwards ); break; //w
        case 115: case 83: forwardsOrBackwards = -1;move_forward ( forwardsOrBackwards ); break; //s
        case 97 : case 65: forwardsOrBackwards = 1; move_left ( forwardsOrBackwards ); break;  //a
        case 100: case 68: forwardsOrBackwards = -1;move_left ( forwardsOrBackwards ); break;  //d
        case 113: case 81: forwardsOrBackwards = -1;move_up ( forwardsOrBackwards ); break; //q
        case 101: case 69: forwardsOrBackwards = 1; move_up ( forwardsOrBackwards ); break; //e
        case 27 : exit ( 0 ); //esc CLOSE PROGRAM
    }
    if ( cuboidBuilding == 0 )   //IF NOT BUILDING A CUBE, MOVE CAMERA COORDS BY THE AMOUNT THEY HAVE CHANGED
    {
        for ( int i = 0; i <=2; i++)
        {
        cameraInformation[2][i] = ORIGINAL_CAMERA_LOCATION[i] + cameraInformation[0][i];
        }
    }
}
/*cuboid TAKES INPUTS OF CENTER OF CUBE, SIZE OF CUBE AND COLOURS OF EACH FACE THEN PRODUCES A CUBE BY SPLITING EACH FACE UP INTO TWO TRIANGLES*/
void cuboid   ( float   OCX,     float OCY,     float OCZ,
                float   xsize,   float ysize,   float zsize,
                float   TR,      float TG,      float TB,
                float   BR,      float BG,      float BB,
                float   FR,      float FG,      float FB,
                float   BWR,     float BWG,     float BWB,
                float   LR,      float LG,      float LB,
                float   RR,      float RG,      float RB )
{
    glBegin( GL_TRIANGLES );
    //MAKE TRIANGLES IN SHAPE OF A CUBE BY SPECIFYING VERTICES OF TRIANGLES
    glColor3f ( TR, TG, TB );                           //TOP
    glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
    glVertex3f( OCX + xsize, OCY + ysize, OCZ + zsize );
    glVertex3f( OCX - xsize, OCY + ysize, OCZ + zsize );
    glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
    glVertex3f( OCX + xsize, OCY + ysize, OCZ + zsize );
    glVertex3f( OCX + xsize, OCY - ysize, OCZ + zsize );
    glColor3f ( BR, BG, BB );                           //BOTTOM
    glVertex3f( OCX - xsize, OCY - ysize, OCZ - zsize );
    glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
    glVertex3f( OCX - xsize, OCY + ysize, OCZ - zsize );
    glVertex3f( OCX - xsize, OCY - ysize, OCZ - zsize );
    glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
    glVertex3f( OCX + xsize, OCY - ysize, OCZ - zsize );
    glColor3f ( FR, FG, FB );                           //FORWARDS
    glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
    glVertex3f( OCX + xsize, OCY - ysize, OCZ - zsize );
    glVertex3f( OCX + xsize, OCY - ysize, OCZ + zsize );
    glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
    glVertex3f( OCX + xsize, OCY - ysize, OCZ - zsize );
    glVertex3f( OCX - xsize, OCY - ysize, OCZ - zsize );
    glColor3f ( BWR, BWG, BWB );                        //BACKWARDS
    glVertex3f( OCX - xsize, OCY + ysize, OCZ + zsize);
    glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
    glVertex3f( OCX + xsize, OCY + ysize, OCZ + zsize );
    glVertex3f( OCX - xsize, OCY + ysize, OCZ + zsize );
    glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
    glVertex3f( OCX - xsize, OCY + ysize, OCZ - zsize );
    glColor3f  ( LR, LG, LB );                          //LEFT
    glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
    glVertex3f( OCX - xsize, OCY + ysize, OCZ - zsize );
    glVertex3f( OCX - xsize, OCY - ysize, OCZ - zsize );
    glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
    glVertex3f( OCX - xsize, OCY + ysize, OCZ - zsize );
    glVertex3f( OCX - xsize, OCY + ysize, OCZ + zsize );
    glColor3f ( RR, RG, RB );                           //RIGHT
    glVertex3f( OCX + xsize, OCY - ysize, OCZ + zsize );
    glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
    glVertex3f( OCX + xsize, OCY - ysize, OCZ - zsize );
    glVertex3f( OCX + xsize, OCY - ysize, OCZ + zsize );
    glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
    glVertex3f( OCX + xsize, OCY + ysize, OCZ + zsize );
    glEnd( );
}
/*place_cuboid TRIGGERS IF LEFT MOUSE BUTTON IS PLACED, CAUSES A TEMPORARY CUBE TO APPEAR AT THE CURSOR LOCATION, THEN WHEN LEFT MOUSE BUTTON IS RELEASED IT SAVES THE CENTER,SIZE AND COLOUR OF THIS TEMPORARY CUBE INTO THE PERMAMENT ARRAYS OF CUBS*/

/*display TAKES THE ARRAYS OF CUBE AND MOLECULE LOCATIONS, SIZE AND COLOURS THEN RENDERS AND CHECKS IF MOLECULES ARE COLLIDING WITH A CUBE*/
void display ( )
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    //SET EDGES OF THE MAP
    cuboid   (  0.0, 0.0, 0.0,
                MAPSIZE, MAPSIZE, MAPSIZE,
                0.0, 0.0, 1.0,
                0.0, 1.0, 0.0,
                0.0, 1.0, 0.0,
                0.0, 1.0, 0.0,
                0.0, 1.0, 0.0,
                0.0, 1.0, 0.0 );
    glColor3d( 1.0, 0.0, 0.0 );
    glPushMatrix( );
    glLoadIdentity( );
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    rotate_camera( ); //ROTATE CAMERA WITH MOUSE
    //MOVE CAMERA
    gluLookAt(  cameraInformation[2][0], cameraInformation[2][1], cameraInformation[2][2], //Camera location
                cameraInformation[2][0] + cameraInformation[1][0], cameraInformation[2][1] + cameraInformation[1][1], cameraInformation[2][2] + cameraInformation[1][2], //LOOK AT
                0.0, 0.0, 1.0 ); //VERTICAL
    glutSwapBuffers();
}

Solution

    • Don't use glutGet() before you've called glutInit()
    • Initialize your variables
    • Use C++-style #includes
    • Set your matrices in your display callback, helps prevent usage errors
    • No need to use Windows to track/hide the cursor, (Free)GLUT has functions for that
    • Wrap your lines to something reasonable
    • A timerfunc or vsync is much friendlier on the battery/CPU fan than an idle callback

    All together:

    #include <GL/freeglut.h>
    #include <cmath>
    
    int cuboidBuilding = 0;//IS A CUBE CURRENTLY BEING BUILT? 0 FOR NO, 1 FOR YES.
    
    const float ORIGINAL_CAMERA_LOCATION[3] = { 0, 0, 0 }, //ORIGINAL CAMERA LOCATION
        ORIGINAL_CAMERA_DIRECTION[3] = { 2.001, 0, 0 },
        PI = 3.14159265359, //PI
        MAPSIZE = 20.0, //SIZE OF THE CUBE SURROUNDING THE CENTER
        SIZESCALE = 100.0; //SCALE THE SIZE OF BOXES
    
    float cameraInformation[3][3], //(CAMERA TRANSLATION FROM ORIGINAL CAMERA LOCATION, CAMERA DIRECTION, CAMERA LOCATION) in (x,y,z)
        cursorAngle[2], //POSITION OF CURSOR CONVERTED TO AN ANGLE, in (y,z)
        cubeInitialOrigin[3], //ORIGIN OF CUBE WHEN STARTING BUILDING, in (x,y,z)
        movementSpeed = 0.0125;
    
    // DETECTS LOCATION OF CURSOR, ADJUSTING THE 
    // DIRECTION LOOKED DEPENDING ON WHAT DIRECTION THE MOUSE IS MOVED
    bool warped = false;
    void passiveMotion( int x, int y )
    {
        if( warped )
        {
            // break warp loop
            warped = false;
            return;
        }
    
        int widthOfMonitor = glutGet( GLUT_WINDOW_WIDTH );
        int heightOfMonitor = glutGet( GLUT_WINDOW_HEIGHT );
    
        //DISPLACEMENT FROM CENTRE OF SCREEN IN X&Y
        int xmpos = ( x - widthOfMonitor / 2 );
        int ympos = ( y - heightOfMonitor / 2 );
    
        //TAKE MOUSE COORDS AND SET WHOLE WINDOW TO BE LENGTH 2PI IN X AND Y
        cursorAngle[0] += - ( ( xmpos * 180 / (widthOfMonitor  / 2) ) * PI / 180 );
        cursorAngle[1] +=   ( ( ympos * 180 / (heightOfMonitor / 2) ) * PI / 180 );
        //DON'T ALLOW ROTATING UP PAST CEILING OR BELOW FLOOR, CAN BE DONE BUT MAKES PERSPECTIVE CONFUSING
        if ( cursorAngle[1] > 0 )
            cursorAngle[1] = - 1E-5;
        else if ( cursorAngle[1] < -PI )
            cursorAngle[1] = -( PI - 1E-5 );
        //CONVERT FROM SPHERICAL POLARS INTO CARTESIANS
        cameraInformation[1][0] =  cos( cursorAngle[0] ) * sin( cursorAngle[1] );
        cameraInformation[1][1] =  sin( cursorAngle[0] ) * sin( cursorAngle[1] );
        cameraInformation[1][2] = -cos( cursorAngle[1] );
    
        //KEEP CURSOR CENTERED TO PREVENT SCREEN GETTING STUCK WHEN ROTATING PAST 2PI.
        warped = true;
        glutWarpPointer( widthOfMonitor / 2, heightOfMonitor / 2 );
    }
    
    // MoveForwards TRIGGERS IF W OR S IS PRESSED AND MOVES FORWARD OR BACKWARDS
    // IN THE DIRECTION FACED IF A CUBE IS NOT BEING BUILT, OR MOVES CUBE FORWARD
    // OR BACKWARDS IN THE DIRECTION FACED IF CUBE IS BEING BUILT
    void move_forward( float forwardsOrBackwards )
    {
        float changeInX, changeInY, changeInZ, length;
        if ( cuboidBuilding == 0 )
        {
            //GO FORWARD/BACK RELATIVE TO CAMERA VIEW
            changeInX = ( forwardsOrBackwards * cameraInformation[1][0] );
            changeInY = ( forwardsOrBackwards * cameraInformation[1][1] );
            changeInZ = ( forwardsOrBackwards * cameraInformation[1][2] );
            //NORMALIZE MOVEMENT
            length = sqrt ( pow ( changeInX, 2.0 ) + pow ( changeInY, 2.0 ) + pow ( changeInZ, 2.0 ) );
            changeInX = changeInX / length;
            changeInY = changeInY / length;
            changeInZ = changeInZ / length;
            //SET SENSITIVITY AND ADD CHANGE FROM STARTING POSITION TO STARTING POSITION TO GET CURRENT POSITION
            cameraInformation[0][0] += changeInX * movementSpeed;
            cameraInformation[0][1] += changeInY * movementSpeed;
            cameraInformation[0][2] += changeInZ * movementSpeed;
        }
    
    }
    
    // move_left TRIGGERS IF A OR D IS PRESSED AND MOVES LEFT OR RIGHT TO THE 
    // DIRECTION FACED IF A CUBE IS NOT BEING BUILT, OR MOVES CUBE
    // LEFT OR RIGHT OF THE DIRECTION FACED IF CUBE IS BEING BUILT
    void move_left( float forwardsOrBackwards )
    {
        float changeInX, changeInY, length;
        if ( cuboidBuilding == 0 )
        {
            //GO LEFT/RIGHT RELATIVE TO CAMERA VIEW
            changeInX = ( -forwardsOrBackwards * cameraInformation[1][1] );
            changeInY = ( forwardsOrBackwards * cameraInformation[1][0] );
            //NORMALIZE MOVEMENT
            length = sqrt ( pow ( changeInX, 2.0 ) + pow ( changeInY, 2.0 ) );
            changeInX = changeInX / length;
            changeInY = changeInY / length;
            //SET SENSITIVITY AND ADD CHANGE FROM STARTING POSITION TO STARTING POSITION TO GET CURRENT POSITION
            cameraInformation[0][0] += changeInX * movementSpeed;
            cameraInformation[0][1] += changeInY * movementSpeed;
        }
    }
    
    // move_up TRIGGERS IF Q OR E IS PRESSED AND MOVES VERTICALLY UP OR DOWN
    // IF A CUBE IS NOT BEING BUILT, OR MOVES CUBE VERTICALLY UP OR DOWN IF CUBE IS BEING BUILT
    void move_up( float forwardsOrBackwards )
    {
        //MOVEMENT AND MAKING CUBE AS THE DIRECTION MOVED IS ALWAYS PARRALEL TO Z COORDS, SO NO CONVERSION FROM CAMERA TO BOX IS REQUIRED
        float changeInZ, length;
        //GO UP/DOWN RELATIVE TO CAMERA VIEW
        changeInZ = ( forwardsOrBackwards );
        //NORMALIZE MOVEMENT
        length = sqrt( pow ( changeInZ, 2.0 ) );
        changeInZ = changeInZ / length;
        //SET SENSITIVITY
        if ( cuboidBuilding == 0 )
            cameraInformation[0][2] += changeInZ * movementSpeed;
        //ADD CHANGE FROM STARTING POSITION TO STARTING POSITION TO GET CURRENT POSITION
    }
    
    // keyboard TRIGGERS IF A KEY ON THE KEYBOARD IS PRESSED,
    // THEN PASSES TO A FUNCTION THAT PROCESSES THE KEY PRESSED,
    // ALSO UPDATES THE LOCATION OF CAMERA IF MOVEMENT KEYS ARE PRESSED
    void keyboard( unsigned char key, int x, int y )
    {
        int forwardsOrBackwards; //FORWARD OR BACKWORDS.
        //PREVENT A POTENTIAL DIVIDE BY 0 ERROR BY SETTING 0 DIRECTIONS TO VERY SMALL DIRECTIONS.
        for ( int i = 0; i <= 2; i++ )
        {
            if ( cameraInformation[1][i] > -1E-5 && cameraInformation[1][i] < 1E-5 )
                cameraInformation[1][i] = 1E-4;
        }
        switch ( key )
        {
        case 122: case 90: //z
            if ( movementSpeed < 0.5 )
                movementSpeed = 1.0;
            else
                movementSpeed = 0.025;
            break;
        case 119: case 52: forwardsOrBackwards = 1; move_forward ( forwardsOrBackwards ); break; //w
        case 115: case 83: forwardsOrBackwards = -1;move_forward ( forwardsOrBackwards ); break; //s
        case 97 : case 65: forwardsOrBackwards = 1; move_left ( forwardsOrBackwards ); break;  //a
        case 100: case 68: forwardsOrBackwards = -1;move_left ( forwardsOrBackwards ); break;  //d
        case 113: case 81: forwardsOrBackwards = -1;move_up ( forwardsOrBackwards ); break; //q
        case 101: case 69: forwardsOrBackwards = 1; move_up ( forwardsOrBackwards ); break; //e
        case 27 : exit ( 0 ); //esc CLOSE PROGRAM
        }
        if ( cuboidBuilding == 0 )   //IF NOT BUILDING A CUBE, MOVE CAMERA COORDS BY THE AMOUNT THEY HAVE CHANGED
        {
            for ( int i = 0; i <=2; i++)
            {
                cameraInformation[2][i] = ORIGINAL_CAMERA_LOCATION[i] + cameraInformation[0][i];
            }
        }
    }
    
    // cuboid TAKES INPUTS OF CENTER OF CUBE, SIZE OF CUBE AND COLOURS OF EACH FACE
    // THEN PRODUCES A CUBE BY SPLITING EACH FACE UP INTO TWO TRIANGLES
    void cuboid
        (
        float   OCX,     float OCY,     float OCZ,
        float   xsize,   float ysize,   float zsize,
        float   TR,      float TG,      float TB,
        float   BR,      float BG,      float BB,
        float   FR,      float FG,      float FB,
        float   BWR,     float BWG,     float BWB,
        float   LR,      float LG,      float LB,
        float   RR,      float RG,      float RB
        )
    {
        glBegin( GL_TRIANGLES );
        //MAKE TRIANGLES IN SHAPE OF A CUBE BY SPECIFYING VERTICES OF TRIANGLES
        glColor3f ( TR, TG, TB );                           //TOP
        glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
        glVertex3f( OCX + xsize, OCY + ysize, OCZ + zsize );
        glVertex3f( OCX - xsize, OCY + ysize, OCZ + zsize );
        glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
        glVertex3f( OCX + xsize, OCY + ysize, OCZ + zsize );
        glVertex3f( OCX + xsize, OCY - ysize, OCZ + zsize );
        glColor3f ( BR, BG, BB );                           //BOTTOM
        glVertex3f( OCX - xsize, OCY - ysize, OCZ - zsize );
        glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
        glVertex3f( OCX - xsize, OCY + ysize, OCZ - zsize );
        glVertex3f( OCX - xsize, OCY - ysize, OCZ - zsize );
        glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
        glVertex3f( OCX + xsize, OCY - ysize, OCZ - zsize );
        glColor3f ( FR, FG, FB );                           //FORWARDS
        glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
        glVertex3f( OCX + xsize, OCY - ysize, OCZ - zsize );
        glVertex3f( OCX + xsize, OCY - ysize, OCZ + zsize );
        glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
        glVertex3f( OCX + xsize, OCY - ysize, OCZ - zsize );
        glVertex3f( OCX - xsize, OCY - ysize, OCZ - zsize );
        glColor3f ( BWR, BWG, BWB );                        //BACKWARDS
        glVertex3f( OCX - xsize, OCY + ysize, OCZ + zsize);
        glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
        glVertex3f( OCX + xsize, OCY + ysize, OCZ + zsize );
        glVertex3f( OCX - xsize, OCY + ysize, OCZ + zsize );
        glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
        glVertex3f( OCX - xsize, OCY + ysize, OCZ - zsize );
        glColor3f  ( LR, LG, LB );                          //LEFT
        glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
        glVertex3f( OCX - xsize, OCY + ysize, OCZ - zsize );
        glVertex3f( OCX - xsize, OCY - ysize, OCZ - zsize );
        glVertex3f( OCX - xsize, OCY - ysize, OCZ + zsize );
        glVertex3f( OCX - xsize, OCY + ysize, OCZ - zsize );
        glVertex3f( OCX - xsize, OCY + ysize, OCZ + zsize );
        glColor3f ( RR, RG, RB );                           //RIGHT
        glVertex3f( OCX + xsize, OCY - ysize, OCZ + zsize );
        glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
        glVertex3f( OCX + xsize, OCY - ysize, OCZ - zsize );
        glVertex3f( OCX + xsize, OCY - ysize, OCZ + zsize );
        glVertex3f( OCX + xsize, OCY + ysize, OCZ - zsize );
        glVertex3f( OCX + xsize, OCY + ysize, OCZ + zsize );
        glEnd( );
    }
    
    // display TAKES THE ARRAYS OF CUBE AND MOLECULE LOCATIONS, SIZE AND
    // COLOURS THEN RENDERS AND CHECKS IF MOLECULES ARE COLLIDING WITH A CUBE
    void display ( )
    {
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    
        //SET THE PERSPECTIVE
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        int widthOfMonitor = glutGet( GLUT_WINDOW_WIDTH );
        int heightOfMonitor = glutGet( GLUT_WINDOW_HEIGHT );
        gluPerspective( 90,     //FOV
            widthOfMonitor / heightOfMonitor,    //DISPLAY ASPECT
            0.01,   //NEAR CLIP
            20000.0 ); //FAR CLIP
    
        //MOVE CAMERA
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt
            (
            cameraInformation[2][0], cameraInformation[2][1], cameraInformation[2][2], //Camera location
            cameraInformation[2][0] + cameraInformation[1][0],
            cameraInformation[2][1] + cameraInformation[1][1],
            cameraInformation[2][2] + cameraInformation[1][2], //LOOK AT
            0.0, 0.0, 1.0
            ); //VERTICAL
    
        glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
        glEnable ( GL_COLOR_MATERIAL ) ;
        glEnable( GL_DEPTH_TEST ); //RENDER OBJECTS CLOSEST TO CAMERA INFRONT OF OBJECTS FURTHER AWAY
    
        //SET EDGES OF THE MAP
        glColor3d( 1.0, 0.0, 0.0 );
        cuboid
            (
            0.0, 0.0, 0.0,
            MAPSIZE, MAPSIZE, MAPSIZE,
            0.0, 0.0, 1.0,
            0.0, 1.0, 0.0,
            0.0, 1.0, 0.0,
            0.0, 1.0, 0.0,
            0.0, 1.0, 0.0,
            0.0, 1.0, 0.0
            );
    
        glutSwapBuffers();
    }
    
    void timer( int value )
    {
        glutPostRedisplay();
        glutTimerFunc( 16, timer, 0 );
    }
    
    int main ( int argc, char **argv )
    {
        glutInit( &argc, argv );
        glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA );
        glutInitWindowSize( 600, 600 );
        glutInitWindowPosition( 0, 0 );
        glutCreateWindow( "SQUARE" );
        glutKeyboardFunc( keyboard );
        glutDisplayFunc( display );
        glutPassiveMotionFunc( passiveMotion );
        glutTimerFunc( 0, timer, 0 );
        glutSetCursor( GLUT_CURSOR_NONE );
        glutMainLoop( );
    }