#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
#include <wingdi.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 

GLfloat g_pos_luz1[4] = {-2.0, 2.0, 2.0, 0.0};
GLfloat g_pos_luz2[4] = {2.0, 2.0, -2.0, 0.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 = 1, nrSeg=8 ;
int Wid, Hei;
GLfloat rad=5, lat=0, lon=0, fv=60;
GLuint baseFont;

void setView()
{
  GLfloat ex, ey, ez, rlat, rlon;

  rlat = rad(lat);
  rlon = rad(lon);
  ex = rad * cos(rlat) * cos(rlon);
  ey = rad * cos(rlat) * sin(rlon);
  ez = rad * sin(rlat);
  printf("ex=%f ey=%f ez=%f\n",ex,ey,ez);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
/*  if (Wid <= Hei)
    glOrtho(-10.0 * (GLfloat) escala, 10.0 * (GLfloat) escala, -10.0  * (GLfloat) escala* (GLfloat) Hei / (GLfloat) Wid,
			10.0  * (GLfloat) escala* (GLfloat) Hei / (GLfloat) Wid, -10.0, 10.0);
  else
    glOrtho(-10.0  * (GLfloat) escala * (GLfloat) Wid / (GLfloat) Hei,
			10.0  * (GLfloat) escala * (GLfloat) Wid / (GLfloat) Hei, -10.0 * (GLfloat) escala, 10.0 * (GLfloat) escala, -10.0, 10.0);
*/
  gluPerspective(60,(GLfloat)Wid/Hei,0.1,20);
  gluLookAt(ex, ey, ez, 0, 0, 0, 0, 0, 1);
  glMatrixMode(GL_MODELVIEW);
}


void BuildFont(void)								// Build Our Bitmap Font
{
	GLYPHMETRICSFLOAT	gmf[256];						// Address Buffer For Font Storage
	HFONT	font;										// Windows Font ID
	HDC hDC;



	baseFont = glGenLists(256);								// Storage For 256 Characters

	font = CreateFont(	-12,							// Height Of Font
						0,								// Width Of Font
						0,								// Angle Of Escapement
						0,								// Orientation Angle
						FW_BOLD,						// Font Weight
						FALSE,							// Italic
						FALSE,							// Underline
						FALSE,							// Strikeout
						DEFAULT_CHARSET
,					// Character Set Identifier
						OUT_TT_PRECIS,					// Output Precision
						CLIP_DEFAULT_PRECIS,			// Clipping Precision
						ANTIALIASED_QUALITY,			// Output Quality
						FF_DONTCARE|DEFAULT_PITCH,		// Family And Pitch
						"Comic Sans MS");				// Font Name

	hDC=GetDC(NULL);

	SelectObject(hDC, font);							// Selects The Font We Created

	wglUseFontOutlines(	hDC,							// Select The Current DC
						0,								// Starting Character
						255,							// Number Of Display Lists To Build
						baseFont,							// Starting Display Lists
						0.1f,							// Deviation From The True Outlines
						0.2f,							// Font Thickness In The Z Direction
						WGL_FONT_POLYGONS,				// Use Polygons, Not Lines
						gmf);							// Address Of Buffer To Recieve Data
}

void KillFont(void)									// Delete The Font
{
  glDeleteLists(baseFont, 256);								// Delete All 256 Characters
}

void glPrint(char *text)								// Custom GL "Print" Routine
{
  if (text == NULL)										// If There's No Text
    return;												// Do Nothing

  glPushAttrib(GL_LIST_BIT);							// Pushes The Display List Bits
    glListBase(baseFont);									// Sets The Base Character to 32
    glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);	// Draws The Display List Text
  glPopAttrib();										// Pops The Display List Bits
}


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);
	if(glIsEnabled(GL_LIGHT0))
	{
		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();
	}
	if(glIsEnabled(GL_LIGHT1))
	{
		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();
	}*/
}


void display(void)
{


	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glLoadIdentity();
	putLights((GLfloat*)white_light);
	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);
	
	glPushMatrix();
		glRotatef(90,1,0,0 );
		glRotatef(90,0,1,0 );
		glPrint("Open GL");
	glPopMatrix();
	

	glFlush();
	glutSwapBuffers();

}

void spin()
{

/* 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 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 'r':
			glutIdleFunc(NULL);
		  break;
		case 'R':
			glutIdleFunc(spin);
		  break;
		if(glIsEnabled(GL_LIGHT0))		
				glDisable(GL_LIGHT0);
			else
				glEnable(GL_LIGHT0);
			glutPostRedisplay();
		  break;
		case '2':
			if(glIsEnabled(GL_LIGHT1))		
				glDisable(GL_LIGHT1);
			else
				glEnable(GL_LIGHT1);
			glutPostRedisplay();
		  break;
		case 27:
			exit(0);
		  break;
    }
	printf("%d\n",key);
}

void special(int key, int x, int y)
{
    switch (key)
    {
        case GLUT_KEY_F1:
			theta[0]=theta[1]=theta[2]=0;
			glutPostRedisplay();
		break;
        case GLUT_KEY_F2:
			theta[0]=theta[1]=0;
			theta[2]=90;
			glutPostRedisplay();
		break;
        case GLUT_KEY_F3:
			theta[0]=theta[2]=0;
			theta[1]=90;
			glutPostRedisplay();
		break;
        case GLUT_KEY_F4:
			theta[1]=theta[2]=0;
			theta[0]=90;
			glutPostRedisplay();
		break;
        case GLUT_KEY_UP:
			if(lat<88) {
				lat+=2;
				setView();
				glutPostRedisplay();
			}
		break;
         case GLUT_KEY_DOWN:
			if(lat>-88) {
				lat-=2;
				setView();
				glutPostRedisplay();
			}
        break;
        case GLUT_KEY_RIGHT:
			if(lon<180) {
				lon+=2;
				setView();
				glutPostRedisplay();
			}
		break;
         case GLUT_KEY_LEFT:
			if(lon>-180) {
				lon-=2;
				setView();
				glutPostRedisplay();
			}
        break;
        case GLUT_KEY_PAGE_UP:
			if(rad<30) {
				rad+=1;
				printf("Rad %f\n",rad);
				setView();
				glutPostRedisplay();
			}
		break;
         case GLUT_KEY_PAGE_DOWN:
			if(rad>2) {
				rad-=1;
				printf("Rad %f\n",rad);
				setView();
				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);
	Wid=w;
	Hei=h;
	setView();	
}


void myInit()
{

	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_LIGHT1);  /* enable light 0 */
	glEnable(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST); /* enable z buffer */
    glDepthFunc(GL_LESS);
	glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
	glEnable(GL_NORMALIZE);
}


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);
	glutSpecialFunc(special);
	glutMouseFunc(mouse);

	myInit();
	BuildFont();
    glutMainLoop();
	KillFont();

}
