#include <math.h>
#include <GL\glut.h>

#define PI (double)3.14159265358979323846

#define graus(X) (double)(X)*180/PI
#define rad(X)   (double)(X)*PI/180

// luzes e materiais

GLint Lv[]={1};

GLfloat g_pos_luz1[4] = {-5.0, 5.0, 5.0, 1.0};
GLfloat g_pos_luz2[4] = {5.0, 5.0, -5.0, 1.0};

const GLfloat red_light[] = {1.0, 0.0, 0.0, 1.0};
const GLfloat green_light[] = {0.0, 1.0, 0.0, 1.0};
const GLfloat blue_light[] = {0.0, 0.0, 1.0, 1.0};
const GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};

const GLfloat brass_ambient[] = {0.33, 0.22, 0.03, 1.0};
const GLfloat brass_diffuse[] = {0.78, 0.57, 0.11, 1.0};
const GLfloat brass_specular[] = {0.99, 0.91, 0.81, 1.0};
const GLfloat brass_shininess = 27.8;

const GLfloat red_plastic_ambient[] = {0.0, 0.0, 0.0};
const GLfloat red_plastic_diffuse[] = {0.5, 0.0, 0.0};
const GLfloat red_plastic_specular[] = {0.7, 0.6, 0.6};
const GLfloat red_plastic_shininess = 32.0;

const GLfloat emerald_ambient[] = {0.0215, 0.1745, 0.0215};
const GLfloat emerald_diffuse[] = {0.07568, 0.61424, 0.07568};
const GLfloat emerald_specular[] = {0.633, 0.727811, 0.633};
const GLfloat emerald_shininess = 76.8;

const GLfloat slate_ambient[] = {0.02, 0.02, 0.02};
const GLfloat slate_diffuse[] = {0.78, 0.78, 0.78};
const GLfloat slate_specular[] = {0.14, 0.14, 0.14};
const GLfloat slate_shininess = 18.78;

const GLfloat solido_azul_ambient[] = {0.0, 0.0, 0.1745};
const GLfloat solido_azul_diffuse[] = {0.0, 0.0,  0.61424};
const GLfloat solido_azul_specular[] = {0.0, 0.0, 0.727811};
const GLfloat solido_azul_shininess = 30.0;

const GLfloat material_preto_ambient[] = {0.02, 0.02, 0.02};
const GLfloat material_preto_diffuse[] = {0.08, 0.08, 0.08};
const GLfloat material_preto_specular[] = {0.03, 0.03, 0.03};
const GLfloat material_preto_shininess = 75.0;

const GLfloat material_cinza_ambient[] = {0.1745, 0.1745, 0.1745};
const GLfloat material_cinza_diffuse[] = {0.61424, 0.61424, 0.61424};
const GLfloat material_cinza_specular[] = {0.727811, 0.727811, 0.727811};
const GLfloat material_cinza_shininess = 60.0;

enum tipo_material {brass, slate, red_plastic, emerald, solido_azul, material_preto, material_cinza};

GLfloat escala=0.2;
int cor_cubo = brass;
GLfloat theta[] = { 0.0, 0.0, 0.0 };
GLint axis = 2;


void material(enum tipo_material mat)
{
	switch (mat)
	{
		case brass:
			glMaterialfv(GL_FRONT, GL_AMBIENT, brass_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, brass_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, brass_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, brass_shininess);
		break;
		case red_plastic:
			glMaterialfv(GL_FRONT, GL_AMBIENT, red_plastic_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, red_plastic_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, red_plastic_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, red_plastic_shininess);
		break;
		case emerald:
			glMaterialfv(GL_FRONT, GL_AMBIENT, emerald_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, emerald_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, emerald_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, emerald_shininess);
		break;
		case slate:
			glMaterialfv(GL_FRONT, GL_AMBIENT, slate_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, slate_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, slate_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, slate_shininess);
		break;
		case solido_azul:
			glMaterialfv(GL_FRONT, GL_AMBIENT, solido_azul_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, solido_azul_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, solido_azul_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, solido_azul_shininess);
		break;
		case material_preto:
			glMaterialfv(GL_FRONT, GL_AMBIENT, material_preto_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, material_preto_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, material_preto_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, material_preto_shininess);
		break;
		case material_cinza:
			glMaterialfv(GL_FRONT, GL_AMBIENT, material_cinza_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, material_cinza_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, material_cinza_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, material_cinza_shininess);
		break;
	}
}



void putLights(GLfloat* diffuse)
{
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
	glLightfv(GL_LIGHT0, GL_POSITION, g_pos_luz1);

	glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
	glLightfv(GL_LIGHT1, GL_POSITION, g_pos_luz2);

	/* desenhar luz */
    material(red_plastic);
	glPushMatrix();
		glTranslatef(g_pos_luz1[0], g_pos_luz1[1], g_pos_luz1[2]);
		glDisable(GL_LIGHTING);
		glColor3f(1.0, 1.0, 1.0);
		glutSolidCube(0.1);
		glEnable(GL_LIGHTING);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(g_pos_luz2[0], g_pos_luz2[1], g_pos_luz2[2]);
		glDisable(GL_LIGHTING);
		glColor3f(1.0, 1.0, 1.0);
		glutSolidCube(0.1);
		glEnable(GL_LIGHTING);
	glPopMatrix();

	//glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
}

void display(void)
{


	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	 
	glRotatef(theta[0], 1.0, 0.0, 0.0);
	glRotatef(theta[1], 0.0, 1.0, 0.0);
	glRotatef(theta[2], 0.0, 0.0, 1.0);
    
	material(cor_cubo);
	
	glutSolidTeapot(1);
	

	glFlush();
	glutSwapBuffers();

}



void keyboard(unsigned char key, int x, int y)
{

    switch (key)
    {
         case 'o':
            if (cor_cubo == material_cinza)
                cor_cubo=brass;
            else
                cor_cubo++;
            glutPostRedisplay();
        break;
         case 'l':
              if(Lv[0])
                  Lv[0]=0;
              else
                  Lv[0]=1;
            	glLightModeliv(GL_LIGHT_MODEL_LOCAL_VIEWER, Lv);
            glutPostRedisplay();
          break;

    }
}

void mouse(int btn, int state, int x, int y)
{

/* mouse callback, selects an axis about which to rotate */

  if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    axis = 0;
  if (btn == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
    axis = 1;
  if (btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
    axis = 2;
}

void myReshape(int w, int h)
{	
	glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (w <= h)
        glOrtho(-10.0 * (GLfloat) escala, 10.0 * (GLfloat) escala, -10.0  * (GLfloat) escala* (GLfloat) h / (GLfloat) w,
            10.0  * (GLfloat) escala* (GLfloat) h / (GLfloat) w, -10.0, 10.0);
    else
        glOrtho(-10.0  * (GLfloat) escala * (GLfloat) w / (GLfloat) h,
            10.0  * (GLfloat) escala * (GLfloat) w / (GLfloat) h, -10.0 * (GLfloat) escala, 10.0 * (GLfloat) escala, -10.0, 10.0);

    glMatrixMode(GL_MODELVIEW);
}

void spin(void)
{

/* Idle callback, spin cube 2 degrees about selected axis */

  theta[axis] += 0.25;
  if (theta[axis] > 360.0)
    theta[axis] -= 360.0;
/* display(); */
  glutPostRedisplay();
}


void myInit()
{

	GLfloat LuzAmbiente[]={0.5,0.5,0.5, 0.0};

	glClearColor (0.0, 0.0, 0.0, 0.0);
	putLights((GLfloat*)white_light);

    glEnable(GL_SMOOTH); /*enable smooth shading */
    glEnable(GL_LIGHTING); /* enable lighting */
    glEnable(GL_LIGHT0);  /* enable light 0 */
    glEnable(GL_DEPTH_TEST); /* enable z buffer */
    glDepthFunc(GL_LESS);
	glEnable(GL_NORMALIZE);

	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, LuzAmbiente); 
	glLightModeliv(GL_LIGHT_MODEL_LOCAL_VIEWER, Lv); 


}

void main(int argc, char **argv)
{
    glutInit(&argc, argv);

/* need both double buffering and z buffer */

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(640, 480);
    glutCreateWindow("OpenGL");
    glutReshapeFunc(myReshape);
    glutDisplayFunc(display);
	glutKeyboardFunc(keyboard);
	glutIdleFunc(spin);
	glutMouseFunc(mouse);

	myInit();

    glutMainLoop();
}
