//Game AI, all walls+ All Detect Collision on Walls + Separate Function + 6 Monsters + 99.1%
#include <windows.h>		// Header File For Windows
#include <math.h>			// Math Library Header File
#include <stdio.h>			// Header File For Standard Input/Output
#include <gl\gl.h>			// Header File For The OpenGL32 Library
#include <gl\glu.h>			// Header File For The GLu32 Library
#include <gl\glaux.h>		// Header File For The Glaux Library
#include <stdlib.h>
#include <mmsystem.h>

#include "main.h"
#include "Md2.h"

#pragma comment( lib, "opengl32.lib")	// Search For OpenGL32.lib While Linking
#pragma comment( lib, "glu32.lib")
#pragma comment( lib, "glaux.lib")
#pragma comment( lib, "winmm.lib")

HDC			hDC=NULL;		// Private GDI Device Context
HGLRC		hRC=NULL;		// Permanent Rendering Context
HWND		hWnd=NULL;		// Holds Our Window Handle
HINSTANCE	hInstance;		// Holds The Instance Of The Application

GLdouble WIDTH;
GLdouble HEIGHT;

bool  keys[256];			// Array Used For The Keyboard Routine
bool  fp;
bool  ip;	
bool active=TRUE;		// Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE;	// Fullscreen Flag Set To Fullscreen Mode By Default
bool gameOver;
bool gameOverOnX;
bool gameOverOnZ;

GLdouble	mouse_x, mouse_y;
GLdouble	mouse_3d_x, mouse_3d_y;
int mouse_wrap_x = 0;
int mouse_wrap_y = 0;
bool invert_mouse = false;  // Used to invert the y-axis for the mouse
GLdouble sensitivity = 64;  // the higher the #, the lower mouse the sensitivity.

const CELL = 256;
#define	MAX_PARTICLES	45
#define	MAX_SHOTS_FIRED	45

#define FILE_NAME  "tris.md2"							// This is the 3D file we will load.
#define TEXTURE_NAME "hobgoblin.bmp"
CLoadMD2 g_LoadMd2;										// This is MD2 class.  This should go in a good model class.
t3DModel g_3DModel;										// This holds the 3D Model info that we load in
typedef struct										
	{ 
		bool  trigger;
		bool  hitStatus;
		int   hitCount;
		float transX;				
		float transXSpeed;
		float transXSpare;
		float transY; 
		float transZ;				
		float transZSpeed;
		float transZSpare;
		float rotateY;				
		float rotateYSpeed;
		float fall;
		float rotateX;				
		float rotateXSpeed;
		float XMultiplier ;  
	}
Monsters;
Monsters Monster[6];

GLdouble	yrot=0;				// Y Rotation

const GLdouble piover180 = 0.0174532925f;
GLdouble XP=0;
GLdouble ZP=0;

GLdouble sceneroty;
GLdouble heading;
GLdouble _heading = 0;
GLdouble zprot;

int frames = 0;

GLdouble FPS = 0;

GLdouble fire_x = 0;
GLdouble fire_y = 10;
GLdouble fire_xp, fire_yp;
GLdouble fire_z = 0;
GLdouble fire_zp = 0;
GLdouble fire_delay = 0;

int shots_fired = 0;

typedef struct							// Create A Structure For Particle
{
	GLdouble	life;					// Particle Life
	GLdouble	fade;					// Fade Speed
	GLdouble	size;					// Fade Speed
	GLdouble	triangle_x1;						// X vertex
	GLdouble	triangle_x2;						// X vertex
	GLdouble	triangle_x3;						// X vertex
	GLdouble	triangle_y1;						// Y vertex
	GLdouble	triangle_y2;						// Y vertex
	GLdouble	triangle_y3;						// Y vertex
	GLdouble	triangle_z1;						// Z vertex
	GLdouble	triangle_z2;						// Z vertex
	GLdouble	triangle_z3;						// Z vertex
	GLdouble	triangle_rotate_x;					// X Rotate
	GLdouble	triangle_rotate_y;					// X Rotate
	GLdouble	triangle_rotate_z;					// X Rotate
	GLdouble	triangle_rotate_xi;					// X Rotate
	GLdouble	triangle_rotate_yi;					// X Rotate
	GLdouble	triangle_rotate_zi;					// X Rotate
	GLdouble	x;						// X Position
	GLdouble	y;						// Y Position
	GLdouble	z;						// Z Position
	GLdouble	xi;						// X Direction
	GLdouble	yi;						// Y Direction
	GLdouble	zi;						// Z Direction
}
particles;							// Particles Structure

particles particle[MAX_PARTICLES][MAX_SHOTS_FIRED];

float m16_kick = 0;
float m16_kicki = 0; 

bool isFire = false;
bool isFireComplete = true;
bool isRicochet = false;

GLdouble BlankNum = 0;

BOOL done=FALSE;								// Bool Variable To Exit Loop
bool isFPS=FALSE;

GLuint	texture[6];

// Absolute value function(comes in handy later).
inline GLdouble ABS(GLdouble A)
{
  if (A < 0)
  A = -A; 
  return A;
}

// Hypotenuse Function
inline GLdouble Hypot(GLdouble a, GLdouble b)
{
  return sqrt((a*a)+(b*b));
}

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);		// Declaration For WndProc
GLvoid KillGLWindow(GLvoid);

typedef struct												// Create A Structure
{
	GLubyte	*imageData;										// Image Data (Up To 32 Bits)
	GLuint	bpp;											// Image Color Depth In Bits Per Pixel.
	GLuint	width;											// Image Width
	GLuint	height;											// Image Height
	GLuint	texID;											// Texture ID Used To Select A Texture
} TextureImage;												// Structure Name

GLuint		base;											// Base Display List For The Font
TextureImage textures[1];	

bool LoadTGA(TextureImage *texture, char *filename)			// Loads A TGA File Into Memory
{    
	GLubyte		TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};	// Uncompressed TGA Header
	GLubyte		TGAcompare[12];								// Used To Compare TGA Header
	GLubyte		header[6];									// First 6 Useful Bytes From The Header
	GLuint		bytesPerPixel;								// Holds Number Of Bytes Per Pixel Used In The TGA File
	GLuint		imageSize;									// Used To Store The Image Size When Setting Aside Ram
	GLuint		temp;										// Temporary Variable
	GLuint		type=GL_RGBA;								// Set The Default GL Mode To RBGA (32 BPP)

	FILE *file = fopen(filename, "rb");						// Open The TGA File

	if(	file==NULL ||										// Does File Even Exist?
		fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare) ||	// Are There 12 Bytes To Read?
		memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0				||	// Does The Header Match What We Want?
		fread(header,1,sizeof(header),file)!=sizeof(header))				// If So Read Next 6 Header Bytes
	{
		if (file == NULL)									// Did The File Even Exist? *Added Jim Strong*
			return false;									// Return False
		else
		{
			fclose(file);									// If Anything Failed, Close The File
			return false;									// Return False
		}
	}

	texture->width  = header[1] * 256 + header[0];			// Determine The TGA Width	(highbyte*256+lowbyte)
	texture->height = header[3] * 256 + header[2];			// Determine The TGA Height	(highbyte*256+lowbyte)
    
 	if(	texture->width	<=0	||								// Is The Width Less Than Or Equal To Zero
		texture->height	<=0	||								// Is The Height Less Than Or Equal To Zero
		(header[4]!=24 && header[4]!=32))					// Is The TGA 24 or 32 Bit?
	{
		fclose(file);										// If Anything Failed, Close The File
		return false;										// Return False
	}

	texture->bpp	= header[4];							// Grab The TGA's Bits Per Pixel (24 or 32)
	bytesPerPixel	= texture->bpp/8;						// Divide By 8 To Get The Bytes Per Pixel
	imageSize		= texture->width*texture->height*bytesPerPixel;	// Calculate The Memory Required For The TGA Data

	texture->imageData=(GLubyte *)malloc(imageSize);		// Reserve Memory To Hold The TGA Data

	if(	texture->imageData==NULL ||							// Does The Storage Memory Exist?
		fread(texture->imageData, 1, imageSize, file)!=imageSize)	// Does The Image Size Match The Memory Reserved?
	{
		if(texture->imageData!=NULL)						// Was Image Data Loaded
			free(texture->imageData);						// If So, Release The Image Data

		fclose(file);										// Close The File
		return false;										// Return False
	}

	for(GLuint i=0; i<int(imageSize); i+=bytesPerPixel)		// Loop Through The Image Data
	{														// Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
		temp=texture->imageData[i];							// Temporarily Store The Value At Image Data 'i'
		texture->imageData[i] = texture->imageData[i + 2];	// Set The 1st Byte To The Value Of The 3rd Byte
		texture->imageData[i + 2] = temp;					// Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
	}

	fclose (file);											// Close The File

	// Build A Texture From The Data
	glGenTextures(1, &texture[0].texID);					// Generate OpenGL texture IDs

	glBindTexture(GL_TEXTURE_2D, texture[0].texID);			// Bind Our Texture
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	// Linear Filtered
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);	// Linear Filtered
	
	if (texture[0].bpp==24)									// Was The TGA 24 Bits
	{
		type=GL_RGB;										// If So Set The 'type' To GL_RGB
	}

   	gluBuild2DMipmaps(GL_TEXTURE_2D, type, texture[0].width, texture[0].height, type, GL_UNSIGNED_BYTE, texture[0].imageData);           

	return true;											// Texture Building Went Ok, Return True
}

GLvoid BuildFont(GLvoid)									// Build Our Font Display List
{
	base=glGenLists(256);									// Creating 256 Display Lists
	glBindTexture(GL_TEXTURE_2D, textures[0].texID);		// Select Our Font Texture
	for (int loop1=0; loop1<256; loop1++)					// Loop Through All 256 Lists
	{
		float cx=float(loop1%16)/16.0f;						// X Position Of Current Character
		float cy=float(loop1/16)/16.0f;						// Y Position Of Current Character

		glNewList(base+loop1,GL_COMPILE);					// Start Building A List
			glBegin(GL_QUADS);								// Use A Quad For Each Character
				glTexCoord2f(cx,1.0f-cy-0.0625f);			// Texture Coord (Bottom Left)
				glVertex2d(0,16);							// Vertex Coord (Bottom Left)
				glTexCoord2f(cx+0.0625f,1.0f-cy-0.0625f);	// Texture Coord (Bottom Right)
				glVertex2i(16,16);							// Vertex Coord (Bottom Right)
				glTexCoord2f(cx+0.0625f,1.0f-cy-0.001f);	// Texture Coord (Top Right)
				glVertex2i(16,0);							// Vertex Coord (Top Right)
				glTexCoord2f(cx,1.0f-cy-0.001f);			// Texture Coord (Top Left)
				glVertex2i(0,0);							// Vertex Coord (Top Left)
			glEnd();										// Done Building Our Quad (Character)
			glTranslated(14,0,0);							// Move To The Right Of The Character
		glEndList();										// Done Building The Display List
	}														// Loop Until All 256 Are Built
}

GLvoid KillFont(GLvoid)										// Delete The Font From Memory
{
	glDeleteLists(base,256);								// Delete All 256 Display Lists
}

GLvoid glPrint(GLint x, GLint y, int set, const char *fmt, ...)	// Where The Printing Happens
{
	char		text[1024];									// Holds Our String
	va_list		ap;											// Pointer To List Of Arguments

	if (fmt == NULL)										// If There's No Text
		return;												// Do Nothing

	va_start(ap, fmt);										// Parses The String For Variables
	    vsprintf(text, fmt, ap);							// And Converts Symbols To Actual Numbers
	va_end(ap);												// Results Are Stored In Text

	if (set>1)												// Did User Choose An Invalid Character Set?
	{
		set=1;												// If So, Select Set 1 (Italic)
	}

	glEnable(GL_TEXTURE_2D);								// Enable Texture Mapping
	glLoadIdentity();										// Reset The Modelview Matrix
	glTranslated(x,y,-500);									// Position The Text (0,0 - Top Left)
	glRotatef(180,0,0,1);
	glRotatef(180,0,1,0);
	glListBase(base-32+(128*set));							// Choose The Font Set (0 or 1)

	glCallLists(strlen(text),GL_UNSIGNED_BYTE, text);		// Write The Text To The Screen
	glDisable(GL_TEXTURE_2D);								// Disable Texture Mapping
}

AUX_RGBImageRec *LoadBMP(char *Filename)				// Loads A Bitmap Image
{
	FILE *File=NULL;									// File Handle

	if (!Filename)										// Make Sure A Filename Was Given
	{
		return NULL;									// If Not Return NULL
	}

	File=fopen(Filename,"r");							// Check To See If The File Exists

	if (File)											// Does The File Exist?
	{
		fclose(File);									// Close The Handle
		return auxDIBImageLoad(Filename);				// Load The Bitmap And Return A Pointer
	}

	return NULL;										// If Load Failed Return NULL
}

// Create A Structure For The Timer Information
struct
{
  __int64       frequency;          // Timer Frequency
  GLdouble            resolution;          // Timer Resolution
  unsigned long mm_timer_start;     
  
  // Multimedia Timer Start Value
  unsigned long mm_timer_elapsed;      // Multimedia Timer Elapsed Time
  bool   performance_timer;    
  
  // Using The Performance Timer?
  __int64       performance_timer_start;      // Performance Timer Start Value
  __int64       performance_timer_elapsed; // Performance Timer Elapsed Time
} timer;

// Initialize Our Timer
void TimerInit(void)
{
     memset(&timer, 0, sizeof(timer));   
 // Clear Our Timer Structure
     // Check To See If A Performance Counter Is Available
     // If One Is Available The Timer Frequency Will Be Updated
     if (!QueryPerformanceFrequency((LARGE_INTEGER *) &timer.frequency))
     {
          // No Performace Counter Available
          timer.performance_timer = FALSE;                      // Set Performance Timer To FALSE
          timer.mm_timer_start = timeGetTime();                 // Use timeGetTime()
          timer.resolution  = 1.0f/1000.0f;                           // Set Our Timer Resolution To .001f
          timer.frequency   = 1000;                                     // Set Our Timer Frequency To 1000
          timer.mm_timer_elapsed = timer.mm_timer_start; // Set The Elapsed Time
     }
     else
     {
          // Performance Counter Is Available, Use It Instead Of The Multimedia Timer
          // Get The Current Time And Store It In performance_timer_start
          QueryPerformanceCounter((LARGE_INTEGER *) &timer.performance_timer_start);
          timer.performance_timer   = TRUE;    // Set Performance Timer To TRUE
          // Calculate The Timer Resolution Using The Timer Frequency
          timer.resolution    = (GLdouble) (((double)1.0f)/((double)timer.frequency));
          // Set The Elapsed Time To The Current Time
          timer.performance_timer_elapsed = timer.performance_timer_start;
     }
}

// Get Time In Milliseconds
inline GLdouble TimerGetTime()
{
  __int64 time;                                  // 'time' Will Hold A 64 Bit Integer
  if (timer.performance_timer)           // Are We Using The Performance Timer?
  {
    QueryPerformanceCounter((LARGE_INTEGER *) &time); // Current Performance Time
    // Return The Time Elapsed since TimerInit was called
    return ( (GLdouble) ( time - timer.performance_timer_start) * timer.resolution)*1000.0f;
  }
  else
  {
    // Return The Time Elapsed since TimerInit was called
    return ( (GLdouble) ( timeGetTime() - timer.mm_timer_start) * timer.resolution)*1000.0f;
  }
}

int LoadGLTextures()									// Load Bitmap And Convert To A Texture
{
  int Status=FALSE;								// Status Indicator
  AUX_RGBImageRec *TextureImage[1];				// Create Storage Space For The Textures
  memset(TextureImage,0,sizeof(void *)*1);		// Set The Pointer To NULL

  if (TextureImage[0]=LoadBMP("Data/walls.bmp"))	// Load Particle Texture
  {
    Status=TRUE;								// Set The Status To TRUE
    glGenTextures(1, &texture[1]);				// Create One Texture

    // Create MipMapped Texture
    glBindTexture(GL_TEXTURE_2D, texture[1]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);           
  }

  if (TextureImage[0]=LoadBMP("Data/crosshair.bmp"))	// Load Particle Texture
  {
    Status=TRUE;								// Set The Status To TRUE
    glGenTextures(1, &texture[2]);				// Create One Texture

    // Create MipMapped Texture
    glBindTexture(GL_TEXTURE_2D, texture[2]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);           
  }

  if (TextureImage[0]=LoadBMP("Data/smoke.bmp"))	// Load Particle Texture
  {
    Status=TRUE;								// Set The Status To TRUE
    glGenTextures(1, &texture[3]);				// Create One Texture

    // Create MipMapped Texture
    glBindTexture(GL_TEXTURE_2D, texture[3]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);           
  }

  if (TextureImage[0]=LoadBMP("hobgoblin.bmp"))	// Load Particle Texture
  {
    Status=TRUE;								// Set The Status To TRUE
    glGenTextures(1, &texture[4]);				// Create One Texture

    // Create MipMapped Texture
    glBindTexture(GL_TEXTURE_2D, texture[4]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);           
  }

  if (TextureImage[0]=LoadBMP("Data/exit.bmp"))	// Load Particle Texture
  {
    Status=TRUE;								// Set The Status To TRUE
    glGenTextures(1, &texture[5]);				// Create One Texture

    // Create MipMapped Texture
    glBindTexture(GL_TEXTURE_2D, texture[5]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);           
  }

  if (TextureImage[0]=LoadBMP("Data/floor.bmp"))	// Load Particle Texture
  {
    Status=TRUE;								// Set The Status To TRUE
    glGenTextures(1, &texture[6]);				// Create One Texture

    // Create MipMapped Texture
    glBindTexture(GL_TEXTURE_2D, texture[6]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);           
  }

  if (TextureImage[0])							// If Texture Exists
	{
    if (TextureImage[0]->data)					// If Texture Image Exists
    {
      free(TextureImage[0]->data);			// Free The Texture Image Memory
    }
    free(TextureImage[0]);						// Free The Image Structure
  }

  return Status;									// Return The Status
}

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		// Resize And Initialize The GL Window
{
	if (height==0)										// Prevent A Divide By Zero By
	{
		height=1;										// Making Height Equal One
	}

	WIDTH=width;
	HEIGHT=height;
	glViewport(0,0,width,height);						// Reset The Current Viewport

	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glLoadIdentity();									// Reset The Projection Matrix

	// Calculate The Aspect Ratio Of The Window
	glLoadIdentity();									// Reset The Modelview Matrix
	gluPerspective(60.0f,(GLdouble)width/(GLdouble)height,1.0f,1250.0f);

	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
	glLoadIdentity();									// Reset The Modelview Matrix
}

static GLuint	ROOM[18], MODEL;				// Storage For The Room Display List

GLdouble xtrans2 = CELL*5-40.0f;				// fail if 80.0f?
GLdouble ytrans2 = 10;
GLdouble ztrans2 = CELL*7-40.0f;

GLdouble xtrans = 0;
GLdouble ztrans = 0;

// Build Cube Display Lists
GLvoid BuildLists()
{ 
	ROOM[0]=glGenLists(18);									// IDENTITY[IJ=1 1], Generate 18 Different Lists
    glNewList(ROOM[0],GL_COMPILE);							// Start With The Box List
    
		glBindTexture(GL_TEXTURE_2D, texture[6]); 
   
		glBegin(GL_QUADS);//bottom
		glTexCoord2d(20,28);  glVertex3d(CELL*5,0,CELL*7);
		glTexCoord2d(20,0);  glVertex3d(CELL*5,0,0);
		glTexCoord2d(0,0);  glVertex3d(0,0,0);
		glTexCoord2d(0,28);  glVertex3d(0,0,CELL*7);
		glEnd();

		glBegin(GL_QUADS);//top
		glTexCoord2d(20,28);  glVertex3d(CELL*5,CELL/4,CELL*7);
		glTexCoord2d(20,0);  glVertex3d(CELL*5,CELL/4,0);
		glTexCoord2d(0,0);  glVertex3d(0,CELL/4,0);
		glTexCoord2d(0,28);  glVertex3d(0,CELL/4,CELL*7);
		glEnd(); 
/////////////////////////Wall Start///////////////////////////////////	
	 
		glBindTexture(GL_TEXTURE_2D, texture[1]); 
		glBegin(GL_QUADS);//front
		glTexCoord2d(4,1);  glVertex3d(CELL*5,CELL/4,CELL*6);
		glTexCoord2d(4,0);  glVertex3d(CELL*5,0,CELL*6);
		glTexCoord2d(0,0);  glVertex3d(CELL*4,0,CELL*6);
		glTexCoord2d(0,1);  glVertex3d(CELL*4,CELL/4,CELL*6);
		glEnd();

		glBegin(GL_QUADS);//back
		glTexCoord2d(4,1);  glVertex3d(CELL*5,CELL/4,CELL*7);
		glTexCoord2d(4,0);  glVertex3d(CELL*5,0,CELL*7);
		glTexCoord2d(0,0);  glVertex3d(CELL*4,0,CELL*7);
		glTexCoord2d(0,1);  glVertex3d(CELL*4,CELL/4,CELL*7);
		glEnd();
	
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL*5,CELL/4,CELL*7);
		glTexCoord2d(4,0);  glVertex3d(CELL*5,0,CELL*7);
		glTexCoord2d(0,0);  glVertex3d(CELL*5,0,CELL*6);
		glTexCoord2d(0,1);  glVertex3d(CELL*5,CELL/4,CELL*6);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[1]=ROOM[0]+1;//IDENTITY[IJ=2 1]
	glNewList(ROOM[1],GL_COMPILE);
	 
		glBegin(GL_QUADS);//back
		glTexCoord2d(4,1);  glVertex3d(CELL*4,CELL/4,CELL*7);
		glTexCoord2d(4,0);  glVertex3d(CELL*4,0,CELL*7);
		glTexCoord2d(0,0);  glVertex3d(CELL*3,0,CELL*7);
		glTexCoord2d(0,1);  glVertex3d(CELL*3,CELL/4,CELL*7);
		glEnd();
	
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL*3,CELL/4,CELL*7);
		glTexCoord2d(4,0);  glVertex3d(CELL*3,0,CELL*7);
		glTexCoord2d(0,0);  glVertex3d(CELL*3,0,CELL*6);
		glTexCoord2d(0,1);  glVertex3d(CELL*3,CELL/4,CELL*6);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[2]=ROOM[1]+1;//IDENTITY[IJ=2 2]
	glNewList(ROOM[2],GL_COMPILE);  
 
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL*4,CELL/4,CELL*6);
		glTexCoord2d(4,0);  glVertex3d(CELL*4,0,CELL*6);
		glTexCoord2d(0,0);  glVertex3d(CELL*4,0,CELL*5);
		glTexCoord2d(0,1);  glVertex3d(CELL*4,CELL/4,CELL*5);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[3]=ROOM[2]+1;//IDENTITY[IJ=2 3]
	glNewList(ROOM[3],GL_COMPILE); 	
	 
		glBegin(GL_QUADS);//left
		glTexCoord2d(4,1);  glVertex3d(CELL*3,CELL/4,CELL*5);
		glTexCoord2d(4,0);  glVertex3d(CELL*3,0,CELL*5);
		glTexCoord2d(0,0);  glVertex3d(CELL*3,0,CELL*4);
		glTexCoord2d(0,1);  glVertex3d(CELL*3,CELL/4,CELL*4);
		glEnd();  
	
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL*4,CELL/4,CELL*5);
		glTexCoord2d(4,0);  glVertex3d(CELL*4,0,CELL*5);
		glTexCoord2d(0,0);  glVertex3d(CELL*4,0,CELL*4);
		glTexCoord2d(0,1);  glVertex3d(CELL*4,CELL/4,CELL*4);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[4]=ROOM[3]+1;//IDENTITY[IJ=2 4]
	glNewList(ROOM[4],GL_COMPILE); 
 
		glBegin(GL_QUADS);//front
		glTexCoord2d(4,1);  glVertex3d(CELL*4,CELL/4,CELL*3);
		glTexCoord2d(4,0);  glVertex3d(CELL*4,0,CELL*3);
		glTexCoord2d(0,0);  glVertex3d(CELL*3,0,CELL*3);
		glTexCoord2d(0,1);  glVertex3d(CELL*3,CELL/4,CELL*3);
		glEnd(); 
	
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL*4,CELL/4,CELL*4);
		glTexCoord2d(4,0);  glVertex3d(CELL*4,0,CELL*4);
		glTexCoord2d(0,0);  glVertex3d(CELL*4,0,CELL*3);
		glTexCoord2d(0,1);  glVertex3d(CELL*4,CELL/4,CELL*3);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[4]=ROOM[3]+1;//IDENTITY[IJ=2 4]
	glNewList(ROOM[4],GL_COMPILE); 
 
		glBegin(GL_QUADS);//front
		glTexCoord2d(4,1);  glVertex3d(CELL*4,CELL/4,CELL*3);
		glTexCoord2d(4,0);  glVertex3d(CELL*4,0,CELL*3);
		glTexCoord2d(0,0);  glVertex3d(CELL*3,0,CELL*3);
		glTexCoord2d(0,1);  glVertex3d(CELL*3,CELL/4,CELL*3);
		glEnd(); 
	
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL*4,CELL/4,CELL*4);
		glTexCoord2d(4,0);  glVertex3d(CELL*4,0,CELL*4);
		glTexCoord2d(0,0);  glVertex3d(CELL*4,0,CELL*3);
		glTexCoord2d(0,1);  glVertex3d(CELL*4,CELL/4,CELL*3);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[5]=ROOM[4]+1;//IDENTITY[IJ=3 2]
	glNewList(ROOM[5],GL_COMPILE); 
 
		glBegin(GL_QUADS);//front
		glTexCoord2d(4,1);  glVertex3d(CELL*3,CELL/4,CELL*5);
		glTexCoord2d(4,0);  glVertex3d(CELL*3,0,CELL*5);
		glTexCoord2d(0,0);  glVertex3d(CELL*2,0,CELL*5);
		glTexCoord2d(0,1);  glVertex3d(CELL*2,CELL/4,CELL*5);
		glEnd(); 
	
		glBegin(GL_QUADS);//back
		glTexCoord2d(4,1);  glVertex3d(CELL*3,CELL/4,CELL*6);
		glTexCoord2d(4,0);  glVertex3d(CELL*3,0,CELL*6);
		glTexCoord2d(0,0);  glVertex3d(CELL*2,0,CELL*6);
		glTexCoord2d(0,1);  glVertex3d(CELL*2,CELL/4,CELL*6);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[6]=ROOM[5]+1;//IDENTITY[IJ=3 4]
	glNewList(ROOM[6],GL_COMPILE); 
 
		glBegin(GL_QUADS);//back
		glTexCoord2d(4,1);  glVertex3d(CELL*3,CELL/4,CELL*4);
		glTexCoord2d(4,0);  glVertex3d(CELL*3,0,CELL*4);
		glTexCoord2d(0,0);  glVertex3d(CELL*2,0,CELL*4);
		glTexCoord2d(0,1);  glVertex3d(CELL*2,CELL/4,CELL*4);
		glEnd();  
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[7]=ROOM[6]+1;//IDENTITY[IJ=3 5]
	glNewList(ROOM[7],GL_COMPILE); 
 
		glBegin(GL_QUADS);//left
		glTexCoord2d(4,1);  glVertex3d(CELL*2,CELL/4,CELL*3);
		glTexCoord2d(4,0);  glVertex3d(CELL*2,0,CELL*3);
		glTexCoord2d(0,0);  glVertex3d(CELL*2,0,CELL*2);
		glTexCoord2d(0,1);  glVertex3d(CELL*2,CELL/4,CELL*2);
		glEnd(); 
	
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL*3,CELL/4,CELL*3);
		glTexCoord2d(4,0);  glVertex3d(CELL*3,0,CELL*3);
		glTexCoord2d(0,0);  glVertex3d(CELL*3,0,CELL*2);
		glTexCoord2d(0,1);  glVertex3d(CELL*3,CELL/4,CELL*2);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[8]=ROOM[7]+1;//IDENTITY[IJ=3 6]
	glNewList(ROOM[8],GL_COMPILE); 
 
		glBegin(GL_QUADS);//front
		glTexCoord2d(4,1);  glVertex3d(CELL*3,CELL/4,CELL);
		glTexCoord2d(4,0);  glVertex3d(CELL*3,0,CELL);
		glTexCoord2d(0,0);  glVertex3d(CELL*2,0,CELL);
		glTexCoord2d(0,1);  glVertex3d(CELL*2,CELL/4,CELL);
		glEnd(); 

		glBegin(GL_QUADS);//left
		glTexCoord2d(4,1);  glVertex3d(CELL*2,CELL/4,CELL*2);
		glTexCoord2d(4,0);  glVertex3d(CELL*2,0,CELL*2);
		glTexCoord2d(0,0);  glVertex3d(CELL*2,0,CELL);
		glTexCoord2d(0,1);  glVertex3d(CELL*2,CELL/4,CELL);
		glEnd(); 
	
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL*3,CELL/4,CELL*2);
		glTexCoord2d(4,0);  glVertex3d(CELL*3,0,CELL*2);
		glTexCoord2d(0,0);  glVertex3d(CELL*3,0,CELL);
		glTexCoord2d(0,1);  glVertex3d(CELL*3,CELL/4,CELL);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[9]=ROOM[8]+1;//IDENTITY[IJ=4 2]
	glNewList(ROOM[9],GL_COMPILE); 
 
		glBegin(GL_QUADS);//front
		glTexCoord2d(4,1);  glVertex3d(CELL*2,CELL/4,CELL*5);
		glTexCoord2d(4,0);  glVertex3d(CELL*2,0,CELL*5);
		glTexCoord2d(0,0);  glVertex3d(CELL,0,CELL*5);
		glTexCoord2d(0,1);  glVertex3d(CELL,CELL/4,CELL*5);
		glEnd(); 
	
		glBegin(GL_QUADS);//back
		glTexCoord2d(4,1);  glVertex3d(CELL*2,CELL/4,CELL*6);
		glTexCoord2d(4,0);  glVertex3d(CELL*2,0,CELL*6);
		glTexCoord2d(0,0);  glVertex3d(CELL,0,CELL*6);
		glTexCoord2d(0,1);  glVertex3d(CELL,CELL/4,CELL*6);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[10]=ROOM[9]+1;//IDENTITY[IJ=4 4]
	glNewList(ROOM[10],GL_COMPILE); 
 
		glBegin(GL_QUADS);//front
		glTexCoord2d(4,1);  glVertex3d(CELL*2,CELL/4,CELL*3);
		glTexCoord2d(4,0);  glVertex3d(CELL*2,0,CELL*3);
		glTexCoord2d(0,0);  glVertex3d(CELL,0,CELL*3);
		glTexCoord2d(0,1);  glVertex3d(CELL,CELL/4,CELL*3);
		glEnd(); 
	
		glBegin(GL_QUADS);//back
		glTexCoord2d(4,1);  glVertex3d(CELL*2,CELL/4,CELL*4);
		glTexCoord2d(4,0);  glVertex3d(CELL*2,0,CELL*4);
		glTexCoord2d(0,0);  glVertex3d(CELL,0,CELL*4);
		glTexCoord2d(0,1);  glVertex3d(CELL,CELL/4,CELL*4);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[11]=ROOM[10]+1;//IDENTITY[IJ=4 6]
	glNewList(ROOM[11],GL_COMPILE); 
 
		glBegin(GL_QUADS);//back
		glTexCoord2d(4,1);  glVertex3d(CELL*2,CELL/4,CELL*2);
		glTexCoord2d(4,0);  glVertex3d(CELL*2,0,CELL*2);
		glTexCoord2d(0,0);  glVertex3d(CELL,0,CELL*2);
		glTexCoord2d(0,1);  glVertex3d(CELL,CELL/4,CELL*2);
		glEnd(); 
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[12]=ROOM[11]+1;//IDENTITY[IJ=4 7]
	glNewList(ROOM[12],GL_COMPILE); 

		glBindTexture(GL_TEXTURE_2D, texture[5]); 
		glBegin(GL_QUADS);//front
		glTexCoord2d(1,1);  glVertex3d(CELL*2-CELL*3/8,CELL/4,0);
		glTexCoord2d(1,0);  glVertex3d(CELL*2-CELL*3/8,0,0);
		glTexCoord2d(0,0);  glVertex3d(CELL+CELL*3/8,0,0);
		glTexCoord2d(0,1);  glVertex3d(CELL+CELL*3/8,CELL/4,0);
		glEnd(); 
 
		glBindTexture(GL_TEXTURE_2D, texture[1]);		
		glBegin(GL_QUADS);//front left
		glTexCoord2d(1.5,1);  glVertex3d(CELL+CELL*3/8,CELL/4,0);
		glTexCoord2d(1.5,0);  glVertex3d(CELL+CELL*3/8,0,0);
		glTexCoord2d(0,0);  glVertex3d(CELL,0,0);
		glTexCoord2d(0,1);  glVertex3d(CELL,CELL/4,0);
		glEnd();
	
		glBegin(GL_QUADS);//front right
		glTexCoord2d(1.5,1);  glVertex3d(CELL*2,CELL/4,0);
		glTexCoord2d(1.5,0);  glVertex3d(CELL*2,0,0);
		glTexCoord2d(0,0);  glVertex3d(CELL*2-CELL*3/8,0,0);
		glTexCoord2d(0,1);  glVertex3d(CELL*2-CELL*3/8,CELL/4,0);
		glEnd();

		glBegin(GL_QUADS);//left
		glTexCoord2d(4,1);  glVertex3d(CELL,CELL/4,CELL);
		glTexCoord2d(4,0);  glVertex3d(CELL,0,CELL);
		glTexCoord2d(0,0);  glVertex3d(CELL,0,0);
		glTexCoord2d(0,1);  glVertex3d(CELL,CELL/4,0);
		glEnd();  

		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL*2,CELL/4,CELL);
		glTexCoord2d(4,0);  glVertex3d(CELL*2,0,CELL);
		glTexCoord2d(0,0);  glVertex3d(CELL*2,0,0);
		glTexCoord2d(0,1);  glVertex3d(CELL*2,CELL/4,0);
		glEnd();

/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[13]=ROOM[12]+1;//IDENTITY[IJ=5 2]
	glNewList(ROOM[13],GL_COMPILE); 
 
		glBegin(GL_QUADS);//back
		glTexCoord2d(4,1);  glVertex3d(CELL,CELL/4,CELL*6);
		glTexCoord2d(4,0);  glVertex3d(CELL,0,CELL*6);
		glTexCoord2d(0,0);  glVertex3d(0,0,CELL*6);
		glTexCoord2d(0,1);  glVertex3d(0,CELL/4,CELL*6);
		glEnd(); 

		glBegin(GL_QUADS);//left
		glTexCoord2d(4,1);  glVertex3d(0,CELL/4,CELL*6);
		glTexCoord2d(4,0);  glVertex3d(0,0,CELL*6);
		glTexCoord2d(0,0);  glVertex3d(0,0,CELL*5);
		glTexCoord2d(0,1);  glVertex3d(0,CELL/4,CELL*5);
		glEnd();  
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[14]=ROOM[13]+1;//IDENTITY[IJ=5 3]
	glNewList(ROOM[14],GL_COMPILE); 
 
		glBegin(GL_QUADS);//front
		glTexCoord2d(4,1);  glVertex3d(CELL,CELL/4,CELL*4);
		glTexCoord2d(4,0);  glVertex3d(CELL,0,CELL*4);
		glTexCoord2d(0,0);  glVertex3d(0,0,CELL*4);
		glTexCoord2d(0,1);  glVertex3d(0,CELL/4,CELL*4);
		glEnd(); 

		glBegin(GL_QUADS);//left
		glTexCoord2d(4,1);  glVertex3d(0,CELL/4,CELL*5);
		glTexCoord2d(4,0);  glVertex3d(0,0,CELL*5);
		glTexCoord2d(0,0);  glVertex3d(0,0,CELL*4);
		glTexCoord2d(0,1);  glVertex3d(0,CELL/4,CELL*4);
		glEnd(); 
	
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL,CELL/4,CELL*5);
		glTexCoord2d(4,0);  glVertex3d(CELL,0,CELL*5);
		glTexCoord2d(0,0);  glVertex3d(CELL,0,CELL*4);
		glTexCoord2d(0,1);  glVertex3d(CELL,CELL/4,CELL*4);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[15]=ROOM[14]+1;//IDENTITY[IJ=5 4]
	glNewList(ROOM[15],GL_COMPILE); 
 
		glBegin(GL_QUADS);//left
		glTexCoord2d(4,1);  glVertex3d(0,CELL/4,CELL*4);
		glTexCoord2d(4,0);  glVertex3d(0,0,CELL*4);
		glTexCoord2d(0,0);  glVertex3d(0,0,CELL*3);
		glTexCoord2d(0,1);  glVertex3d(0,CELL/4,CELL*3);
		glEnd();  
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[16]=ROOM[15]+1;//IDENTITY[IJ=5 5]
	glNewList(ROOM[16],GL_COMPILE); 
 
		glBegin(GL_QUADS);//left
		glTexCoord2d(4,1);  glVertex3d(0,CELL/4,CELL*3);
		glTexCoord2d(4,0);  glVertex3d(0,0,CELL*3);
		glTexCoord2d(0,0);  glVertex3d(0,0,CELL*2);
		glTexCoord2d(0,1);  glVertex3d(0,CELL/4,CELL*2);
		glEnd(); 
	
		glBegin(GL_QUADS);//right
		glTexCoord2d(4,1);  glVertex3d(CELL,CELL/4,CELL*3);
		glTexCoord2d(4,0);  glVertex3d(CELL,0,CELL*3);
		glTexCoord2d(0,0);  glVertex3d(CELL,0,CELL*2);
		glTexCoord2d(0,1);  glVertex3d(CELL,CELL/4,CELL*2);
		glEnd();
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	ROOM[17]=ROOM[16]+1;//IDENTITY[IJ=5 6]
	glNewList(ROOM[17],GL_COMPILE); 
 
		glBegin(GL_QUADS);//front
		glTexCoord2d(4,1);  glVertex3d(CELL,CELL/4,CELL);
		glTexCoord2d(4,0);  glVertex3d(CELL,0,CELL);
		glTexCoord2d(0,0);  glVertex3d(0,0,CELL);
		glTexCoord2d(0,1);  glVertex3d(0,CELL/4,CELL);
		glEnd(); 

		glBegin(GL_QUADS);//left
		glTexCoord2d(4,1);  glVertex3d(0,CELL/4,CELL*2);
		glTexCoord2d(4,0);  glVertex3d(0,0,CELL*2);
		glTexCoord2d(0,0);  glVertex3d(0,0,CELL);
		glTexCoord2d(0,1);  glVertex3d(0,CELL/4,CELL);
		glEnd();  
/////////////////////////Wall End///////////////////////////////////	
    glEndList();

	//glEnable(GL_BLEND);
}

GLvoid BuildLists1()
{
	MODEL=glGenLists(1);									// Generate 2 Different Lists
    glNewList(MODEL,GL_COMPILE);							// Start With The Box List
glDisable(GL_BLEND);
	//////////// *** NEW *** ////////// *** NEW *** ///////////// *** NEW *** ////////////////////
glBindTexture(GL_TEXTURE_2D, texture[4]);
	if(g_3DModel.pObject.size() > 0)
	{
		// Get the current object that we are displaying
		t3DObject *pObject = &g_3DModel.pObject[0];

		// Render lines or normal triangles mode, depending on the global variable
		glBegin(GL_TRIANGLES);

		// Go through all of the faces (polygons) of the object and draw them
		for(int j = 0; j < pObject->numOfFaces; j++)
		{
			// Go through each corner of the triangle and draw it.
			for(int whichVertex = 0; whichVertex < 3; whichVertex++)
			{
				// Get the index for each point in the face
				int index = pObject->pFaces[j].vertIndex[whichVertex];

				// Get the index for each texture coord in the face
				int index2 = pObject->pFaces[j].coordIndex[whichVertex];
			
				// Give OpenGL the normal for this vertex.  Notice that we put a 
				// - sign in front.  It appears that because of the ordering of Quake2's
				// polygons, we need to invert the normal
				glNormal3f(-pObject->pNormals[ index ].x, -pObject->pNormals[ index ].y, -pObject->pNormals[ index ].z);
					
				// Make sure there was a UVW map applied to the object or else it won't have tex coords.
				if(pObject->pTexVerts) 
				{
					glTexCoord2f(pObject->pTexVerts[ index2 ].x, pObject->pTexVerts[ index2 ].y);
				}
				
				// Pass in the current vertex of the object (Corner of current face)
				glVertex3f(pObject->pVerts[ index ].x, pObject->pVerts[ index ].y, pObject->pVerts[ index ].z);
			}
		}

		glEnd();
	}
glEnable(GL_BLEND);
	glEndList();
}

GLdouble Time1;
GLdouble Time2;
GLdouble DiffTime;
GLdouble StartTime;
LPARAM lParam;

int InitGL(GLvoid)										// All Setup For OpenGL Goes Here
{
	if (!g_LoadMd2.ImportMD2(&g_3DModel, FILE_NAME, TEXTURE_NAME))								// KEY of Clashing
      return false; 
	
	if (!LoadTGA(&textures[0],"Data/Font.TGA"))				// Load The Font Texture
	{
		return false;										// If Loading Failed, Return False
	}
	
	if (!LoadGLTextures())								// Jump To Texture Loading Routine
      return false;  

	//LPARAM lParam;
	SetCursorPos(322,240);	
	float temp_mouse_x = LOWORD(lParam);
	float temp_mouse_y = HIWORD(lParam);
	SetCursorPos(320,240);

  BuildLists();
  BuildLists1();

  glEnable(GL_TEXTURE_2D);					// Enable Texture Mapping
	glClearColor(0, 0, 0, 1.0f);				// Black Background
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  TimerInit(); //initialize timer
  BuildFont();   
  StartTime = TimerGetTime()/1000; 
	return TRUE;										// Initialization Went OK
}

// Detect collision and reflect movement if collision is detected
// cx = x position; cy = y position; cz = z position;
// cxi = x increment; cyi = y increment; czi = z increment;
// padding = a square border around the object.  your value will be 1/2 the length of one side of the square
// bounce = bounce coefficient -- 0 = no bounce; 1 = perfect bounce
inline bool Collision11(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx > CELL*5-padding) //right
  {	
    cx = CELL*5-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz > CELL*7-padding) //back		
  {
    cz = CELL*7-padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }
  else if (cz < CELL*6+padding) //front		
  {
    cz = CELL*6+padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision21(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < CELL*3+padding)//left
  {
    cx = CELL*3+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz > CELL*7-padding) //back		
  {
    cz = CELL*7-padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  } 

  return Status;
}

inline bool Collision22(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx > CELL*4-padding)//right
  {
    cx = CELL*4-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  } 

  return Status;
}

inline bool Collision23(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < CELL*3+padding)//left
  {
    cx = CELL*3+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }
  else if (cx > CELL*4-padding)//right
  {
    cx = CELL*4-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision24(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx > CELL*4-padding)//right
  {
    cx = CELL*4-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz < CELL*3+padding) //front		
  {
    cz = CELL*3+padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision32(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false; 
  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz > CELL*6-padding) //back		
  {
    cz = CELL*6-padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }
  else if (cz < CELL*5+padding) //front		
  {
    cz = CELL*5+padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision34(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false; 
  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz > CELL*4-padding) //back		
  {
    cz = CELL*4-padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  } 

  return Status;
}

inline bool Collision35(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < CELL*2+padding)//left
  {
    cx = CELL*2+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }
  else if (cx > CELL*3-padding)//right
  {
    cx = CELL*3-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision36(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < CELL*2+padding)//left
  {
    cx = CELL*2+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }
  else if (cx > CELL*3-padding)//right
  {
    cx = CELL*3-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz < CELL+padding) //front		
  {
    cz = CELL+padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision42(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false; 
  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz > CELL*6-padding) //back		
  {
    cz = CELL*6-padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }
  else if (cz < CELL*5+padding) //front		
  {
    cz = CELL*5+padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision44(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz > CELL*4-padding) //back		
  {
    cz = CELL*4-padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }
  else if (cz < CELL*3+padding) //front		
  {
    cz = CELL*3+padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision46(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx > CELL*2-padding) //right
  {	
    cx = CELL*2-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz > CELL*2-padding) //back		
  {
    cz = CELL*2-padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  } 
  return Status;
}

inline bool Collision47(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < CELL+padding)//left
  {
    cx = CELL+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }
  else if (cx > CELL*2-padding)//right
  {
    cx = CELL*2-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  } 

  if (cz < 0+padding && 
			(cx < CELL*1+CELL*3/8+padding || 
				cx > CELL*2-CELL*3/8-padding))	//[4 7]front door	
  {
    cz = 0+padding;
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision52(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < 0+padding) //left
  {	
    cx = 0+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz > CELL*6-padding) //back		
  {
    cz = CELL*6-padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  } 
  return Status;
}

inline bool Collision53(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < 0+padding)//left
  {
    cx = 0+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }
  else if (cx > CELL-padding)//right
  {
    cx = CELL-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz < CELL*4+padding) //front		
  {
    cz = CELL*4+padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision54(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < 0+padding) //left
  {	
    cx = 0+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz > CELL*4-padding) //back		
  {
    cz = CELL*4-padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool Collision55(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < 0+padding)//left
  {
    cx = 0+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }
  else if (cx > CELL-padding)//right
  {
    cx = CELL-padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
 
  return Status;
}

inline bool Collision56(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
  bool Status = false;
  if (cx < 0+padding)//left
  {
    cx = 0+padding; 
    cxi = -cxi;
    cxi *= bounce; 
    Status = true;
  }

  if (cy > CELL/4-padding) //top
  {
    cy = CELL/4-padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }
  else if (cy < 0+padding)	//bottom	
  {
    cy = 0+padding; 
    cyi = -cyi;
    cyi *= bounce; 
    Status = true;
  }

  if (cz < CELL+padding) //front		
  {
    cz = CELL+padding; 
    czi = -czi;
    czi *= bounce; 
    Status = true;
  }

  return Status;
}

inline bool CollisionAll(GLdouble &cx, GLdouble &cy, GLdouble &cz, GLdouble &cxi, GLdouble &cyi, GLdouble &czi, GLdouble padding, GLdouble bounce)
{
	bool Status = false;

	if( xtrans2 > CELL*3 && xtrans2 < CELL*5 &&
		ztrans2 > CELL*6 && ztrans2 < CELL*7 ) //[11][21]
	{
		if (cx > CELL*5-padding) //right
		{	
			cx = CELL*5-padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}
		else if (cx < CELL*3+padding)//left
		{
			cx = CELL*3+padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}

		if (cy > CELL/4-padding) //top
		{
			cy = CELL/4-padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}
		else if (cy < 0+padding)	//bottom	
		{
			cy = 0+padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}

		if (cz > CELL*7-padding) //back		
		{
			cz = CELL*7-padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
		else if (cz < CELL*6+padding) //front		
		{
			cz = CELL*6+padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
	}
	else if( xtrans2 > 0 && xtrans2 < CELL*4 &&
		ztrans2 > CELL*5 && ztrans2 < CELL*6 ) //[22][32][42][52]
	{
		if (cx > CELL*4-padding) //right
		{	
			cx = CELL*4-padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}
		else if (cx < 0+padding)//left
		{
			cx = 0+padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}

		if (cy > CELL/4-padding) //top
		{
			cy = CELL/4-padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}
		else if (cy < 0+padding)	//bottom	
		{
			cy = 0+padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}

		if (cz > CELL*6-padding) //back		
		{
			cz = CELL*6-padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
		else if (cz < CELL*5+padding) //front		
		{
			cz = CELL*5+padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
	}

	else if( xtrans2 > CELL*3 && xtrans2 < CELL*4 &&
		ztrans2 > CELL*3 && ztrans2 < CELL*5 ) //[23][24]
	{
		if (cx > CELL*4-padding) //right
		{	
			cx = CELL*4-padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}
		else if (cx < CELL*3+padding)//left
		{
			cx = CELL*3+padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}

		if (cy > CELL/4-padding) //top
		{
			cy = CELL/4-padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}
		else if (cy < 0+padding)	//bottom	
		{
			cy = 0+padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}

		if (cz > CELL*5-padding) //back		
		{
			cz = CELL*5-padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
		else if (cz < CELL*3+padding) //front		
		{
			cz = CELL*3+padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
	}
	
	else if( xtrans2 > 0 && xtrans2 < CELL &&
		ztrans2 > CELL*4 && ztrans2 < CELL*5 ) //[53]
	{
		if (cx > CELL-padding) //right
		{	
			cx = CELL-padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}
		else if (cx < 0+padding)//left
		{
			cx = 0+padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}

		if (cy > CELL/4-padding) //top
		{
			cy = CELL/4-padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}
		else if (cy < 0+padding)	//bottom	
		{
			cy = 0+padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}

		if (cz > CELL*5-padding) //back		
		{
			cz = CELL*5-padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
		else if (cz < CELL*4+padding) //front		
		{
			cz = CELL*4+padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
	}

	else if( xtrans2 > CELL*2 && xtrans2 < CELL*3 &&
		ztrans2 > CELL && ztrans2 < CELL*4 ) //[34][35][36]
	{
		if (cx > CELL*3-padding) //right
		{	
			cx = CELL*3-padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}
		else if (cx < CELL*2+padding)//left
		{
			cx = CELL*2+padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}

		if (cy > CELL/4-padding) //top
		{
			cy = CELL/4-padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}
		else if (cy < 0+padding)	//bottom	
		{
			cy = 0+padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}

		if (cz > CELL*4-padding) //back		
		{
			cz = CELL*4-padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
		else if (cz < CELL+padding) //front		
		{
			cz = CELL+padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
	}

	else if( xtrans2 > CELL && xtrans2 < CELL*2 &&
		ztrans2 > CELL*3 && ztrans2 < CELL*4 ) //[44]
	{
		if (cx > CELL*2-padding) //right
		{	
			cx = CELL*2-padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}
		else if (cx < CELL+padding)//left
		{
			cx = CELL+padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}

		if (cy > CELL/4-padding) //top
		{
			cy = CELL/4-padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}
		else if (cy < 0+padding)	//bottom	
		{
			cy = 0+padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}

		if (cz > CELL*4-padding) //back		
		{
			cz = CELL*4-padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
		else if (cz < CELL*3+padding) //front		
		{
			cz = CELL*3+padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
	}

	else if( xtrans2 > 0 && xtrans2 < CELL &&
		ztrans2 > CELL && ztrans2 < CELL*4 ) //[54][55][56]
	{
		if (cx > CELL-padding) //right
		{	
			cx = CELL-padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}
		else if (cx < 0+padding)//left
		{
			cx = 0+padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}

		if (cy > CELL/4-padding) //top
		{
			cy = CELL/4-padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}
		else if (cy < 0+padding)	//bottom	
		{
			cy = 0+padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}

		if (cz > CELL*4-padding) //back		
		{
			cz = CELL*4-padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
		else if (cz < CELL+padding) //front		
		{
			cz = CELL+padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
	}
	
	else if( xtrans2 > CELL && xtrans2 < CELL*2 &&
		ztrans2 > 0 && ztrans2 < CELL*2 ) //[46][47]
	{
		if (cx > CELL*2-padding) //right
		{	
			cx = CELL*2-padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}
		else if (cx < CELL+padding)//left
		{
			cx = CELL+padding; 
			cxi = -cxi;
			cxi *= bounce; 
			Status = true;
		}

		if (cy > CELL/4-padding) //top
		{
			cy = CELL/4-padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}
		else if (cy < 0+padding)	//bottom	
		{
			cy = 0+padding; 
			cyi = -cyi;
			cyi *= bounce; 
			Status = true;
		}

		if (cz > CELL*2-padding) //back		
		{
			cz = CELL*2-padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
		else if (cz < 0+padding) //front		
		{
			cz = 0+padding; 
			czi = -czi;
			czi *= bounce; 
			Status = true;
		}
	}

  return Status;
}

inline void Ricochet()
{
  int i;
  
  for (i = 0; i < MAX_PARTICLES; i++)
  {
    if (i == 0)
      particle[i][shots_fired].size = 2;
    else
      particle[i][shots_fired].size = GLdouble((rand()%25)+25)/50;
    
    particle[i][shots_fired].triangle_x1 = GLdouble((rand()%50)-25)/75.f;
    particle[i][shots_fired].triangle_x2 = GLdouble((rand()%50)-25)/75.f;
    particle[i][shots_fired].triangle_x3 = GLdouble((rand()%50)-25)/75.f;

    particle[i][shots_fired].triangle_y1 = GLdouble((rand()%50)-25)/75.f;
    particle[i][shots_fired].triangle_y2 = GLdouble((rand()%50)-25)/75.f;
    particle[i][shots_fired].triangle_y3 = GLdouble((rand()%50)-25)/75.f;
    
    particle[i][shots_fired].triangle_z1 = GLdouble((rand()%50)-25)/75.f;
    particle[i][shots_fired].triangle_z2 = GLdouble((rand()%50)-25)/75.f;
    particle[i][shots_fired].triangle_z3 = GLdouble((rand()%50)-25)/75.f;

    particle[i][shots_fired].triangle_rotate_x = rand()%360;
    particle[i][shots_fired].triangle_rotate_y = rand()%360;
    particle[i][shots_fired].triangle_rotate_z = rand()%360;

    particle[i][shots_fired].triangle_rotate_xi = GLdouble((rand()%50)-25)/5;
    particle[i][shots_fired].triangle_rotate_yi = GLdouble((rand()%50)-25)/5;
    particle[i][shots_fired].triangle_rotate_zi = GLdouble((rand()%50)-25)/5;

    particle[i][shots_fired].life = 1;
    particle[i][shots_fired].fade = GLdouble(rand()%100)/5000 + .02f;
    particle[i][shots_fired].x = fire_x;
    particle[i][shots_fired].y = fire_y;
    particle[i][shots_fired].z = fire_z;
    GLdouble angle = rand()%360;
    GLdouble angle2 = rand()%360;
    GLdouble speed = GLdouble(rand()%100) / 500;
    GLdouble Hyp = Hypot(angle,angle2);
	
    particle[i][shots_fired].xi = sin(Hypot(angle,Hyp))*speed + fire_xp;
    particle[i][shots_fired].yi = cos(Hypot(angle,Hyp))*speed + fire_yp;
    particle[i][shots_fired].zi = cos(Hypot(angle2,Hyp))*speed + fire_zp;
  }
}

void LoadMonster( int ID,float xPosition, float yPosition, float zPosition)
{ 
  Monster[ID].transX = xPosition;
  Monster[ID].transY = yPosition;
  Monster[ID].transZ = zPosition;
if(Monster[ID].trigger == true )
{	  
  if( Monster[ID].hitStatus == false )
  {	 
	//glPushMatrix();
//////////// *** NEW *** //////////  START GAME AI ///////////// *** NEW *** ///////////////
	if((xtrans2 - Monster[ID].transX ) > 15) //if on the left, move towards right
	{
		Monster[ID].transXSpeed += 0.5f;
		gameOverOnX = false;
	}else if((Monster[ID].transX - xtrans2) > 15) //if on the right, move towards left
	{
		Monster[ID].transXSpeed -= 0.5f;
		gameOverOnX = false;
	}else
	{
		Monster[ID].transXSpeed = 0.0f; 
		gameOverOnX = true;
	}
	Monster[ID].transX += Monster[ID].transXSpeed;
	glTranslatef(Monster[ID].transX, 0, 0);

	if((ztrans2 - Monster[ID].transZ) > 15) //if on the front, move forwards 
	{
		Monster[ID].transZSpeed += 0.5f;
		gameOverOnZ = false;
	}else if( ( Monster[ID].transZ - ztrans2) > 15) //if on the back, move backwards
	{
		Monster[ID].transZSpeed -= 0.5f; 
		gameOverOnZ = false;
	}else
	{
		Monster[ID].transZSpeed = 0.0f;
		gameOverOnZ = false;
	} 
	Monster[ID].transZ += Monster[ID].transZSpeed;
	glTranslatef( 0, 0, Monster[ID].transZ);

	if( gameOverOnX == true && gameOverOnZ == true)
	{
		gameOver = true;
	}else
	{
		gameOver = false;
	}
	 
	//////////// *** NEW *** AI to let Monster face player always *** NEW *** //////////////////// 
	Monster[ID].rotateX = atan ( (ztrans2 - Monster[ID].transZ) / (xtrans2 - Monster[ID].transX + 0.5f) ) / piover180;
	
	//if degree is in 3rd quadrant
	if( (ztrans2 - Monster[ID].transZ) < 0.0f && (xtrans2 - Monster[ID].transX) < 0.0f ) 
	{
		Monster[ID].XMultiplier = -1.0f;
	}
	//if degree is in 2nd quadrant
	else if( (xtrans2 - Monster[ID].transX) < 0.0f &&  (ztrans2 - Monster[ID].transZ) > 0.0f) 
	{
		Monster[ID].XMultiplier = 0.5f;
	}
	//if degree is in 4th quadrant
	else if( (xtrans2 - Monster[ID].transX) > 0.0f &&  (ztrans2 - Monster[ID].transZ) < 0.0f) 
	{
		Monster[ID].XMultiplier = -1.0f;
	}
	//if degree is in 1st quadrant
	else
	{
		Monster[ID].XMultiplier = 0.0f;
	}
    // Face the player around the Y-Axis
	glRotatef(Monster[ID].XMultiplier * 90.0f + Monster[ID].rotateX - 135.0f, 0.0f, 1.0f, 0.0f); 
//////////// *** NEW *** ////////// END GAME AI ///////////// *** NEW *** //////////////////
	if( (atan((Monster[ID].transZ - fire_z)/(Monster[ID].transX - fire_x + 0.5f)) 
	  - atan((ztrans2 -Monster[ID].transZ)/(xtrans2 - Monster[ID].transX + 0.5f)) < 0.0873*2) && //5 degrees in radian
	  (atan((Monster[ID].transZ - fire_z)/(Monster[ID].transX - fire_x + 0.5f))
	  - atan((ztrans2 -Monster[ID].transZ)/(xtrans2 - Monster[ID].transX + 0.5f)) > -0.0873*2) &&
	  isFire == true &&
	  ( (ztrans2 > Monster[ID].transZ && Monster[ID].transZ > fire_z) ||
	     (ztrans2 < Monster[ID].transZ && Monster[ID].transZ < fire_z) ) &&
	  ( (xtrans2 > Monster[ID].transX && Monster[ID].transX > fire_x) ||
	     (xtrans2 < Monster[ID].transX && Monster[ID].transX < fire_x) ))
		{
			Monster[ID].hitCount += 1;
			if( Monster[ID].hitCount == 3)
			{
				Monster[ID].transXSpare = Monster[ID].transX; 
				Monster[ID].transZSpare = Monster[ID].transZ;
				Monster[ID].hitStatus = true;
			}
		}

		glTranslatef( 0, 25.0f, 0); //move the model upwards
		glCallList(MODEL);
		//glPopMatrix(); 
	 }
	else
	{ 
		glTranslatef( Monster[ID].transXSpare, 25.0f + Monster[ID].fall, Monster[ID].transZSpare);
		glRotatef(Monster[ID].XMultiplier * 90.0f + Monster[ID].rotateX- 135.0f, 0.0f, 1.0f, 0.0f);
  
		if(ABS(Monster[ID].rotateY) < 89.0f)
		{
			Monster[ID].rotateYSpeed += 1.0f;
			Monster[ID].fall -= 1.01f;
		}else
		{
			Monster[ID].rotateYSpeed = 0.0f;
		}	 
		Monster[ID].rotateY += Monster[ID].rotateYSpeed;  
		glRotatef(Monster[ID].rotateY, 1.0f, 0.0f, -1.0f);	 // Fall@Rotate the object around the XZ-Axis
		glCallList(MODEL);
	}
}
}

int DrawGLScene(GLvoid)									// Here's Where We Do All The Drawing
{
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer

  XP *= 0.8f; 
  ZP *= 0.8f; 
  xtrans2 += XP/10;
  ztrans2 += ZP/10;

  xtrans = -xtrans2;
  ztrans = -ztrans2;
 
  if( gameOver == false)
  {
	if(ztrans2>CELL*6 && ztrans2<CELL*7 && 
		xtrans2>CELL*4 && xtrans2<CELL*5)
	{ 
		Collision11(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*6 && ztrans2<CELL*7 && 
			xtrans2>CELL*3 && xtrans2<CELL*4) 
	{
		Collision21(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*5 && ztrans2<CELL*6 && 
			xtrans2>CELL*3 && xtrans2<CELL*4) 
	{
		Collision22(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*4 && ztrans2<CELL*5 && 
			xtrans2>CELL*3 && xtrans2<CELL*4) 
	{
		Collision23(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*3 && ztrans2<CELL*4 && 
			xtrans2>CELL*3 && xtrans2<CELL*4)
	{
		Collision24(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*5 && ztrans2<CELL*6 && 
			xtrans2>CELL*2 && xtrans2<CELL*3)
	{
		Collision32(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*3 && ztrans2<CELL*4 && 
			xtrans2>CELL*2 && xtrans2<CELL*3)
	{
		Collision34(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*2 && ztrans2<CELL*3 && 
			xtrans2>CELL*2 && xtrans2<CELL*3)
	{
		Collision35(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL && ztrans2<CELL*2 && 
			xtrans2>CELL*2 && xtrans2<CELL*3)
	{
		Collision36(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*5 && ztrans2<CELL*6 && 
			xtrans2>CELL && xtrans2<CELL*2)
	{
		Collision42(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*3 && ztrans2<CELL*4 && 
			xtrans2>CELL && xtrans2<CELL*2)
	{
		Collision44(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL && ztrans2<CELL*2 && 
			xtrans2>CELL && xtrans2<CELL*2)
	{
		Collision46(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>0 && ztrans2<CELL && 
			xtrans2>CELL && xtrans2<CELL*2)
	{
		Collision47(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*5 && ztrans2<CELL*6 && 
			xtrans2>0 && xtrans2<CELL)
	{
		Collision52(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*4 && ztrans2<CELL*5 && 
			xtrans2>0 && xtrans2<CELL)
	{
		Collision53(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*3 && ztrans2<CELL*4 && 
			xtrans2>0 && xtrans2<CELL)
	{
		Collision54(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL*2 && ztrans2<CELL*3 && 
			xtrans2>0 && xtrans2<CELL)
	{
		Collision55(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}
	else if(ztrans2>CELL && ztrans2<CELL*2 && 
			xtrans2>0 && xtrans2<CELL)
	{
		Collision56(xtrans2, ytrans2, ztrans2, XP, BlankNum, ZP, 5.0f, 0);
	}

  zprot*=.9f;
  _heading += zprot;
  heading = mouse_3d_x + _heading;
    
  yrot = heading;
	
  sceneroty = 360.0f - yrot;

  glLoadIdentity();
  m16_kicki += -m16_kick/50;
  m16_kick += m16_kicki/10;
  m16_kicki *= .8f;
  m16_kick *= .9f;
  if (m16_kick != 0)
  {
    glRotated(-m16_kick,1,0,0);
    glTranslatef(0,0,-m16_kick);
  }

  glLoadIdentity();

  glRotated(mouse_3d_y,1.f,0,0);
  glRotated(sceneroty,0,1.f,0); 
  glTranslated(xtrans, -25 ,ztrans);		// Player position

  glDisable(GL_BLEND);
  for(int i=0; i<18; i++)
  {
	glCallList(ROOM[i]);
  }
  glEnable(GL_BLEND);

//////////// *** NEW *** ////////// GAME AI ///////////// *** NEW *** ////////////////////
  LoadMonster(0, CELL*4 + 20.0f, 0.0, CELL*6 + 20.0f);
  if(xtrans2 > CELL*3 && xtrans2 < CELL*5 &&
	  ztrans2 > CELL*6 && ztrans2 < CELL*7 )
  {	  
	  Monster[0].trigger = true;
  }else
  {
	  Monster[0].trigger = false;
  }

  LoadMonster(1, CELL*2 + 20.0f, 0.0, CELL*5 + 20.0f);
  if(xtrans2 > 0 && xtrans2 < CELL*4 &&
	  ztrans2 > CELL*5 && ztrans2 < CELL*6 )
  {	  
	  Monster[1].trigger = true;
  }else
  {
	  Monster[1].trigger = false;
  }

  LoadMonster(2, 20.0f, 0.0, CELL*4 + 20.0f);
  if(xtrans2 > 0 && xtrans2 < CELL &&
	  ztrans2 > CELL*4 && ztrans2 < CELL*5 )
  {		
	  Monster[2].trigger = true;
  }else
  {
	  Monster[2].trigger = false;
  }

  LoadMonster(3, CELL*2 + 20.0f, 0.0, CELL*2 + 20.0f);
  if(xtrans2 > CELL*2 && xtrans2 < CELL*3 &&
	  ztrans2 > CELL && ztrans2 < CELL*4 )
  {		
	  Monster[3].trigger = true;
  }else
  {
	  Monster[3].trigger = false;
  }
  LoadMonster(4, 20.0f, 0.0, CELL*2 + 20.0f);
  if(xtrans2 > 0 && xtrans2 < CELL &&
	  ztrans2 > CELL && ztrans2 < CELL*4 )
  {		
	  Monster[4].trigger = true;
  }else
  {
	  Monster[4].trigger = false;
  }

  LoadMonster(5, CELL + 20.0f, 0.0, 20.0f);
  if(xtrans2 > CELL && xtrans2 < CELL*2 &&
	  ztrans2 > 0 && ztrans2 < CELL*2 )
  {		
	  Monster[5].trigger = true;
  }else
  {
	  Monster[5].trigger = false;
  } 
//////////// *** NEW *** ////////// GAME AI ///////////// *** NEW *** ////////////////////
// Determine if you have fired a weapon
  if (isFire)
  {
    PlaySound("Data/rifle.WAV", NULL, SND_ASYNC);
    m16_kicki = 1;
    
    shots_fired++;
    if (shots_fired > MAX_SHOTS_FIRED-1) shots_fired = 0;
    isFireComplete = false;
    isFire = false;
	
    fire_x = -xtrans;
    fire_y = 10;
    fire_z = -ztrans;

    fire_xp = -(GLdouble)sin(heading*piover180) / 5;	
    fire_yp = -(GLdouble)tan(mouse_3d_y*piover180) / 5;
    fire_zp = -(GLdouble)cos(heading*piover180) / 5;
  }
  int fire_counter = 0;

  // Begin calculations for the projectile
  while (!isFireComplete)
  {     
    fire_counter++;
    fire_x += fire_xp;
    fire_y += fire_yp;
    fire_z += fire_zp;
      
    if (CollisionAll(fire_x,  fire_y,  fire_z, BlankNum, BlankNum, BlankNum, 0, 0))
    {
      isFireComplete = true;
      Ricochet();
      isRicochet = true; 
    }
    else if (fire_counter > 10000)
    {
      isFireComplete = true;
    } 
  } 

	// Determine if it was the M16 that was fired.
  if (isRicochet)
  {   
    int i;
    bool isRicochetComplete = true;
    glDisable(GL_TEXTURE_2D);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	
    for (int j = 0; j < MAX_SHOTS_FIRED; j++)
    {
      for (i = 8; i < MAX_PARTICLES; i++)
      {
        if (particle[i][j].life > 0)
        {
          isRicochetComplete = false;
		
          particle[i][j].x += particle[i][j].xi;
          particle[i][j].y += particle[i][j].yi;
          particle[i][j].z += particle[i][j].zi;

          CollisionAll(particle[i][j].x,  particle[i][j].y,  particle[i][j].z,
                          particle[i][j].xi, particle[i][j].yi, particle[i][j].zi, 0, .75f);

          particle[i][j].yi -= .01f;  // cheap simulated gravity
          particle[i][j].xi *= .99;
          particle[i][j].yi *= .99;
          particle[i][j].zi *= .99;
          particle[i][j].life -= particle[i][j].fade;
        
          glLoadIdentity();
          glRotated(mouse_3d_y,1.f,0,0);
          glRotated(sceneroty,0,1.f,0);
          glTranslated(xtrans,-10,ztrans);  
          glTranslated(particle[i][j].x,particle[i][j].y,particle[i][j].z);
          glRotated(-sceneroty,0,1.f,0);
          glRotated(-mouse_3d_y,1.f,0,0);
		
          particle[i][j].triangle_rotate_x += particle[i][j].triangle_rotate_xi;
          particle[i][j].triangle_rotate_y += particle[i][j].triangle_rotate_yi;
          particle[i][j].triangle_rotate_z += particle[i][j].triangle_rotate_zi;
          particle[i][j].triangle_rotate_xi -= particle[i][j].fade;
          particle[i][j].triangle_rotate_yi -= particle[i][j].fade;
          particle[i][j].triangle_rotate_zi -= particle[i][j].fade;
          glRotated(particle[i][j].triangle_rotate_x,1,0,0);
          glRotated(particle[i][j].triangle_rotate_y,0,1,0);
          glRotated(particle[i][j].triangle_rotate_z,0,0,1);

          glColor4d(0,0,0,particle[i][j].life);

          glBegin(GL_TRIANGLES);
          glVertex3d(particle[i][j].triangle_x1, particle[i][j].triangle_y1, particle[i][j].triangle_z1);
          glVertex3d(particle[i][j].triangle_x2, particle[i][j].triangle_y2, particle[i][j].triangle_z2);
          glVertex3d(particle[i][j].triangle_x3, particle[i][j].triangle_y3, particle[i][j].triangle_z3);
          glEnd();
        }
      }
    }
    glEnable(GL_TEXTURE_2D);
    glDisable(GL_DEPTH_TEST);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);

    glBindTexture(GL_TEXTURE_2D, texture[3]);

    // Display particles of the ricochet from the M16
    for (j = 0; j < MAX_SHOTS_FIRED; j++)
    {
      for (i = 0; i < 8; i++)
      {  	  
        if (particle[i][j].life > 0)
        {
          isRicochetComplete = false;

          particle[i][j].x += particle[i][j].xi/2;
          particle[i][j].y += particle[i][j].yi/2;
          particle[i][j].z += particle[i][j].zi/2;

          particle[i][j].yi += .01f;

          particle[i][j].xi *= .9f;
          particle[i][j].yi *= .9f;
          particle[i][j].zi *= .9f;
        
          particle[i][j].life -= particle[i][j].fade/2;
		
          glLoadIdentity();
          glRotated(mouse_3d_y,1.f,0,0);
          glRotated(sceneroty,0,1.f,0);
          glTranslated(xtrans,-10,ztrans);  	    
          glTranslated(particle[i][j].x,particle[i][j].y,particle[i][j].z);
          glRotated(-sceneroty,0,1.f,0);
          glRotated(-mouse_3d_y,1.f,0,0);

          glColor4d(.18f,.17f,.15f,particle[i][j].life);
          glBegin(GL_QUADS);
          glTexCoord2d(1,1); glVertex3d( particle[i][j].size, particle[i][j].size,0);
          glTexCoord2d(1,0); glVertex3d( particle[i][j].size,-particle[i][j].size,0);
          glTexCoord2d(0,0); glVertex3d(-particle[i][j].size,-particle[i][j].size,0);
          glTexCoord2d(0,1); glVertex3d(-particle[i][j].size, particle[i][j].size,0);
          glEnd();
        }  
      }
    }
    glEnable(GL_DEPTH_TEST);
	
    if (isRicochetComplete)
      isRicochet = false;
  }
	// Crosshair  
  glDisable(GL_DEPTH_TEST);
  glLoadIdentity();
  glTranslated(0.0f,0.0f,-35.0f);   
	
  glBlendFunc(GL_SRC_ALPHA,GL_ONE);

  glColor4f(1,1,1,1);
  glBindTexture(GL_TEXTURE_2D,texture[2]);
  glBegin(GL_QUADS);
  glTexCoord2d(1,1); glVertex2f(1,1);
  glTexCoord2d(1,0); glVertex2f(1,-1);
  glTexCoord2d(0,0); glVertex2f(-1,-1);
  glTexCoord2d(0,1); glVertex2f(-1,1);
  glEnd(); 
  
	glDisable(GL_DEPTH_TEST);   
		glBindTexture(GL_TEXTURE_2D, textures[0].texID);	// Select Our Font Texture
		glColor4d(1,1,1,1);	
		glPrint(150,250,1,"Distance: %4.0f", Hypot( (xtrans2-CELL*3/2.0), (ztrans2-5.0) ) );
		for( int k=0; k<6;k++)
		{
			if( Monster[k].trigger == true && Monster[k].hitCount < 3)
			{
				glColor4d(1,0,0,1);	
				glPrint(150,230,1,"ALERT!");
			}
			if( xtrans2 - Monster[k].transX < 15.0&& Monster[k].hitCount < 3)
			{
				glColor4d(1,0,0,1);	
				glPrint(150,230,1,"ALERT!");
			}
		}
		glColor4d(1,1,1,1);	
	glEnable(GL_DEPTH_TEST);
	glDisable(GL_TEXTURE_2D);
    glEnable(GL_TEXTURE_2D);

//  ESTABLISH A FPS FRAMERATE COUNTER
  if (isFPS)
  { 
    glDisable(GL_DEPTH_TEST);
    frames++;    
    if (frames%10 == 0) 
    {
      Time2 = TimerGetTime()/1000;
      DiffTime = ABS(Time2-Time1);      
      Time1 = TimerGetTime()/1000;     
      if (DiffTime != 0)
	      FPS = 10/(DiffTime);
    }             
    
	glBindTexture(GL_TEXTURE_2D, textures[0].texID);		// Select Our Font Texture
    glColor4d(1,1,1,1);	
	glPrint(-350,250,1,"FPS: %4.0f", FPS);					
	  
	glPrint(-350,230,1,"transX[0]: %4.2f C", Monster[0].transX);
	glPrint(-350,210,1,"transZ[0]: %4.2f C", Monster[0].transZ);
	glPrint(-350,190,1,"(xtrans2-transX): %4.2f", (xtrans2-Monster[0].transX) );
	glPrint(-350,170,1,"xtrans2: %4.2f C", xtrans2/CELL);
	glPrint(-350,150,1,"ztrans2: %4.2f C", ztrans2/CELL);
	glPrint(-350,130,1,"(ztrans2-transZ): %4.2f", (ztrans2-Monster[0].transZ) );
	glPrint(-350,110,1,"rotateX@atan: %4.2f", Monster[0].rotateX );
	glPrint(-350,90,1,"multiplier+atan: %4.2f", Monster[0].XMultiplier*90.0f+Monster[0].rotateX-135.0f);
	glPrint(-350,70,1,"fire_x: %4.2f C", fire_x/CELL );
	glPrint(-350,50,1,"fire_y: %4.2f C", fire_y/CELL );
	glPrint(-350,30,1,"fire_z: %4.2f C", fire_z/CELL );
	glPrint(-350,10,1,"deg(M-H): %4.2f", atan((Monster[0].transZ - fire_z)/(Monster[0].transX - fire_x + 0.5f))/ piover180 );
	glPrint(-350,-10,1,"deg(P-M): %4.2f", atan((ztrans2 -Monster[0].transZ)/(xtrans2 - Monster[0].transX + 0.5f))/ piover180);
	glPrint(-350,-30,1,"condition[0]: %4.2f", atan((Monster[0].transZ - fire_z)/(Monster[0].transX - fire_x + 0.5f))/ piover180
											- atan((ztrans2 -Monster[0].transZ)/(xtrans2 - Monster[0].transX + 0.5f))/ piover180);
	glPrint(-350,-50,1,"[0]hit %2.0d", Monster[0].hitCount);
	if( Monster[0].hitStatus == true )
	{
		glPrint(-350,-70,1,"[0]dead");
	}
	glPrint(-350,-90,1,"transX[1]: %4.2f C", Monster[1].transX/CELL);
	glPrint(-350,-110,1,"transZ[1]: %4.2f C", Monster[1].transZ/CELL);
	glPrint(-350,-130,1,"condition[1]: %4.2f", atan((Monster[1].transZ - fire_z)/(Monster[1].transX - fire_x + 0.5f))/ piover180
											- atan((ztrans2 -Monster[1].transZ)/(xtrans2 - Monster[1].transX + 0.5f))/ piover180);
	glPrint(-350,-150,1,"[1]hit %2.0d", Monster[1].hitCount);
	if( Monster[1].hitStatus == true )
	{
		glPrint(-350,-170,1,"[1]dead");
	}
	glPrint(0,110,1,"transX[2]: %4.2f C", Monster[2].transX/CELL);
	glPrint(0,90,1,"transZ[2]: %4.2f C", Monster[2].transZ/CELL);
	glPrint(0,70,1,"condition[2]: %4.2f", atan((Monster[2].transZ - fire_z)/(Monster[2].transX - fire_x + 0.5f))/ piover180
											- atan((ztrans2 -Monster[2].transZ)/(xtrans2 - Monster[2].transX + 0.5f))/ piover180);
	glPrint(0,50,1,"[2]hit %2.0d", Monster[2].hitCount);
	if( Monster[2].hitStatus == true )
	{
		glPrint(0,30,1,"[2]dead");
	}
	glPrint(0,10,1,"transX[3]: %4.2f C", Monster[3].transX/CELL);
	glPrint(0,-10,1,"transZ[3]: %4.2f C", Monster[3].transZ/CELL);
	glPrint(0,-30,1,"condition[3]: %4.2f", atan((Monster[3].transZ - fire_z)/(Monster[3].transX - fire_x + 0.5f))/ piover180
											- atan((ztrans2 -Monster[3].transZ)/(xtrans2 - Monster[3].transX + 0.5f))/ piover180);
	glPrint(0,-50,1,"[3]hit %2.0d", Monster[3].hitCount);
	if( Monster[3].hitStatus == true )
	{
		glPrint(0,-70,1,"[3]dead");
	}
	glPrint(0,-90,1,"transX[4]: %4.2f C", Monster[4].transX/CELL);
	glPrint(0,-110,1,"transZ[4]: %4.2f C", Monster[4].transZ/CELL);
	glPrint(0,-130,1,"condition[4]: %4.2f", atan((Monster[4].transZ - fire_z)/(Monster[4].transX - fire_x + 0.5f))/ piover180
											- atan((ztrans2 -Monster[4].transZ)/(xtrans2 - Monster[4].transX + 0.5f))/ piover180);
	glPrint(0,-150,1,"[4]hit %2.0d", Monster[4].hitCount);
	if( Monster[4].hitStatus == true )
	{
		glPrint(0,-170,1,"[4]dead");
	}
	glPrint(0,-190,1,"transX[5]: %4.2f C", Monster[5].transX/CELL);
	glPrint(0,-210,1,"transZ[5]: %4.2f C", Monster[5].transZ/CELL);
	glPrint(0,-230,1,"condition[5]: %4.2f", atan((Monster[5].transZ - fire_z)/(Monster[5].transX - fire_x + 0.5f))/ piover180
											- atan((ztrans2 -Monster[5].transZ)/(xtrans2 - Monster[5].transX + 0.5f))/ piover180);
	glPrint(0,-250,1,"[5]hit %2.0d", Monster[5].hitCount);
	if( Monster[5].hitStatus == true )
	{
		glPrint(0,-270,1,"[5]dead");
	}

	glEnable(GL_DEPTH_TEST);           
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_TEXTURE_2D);
  }
}else
{
	glDisable(GL_DEPTH_TEST);   
		glBindTexture(GL_TEXTURE_2D, textures[0].texID);	// Select Our Font Texture
		glColor4d(1,1,1,1);	
		glPrint(150,190,1,"Game Over!");
	glEnable(GL_DEPTH_TEST);
	glDisable(GL_TEXTURE_2D);
    glEnable(GL_TEXTURE_2D);
}
  return TRUE;										// Keep Going

}

GLvoid KillGLWindow(GLvoid)								// Properly Kill The Window
{
	// When we are done, we need to free all the model data
	// We do this by walking through all the objects and freeing their information

	// Go through all the objects in the scene
	for(int i = 0; i < g_3DModel.numOfObjects; i++)
	{
		// Free the faces, normals, vertices, and texture coordinates.
		if(g_3DModel.pObject[i].pFaces)		delete [] g_3DModel.pObject[i].pFaces;
		if(g_3DModel.pObject[i].pNormals)	delete [] g_3DModel.pObject[i].pNormals;
		if(g_3DModel.pObject[i].pVerts)		delete [] g_3DModel.pObject[i].pVerts;
		if(g_3DModel.pObject[i].pTexVerts)	delete [] g_3DModel.pObject[i].pTexVerts;
	}
	
	KillFont();
	if (hRC)											// Do We Have A Rendering Context?
	{
		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
		{
			MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}

		if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?
		{
			MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}
		hRC=NULL;										// Set RC To NULL
	}

	if (hDC && !ReleaseDC(hWnd,hDC))					// Are We Able To Release The DC
	{
		MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hDC=NULL;										// Set DC To NULL
	}

	if (hWnd && !DestroyWindow(hWnd))					// Are We Able To Destroy The Window?
	{
		MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hWnd=NULL;										// Set hWnd To NULL
	}

	if (fullscreen)										// Are We In Fullscreen Mode?
	{
		ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop
		ShowCursor(TRUE);								// Show Mouse Pointer
	}
}

/*	This Code Creates Our OpenGL Window.  Parameters Are:					*
 *	title			- Title To Appear At The Top Of The Window				*
 *	width			- Width Of The GL Window Or Fullscreen Mode				*
 *	height			- Height Of The GL Window Or Fullscreen Mode			*
 *	bits			- Number Of Bits To Use For Color (8/16/24/32)			*
 *	fullscreenflag	- Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE)	*/
 
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
	GLuint		PixelFormat;			// Holds The Results After Searching For A Match
	WNDCLASS	wc;						// Windows Class Structure
	DWORD		dwExStyle;				// Window Extended Style
	DWORD		dwStyle;				// Window Style
	RECT		WindowRect;				// Grabs Rectangle Upper Left / Lower Right Values
	WindowRect.left=(long)0;			// Set Left Value To 0
	WindowRect.right=(long)width;		// Set Right Value To Requested Width
	WindowRect.top=(long)0;				// Set Top Value To 0
	WindowRect.bottom=(long)height;		// Set Bottom Value To Requested Height

	fullscreen=fullscreenflag;			// Set The Global Fullscreen Flag

	hInstance			= GetModuleHandle(NULL);				// Grab An Instance For Our Window
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Redraw On Size, And Own DC For Window.
	wc.lpfnWndProc		= (WNDPROC) WndProc;					// WndProc Handles Messages
	wc.cbClsExtra		= 0;									// No Extra Window Data
	wc.cbWndExtra		= 0;									// No Extra Window Data
	wc.hInstance		= hInstance;							// Set The Instance
	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	wc.hbrBackground	= NULL;									// No Background Required For GL
	wc.lpszMenuName		= NULL;									// We Don't Want A Menu
	wc.lpszClassName	= "OpenGL";								// Set The Class Name

	if (!RegisterClass(&wc))									// Attempt To Register The Window Class
	{
		MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;											// Return FALSE
	}
	
	if (fullscreen)												// Attempt Fullscreen Mode?
	{
		DEVMODE dmScreenSettings;								// Device Mode
		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	// Makes Sure Memory's Cleared
		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
		dmScreenSettings.dmPelsWidth	= width;				// Selected Screen Width
		dmScreenSettings.dmPelsHeight	= height;				// Selected Screen Height
		dmScreenSettings.dmBitsPerPel	= bits;					// Selected Bits Per Pixel
		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
			{
				fullscreen=FALSE;		// Windowed Mode Selected.  Fullscreen = FALSE
			}
			else
			{
				// Pop Up A Message Box Letting User Know The Program Is Closing.
				MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
				return FALSE;									// Return FALSE
			}
		}
	}

	if (fullscreen)												// Are We Still In Fullscreen Mode?
	{
		dwExStyle=WS_EX_APPWINDOW;								// Window Extended Style
		dwStyle=WS_POPUP;										// Windows Style
		ShowCursor(FALSE);										// Hide Mouse Pointer
	}
	else
	{
		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
		dwStyle=WS_OVERLAPPEDWINDOW;							// Windows Style
	}

	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		// Adjust Window To True Requested Size

	// Create The Window
	if (!(hWnd=CreateWindowEx(	dwExStyle,							// Extended Style For The Window
								"OpenGL",							// Class Name
								title,								// Window Title
								dwStyle |							// Defined Window Style
								WS_CLIPSIBLINGS |					// Required Window Style
								WS_CLIPCHILDREN,					// Required Window Style
								0, 0,								// Window Position
								WindowRect.right-WindowRect.left,	// Calculate Window Width
								WindowRect.bottom-WindowRect.top,	// Calculate Window Height
								NULL,								// No Parent Window
								NULL,								// No Menu
								hInstance,							// Instance
								NULL)))								// Dont Pass Anything To WM_CREATE
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
		1,											// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,							// Must Support Double Buffering
		PFD_TYPE_RGBA,								// Request An RGBA Format
		bits,										// Select Our Color Depth
		0, 0, 0, 0, 0, 0,							// Color Bits Ignored
		0,											// No Alpha Buffer
		0,											// Shift Bit Ignored
		0,											// No Accumulation Buffer
		0, 0, 0, 0,									// Accumulation Bits Ignored
		16,											// 16Bit Z-Buffer (Depth Buffer)  
		0,											// No Stencil Buffer
		0,											// No Auxiliary Buffer
		PFD_MAIN_PLANE,								// Main Drawing Layer
		0,											// Reserved
		0, 0, 0										// Layer Masks Ignored
	};
	
	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if (!(hRC=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if(!wglMakeCurrent(hDC,hRC))					// Try To Activate The Rendering Context
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	ShowWindow(hWnd,SW_SHOW);						// Show The Window
	SetForegroundWindow(hWnd);						// Slightly Higher Priority
	SetFocus(hWnd);									// Sets Keyboard Focus To The Window
	ReSizeGLScene(width, height);					// Set Up Our Perspective GL Screen

	if (!InitGL())									// Initialize Our Newly Created GL Window
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	return TRUE;									// Success
}

LRESULT CALLBACK WndProc(	HWND	hWnd,			// Handle For This Window
							UINT	uMsg,			// Message For This Window
							WPARAM	wParam,			// Additional Message Information
							LPARAM	lParam)			// Additional Message Information
{
		if (uMsg == WM_MOUSEMOVE)
		{
			if (LOWORD(lParam) > 370) SetCursorPos(10,(int)mouse_y), mouse_wrap_x--;
			else if (LOWORD(lParam) < 10) SetCursorPos(370,(int)mouse_y), mouse_wrap_x++;

			if (HIWORD(lParam) > 370) SetCursorPos((int)mouse_x,10), mouse_wrap_x--;
			else if (HIWORD(lParam) < 10) SetCursorPos((int)mouse_x,370), mouse_wrap_x++;
			
			if (ABS(mouse_x-LOWORD(lParam)) > 300)
			{
				if (mouse_x > 360/2)
					mouse_3d_x += ((mouse_x-360)-LOWORD(lParam))/sensitivity;
				else if (LOWORD(lParam) > 360/2)
					mouse_3d_x += (mouse_x-(LOWORD(lParam)-360))/sensitivity;
			}
			else
			{ 
				mouse_3d_x += (mouse_x-LOWORD(lParam))/sensitivity;
			} 

			if (mouse_3d_x > 360) mouse_3d_x = 0;
			else if (mouse_3d_x < 0) mouse_3d_x = 360;

			if (invert_mouse)
			{
				if (ABS(mouse_y-HIWORD(lParam)) > 300)
				{ 
					if (mouse_y > 360/2)
						mouse_3d_y -= (HIWORD(lParam)-(mouse_y-360))/sensitivity;
					else if (LOWORD(lParam) > 360/2)
						mouse_3d_y -= ((HIWORD(lParam)-360)-mouse_y)/sensitivity;
				}
				else
				{ 
					mouse_3d_y -= (HIWORD(lParam)-mouse_y)/sensitivity;
				} 
			}
			else
			{
				if (ABS(mouse_y-HIWORD(lParam)) > 300)
				{ 
					if (mouse_y > 360/2)
						mouse_3d_y -= ((mouse_y-360)-HIWORD(lParam))/sensitivity;
					else if (LOWORD(lParam) > 360/2)
						mouse_3d_y -= (mouse_y-(HIWORD(lParam)-360))/sensitivity;
				}
				else
				{ 
					mouse_3d_y -= (mouse_y-HIWORD(lParam))/sensitivity;
				} 
			}

			if (mouse_3d_x > 360) mouse_3d_x = 0;
			else if (mouse_3d_x < 0) mouse_3d_x = 360;

			if (mouse_3d_y > 85) mouse_3d_y = 85;
			else if (mouse_3d_y < -85) mouse_3d_y = -85;
			
			mouse_x = LOWORD(lParam);          
			mouse_y = HIWORD(lParam);
		}	
		
		else if (uMsg == WM_LBUTTONDOWN)
		{     
			isFire = true;
		}

		else if (uMsg == WM_ACTIVATE)				// Watch For Window Activate Message
		{
			if (!HIWORD(wParam))					// Check Minimization State
			{
				active=TRUE;						// Program Is Active
			}
			else
			{
				active=FALSE;						// Program Is No Longer Active
			}

		}
        
		else if (uMsg == WM_SYSCOMMAND)				// Intercept System Commands
		{
			switch (wParam)							// Check System Calls
			{
				case SC_SCREENSAVE:					// Screensaver Trying To Start?
				case SC_MONITORPOWER:				// Monitor Trying To Enter Powersave?
				
				return 0;							// Prevent From Happening
			}
		}
        
		else if (uMsg == WM_CLOSE)					// Did We Receive A Close Message?
		{
			 PostQuitMessage(0);					// Send A Quit Message
		}
        
		else if (uMsg == WM_KEYDOWN)				// Is A Key Being Held Down?
		{
			keys[wParam] = TRUE;					// If So, Mark It As TRUE
		}
        
		else if (uMsg == WM_KEYUP)					// Has A Key Been Released?
		{
			keys[wParam] = FALSE;					// If So, Mark It As FALSE
		}
        
		else if (uMsg == WM_SIZE)					// Resize The OpenGL Window
		{
			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));  // LoWord=Width, HiWord=Height
		}        		

		// Pass All Unhandled Messages To DefWindowProc
		return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

int is_Fired = 0; 

int WINAPI WinMain(	HINSTANCE	hInstance,			// Instance
					HINSTANCE	hPrevInstance,		// Previous Instance
					LPSTR		lpCmdLine,			// Command Line Parameters
					int			nCmdShow)			// Window Show State
{
	MSG		msg;									// Windows Message Structure
	BOOL	done=FALSE;								// Bool Variable To Exit Loop

	// Ask The User Which Screen Mode They Prefer
	if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode(Support Mouse Movement)?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
	{
		fullscreen=FALSE;							// Windowed Mode
	}

	// Create Our OpenGL Window
	if (!CreateGLWindow("First Person Shooter",640,480,16,fullscreen))
	{
		return 0;									// Quit If Window Was Not Created
	}

	while(!done)									// Loop That Runs While done=FALSE
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?
		{
			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
			{
				done=TRUE;							// If So done=TRUE
			}
			else									// If Not, Deal With Window Messages
			{
				TranslateMessage(&msg);				// Translate The Message
				DispatchMessage(&msg);				// Dispatch The Message
			}
		}
		else										// If There Are No Messages
		{
			// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
			if ((active && !DrawGLScene()) || keys[VK_ESCAPE])	// Active?  Was There A Quit Received?
			{
				done=TRUE;							// ESC or DrawGLScene Signalled A Quit
			}
			else									// Not Time To Quit, Update Screen
			{
				SwapBuffers(hDC);					// Swap Buffers (Double Buffering)

				is_Fired--;
				if (is_Fired < 0) is_Fired = 0;

		if (keys[VK_UP])  // Move forwards
        {
          XP -= (GLdouble)sin(heading*piover180) * 10.0f;	
          ZP -= (GLdouble)cos(heading*piover180) * 10.0f;
        }
        else if (keys['W'])  // Move forwards
        {
          XP -= (GLdouble)sin(heading*piover180) * 10.0f;	
          ZP -= (GLdouble)cos(heading*piover180) * 10.0f;
        }

        if (keys[VK_DOWN]) // Move backwards
        {
          XP += (GLdouble)sin(heading*piover180) * 10.0f;	
          ZP += (GLdouble)cos(heading*piover180) * 10.0f;
        }	               
        else if (keys['S']) // Move backwards
        {
          XP += (GLdouble)sin(heading*piover180) * 10.0f;	
          ZP += (GLdouble)cos(heading*piover180) * 10.0f;
        }	
				
        if (keys['A'])  // strafe left
        {
          XP += (GLdouble)sin((heading-90)*piover180) * 10.0f;	
          ZP += (GLdouble)cos((heading-90)*piover180) * 10.0f;
        }

        if (keys['D']) // strafe right
        {
          XP += (GLdouble)sin((heading+90)*piover180) * 10.0f;	
          ZP += (GLdouble)cos((heading+90)*piover180) * 10.0f;
        }	               
		
        if (keys[VK_LEFT]) // Turn left
        {
          zprot += .5f;
        }
        else if (keys[VK_RIGHT]) // Turn right
        {
          zprot -= .5f;
        }	
		
		if (keys['F'] && !fp) // Toggle Frame Per Second Counter
        {
          isFPS = !isFPS;
          fp = true;
        }
        else if (!keys['F'])
        {
          fp = false;
        }        

		if (keys['I'] && !ip) // Invert y-axis for the mouse
        {
          invert_mouse = !invert_mouse;
          ip = true;
        }
        else if (!keys['I'])
        {
          ip = false;
        }
      }
    }
  }

	// Shutdown
	KillGLWindow();										// Kill The Window
	return (msg.wParam);								// Exit The Program
}