 
/*

USING: Click on any point within the window to set the rotating position

x - Rotate ROT_ANGLE degrees about the x-coordinate.
X - Rotate -ROT_ANGLE degrees about the x-coordinate.
and similarly for y, Y, z and Z.

use 'q' or 'Q' to quit.
*/

#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#define ROT_ANGLE 2 

int clicked_point[3];
GLfloat rotate_point[3];

void myInit () {
	 
	 glClearColor (1.0, 1.0, 1.0, 1.0);
	 glEnable (GL_DEPTH_TEST);
	 
	 glMatrixMode (GL_PROJECTION);
	 glLoadIdentity();
	 glOrtho (-20, 20, -20, 20, -20, 20);
	 glMatrixMode (GL_MODELVIEW);
}
 
void myRotate (unsigned char axis) {
	 
	/* Now call glTranslatef to set this as the origin. */
	glTranslatef (rotate_point[0], rotate_point[1], rotate_point[2]);
	
	switch (axis) {
		case 'x':
			glRotatef (ROT_ANGLE, 1.0, 0.0, 0.0);
			break;
		case 'y':
			glRotatef (ROT_ANGLE, 0.0, 1.0, 0.0);
			break;
		case 'z':
			glRotatef (ROT_ANGLE, 0.0, 0.0, 1.0);
			break;
		case 'X':
			glRotatef (-ROT_ANGLE, 1.0, 0.0, 0.0);
			break;
		case 'Y':
			glRotatef (-ROT_ANGLE, 0.0, 1.0, 0.0);
			break;
		case 'Z':
			glRotatef (-ROT_ANGLE, 0.0, 0.0, 1.0);
			break;
	}
	
	glTranslatef (-rotate_point[0], -rotate_point[1], -rotate_point[2]);
	
}
 
void display () {
	 
	 GLfloat cube[8][3] = { {5.0, 5.0, -5.0}, {5.0, 5.0, 5.0}, {-5.0, 5.0, -5.0}, {-5.0, 5.0, 5.0},
	 {-5.0, -5.0, -5.0}, {-5.0, -5.0, 5.0}, {5.0, -5.0, -5.0}, {5.0, -5.0, 5.0} };
	 
	 GLfloat apex[3] = {0.0, 10.0, 0.0};
	 
	 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	 glColor3f (0.0, 0.0, 0.0);
	 glBegin (GL_LINE_LOOP);
	 	glVertex3fv (cube[1]);
		glVertex3fv (cube[3]);
		glVertex3fv (cube[5]);
		glVertex3fv (cube[7]);
	 glEnd();
	 glBegin (GL_LINE_LOOP);
	  	glVertex3fv (cube[2]);
		glVertex3fv (cube[0]);
		glVertex3fv (cube[6]);
		glVertex3fv (cube[4]);
	
	glEnd();
	glBegin (GL_LINE_LOOP);
		glVertex3fv (cube[5]);
		glVertex3fv (cube[4]);
		glVertex3fv (cube[2]);
		glVertex3fv (cube[3]);
	glEnd();
	glBegin (GL_LINE_LOOP);	 
	 	glVertex3fv (cube[7]);
		glVertex3fv (cube[6]);
		glVertex3fv (cube[0]);
		glVertex3fv (cube[1]);
	glEnd();
	glBegin (GL_LINE_LOOP);
		glVertex3fv (cube[5]);
		glVertex3fv (cube[4]);
		glVertex3fv (cube[6]);
		glVertex3fv (cube[7]);
	glEnd();
	glBegin (GL_LINE_LOOP);
		glVertex3fv (cube[0]);
		glVertex3fv (cube[1]);
		glVertex3fv (cube[3]);
		glVertex3fv (cube[2]);
	 glEnd();
	 
	 /* The above draws the cube. Now draw a prism over the cube */
	 /* Draw four lines from the top four points to 5 units above the
	 center of the top square. */
	 
	glBegin (GL_LINES);
		glVertex3fv (cube[0]);
		glVertex3fv (apex);
		
		glVertex3fv (cube[1]);
		glVertex3fv (apex);
		
		glVertex3fv (cube[2]);
		glVertex3fv (apex);
		
		glVertex3fv (cube[3]);
		glVertex3fv (apex);
	glEnd();
	
	/* Now draw a door :) */
	
	glBegin (GL_QUADS);
		glVertex3f (-2.0, -5.0, 5.0);
		glVertex3f (-2.0, -2.0, 5.0);
		glVertex3f (2.0, -2.0, 5.0);
		glVertex3f (2.0, -5.0, 5.0);
	glEnd();
	 
	glFlush();
}
 
void keyReact (unsigned char key, int x, int y) {
	 
	 switch (key) {
		 case 'q':
		 case 'Q':
			 exit (EXIT_SUCCESS);
			 break;
		 case 'x':
		 case 'y':
		 case 'z':
		 case 'X':
		 case 'Y':
		 case 'Z':
			 myRotate(key);
			 glutPostRedisplay();
			 break;
	}
}

void myTransformCoordinates () {
	
	/* This function transforms clicked_point to rotate_point, where
	the former is in the window coordinates and the latter is in the
	internal coordinates used in openGL. */
	
	int x_size, y_size;
	
	x_size = glutGet (GLUT_WINDOW_WIDTH);
	y_size = glutGet (GLUT_WINDOW_HEIGHT);
	
	/* clicked_point contains the coordinates of the point that was clicked, 
	w.r.t the origin of the window (top-left), in pixels. We need to convert
	this to our internal coordinates, which ranges from -20 to +20 (40 range)
	on both the x and y coordinates. (we specified it in glOrtho()) */
	
	rotate_point[0] = (((float)clicked_point[0]/(float) x_size)*40)-20;
	rotate_point[1] = -(((float)clicked_point[1]/(float) y_size)*40)+20;
	rotate_point[2] = 0.0;
	
}
/* When the user clicks somewhere in the window, that point is considered the
rotate about point. */
void mouseReact (int btn, int state, int x, int y) {
	
	int i;
	if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
		clicked_point[0] = x;
		clicked_point[1] = y;
		clicked_point[2] = 0.0;
	}
	
	/* This will set rotate_point to the clicked_point equavalent. */
	myTransformCoordinates ();

	return;
}
 
int main (int argc, char **argv) {
	 
	 glutInit (&argc, argv);
	 glutInitDisplayMode (GLUT_RGB | GLUT_DEPTH | GLUT_SINGLE);
	 glutCreateWindow ("Cube");	
	 glutInitWindowPosition (0, 0);
	 glutInitWindowSize (400, 500);
	 glutDisplayFunc (display);
	 glutKeyboardFunc (keyReact);
	 glutMouseFunc (mouseReact);
	 myInit();
	 glutMainLoop();
	 return 0;
}
 

