#include "cs148.h"


// Globals to keep track of current object orientation
float x_angle = 0.0, y_angle = 0.0, z_angle = 0.0;
float rotate_speed = 0.2, step_speed = 2.0;
float view_distance = 50.0, cycle = 0.0;
int rotating = 0, zooming = 0;


void draw(void)
{
	static double lastt = CS148::getTime();
	double t = CS148::getTime(), dt = t - lastt;
	lastt = t;

	if(rotating)
	{
		// Simply update the angles:
		x_angle += 100. * rotate_speed * dt;
		y_angle += 100. * rotate_speed * dt;
		z_angle += 100. * rotate_speed * dt;
	}

	if(zooming)
	{
		cycle = cycle + 5. * dt;
		view_distance = 50.0 + 25.0*sin(cycle);
	}

	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 

	// Initially, place the centre of the object down the -z axis
	// a bit so we can see it in the camera
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0.0, 0.0, -view_distance);

	// Apply the rotations
	glRotatef(x_angle, 1.0, 0.0, 0.0);
	glRotatef(y_angle, 0.0, 1.0, 0.0);
	glRotatef(z_angle, 0.0, 0.0, 1.0);

	// Create the cube now: could have done this with GL_TRIANGLES
	// or GL_QUADS also.  Give each vertex a colour.  With the
	// shading mode set to smooth these colours are blended across
	// the surface of the polygon.

	glBegin(GL_POLYGON);  // face 1
		glColor3f(1.0, 0.0, 0.0);
		glVertex3f(5.0, -5.0, -5.0);
		glColor3f(1.0, 1.0, 0.0);
		glVertex3f(5.0, 5.0, -5.0);
		glColor3f(0.0, 1.0, 0.0);
		glVertex3f(-5.0, 5.0, -5.0);
		glColor3f(0.0, 0.0, 0.0);
		glVertex3f(-5.0, -5.0, -5.0);
	glEnd();

	glBegin(GL_POLYGON);  // face 2
		glColor3f(1.0, 0.0, 1.0);
		glVertex3f(5.0, -5.0, 5.0);
		glColor3f(1.0, 1.0, 1.0);
		glVertex3f(5.0, 5.0, 5.0);
		glColor3f(0.0, 1.0, 1.0);
		glVertex3f(-5.0, 5.0, 5.0);
		glColor3f(0.0, 0.0, 1.0);
		glVertex3f(-5.0, -5.0, 5.0);
	glEnd();

	glBegin(GL_POLYGON);  // face 3
		glColor3f(1.0, 0.0, 1.0);
		glVertex3f(5.0, -5.0, 5.0);
		glColor3f(1.0, 1.0, 1.0);
		glVertex3f(5.0, 5.0, 5.0);
		glColor3f(1.0, 1.0, 0.0);
		glVertex3f(5.0, 5.0, -5.0);
		glColor3f(1.0, 0.0, 0.0);
		glVertex3f(5.0, -5.0, -5.0);
	glEnd();

	glBegin(GL_POLYGON);  // face 4
		glColor3f(0.0, 0.0, 1.0);
		glVertex3f(-5.0, -5.0, 5.0);
		glColor3f(0.0, 1.0, 1.0);
		glVertex3f(-5.0, 5.0, 5.0);
		glColor3f(0.0, 1.0, 0.0);
		glVertex3f(-5.0, 5.0, -5.0);
		glColor3f(0.0, 0.0, 0.0);
		glVertex3f(-5.0, -5.0, -5.0);
	glEnd();

	glBegin(GL_POLYGON);  // face 5
		glColor3f(0.0, 0.0, 1.0);
		glVertex3f(-5.0, -5.0, 5.0);
		glColor3f(1.0, 0.0, 1.0);
		glVertex3f(5.0, -5.0, 5.0);
		glColor3f(1.0, 0.0, 0.0);
		glVertex3f(5.0, -5.0, -5.0);
		glColor3f(0.0, 0.0, 0.0);
		glVertex3f(-5.0, -5.0, -5.0);
	glEnd();

	glBegin(GL_POLYGON);  // face 6
		glColor3f(0.0, 1.0, 1.0);
		glVertex3f(-5.0, 5.0, 5.0);
		glColor3f(1.0, 1.0, 1.0);
		glVertex3f(5.0, 5.0, 5.0);
		glColor3f(1.0, 1.0, 0.0);
		glVertex3f(5.0, 5.0, -5.0);
		glColor3f(0.0, 1.0, 0.0);
		glVertex3f(-5.0, 5.0, -5.0);
	glEnd();

	// Ensure all drawing is finished and then swap
	// buffers to prepare for the next animation frame.
	glFlush();
	glutSwapBuffers();
}

void idle(void)
{
	// now redraw the window but only if the view has changed
	if(rotating || zooming)
		glutPostRedisplay();
}

void key(unsigned char k, int x, int y)
{
	switch(k)
	{
	case 27:  /* Escape */
		exit(0);
		break;
	case 'r':
		rotating = ~rotating;
		break;
	case 'v':
		zooming = ~zooming;
		if(!zooming)
		{
			view_distance = 50.0;
			draw();
		}
		break;
	case 'x':
		x_angle += step_speed;
		draw();
		break;
	case 'X':
		x_angle -= step_speed;
		draw();
		break;
	case 'y':
		y_angle += step_speed;
		draw();
		break;
	case 'Y':
		y_angle -= step_speed;
		draw();
		break;
	case 'z':
		z_angle += step_speed;
		draw();
		break;
	case 'Z':
		z_angle -= step_speed;
		draw();
		break;
	case '=':
		rotate_speed += 0.1;
		break;
	case '-':
		rotate_speed -= 0.1;
		break;
	}
}

void reshape(int width, int height)
{
	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, (float)width/(float)height, 1.0, 100.0);
	draw();
}


// 
// Setup OpenGL state in advance of drawing.
//
void init_drawing(void)
{
	// This ensures that colours are blended across
	// the surface of the polygon.  
	glShadeModel(GL_SMOOTH);
	glDisable(GL_LIGHTING);
	// Enable standard hidden surface removal
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_DEPTH_TEST);
}


// If iconified we don't want to do any real work so disable the
// idle function temporarily.  
//
void visible(int vis)
{
	if (vis == GLUT_VISIBLE)
		glutIdleFunc(idle);
	else
		glutIdleFunc(NULL);
}


int main(int argc, char *argv[])
{

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
	glutCreateWindow("Basic OpenGL Application");
	init_drawing();
	glutReshapeFunc(reshape);
	glutKeyboardFunc(key);
	glutIdleFunc(idle);
	glutDisplayFunc(draw);
	glutInitWindowSize(600, 480);
	glutReshapeWindow(600,480); 
	glutMainLoop();
	return 0;             
}


