#include <GL/glut.h>
#include <stdlib.h>

int smoke = 0, spin = 0, doorspin = 0, uPressed = 0, a = 0, b = 0, c = 0, r=5 ,t = 20, exh = 0, wheelspin = 0; /*rotation*/
float motion = 0, motiony = 0, motionz = 0;
float scaling = 1, slide = 0;
static GLfloat zdisp=-5.0;


/* define a draw routine to draw the x,y and z axis */
void coordinates(void) /*x,y,z*/
{ 
  // x coordinates to draw the x axis
  GLdouble x1[3] = {10.0, 0.0, 0.0};
  GLdouble x2[3] = {10.0, 0.0, 0.0};

  // y coordinates to draw the y axis
  GLdouble y1[3] = {0.0, 10.0, 0.0};
  GLdouble y2[3] = {0.0, 10.0, 0.0};

  // z coordinates to draw the z axis
  GLdouble z1[3] = {0.0, 0.0, 10.0};
  GLdouble z2[3] = {0.0, 0.0, 10.0};


  glBegin(GL_LINES);
  glColor3f(1.0, 0.0, 0.0);  //give different color to the three axis, red for x axis
  glVertex3dv(x1);
  glVertex3dv(x2);
  glColor3f(0.0, 1.0, 0.0); //give green color to y axis
  glVertex3dv(y1);
  glVertex3dv(y2);
  glColor3f(0.0, 0.0, 1.0); //give blue color to z axis
  glVertex3dv(z1);
  glVertex3dv(z2);
  glEnd();

}



void slab(void)
// draw a cube which will eventually turn into a slab
{
    glColor3f(0.1, 0.1, 0.1);
	glScaled(100,0.5,40);
	glTranslated(-0.35,-9,0);
    glutSolidCube(1.0);// use pre-defined primitive 'a unit cube'
}
void roadshadow(void)
// draw a cube which will eventually turn into a slab
{
    glColor3f(0.3, 0.3, 0.3);
	glScaled(1,0.5,1);
	glTranslated(-0.0,-2,0);
    glutSolidCube(1.0);// use pre-defined primitive 'a unit cube'
}

void cubeone(void) //x,y,z
{ 
  // x coordinates to draw the x axis
  GLdouble x1[3] = {2.0, 0.0, 0.0};
  GLdouble x2[3] = {2.0, 0.0, 0.0};

  // y coordinates to draw the y axis
  GLdouble y1[3] = {0.0, 4.0, 0.0};
  GLdouble y2[3] = {0.0, 4.0, 0.0};

  // z coordinates to draw the z axis
  GLdouble z1[3] = {0.0, 0.0, 2.0};
  GLdouble z2[3] = {0.0, 0.0, 2.0};


  glBegin(GL_POLYGON);
  glColor3f(0.8, 0.0, 0.0);  //color the x axis
  glVertex3dv(x1);
  glVertex3dv(x2);
  glColor3f(0.0, 0.8, 0.0); //color for y axis
  glVertex3dv(y1);
  glVertex3dv(y2);
  glColor3f(0.0, 0.0, 0.8); //color for z axis
  glVertex3dv(z1);
  glVertex3dv(z2);
  glEnd();


}
void door(void)
{
	//Door Right
	glColor3f(0.2, 0.2, 0.8);
	glPushMatrix();
	glTranslated(8.0, -0.8, 5);
	glScaled(2.0, 3.0, 0.5);
	glutSolidCube(1.0);
	glColor3f(0.1, 0.1, 0.1);
	glutWireCube(1.0);
	glPopMatrix();
}
void backdoor1(void)
{
	//Back(loading) Right
	glColor3f(0.2, 0.2, 0.8);
	glPushMatrix();
	glTranslated(-3.8, 0.8, -0.3);
	glScaled(0.6, 6.0, 3.0);
	glutSolidCube(1.0);
	glColor3f(0.1, 0.1, 0.1);
	glutWireCube(1.0);
	glPopMatrix();
}
void backdoor2(void)
{
	//Back(loading) Left
	glColor3f(0.2, 0.2, 0.8);
	glPushMatrix();
	glTranslated(-3.8, 0.8, 2.7);
	glScaled(0.6, 6.0, 3.0);
	glutSolidCube(1.0);
	glColor3f(0.1, 0.1, 0.1);
	glutWireCube(1.0);
	glPopMatrix();
}
void window(void)
{
	//Window Right
	glColor3f(0.6, 0.6, 0.8);
	glPushMatrix();
	glTranslated(8.0, 1.2, 4.8);
	glScaled(2.0, 1.0, 0.5);
	glutSolidCube(1.0);
	glPopMatrix();
	//Window Left
	glColor3f(0.6, 0.6, 0.8);
	glPushMatrix();
	glTranslated(8.0, 1.2, -2.8);
	glScaled(2.0, 1.0, 0.5);
	glutSolidCube(1.0);
	glPopMatrix();
}

void exhaust(void)
{
	if (exh <= 1){
	glColor3f(1.0, 1.0, 1.0);
	glPushMatrix();
	glTranslated(-8.0, -2.0, -1.0);
	glScaled(0, 0, 0);
	glutSolidTorus(0,0,0,0);
	glPopMatrix();
	}

	else if (exh <= 2){
	glColor3f(0.3, 0.3, 0.3);
	glPushMatrix();
	glTranslated(-8.0, -2.0, -1.0);
	glScaled(0.3, 0.3, 0.3);
	glutSolidTorus(2.1,2.0,15,15);
	glPopMatrix();
	}
	
	else if (exh <= 4){
	glColor3f(0.3, 0.3, 0.3);
	glPushMatrix();
	glTranslated(-10.5, -1.0, -1.0);
	glScaled(0.5, 0.5, 0.5);
	glutSolidTorus(2.1,2.0,15,15);
	glPopMatrix();
	}

	else if (exh <= 6){
	glColor3f(0.3, 0.3, 0.3);
	glPushMatrix();
	glTranslated(-14.0, 0.5, -1.0);
	glScaled(0.6, 0.6, 0.6);
	glutSolidTorus(2.1,2.0,15,15);
	glPopMatrix();
	}

	else if (exh <= 8){
	glColor3f(0.3, 0.3, 0.3);
	glPushMatrix();
	glTranslated(-18.0, 1.5, -1.0);
	glScaled(0.6, 0.6, 0.6);
	glutSolidTorus(2.1,2.0,15,15);
	glPopMatrix();
	}

	else if (exh <= 10){
	glColor3f(0.3, 0.3, 0.3);
	glPushMatrix();
	glTranslated(-22.0, 2.5, -1.0);
	glScaled(0.8, 0.8, 0.8);
	glutSolidTorus(2.1,2.0,15,15);
	glPopMatrix();
	}
}
void vehicle(void)
{
	//Back
	glColor3f(0.9, 0.9, 1.0);
	glPushMatrix();
	glTranslated(1.0, 1.0, 1.0);
	glScaled(9.4, 8.0, 8.0);
	glutSolidCube(1.0);
	glColor3f(0.8, 0.8, 1.0);
	glutWireCube(1.0);
	glPopMatrix();
	//Front
	glColor3f(0.8, 0.8, 1.0);
	glPushMatrix();
	glTranslated(8.0, 0.0, 1.0);
	glScaled(5.0, 6.0, 8.0);
	glutSolidCube(1.0);
	glColor3f(0.9, 0.9, 1.0);
	glutWireCube(1.0);
	glPopMatrix();

	//Black Door Hole
	glColor3f(0.3, 0.3, 0.3);
	glPushMatrix();
	glTranslated(8.0, -0.2, 4.8);
	glScaled(2.0, 3.0, 0.5);
	glutSolidCube(1.0);
	glPopMatrix();

	//Door Left
	glColor3f(0.2, 0.2, 0.8);
	glPushMatrix();
	glTranslated(8.0, -0.2, -3.0);
	glScaled(2.0, 3.0, 0.5);
	glutSolidCube(1.0);
	glColor3f(0.1, 0.1, 0.1);
	glutWireCube(1.0);
	glPopMatrix();
	//Front Windscreen
	glColor3f(0.6, 0.6, 0.8);
	glPushMatrix();
	glTranslated(10.2, 0.3, 1.0);
	glScaled(1.0, 3.0, 6.0);
	glutSolidCube(1.0);
	glPopMatrix();
}
void wheels(void){
	//Wheels
	glColor3f(0.1, 0.1, 0.1);
	glPushMatrix();
	glTranslated(3.0, -3.0, -3.0);
    glRotatef(-wheelspin,0.0,0.0,1.0);
    glTranslated(0,0,0);
	glScaled(0.5, 0.5, 0.5);
	glutSolidTorus(1.4,1.4,15,15);
	glColor3f(0.7, 0.7, 0.7);
	glutWireTorus(1.5,1.5,15,15);
	glPopMatrix();
	//Wheels 2
	glColor3f(0.1, 0.1, 0.1);
	glPushMatrix();
	glTranslated(-1.0, -3.0, -3.0);
    glRotatef(-wheelspin,0.0,0.0,1.0);
    glTranslated(0,0,0);
	glScaled(0.5, 0.5, 0.5);
	glutSolidTorus(1.4,1.4,15,15);
	glColor3f(0.7, 0.7, 0.7);
	glutWireTorus(1.5,1.5,15,15);
	glPopMatrix();
	//Wheels 3
	glColor3f(0.1, 0.1, 0.1);
	glPushMatrix();
	glTranslated(3.0, -3.0, 5.0);
    glRotatef(-wheelspin,0.0,0.0,1.0);
    glTranslated(0,0,0);
	glScaled(0.5, 0.5, 0.5);
	glutSolidTorus(1.4,1.4,15,15);
	glColor3f(0.7, 0.7, 0.7);
	glutWireTorus(1.5,1.5,15,15);
	glPopMatrix();
	//Wheels 4
	glColor3f(0.1, 0.1, 0.1);
	glPushMatrix();
	glTranslated(-1.0, -3.0, 5.0);
    glRotatef(-wheelspin,0.0,0.0,1.0);
    glTranslated(0,0,0);
	glScaled(0.5, 0.5, 0.5);
	glutSolidTorus(1.4,1.4,15,15);
	glColor3f(0.7, 0.7, 0.7);
	glutWireTorus(1.5,1.5,15,15);
	glPopMatrix();
}
void light(void) {
	//Front Light 1
	glColor3f(0.9, 0.9, 0.0);
	glPushMatrix();
	glRotated(270,0,1,0);
	glTranslated(-1.0, -2.5, -18.0); // Blue / Green / Red
	glScaled(0.5, 0.5, 0.5);
	glutSolidCone(2,20,50,50);
	glPopMatrix();
	//Front Light 2	
	glColor3f(0.9, 0.9, 0.0);
	glPushMatrix();
	glRotated(270,0,1,0);
	glTranslated(3.0, -2.5, -18.0); // Blue / Green / Red
	glScaled(0.5, 0.5, 0.5);
	glutSolidCone(2,20,50,50);
	glPopMatrix();
	//Light cap1
	glColor3f(0.9, 0.9, 0.0);
	glPushMatrix();
	glRotated(90,0,1,0);
	glTranslated(1.0, -2.45, 18.0);
	glScaled(0.25, 0.25, 0.25);
	glutSolidTorus(2,2,16,16);
	//Light cap2
	glPopMatrix();
	glColor3f(0.9, 0.9, 0.0);
	glPushMatrix();
	glRotated(90,0,1,0);
	glTranslated(-3.0, -2.45, 18.0);
	glScaled(0.25, 0.25, 0.25);
	glutSolidTorus(2,2,16,16);
	glPopMatrix();
	}

/* reshape callback function
   executed when window is moved or resized */
void reshape(int width, int height)
{
   glViewport(0, 0, width, height);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   //gluPerspective(50.0,1.0,15.0,150.0);
   //gluPerspective(50.0,1.0,15.0,350.0);
   glOrtho(-25.0,25.0, -25.0,25.0, 0.0, 125.0); // near and far plane is 0 and 125
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}



/* display callback function
   called whenever contents of window need to be re-displayed */
void display(void)
{
   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   /* clear window */ 
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

  gluLookAt(50.0, 20.0, 50.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
  glPolygonMode(GL_FRONT,GL_FILL); //Draw the polygon in line mode
  glPolygonMode(GL_BACK,GL_FILL);

  //Begin Matrix
  glPushMatrix();
  //Rotating on each axis
  glRotatef(spin,a,b,c);
  //Move to the origin
  glTranslated(0.0,-0.5,0.0);
  //Moving forward/back etc
  glTranslatef(motion,motiony,motionz);
  //Scaling larger and smaller
  glScaled(scaling,scaling,scaling);
  //Draw vehicle
  vehicle();
  //End Matrix
  glPopMatrix();

  //Begin Matrix
  glPushMatrix();
  //Rotating on each axis
  glRotatef(spin,a,b,c);
  //Move to the origin
  //glTranslatef(0,0,0);

  //Moving forward/back etc
  glTranslatef(motion,motiony,motionz);
  //Scaling larger and smaller
  glScaled(scaling,scaling,scaling);
  //Draw wheels
  wheels();
  //End Matrix
  glPopMatrix();

  //Begin Matrix
  glPushMatrix();
  //Rotating on each axis
  glRotatef(spin,a,b,c);
  //Move to the origin
  glTranslated(0.0,-0.5,0.0);
  //Moving forward/back etc
  glTranslatef(motion,motiony,motionz);
  //Scaling larger and smaller
  glScaled(scaling,scaling,scaling);
  //Draw exhaust
  exhaust();
  //End Matrix
  glPopMatrix();

  // Right Door (Opening/Rotating)
  glPushMatrix();
  glRotatef(spin,a,b,c);
  glTranslatef(0,0,0);
  glTranslated(7.0, -0.8, 5);
  glRotatef(-doorspin,0.0,1.0,0.0);
  glTranslatef(-7.0, 0.8, -5);
  glTranslatef(motion,motiony,motionz);
  glScaled(scaling,scaling,scaling);
  door();
  glPopMatrix();

  // Back(loading) Door1 (Opening/Rotating)
  glPushMatrix();
  glRotatef(spin,a,b,c);
  glTranslatef(0,0,0);
  glTranslatef(motion,motiony,motionz);
  glScaled(scaling,scaling,scaling);
  backdoor1();
  glPopMatrix();

  // Back(loading) Door2 (Opening/Rotating)
  glPushMatrix();
  glRotatef(spin,a,b,c);
  glTranslatef(0,0,0);
  glTranslatef(motion,motiony,motionz);
  glScaled(scaling,scaling,scaling);
  backdoor2();
  glPopMatrix();
 
  //Begin Matrix
  glPushMatrix();
  //Rotating on each axis
  glRotatef(spin,a,b,c);
  //Move to the origin
  glTranslated(0.0,0.0,0.0);
  //Slide window down
  glTranslatef(0,slide,0);
  //Moving forward/back etc
  glTranslatef(motion,motiony,motionz);
  //Scaling larger and smaller
  glScaled(scaling,scaling,scaling);
  //Draw window
  window();
  //End Matrix
  glPopMatrix();

 
  if (uPressed == 0){
  //Begin Matrix
  glPushMatrix();
  //Rotating on each axis
  glRotatef(spin,a,b,c);
  //Move to the origin
  glTranslated(0.0,0.0,0.0);
  //Moving forward/back etc
  glTranslatef(motion,motiony,motionz);
  //Scaling larger and smaller
  glScaled(scaling,scaling,scaling);
  //Draw light
  light();
  //End Matrix
  glPopMatrix();
  }

  //coordinates();  // draw the coordinate axis
  //cubeone();
  slab();
  roadshadow();

  glutSwapBuffers();
  glFlush();
}

/* graphics initialisation */ 
void init(void)
{

   glClearColor (1.0, 1.0, 1.0, 0.0);   /* window will be cleared to black */
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_CULL_FACE);  // Enable back  culling
   glCullFace(GL_BACK);     // Cull back faces

}
//Idle Call back 

void movevehicleplz(){
    if (motion <= 20){
 		motion += 0.1;
		if (exh <= 10)exh = (exh + 1);
		else if (exh == 11)exh = 0;
		wheelspin = (wheelspin + 10) % 360;

	}
	else {
		motiony -= 0.2;
		exh = 0;
		if (scaling >= 0) scaling -= 0.01;
		}
    glutPostRedisplay();
  }

//Use of Mouse Call Back
void myMouse(int button, int state, int x, int y)
  {
	  switch(button)
	  {
	  case GLUT_LEFT_BUTTON:
		  if (state==GLUT_DOWN)
			  glutIdleFunc(NULL);
		  break;

	  case GLUT_RIGHT_BUTTON:
		  if (state==GLUT_DOWN)
			  glutIdleFunc(movevehicleplz);
		  break;
	 default:
	   return;
	  }
}

/* Use of keyboard */
void keyboard(unsigned char key, int x, int y) 
{
   switch (key) {


   case 'x':
            spin = (spin + 10) % 360;
		    a = 1;
			glutPostRedisplay();  // Use display function with new value of spin & a        	
         break;

 case 'y':
            spin = (spin + 10) % 360;
		    b = 1;
			glutPostRedisplay(); // Use display function with new value of spin & b
         break;

 case 'o':
			if (motion == 0){
				if (scaling == 1)doorspin = (doorspin + 10) % 90;
			}
			b = 1;
			glutPostRedisplay(); // Use display function with new value of doorspin & b
         break;

case 'u':
	if (uPressed == 0){
		uPressed = 1;
		glClearColor (1.0, 1.0, 1.0, 1.0);
	}
	else if (uPressed == 1)
	{
		uPressed = 0;
		glClearColor (0.0, 0.0, 0.0, 0.0);
	}
			glutPostRedisplay(); // Use display function with new values
		break;

  case 'p':
	  if (slide <= 0){
		  if (slide >= -0.6) slide = (slide - 0.1);
		else if (slide <= -0.6) slide = (slide + 0.6);
	  }

			glutPostRedisplay(); // Use display function with new value of slide
         break;

 case 'z':
			spin = (spin + 10) % 360;
		    c = 1;
			glutPostRedisplay();  //Use display function with new value of spin & c
         break;

 case 'e':
	if (smoke == 0) smoke = 1;
	else if (smoke == 1) smoke = 0;
			glutPostRedisplay(); // Use display function with new values
		break;
 
 case 'c': 
	        	spin = 0;
	        	a = 0;
            		b = 0;           
		   	c = 0;
			motion = 0;
			motiony = 0;
			motionz = 0;
			wheelspin = 0;
			scaling = 1;
			slide = 0;
			doorspin = 0;
			exh = 0;

			glutPostRedisplay(); 
         break;

 case 'l':
			 if (scaling <= 1.8) scaling = (scaling + 0.1);
			 glutPostRedisplay(); 
         break;

 case 's':
			 if (scaling >= 0.4) scaling = (scaling - 0.1);
			 glutPostRedisplay(); 
         break;

 case 'f':
            motion = (motion + 1);
			if (exh <= 10)exh = (exh + 1);
			else if (exh == 11)exh = 0;
			wheelspin = (wheelspin + 10) % 360;
			glutPostRedisplay();  // Use display function with new value of motion    	
         break;
 case 'b':
            motion = (motion - 1);
			exh = 0;
			wheelspin = (wheelspin - 10) % 360;
			glutPostRedisplay();  // Use display function with new value of motion 	
         break;

   }
}

int main(int argc, char** argv)
{
   /* window management code ... */
   /* initialises GLUT and processes any command line arguments */  
   glutInit(&argc, argv);
   /* use single-buffered window and RGBA colour model */
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   /* enable the depth test */
   glEnable(GL_DEPTH_TEST);
   /* window width = 400 pixels, height = 400 pixels */
   glutInitWindowSize (600, 600);
   /* window upper left corner at (100, 100) */
   glutInitWindowPosition (0, 0);
   /* creates an OpenGL window with command argument in its title bar */
   glutCreateWindow ("Newbie C++ OpenGL Project");
  
   init();
   
   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);
   glutMouseFunc(myMouse);
   glutMainLoop();
   return 0;
}

