//-------------------------------------------------------------
// Lighting Code
// John Brosz, Nov, 2008
// Based on code by Pauline Jepp
//-------------------------------------------------------------

#include <math.h>
#include <GL/glut.h>
#include <stdio.h>

#define PI 3.141592653;

// let's define some colors for use later (RGB)
  GLfloat mat_R[] = {1.0, 0.0, 0.0};
  GLfloat mat_G[] = {0.0, 1.0, 0.};
  GLfloat mat_B[] = {0.0, 0.0, 1.0};
  GLfloat mat_Y[] = {1.0, 1.0, 0.0};
  GLfloat mat_M[] = {1.0, 0.0, 1.0};
  GLfloat mat_C[] = {0.0, 1.0, 1.0};

  float yRot = 0.0f; // tracks rotation of our object from frame to frame


// openGL initiation stuff
void init()
{
	// the usual stuff
	glClearColor(0,0,0,0);
	glShadeModel(GL_SMOOTH); // enable smooth shading so you can have more than 1 normal per face
	glEnable(GL_DEPTH_TEST);

	// various properties for material shininess, light color, position, etc
	GLfloat mat_shininess[] = { 90.0 };
	GLfloat light0_position[] = { 1.0, -2.0, 5.0, 0.0 };
	GLfloat light1_position[] = { -1.0, 10.0, -5.0, 1.0 };
	GLfloat dim_light[] = {0.7, 0.7, 0.7, 1};
	GLfloat white_light[] = {1, 1, 1, 1};
	GLfloat lmodel_ambient[] = {0.1, 0.1, 0.1, 1.0};

	// set up two lights
	glLoadIdentity();
	glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, dim_light);
	glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
	glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, dim_light);
	glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);

	// we're going to have all objects have the same shininess and specular, so define that now
	glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white_light);


	// set up global ambient
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);

	// turn on the lights
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
} // end init

// window resizing
void OnReshape(int w, int h)
{
	// set the drawable region of the window
	glViewport(0,0,w,h);
	// set up the projection matrix 
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	const float scale = 1.0f;
	if (w > h)
	{
		float aspect = (float)w/(float)h;
		glFrustum(scale * -aspect, scale * aspect, -scale, scale, 1.5, 20);
	} else {
		float aspect = (float)h/(float)w;
		glFrustum(-scale, scale, scale * -aspect, scale * aspect, 1.5, 20);
	}
	// go back to modelview matrix
	glMatrixMode(GL_MODELVIEW);
}

// our display function, mostly the usual stuff, be sure to multiply in our rotation matrix
void display() 
{
	// clear the screen & depth buffer
	glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);

	// clear any previous transform
	glLoadIdentity();

	// set the camera position
	gluLookAt(	0,0,-8,	//	eye pos
				0,0,0,	//	aim point
				0,1,0);	//	up direction

	// draw a cube
	glPushMatrix();
    glRotatef(yRot, 0, 1, 0);
	glTranslatef(2,0,0);
	glRotatef(yRot, 1, 0, 0);

	// draw a cube
	 glBegin(GL_POLYGON); //top
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_M);
		glNormal3f(0, 1, 0);
		glVertex3f(-1, 1, -1); //1
		glVertex3f(1, 1, -1); //2
		glVertex3f(1, 1, 1); //7
		glVertex3f(-1, 1, 1); //6
    glEnd();
	 glBegin(GL_POLYGON); //bottom
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_B);
		glNormal3f(0, -1, 0);
		glVertex3f(-1, -1, -1);
		glVertex3f(1, -1, -1);
		glVertex3f(1, -1, 1);
		glVertex3f(-1, -1, 1);
    glEnd();
	 glBegin(GL_POLYGON); //front
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_Y);
		glNormal3f(0,0,-1);
		glVertex3f(-1, 1, -1);
		glVertex3f(-1, -1, -1);
		glVertex3f(1, -1, -1); 
		glVertex3f(1, 1, -1);
    glEnd();
	 glBegin(GL_POLYGON); //back
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_R);
		glNormal3f(0,0,1);
		glVertex3f(-1, 1, 1);
		glVertex3f(1, 1, 1);
		glVertex3f(1, -1, 1); 
		glVertex3f(-1, -1, 1);
    glEnd();
	 glBegin(GL_POLYGON); //left
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_G);
		glNormal3f(-1,0,0);
		glVertex3f(-1,1,-1);
		glVertex3f(-1,1,1);
		glVertex3f(-1,-1,1); 
		glVertex3f(-1,-1,-1);
    glEnd();
	 glBegin(GL_POLYGON); //right
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_C);
		glNormal3f(1,0,0);
		glVertex3f(1,1,-1);
		glVertex3f(1,-1,-1);
		glVertex3f(1,-1,1); 
		glVertex3f(1,1,1);
    glEnd();

	glPopMatrix();

	// draw a sphere
	glPushMatrix();
	glRotatef(yRot, 0, 1, 0);
	glTranslatef(-2, 0 ,0);
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_C);
	glutSolidSphere(2, 16, 16);
	glPopMatrix();

	// currently we've been drawing to the back buffer, we need to swap the back buffer with the front one to make the image visible
	glutSwapBuffers();
} // end display

void idle()
{
	yRot += 0.4f;
	glutPostRedisplay();
} // end idle

int main(int argc,char** argv) {

	// initialise glut
	glutInit(&argc,argv);

	// we want depth buffer, RGBA display mode, and double buffering
	glutInitDisplayMode(GLUT_DEPTH|GLUT_RGBA|GLUT_DOUBLE);

	// set the window size
	glutInitWindowSize(500,500);

	// create the window
	glutCreateWindow("Lights, Camera, Action!");

	// set the callbacks
	glutIdleFunc(idle);
	glutDisplayFunc(display);
	glutReshapeFunc(OnReshape);

	// do our intialization
	init();

	glutMainLoop();
	return 0;
}

