#include <GL/glut.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <stdlib.h>
#include <stdio.h>

GLfloat rotx=0.0;
GLfloat roty=0.0;
GLfloat rot_tr=0.0;
GLfloat tras_tr_x=0.0;
GLfloat tras_tr_z=0.0;
GLfloat tras_tav_x=0.0;
GLfloat tras_tav_z=0.0;


#define GAMBA 1

void init (void)
{
   GLfloat  ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f};

   GLfloat light0_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat light0_specular[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat light0_position[] = { 1.0, 0.2, 0.0, 0.0 };
   GLfloat specref[] = { 0.7f, 0.7f, 0.7f, 1.0f };
  
   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);

   glLightfv (GL_LIGHT0, GL_AMBIENT, light0_ambient);
   glLightfv (GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
   glLightfv (GL_LIGHT0, GL_SPECULAR, light0_specular);
   glLightfv (GL_LIGHT0, GL_POSITION, light0_position);
   glEnable(GL_LIGHT0);

   glEnable(GL_COLOR_MATERIAL);
   glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
   glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
   glMateriali(GL_FRONT, GL_SHININESS,30);
   
   glEnable (GL_LIGHTING);
   glEnable(GL_CULL_FACE);
   glEnable(GL_DEPTH_TEST);
   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

   glEnable(GL_NORMALIZE);

   glShadeModel(GL_SMOOTH);
   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

   glClearColor(0.0, 0.0, 0.0, 0.0);

   glNewList(GAMBA,GL_COMPILE);
    glColor3f (0.4, 0.2, 0.0);
	glScalef (2.0, 12.0, 2.0);
    glutSolidCube(1);
   glEndList();

}

void display (void)
{
   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glPushMatrix ();
   glTranslatef (0.0, 0.0, -50.0); 
   glRotatef (45.0, 1.0, 0.0, 0.0);
   glRotatef (rotx, 1.0, 0.0, 0.0);
   glRotatef (roty, 0.0, 1.0, 0.0);

   glPushMatrix ();
   glTranslatef (tras_tav_x, 0.0 , tras_tav_z); 
 
   glPushMatrix ();
   glTranslatef (10.0, 6.0, 0.0); 
   glCallList(GAMBA);
   glPopMatrix ();

   glPushMatrix ();
   glTranslatef (10.0, 6.0, -20.0); 
   glCallList(GAMBA);
   glPopMatrix ();

   glPushMatrix ();
   glTranslatef (-10.0, 6.0, 0.0); 
   glCallList(GAMBA);
   glPopMatrix ();

   glPushMatrix ();
   glTranslatef (-10.0, 6.0, -20.0); 
   glCallList(GAMBA);
   glPopMatrix ();

   glPushMatrix ();
   glColor3f (0.4, 0.2, 0.0);
   glTranslatef (0.0, 13.0, -10.0); 
   glScalef (22.0, 2.0, 22.0);
   glutSolidCube(1);
   glPopMatrix ();

   glPushMatrix ();
   glTranslatef (tras_tr_x, 0.0 , tras_tr_z); 
   glRotatef (rot_tr, 0.0, 1.0, 0.0);
   glPushMatrix ();
   glColor3f (0.0, 0.0, 0.5);
   glTranslatef (0.0, 17.0, 0.0); 
   glRotatef (90.0, 1.0, 0.0, 0.0);
   glutSolidCone(1,3,40,40);
   glPopMatrix ();

   glPushMatrix ();
   glColor3f (0.0, 0.5, 0.0);
   glTranslatef (0.0, 17.5, 0.0); 
   glScalef (3.0, 1.0, 1.0);
   glutSolidCube(1);
   glPopMatrix ();
   glPopMatrix ();
   glPopMatrix ();

  
   glDisable(GL_LIGHTING);
   glColor3f(0.5,0.5,0.5);
   glRotatef (-90.0, 1.0, 0.0, 0.0);
   glRectf(-80,-80,80,80);
   glEnable(GL_LIGHTING);
    
   glPopMatrix ();

   glutSwapBuffers();
}

void Timer(int value)
{ 
 rot_tr+=2.0;
 if (rot_tr>=360)
	 rot_tr=0;
 glutPostRedisplay();
 glutTimerFunc(50, Timer, 0);
}

void reshape(int w, int h)
{
   // Prevent a divide by zero
	if(h == 0)
		h = 1;

	// Set Viewport to window dimensions
    glViewport(0, 0, w, h);

	// Calculate aspect ratio of the window
	float fAspect = (GLfloat)w/(GLfloat)h;

	// Set the perspective coordinate system
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(75.0, (GLfloat) w/(GLfloat) h, 10.0, 140.0);

    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();

}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
         exit(0);
         break;
      case 'c':
         rotx+=2.0;
         break;
      case 'v':
         rotx-=2.0;
         break;
	  case 'z':
         roty+=2.0;
         break;
      case 'x':
         roty-=2.0;
         break;
      case 'a':
         if (tras_tr_x>-11.0)
         tras_tr_x-=0.5;
         break;
      case 'd':
         if (tras_tr_x<11.0)
         tras_tr_x+=0.5;
         break;
	  case 'w':
         if (tras_tr_z>-21.0)
         tras_tr_z-=0.5;
         break;
      case 's':
         if (tras_tr_z<1.0)
         tras_tr_z+=0.5;
         break;
   }
   glutPostRedisplay();
}

void processSpecialKeys(int key, int x, int y) 
{
  switch(key) {
		case GLUT_KEY_UP : 
				if (tras_tav_z>-60.0)
                  tras_tav_z-=0.5; break;
		case GLUT_KEY_DOWN : 
				if (tras_tav_z<60.0)
                  tras_tav_z+=0.5; break;
		case GLUT_KEY_LEFT : 
				if (tras_tav_x>-60.0)
                  tras_tav_x-=0.5; break;
		case GLUT_KEY_RIGHT : 
				if (tras_tav_x<60.0)
                  tras_tav_x+=0.5; break;
	}
}

int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize (500, 500);
   glutCreateWindow (argv[0]);
   init ();
   glutReshapeFunc (reshape);
   glutDisplayFunc(display);
   glutKeyboardFunc (keyboard);
   glutSpecialFunc(processSpecialKeys);	
   glutTimerFunc(50, Timer, 0);
   glutMainLoop();
   return 0; 
}
