// Lights can be adjusted using:
// glLightfv (GLenum light, GLenum paramName, TYPE *param);
// light refers to which light, EG: GL_LIGHT0, GL_LIGHT1, etc
// paramName refers to the lighting property to change, EG: GL_POSITION, 
// the Lighting types, etc
// param refers to the adjustment to be made, EG: {1.0, 0.0, 0.0} as seen in 
// redDiffuseMaterial listed below.
//
// Lighting types include: 
// GL_AMBIENT, ambient light is light seen from all angles
// GL_DIFFUSE, diffuse light is the light coming from a point
// GL_SPECULAR, specular light is the bright highlights reflected back from a light

// Now with this one you will notice that after you move the light, some of the sides
// of the cube dissappear, they do no dissappear but are simply not visible due
// to no light being shon on them. This is perfectly normal.

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

//angle of rotation
GLfloat angle = 0.0;

//diffuse light color variables
GLfloat dlr = 1.0;
GLfloat dlg = 1.0;
GLfloat dlb = 1.0;

//ambient light color variables
GLfloat alr = 1.0;
GLfloat alg = 1.0;
GLfloat alb = 1.0;

//light position variables
GLfloat lx = 0.0;
GLfloat ly = 0.0;
GLfloat lz = 1.0;
GLfloat lw = 0.0;

//draw the cube
void cube (void) {
	glRotatef(angle, 1.0, 0.0, 0.0); //rotate on the x axis
	glRotatef(angle, 0.0, 1.0, 0.0); //rotate on the y axis
	glRotatef(angle, 0.0, 0.0, 1.0); //rotate on the z axis
	glutSolidCube(2); //draw the cube
}

void init (void) {
	glEnable (GL_DEPTH_TEST); //enable the depth testing
	glEnable (GL_LIGHTING); //enable the lighting
	glEnable (GL_LIGHT0); //enable LIGHT0, our Diffuse Light
	glEnable (GL_LIGHT1); //enable LIGHT1, our Ambient Light
	glShadeModel (GL_SMOOTH); //set the shader to smooth shader
}

void display (void) {
	glClearColor (0.0,0.0,0.0,1.0); //clear the screen to black
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear the color buffer and the depth buffer
    glLoadIdentity();  
	GLfloat DiffuseLight[] = {dlr, dlg, dlb}; //set DiffuseLight[] to the specified values
	GLfloat AmbientLight[] = {alr, alg, alb}; //set AmbientLight[] to the specified values
	glLightfv (GL_LIGHT0, GL_DIFFUSE, DiffuseLight); //change the light accordingly
	glLightfv (GL_LIGHT1, GL_AMBIENT, AmbientLight); //change the light accordingly
	GLfloat LightPosition[] = {lx, ly, lz, lw}; //set the LightPosition to the specified values
	glLightfv (GL_LIGHT0, GL_POSITION, LightPosition); //change the light accordingly
	gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //camera position, x,y,z, looking at x,y,z, Up Positions of the camera
	cube(); //call the cube drawing function
	glutSwapBuffers(); //swap the buffers
	angle++; //increase the angle
}

void reshape (int w, int h) {
	glViewport (0, 0, (GLsizei)w, (GLsizei)h); //set the viewport to the current window specifications
	glMatrixMode (GL_PROJECTION); //set the matrix to projection
	glLoadIdentity ();
	gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0); //set the perspective (angle of sight, width, height, , depth)
	glMatrixMode (GL_MODELVIEW); //set the matrix back to model
}

void keyboard (unsigned char key, int x, int y) {
	if (key=='r') { 
		dlr = 1.0; //change light to red
		dlg = 0.0;
		dlb = 0.0;
	}
	if (key=='g') { 
		dlr = 0.0; //change light to green
		dlg = 1.0;
		dlb = 0.0;
	}
	if (key=='b') { 
		dlr = 0.0; //change light to blue
		dlg = 0.0;
		dlb = 1.0;
	}
	if (key=='w') { 
		ly += 10.0; //move the light up
	}
	if (key=='s') { 
		ly -= 10.0; //move the light down
	}
	if (key=='a') { 
		lx -= 10.0; //move the light left
	}
	if (key=='d') { 
		lx += 10.0; //move the light right
	}
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH); //set the display to Double buffer, with depth
	glutInitWindowSize (500, 500); //set the window size
	glutInitWindowPosition (100, 100); //set the position of the window
    glutCreateWindow ("A basic OpenGL Window"); //the caption of the window
	init (); //call the init function
    glutDisplayFunc (display); //use the display function to draw everything
	glutIdleFunc (display); //update any variables in display, display can be changed to anyhing, as long as you move the variables to be updated, in this case, angle++;
	glutReshapeFunc (reshape); //reshape the window accordingly
	glutKeyboardFunc (keyboard); //check the keyboard
    glutMainLoop (); //call the main loop
    return 0;
}

