/* Rotating Cube.c        */

/* Rotating cube with color interpolation */

/* E. Angel, Interactive Computer Graphics */
/* A Top-Down Approach with OpenGL, Third Edition */
/* Addison-Wesley Longman, 2003 */

/* Demonstration of use of homogeneous coordinate 
transformations and simple data structure for representing
cube from Chapter 4 */

/* Colors are assigned to the vertices */
/* Mouse buttons control direction of rotation */

#include <stdlib.h>
#include <GL/glut.h>
#include <iostream.h>
#include <math.h>

	GLfloat vertices[][3] = {
		{-1,-1,-1}, {1,-1,-1}, {1,1,-1}, 
		{-1,1,-1}, {-1,-1,1}, {1,-1,1}, 
		{1,1,1}, {-1,1,1}
	};

	GLfloat colors[][3] = {
		{0.0,0.0,0.0}, {1.0,0.0,0.0}, {1.0,1.0,0.0}, 
		{0.0,1.0,0.0}, {0.0,0.0,1.0}, {1.0,0.0,1.0}, 
		{1.0,1.0,1.0}, {0.0,1.0,1.0}
	};
void draw_axis(){
	glColor3f(0,1,0);
	glBegin(GL_LINES);
		glVertex3f(-2,0,0);
		glVertex3f(2,0,0);
		glVertex3f(0,-2,0);
		glVertex3f(0,2,0);
		glVertex3f(0,0,-2);
		glVertex3f(0,0,2);
	glEnd();

}
void polygon(int a, int b, int c , int d) {

/* draw a polygon via list of vertices */

 	glBegin(GL_POLYGON);
		glColor3fv(colors[a]);
		glVertex3fv(vertices[a]);
		glColor3fv(colors[b]);
		glVertex3fv(vertices[b]);
		glColor3fv(colors[c]);
		glVertex3fv(vertices[c]);
		glColor3fv(colors[d]);
		glVertex3fv(vertices[d]);
	glEnd();
																										}

void colorcube(void){ /* map vertices to faces */

	polygon(0,3,2,1);
	polygon(2,3,7,6);
	polygon(0,4,7,3);
	polygon(1,2,6,5);
	polygon(4,5,6,7);
	polygon(0,1,5,4);
}

static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 1;
GLfloat factor[] = {1, 1, 1 };
GLfloat eyeX=0,eyeY=0,eyeZ=2;
GLfloat atX=0, atY=0, atZ=0;

void display(void) {
/* display callback, clear frame buffer and z buffer,
   rotate cube and draw, swap buffers */

	float angle = (3.14159/8) ;
	float m[16];
	int i;
	for (i=0;i<15; i++)
			m[i]=0;
	m[0]=m[5]=m[10]=m[15]=1;
//	m[4]= 1/tan(angle);//shear x
	m[1]= 1/tan(angle);//shear y
//	m[6]= 1/tan(angle);//shear z

	glClearColor(1,1,1,1); 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	glMultMatrixf(m);
//	gluLookAt(eyeX,eyeY,eyeZ,atX,atY,atZ,0,1,0);
//	draw_axis();
	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);
//	glTranslatef(0,0,dispX);
//	glFushMatrix();

//	glPopMatrix();
	colorcube();
	glFlush();
	glutSwapBuffers();
}

void spinCube() {

	/* Idle callback, spin cube 2 degrees about selected axis */

	theta[axis] += 0.1;
	if( theta[axis] > 360.0 ) 
		theta[axis] -= 360.0;
	if(theta[axis]< -360)
		theta[axis] += 360;
	/* display(); */
	glutPostRedisplay();
}

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 = 1;
		theta[axis] +=0.1;
		// cout << "theta[" << axis << "]=" << theta[axis] << "\n";
	}
	if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) {
		axis = 1;
		theta[axis] -= 2;
		// cout << "theta[" << axis << "]=" << theta[axis] << "\n";
	}
	if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
		axis = 1;
		theta[axis] -=0.1;
	}
	spinCube();
}
int lastPos[3];
int znear=0;
void mouseMotion(int x, int y) {
	int dx, dy;

	dx = x-lastPos[0];
	dy = y-lastPos[1];
	if(dy>0)
		glTranslatef(0,0,1);
	else 
		glTranslatef(0,0,-1);
	lastPos[0] = x;
	lastPos[1] = y;
}

void keys(unsigned char key, int x, int y) {
	if(key=='x')
		eyeX += 0.1;
	if(key == 'X') 
		eyeX -= 0.1;
	if(key == 'y') 
		eyeY  += 0.1;
	if(key == 'Y') 
		eyeY -= 0.1;
	if(key == 'z') 
		eyeZ += 0.1;
	if(key == 'Z') 
		eyeZ -= 0.1;
	glutPostRedisplay();
}

void myReshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho(-2, 2, -2 * (GLfloat) h / (GLfloat) w,
            2 * (GLfloat) h / (GLfloat) w, 0.5, 4);
    else
        glOrtho(-2 * (GLfloat) w / (GLfloat) h,
            2 * (GLfloat) w / (GLfloat) h, -2, 2, 0.5,4);
    glMatrixMode(GL_MODELVIEW);
}

void main(int argc, char **argv) {
    glutInit(&argc, argv);

/* need both double buffering and z buffer */

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(500, 400);
    glutCreateWindow("colorcube");
    glutReshapeFunc(myReshape);
    glutDisplayFunc(display);
	glutMouseFunc(mouse);
	glutKeyboardFunc(keys);
	glutIdleFunc(spinCube);
//	glutMotionFunc(mouseMotion);
	glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
    glutMainLoop();
}