// firstApp
// Author:  Keith Andersch
// Date:    9.16.2002
// Class:   CptS 442
// description:  This is the first assignment using the firstGlut files as a base.
//               This will display stars using my own class (GLStar) in various motion 
//               across the screen.
// dependancies: GLStar.h, GLStar.cpp

//using namespace std;
//#pragma comment(lib, "opengl32.lib")
//#pragma comment(lib, "glu32.lib")
//#pragma comment(lib, "glut32.lib")
#pragma comment(lib, "glaux.lib")

//#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glaux.h>
#include <cstdlib> // for exit()
#include <iostream>
#include <cstdio> // for sprintf() in CalculatFrameRate()
#include <string>
#include <windows.h> // for CalculatFrameRate()
#include "Maze.h"
#include "camera.h"

using namespace std;

// The basic GLUT functions
void displayHandler(void);
void keyboardHandler(unsigned char key, int x, int y);
void modelRedraw(void);
void viewInit();
void reshape(int w, int h);

// Functions that handle drawing, moving, etc...
void drawLevel();
void setupLists();
void levelInit();
bool isValidMove(int isBackward); // checks to see if move is valid
void updatePlayer(int isBackward);
void CreateTexture(UINT textureArray[], LPSTR strFileName, int textureID);
void isEndPoint();


// a function to calculat frame per second
void CalculateFrameRate();


const float screenSize = 20.0;

char *gstr_AppName = "Maze: "; // name of the application
string g_fileName("maze1.dat"); // file name of the maze level

GLuint g_cube; // used to hold the cube display list
GLuint g_floor; // used for the floor display list
maze g_level; // the maze object
Camera g_camera; // the camera object

point2 g_start, g_end; // the start and ending points in the maze
point2 currentPos; // current position of player

Point3 g_eye( 0.0, 0.5, 2.0);
Point3 g_look( 10.0, 0.5, 2.0 );
Vector3 g_up( 0.0, 1.0, 0.0 );

GLfloat g_cubeSize = 1.0; // size of cube from 0,0,0
int g_cubeFactor = 2.0; // actual size of a side
float g_yHeight = 0.5; // the camera height

enum Movement {UP, LEFT, RIGHT, DOWN, NONE};

Movement g_movement; // flag to indicate what type of movement

enum Direction {NORTH, EAST, SOUTH, WEST};

// flag to indicate direction player is facing
// needed so we don't go through walls
Direction g_direction;

// This array holds the possible values of viewing frustrum
float FrustArray[3] = {150.0, 100.0, 50.0}; 
int g_FrustPos = 1; // indicates the initial starting point

float g_width, g_height; // holds the width and height of window

float g_speed = 0.2; // speed of movement
int g_rotateSpeed = 10; // 
int g_numOfEnds = 0;
void movePlayer();

#define MAX_TEXTURES 10
// This will reference to our texture data stored with 
// OpenGL UINT is an unsigned int (only positive numbers)
UINT g_Texture[MAX_TEXTURES];

// list of texture names
// These textures were downloaded from www.planetunreal.com/TextureUniverse/
// I thank them for having these free textures.
char *textureNames[7] = {"metal004.bmp", "pipes6lights.bmp", "pipeslights.bmp",
	"pipeslightswires.bmp", "StoneWallImproved.bmp", "RustyBricksGrate.bmp",
	"SteelBoxFan.bmp"};


// a time struct used in CalculateFrameRate()
//tms *timeStruct;

void levelInit()
{
	// here we initialize the level and load textures
	if(!g_level.loadLevel(g_fileName))
	{
		cout << g_fileName << " can not be opened. Exiting program." << endl;
		exit(1);
	}
	

	// grab the start and end points for easy reference later
	g_start = g_level.getStart();
	g_numOfEnds = g_level.getNumEnd();

	// make the display lists
	setupLists();


	// load texture here
	for(int count = 0; count < 7; count++)
	{
		CreateTexture(g_Texture, textureNames[count], count);
	}
}

void setupLists()
{
	// this function is used to setup up two display lists:
	// a cube and a plane

	g_cube = glGenLists(2);
	glNewList(g_cube, GL_COMPILE);
		glBegin(GL_QUADS);							// Start Drawing Quads
			// Bottom Face
			glTexCoord2f(1.0f, 1.0f); glVertex3f(-g_cubeSize, -g_cubeSize, -g_cubeSize);	// Top Right Of The Texture and Quad
			glTexCoord2f(0.0f, 1.0f); glVertex3f( g_cubeSize, -g_cubeSize, -g_cubeSize);	// Top Left Of The Texture and Quad
			glTexCoord2f(0.0f, 0.0f); glVertex3f( g_cubeSize, -g_cubeSize,  g_cubeSize);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(1.0f, 0.0f); glVertex3f(-g_cubeSize, -g_cubeSize,  g_cubeSize);	// Bottom Right Of The Texture and Quad
			// Front Face
			glTexCoord2f(0.0f, 0.0f); glVertex3f(-g_cubeSize, -g_cubeSize,  g_cubeSize);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(1.0f, 0.0f); glVertex3f( g_cubeSize, -g_cubeSize,  g_cubeSize);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(1.0f, 1.0f); glVertex3f( g_cubeSize,  g_cubeSize,  g_cubeSize);	// Top Right Of The Texture and Quad
			glTexCoord2f(0.0f, 1.0f); glVertex3f(-g_cubeSize,  g_cubeSize,  g_cubeSize);	// Top Left Of The Texture and Quad
			// Top Face
			glTexCoord2f(0.0f, 1.0f); glVertex3f(-g_cubeSize,  g_cubeSize, -g_cubeSize);
			glTexCoord2f(0.0f, 0.0f); glVertex3f(-g_cubeSize,  g_cubeSize,  g_cubeSize);
			glTexCoord2f(1.0f, 0.0f); glVertex3f( g_cubeSize,  g_cubeSize,  g_cubeSize);
			glTexCoord2f(1.0f, 1.0f); glVertex3f( g_cubeSize,  g_cubeSize, -g_cubeSize);
			// Back Face
			glTexCoord2f(1.0f, 0.0f); glVertex3f(-g_cubeSize, -g_cubeSize, -g_cubeSize);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(1.0f, 1.0f); glVertex3f(-g_cubeSize,  g_cubeSize, -g_cubeSize);	// Top Right Of The Texture and Quad
			glTexCoord2f(0.0f, 1.0f); glVertex3f( g_cubeSize,  g_cubeSize, -g_cubeSize);	// Top Left Of The Texture and Quad
			glTexCoord2f(0.0f, 0.0f); glVertex3f( g_cubeSize, -g_cubeSize, -g_cubeSize);	// Bottom Left Of The Texture and Quad
			// Right face
			glTexCoord2f(1.0f, 0.0f); glVertex3f( g_cubeSize, -g_cubeSize, -g_cubeSize);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(1.0f, 1.0f); glVertex3f( g_cubeSize,  g_cubeSize, -g_cubeSize);	// Top Right Of The Texture and Quad
			glTexCoord2f(0.0f, 1.0f); glVertex3f( g_cubeSize,  g_cubeSize,  g_cubeSize);	// Top Left Of The Texture and Quad
			glTexCoord2f(0.0f, 0.0f); glVertex3f( g_cubeSize, -g_cubeSize,  g_cubeSize);	// Bottom Left Of The Texture and Quad
			// Left Face
			glTexCoord2f(0.0f, 0.0f); glVertex3f(-g_cubeSize, -g_cubeSize, -g_cubeSize);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(1.0f, 0.0f); glVertex3f(-g_cubeSize, -g_cubeSize,  g_cubeSize);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(1.0f, 1.0f); glVertex3f(-g_cubeSize,  g_cubeSize,  g_cubeSize);	// Top Right Of The Texture and Quad
			glTexCoord2f(0.0f, 1.0f); glVertex3f(-g_cubeSize,  g_cubeSize, -g_cubeSize);	// Top Left Of The Texture and Quad
		glEnd();								// Done Drawing Quads
	glEndList();

	// I increase the tex coordinates here to repeat the texture to make it look
	// slightly better than the orginal at this resolution
	g_floor = g_cube + 1;
	glNewList(g_floor, GL_COMPILE);
		glBegin(GL_QUADS);
			glTexCoord2f(2.0f, 2.0f); glVertex3f(-g_cubeSize, -g_cubeSize, -g_cubeSize);	// Top Right Of The Texture and Quad
			glTexCoord2f(0.0f, 2.0f); glVertex3f(-g_cubeSize, -g_cubeSize, g_cubeSize);	// Top Left Of The Texture and Quad
			glTexCoord2f(0.0f, 0.0f); glVertex3f(g_cubeSize, -g_cubeSize, g_cubeSize);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(2.0f, 0.0f); glVertex3f(g_cubeSize, -g_cubeSize, -g_cubeSize);
		glEnd();
	glEndList();

} // end of setupList()

void drawLevel()
{
	// this places all of the geometry into the level based on maze.dat

	int sizeX, sizeY;  // used to hold the size of the maze
	
	char elementValue; // used to see which type of block should be rendered

	// get the size of the maze
	g_level.getSize(sizeX, sizeY);

	// set the matrix mode to modelview, just in case
	// Had problem with glLoadIdenity() after this statement, as
	// nothing would render correctly
	glMatrixMode(GL_MODELVIEW);
	

	for (int x = 0; x < sizeY; x++)
	{
		
		for(int y = 0; y < sizeX; y++)
		{
			elementValue = g_level.getElement(y, x);

			switch(elementValue){
			// is this a floor?
			case ' ':
			case 'x':
			case '*':
			{
				glPushMatrix();
				glEnable(GL_TEXTURE_2D);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
				glTranslatef(GLfloat(y*g_cubeFactor), 0.0, GLfloat(x*g_cubeFactor));
				glColor3f(0.5, 0.5, 0.5);
				glBindTexture(GL_TEXTURE_2D, g_Texture[0]);

				glCallList(g_floor);
				glDisable(GL_TEXTURE_2D);
				glPopMatrix();
				break;
			}
			case 'r':
			{
				glPushMatrix();
				glEnable(GL_TEXTURE_2D);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
				
				glTranslatef(GLfloat(y*g_cubeFactor), 0.0, GLfloat(x*g_cubeFactor));
				glColor3f(1.0, 0.0, 0.0);
				glBindTexture(GL_TEXTURE_2D, g_Texture[1]);
				glCallList(g_cube);
				glDisable(GL_TEXTURE_2D);
				glPopMatrix();
				break;
			}
			case 'g':
			{
				glPushMatrix();
				glEnable(GL_TEXTURE_2D);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);


				glTranslatef(GLfloat(y*g_cubeFactor), 0.0, GLfloat(x*g_cubeFactor));
				glColor3f(0.0, 1.0, 0.0);
				glBindTexture(GL_TEXTURE_2D, g_Texture[2]);

				glCallList(g_cube);
				glDisable(GL_TEXTURE_2D);

				glPopMatrix();
				break;
			}
			case 'b':
			{
				glPushMatrix();
				glEnable(GL_TEXTURE_2D);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
				glBindTexture(GL_TEXTURE_2D, g_Texture[3]);


				glTranslatef(GLfloat(y*g_cubeFactor), 0.0, GLfloat(x*g_cubeFactor));
				glColor3f(0.0, 0.0, 1.0);

				glCallList(g_cube);
				glDisable(GL_TEXTURE_2D);
				glPopMatrix();
				break;
			}
			case 'c':
			{
				glPushMatrix();
				glEnable(GL_TEXTURE_2D);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
				glBindTexture(GL_TEXTURE_2D, g_Texture[4]);

				glTranslatef(GLfloat(y*g_cubeFactor), 0.0, GLfloat(x*g_cubeFactor));
				glColor3f(0.0, 1.0, 1.0);
				glCallList(g_cube);
				glDisable(GL_TEXTURE_2D);

				glPopMatrix();
				break;
			}
			case 'm':
			{
				glPushMatrix();
				glEnable(GL_TEXTURE_2D);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
				glBindTexture(GL_TEXTURE_2D, g_Texture[5]);

				glTranslatef(GLfloat(y*g_cubeFactor), 0.0, GLfloat(x*g_cubeFactor));
				glColor3f(1.0, 0.0, 1.0);
				glCallList(g_cube);
				glDisable(GL_TEXTURE_2D);

				glPopMatrix();
				break;
			}
			case 'y':
			{
				glPushMatrix();
				glEnable(GL_TEXTURE_2D);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
				glBindTexture(GL_TEXTURE_2D, g_Texture[6]);

				glTranslatef(GLfloat(y*g_cubeFactor), 0.0, GLfloat(x*g_cubeFactor));
				glColor3f(1.0, 1.0, 0.0);
				glCallList(g_cube);
				glDisable(GL_TEXTURE_2D);
				glPopMatrix();
				break;
			}
			} // end of switch


		}
	}

}	

void movePlayer()
{
// this function looks at currentPos which is used to position
	// the player in the maze.  
	static float animateValueForward = 0.0;
	static float animateValueBackward = 0.0;
	static int animateValueLeft = 0;
	static int animateValueRight = 0;
	

	if(g_movement == UP)
	{	
		if(isValidMove(0)) // not going backwards
		{
			// do the animation of going forward
			if(animateValueForward < (float)g_cubeFactor)
			{
				g_camera.slide(0, 0, -g_speed);
				animateValueForward += g_speed;
			}
			else
			{	
				// change movement flat back to none
				// after end of animation
				g_movement = NONE;
				animateValueForward = 0.0;
				// and change the player position
				updatePlayer(0);
				isEndPoint();
			}
		}
		else // make sure movement is NONE so it's not doing this forever
			// if there can be no movement
			g_movement = NONE;
	}
	else if(g_movement == DOWN)
	{
		// do the same for going backwards
		if(isValidMove(1))
		{
			if(animateValueBackward < (float)g_cubeFactor)
			{
				g_camera.slide(0, 0, g_speed);
				animateValueBackward += g_speed;
			}
			else
			{
				g_movement = NONE;
				animateValueBackward = 0.0;
				updatePlayer(1);
				isEndPoint();
			}
		}
		else
			g_movement = NONE;
		

	}
	else if(g_movement == RIGHT)
	{
		if(animateValueRight < 90)
		{
			g_camera.yaw(g_rotateSpeed);
			animateValueRight += g_rotateSpeed;
		}
		else
		{
			if(g_direction == EAST)
				g_direction = SOUTH;
			else if(g_direction == SOUTH)
				g_direction = WEST;
			else if(g_direction == WEST)
				g_direction = NORTH;
			else if(g_direction == NORTH)
				g_direction = EAST;
			animateValueRight = 0;
			g_movement = NONE;
		}
	}
	else if(g_movement == LEFT)
	{

		if(animateValueLeft < 90)
		{
			g_camera.yaw(-g_rotateSpeed);
			animateValueLeft += g_rotateSpeed;
		}
		else
		{
			if(g_direction == EAST)
				g_direction = NORTH;
			else if(g_direction == NORTH)
				g_direction = WEST;
			else if(g_direction == WEST)
				g_direction = SOUTH;
			else if(g_direction == SOUTH)
				g_direction = EAST;
			animateValueLeft = 0;
			g_movement = NONE;
		}
	}


	
} // end of MovePlayer()

void updatePlayer(int isBackward)
{
// this function simply udates currentPos 

	if(g_direction == EAST && isBackward == 0) // forwards
		currentPos.x++;
	else if(g_direction == EAST && isBackward == 1) // backwards
		currentPos.x--;
	else if(g_direction == WEST && isBackward == 0)
		currentPos.x--;
	else if(g_direction == WEST && isBackward == 1)
		currentPos.x++;
	else if(g_direction == NORTH && isBackward == 0)
		currentPos.y--;
	else if(g_direction == NORTH && isBackward == 1)
		currentPos.y++;
	else if(g_direction == SOUTH && isBackward == 0)
		currentPos.y++;
	else if(g_direction == SOUTH && isBackward == 1)
		currentPos.y--;


} // end of updatePlayer(...)

bool isValidMove(int isBackward)
{
	// this checks with maze to see if move is a wall or floor
	// It takes the currentPos and looks ahead or behind to see
	// if it can moved onto
	char test;
	int newX = currentPos.y;
	int newY = currentPos.x;

	// 
	if(g_direction == EAST && isBackward == 0) // forwards
		newY = currentPos.x + 1;
	else if(g_direction == EAST && isBackward == 1) // backwards
		newY = currentPos.x - 1;
	else if(g_direction == WEST && isBackward == 0)
		newY = currentPos.x - 1;
	else if(g_direction == WEST && isBackward == 1)
		newY = currentPos.x + 1;
	else if(g_direction == NORTH && isBackward == 0)
		newX = currentPos.y - 1;
	else if(g_direction == NORTH && isBackward == 1)
		newX = currentPos.y + 1;
	else if(g_direction == SOUTH && isBackward == 0)
		newX = currentPos.y + 1;
	else if(g_direction == SOUTH && isBackward == 1)
		newX = currentPos.y - 1;


	// grab the element
	test = g_level.getElement(newY, newX);

	// ... and test to see if the space is a movable space
	if(test == ' ' || test == '*' || test == 'x')
		return true;
	else
		return false;

}

void CreateTexture(UINT textureArray[], LPSTR strFileName, int textureID)
{
// This function to load a image from a file and store it as a texture is from
// a tutorial on www.gametutorials.com on how to load textures.  
	AUX_RGBImageRec *pBitmap = NULL;

	// Return from the function if no file name was passed in
	if(!strFileName)
		return;
	
	// We need to load the texture data, so we use a cool API that the glaux.lib offers.
	
	// Load the bitmap and store the data
	pBitmap = auxDIBImageLoad(strFileName);
	
	
	// If we can't load the file, quit!
	if(pBitmap == NULL)
		exit(0);


	// Generate a texture with the associative texture ID stored in the array
	glGenTextures(1, &textureArray[textureID]);


	// Bind the texture to the texture arrays index and init the texture
	glBindTexture(GL_TEXTURE_2D, textureArray[textureID]);


	// Build Mipmaps (builds different versions of the picture for distances - looks better)
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pBitmap->sizeX, pBitmap->sizeY, 
		GL_RGB, GL_UNSIGNED_BYTE, pBitmap->data);

	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR);

	// Now we need to free the bitmap data that we loaded 
	// since openGL stored it as a texture

	if (pBitmap) // If we loaded the bitmap
	{
		if (pBitmap->data)	// If there is texture data
		{
			free(pBitmap->data); // Free the texture data, we don't need it anymore
		}

		free(pBitmap);	// Free the bitmap structure
	}
}

void isEndPoint()
{
	// this function 
	int count;
	point2 tempVar;
	
	for(count = 0; count < g_numOfEnds; count++)
	{
		tempVar = g_level.getEnd(count);
		if((currentPos.x == tempVar.x) && (currentPos.y == tempVar.y))
		{
			cout << "You found the end.  Congratulations!!!!" << endl;
			exit(0);
		}
	}
}
/* dsply_hndlr -- dsply (redraw) handler */
void displayHandler(void)
{	

    modelRedraw();

    glutSwapBuffers();
	glFlush();
    CalculateFrameRate();
}

/* mdl_redraw -- redraw the model */
void modelRedraw(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


	drawLevel();
	movePlayer();

	glutPostRedisplay();

}

/* kbd_hndlr -- keyboard handler */
void keyboardHandler( unsigned char key, int x, int y)
{
    switch (key) {

    case '\033':  /* ESC */
    case 'q':
    case 'Q':
        exit(0);
        break;

	// the movement flag to reflect what type of movement
	// to do
	case 'w': // should be GLUT_KEY_UP
		// here we make sure that the player can only do the
		// certain movement so the player does not get outside
		// the maze
		if(g_movement == NONE)
			g_movement = UP;
		//glutPostRedisplay();
		
		break;

	case 'a': //should be GLUT_KEY_LEFT
		if(g_movement == NONE)
			g_movement = LEFT;
		break;

	case 'd': // should be GLUT_KEY_RIGHT:
		if(g_movement == NONE)
			g_movement = RIGHT;
		break;

	case 's': // should be GLUT_KEY_DOWN:
		if(g_movement == NONE)
			g_movement = DOWN;
		break;

	case 'v':
	case 'V':
		g_FrustPos++;
		if(g_FrustPos > 2)
			g_FrustPos = 0;

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		// cycle through the frustrum setting here
		gluPerspective(FrustArray[g_FrustPos],(GLfloat)g_width/(GLfloat)g_height,
			0.2, 10.0f);

		// and reset the matrix mode to modelview
		glMatrixMode(GL_MODELVIEW);
		break;


    }
}

/* vw_init -- initialize the view */
void viewInit()
{
	
	glClearColor(0.5, 0.5, 1.0, 1.0);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);

	// turn on culling
	glEnable(GL_CULL_FACE);
	// make it look better
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	// test out how anti-alias looks here
	glEnable(GL_LINE_SMOOTH);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);

	// see what fog enabled looks like
	GLfloat fogColor[4] = {0.5, 0.5, 1.0, 1.0};
	/*
	glEnable(GL_FOG);
	glFogi(GL_FOG_MODE, GL_EXP);
	glFogfv(GL_FOG_COLOR, fogColor);
	glFogf(GL_FOG_DENSITY, 0.5);
	glHint(GL_FOG_HINT, GL_NICEST);
	glFogf(GL_FOG_START, 5.0);
	glFogf(GL_FOG_END, 10.0);
*/

	// load the level
	levelInit();

	// position the camera at the start
	g_eye.set(g_start.x*g_cubeFactor, g_yHeight, g_start.y*g_cubeFactor);
	g_look.set(10.0, g_yHeight, g_start.y*g_cubeFactor);
	g_camera.set(g_eye, g_look, g_up);
	
	currentPos.x = g_start.x;
	currentPos.y = g_start.y;

	g_direction = EAST;
	g_movement = NONE;


	
}

void reshape(int w, int h)
{
// this is code from the red book
	glViewport(0, 0,w, h);
	g_width = w;
	g_height = h;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(FrustArray[g_FrustPos],(GLfloat)w/(GLfloat)h, 0.2, 10.0f);

	glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();

}


void CalculateFrameRate()
{
// This function simply calculates the frame rate of the animation.
// I did find this code in a tutorial on www.gametutorials.com which used
// SDL(Simple Directmedia Layer).  I changed the time functions so it would
// work in linux without SDL.  I also put in glutSetWindowTitle for the 
// display of the framerate.

    static float framesPerSecond    = 0.0;
    static float lastTime            = 0.0;
    static char strFrameRate[50] = {0};

    float currentTime = timeGetTime() * 0.001;


     ++framesPerSecond;

   if( currentTime - lastTime > 1.0 )
    {
        lastTime = currentTime;
       sprintf(strFrameRate, "%s Current Frames Per Second: %d", gstr_AppName, int(framesPerSecond));

       glutSetWindowTitle(strFrameRate);

	   framesPerSecond = 0;
    }
}

int main( int argc, char *argv[])
{
	glutInit(&argc, argv);
	// need to use GLUT_DOUBLE for animation
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB );
	// simply the window size
	glutInitWindowSize(500, 500);
	// and the title on the window
	glutCreateWindow(gstr_AppName);

	viewInit();

	glutDisplayFunc(displayHandler);
 	glutReshapeFunc(reshape);

	glutKeyboardFunc(keyboardHandler);
	glutMainLoop();
	return 0;
}

