/*
 * 3d-movie.c
 * Jeffrey Grafton <jgrafton at tjhsst dot edu>
 * 12/19/2002
 *
 * This program is released under the GNU General Public License.
 * A copy of this license is available online at
 * http://www.gnu.org/copyleft/gpl.html.
 * */

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

#define WINDOW_WIDTH 600
#define WINDOW_HEIGHT 600

GLfloat view_position[] = {0.0, 1.0, 5.0};

GLfloat spin_val = 0.0;
GLfloat mat_specular[] = {0.5, 0.5, 0.5, 1.0};
GLfloat mat_shininess[]= {50.0};
GLdouble head_spin = 0.0;
GLdouble arm_spin = 60.0;
GLdouble body_spin = 0.0;
GLdouble view_spin = 0.0;	
GLdouble leg_spin = 90.0;
GLfloat fog_color[] = {0.3, 0.3, 0.3, 1.0};
GLdouble arm_move = 5.0;
GLdouble head_move = 10.0;
GLdouble bomb_time = 0.0;
int explode = 0;
int threshold = 0;
int height = 0;
GLdouble explosion_size = 1.0;

void init(void)
{
	glClearColor(0.3, 0.3, 0.3, 1.0);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_COLOR_MATERIAL);
	
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
	glEnable(GL_LIGHT2);
	glEnable(GL_LIGHT3);

	glEnable(GL_FOG);
	glFogi(GL_FOG_MODE, GL_EXP2);
	glFogfv(GL_FOG_COLOR, fog_color);
	glFogf(GL_FOG_DENSITY, 0.015);
	glHint(GL_FOG_HINT, GL_NICEST);

	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}

void display(void)
{
	int i;
	GLfloat light_0_position[] = {-50.0, 11.0, -50.0, 1.0};
	GLfloat light_1_position[] = {-50.0, 11.0, 50.0, 1.0};
	GLfloat light_2_position[] = {50.0, 11.0, 50.0, 1.0};
	GLfloat light_3_position[] = {50.0, 11.0, -50.0, 1.0};
	GLfloat red_light[] = {0.7, 0.2, 0.2, 1.0};
	GLfloat green_light[] = {0.2, 0.7, 0.2, 1.0};
	GLfloat blue_light[] = {0.2, 0.2, 0.7, 1.0};
	GLfloat yellow_light[] = {0.7, 0.7, 0.2, 1.0};
	GLdouble wall_colors[][4] = {{1.0, 0.0, 0.0, 1.0}, {0.0, 1.0, 0.0, 1.0}, {0.0, 0.0, 1.0, 1.0}, {1.0, 1.0, 0.0, 1.0}};
	GLfloat blackness[] = {0.0, 0.0, 0.0, 1.0};
	
	GLUquadric *quadric = gluNewQuadric();
	gluQuadricDrawStyle(quadric, GLU_FILL); 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
	glLoadIdentity();
	gluLookAt(view_position[0], view_position[1], view_position[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	glRotated(view_spin, 0.0, 1.0, 0.0);
	
	glPushMatrix();
		if (explode)
		{
			glLightfv(GL_LIGHT0, GL_DIFFUSE, blackness);
			glLightfv(GL_LIGHT1, GL_DIFFUSE, blackness);
			glLightfv(GL_LIGHT2, GL_DIFFUSE, blackness);
			glLightfv(GL_LIGHT3, GL_DIFFUSE, blackness);
		}
		
		if (!explode)
		{
		glLightfv(GL_LIGHT0, GL_POSITION, light_0_position);
		glLightfv(GL_LIGHT0, GL_DIFFUSE, blue_light);
		glLightfv(GL_LIGHT1, GL_POSITION, light_1_position);
		glLightfv(GL_LIGHT1, GL_DIFFUSE, yellow_light);
		glLightfv(GL_LIGHT2, GL_POSITION, light_2_position);
		glLightfv(GL_LIGHT2, GL_DIFFUSE, red_light);
		glLightfv(GL_LIGHT3, GL_POSITION, light_3_position);
		glLightfv(GL_LIGHT3, GL_DIFFUSE, green_light);

		glColor3d(0.4, 0.4, 0.4);
		glBegin(GL_TRIANGLES);
			glVertex3d(100.0, -2.0, 100.0);
			glVertex3d(-100.0, -2.0, 100.0);
			glVertex3d(100.0, -2.0, -100.0);
			glVertex3d(100.0, -2.0, -100.0);
			glVertex3d(-100.0, -2.0, 100.0);
			glVertex3d(-100.0, -2.0, -100.0);
		glEnd();
		
		for (i = 0; i < 4; i++)
		{
			glPushMatrix();
				glRotated(90.0 * (double)i, 0.0, 1.0, 0.0);
				glColor4dv(wall_colors[i]);
				glBegin(GL_TRIANGLES);
					glVertex3d(0.0, 0.0, 100.0);
					glVertex3d(50.0, 10.0, 50.0);
					glVertex3d(100.0, 0.0, 0.0);
					glVertex3d(0.0, -2.0, 100.0);
					glVertex3d(100.0, -2.0, 0.0);
					glVertex3d(100.0, 0.0, 0.0);
					glVertex3d(0.0, 0.0, 100.0);
					glVertex3d(0.0, -2.0, 100.0);
					glVertex3d(100.0, 0.0, 0.0);
				glEnd();
			glPopMatrix();
		}
			/*
			glColor3d(1.0, 0.0, 0.0);
			
			glVertex3d(0.0, 0.0, -100.0);
			glVertex3d(-50.0, 10.0, -50.0);
			glVertex3d(-100.0, 0.0, 0.0);
			*/
	/*		glVertex3d(0.0, -2.0, -100.0);
			glVertex3d(-100.0, -2.0, 0.0);
			glVertex3d(-100.0, 0.0, 0.0);

			glVertex3d(-100.0, 0.0, 0.0);
			glVertex3d(0.0, -2.0, -100.0);
			glVertex3d(0.0, 0.0, -100.0);
		*/	

			
		
		glColor3d(0.5, 0.5, 0.5);
		glPushMatrix();
			glRotated(body_spin, 0.0, 1.0, 0.0);
			glPushMatrix();
				glScaled(1.2, 1.7, 1.0);
				glutSolidSphere(0.5, 50, 50);
			glPopMatrix();
		
			glPushMatrix();
				glRotated(head_spin, 0.0, 1.0, 0.0);
				glPushMatrix();
					glRotated(90.0, 0.0, 1.0, 0.0);
					glTranslated(0.0, 1.0, 0.0);
					glPushMatrix();
						glScaled(1.8, 1.0, 1.2);
						gluCylinder(quadric, 0.3, 0.0, 0.7, 20, 20);
					glPopMatrix();
				glPopMatrix();
				glPushMatrix();
					glRotated(270.0, 0.0, 1.0, 0.0);
					glTranslated(0.0, 1.0, 0.0);
					glPushMatrix();
						glScaled(1.8, 1.0, 1.2);
						gluCylinder(quadric, 0.3, 0.0, 0.7, 20, 20);
					glPopMatrix();
				glPopMatrix();
				glPushMatrix();
					glTranslated(0.0, 1.0, 0.0);
					glRotated(90, 1.0, 0.0, 0.0);
					gluCylinder(quadric, 0.3, 0.3, 0.5, 20, 20);
				glPopMatrix();
				glPushMatrix();
					glColor3d(1.0, 1.0, 0.0);
					glTranslated(0.2, 1.0, 0.4);
					glutSolidCube(0.05);
					
					glTranslated(-0.4, 0.0, 0.0);
					glutSolidCube(0.05);
				glPopMatrix();
			glPopMatrix();
		
			glColor3d(0.5, 0.5, 0.5);
			glPushMatrix();	
				glTranslated(0.35, 0.5, 0.0);
				glRotated(90.0, 0.0, 1.0, 0.0);
				glRotated(arm_spin, 1.0, 0.0, 0.0);
				gluCylinder(quadric, 0.1, 0.1, 0.9, 20, 20);
			glPopMatrix();
			glPushMatrix();
				glTranslated(-0.35, 0.5, 0.0);
				glRotated(90.0, 0.0, 1.0, 0.0);
				glRotated(150 + arm_spin, 1.0, 0.0, 0.0);
				gluCylinder(quadric, 0.1, 0.1, 0.9, 20, 20);
			glPopMatrix();
		glPopMatrix();

		glPushMatrix();
			glTranslated(0.0, -0.8, 0.0);
			glPushMatrix();
				glScaled(2.0, 1.0, 1.5);
				glutSolidSphere(0.3, 50, 50);
			glPopMatrix();
			glPushMatrix();
				glTranslated(0.4, 0.0, 0.0);
				glRotated(90, 1.0, 0.0, 0.0);
				gluCylinder(quadric, 0.17, 0.07, 1.1, 20, 20);
			glPopMatrix();
			glPushMatrix();
				glTranslated(-0.4, 0.0, 0.0);
				glRotated(90, 1.0, 0.0, 0.0);
				gluCylinder(quadric, 0.17, 0.07, 1.1, 20, 20);
			glPopMatrix();
		glPopMatrix();
		}
		if (view_position[2] > threshold)
		{
			if (explode)
			{
				glColor3d(1.0, 1.0, 1.0);
				glutSolidSphere(explosion_size, 50, 50);
				glColor3d(1.0, 0.7, 0.0);
				glutSolidTorus(0.5, explosion_size * 3.0, 50, 50);
				explosion_size += 0.5;
				if (explosion_size > 50.0)
					exit(0);
			}
			
			else
			{
				glColor3d(0.2, 0.0, 0.0);
				glPushMatrix();
					glTranslated(50.0 + 50.0 * cos(bomb_time), height * sin(bomb_time), 50.0 + 50.0 * cos(bomb_time));
               glScaled(1.8, 1.0, 1.0);
					glutSolidSphere(1.0, 50, 50);
				glPopMatrix();
				if (cos(bomb_time) < -0.9999)
					explode = 1;
				else
					bomb_time += 0.02;
			}
		}
	glPopMatrix();
	
	glutSwapBuffers();
}

void spin ()
{
	view_spin -= 1.0;
	view_position[2] += 0.1;
	view_position[1] += 0.05;
	if (arm_spin >= 60.0 || arm_spin <= -30.0)
			arm_move *= -1.0;
	arm_spin += arm_move;
	if (head_spin >= 60.0 || head_spin <= -60.0)
			head_move *= -1.0;
	head_spin += head_move;
	glutPostRedisplay();
}

void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 200.0);
	glMatrixMode(GL_MODELVIEW);
}

void keyboard (unsigned char key, int x, int y)
{
	if(key == 'o')
		view_spin += 5.0;
	if(key == 'p')
		view_spin -= 5.0;
	if(key == 'k')
		head_spin += 5.0;
	if(key == 'l')
		head_spin -= 5.0;
	if(key == 'q' && arm_spin > -30.0)
		arm_spin -= 5.0;
	if(key == 'a' && arm_spin < 60.0)
		arm_spin += 5.0;
	if(key == 'n')
		body_spin += 5.0;
	if(key == 'm')
		body_spin -= 5.0;
	if(key == '[')
	{
		view_position[2] -= 1.0;
		view_position[1] -= 0.1;
	}
	if(key == ']')
	{
		view_position[2] += 1.0;
		view_position[1] += 0.1;
	}
	if(key == 'w' && leg_spin > 45.0)
		leg_spin -= 5.0;
	if(key == 's' && leg_spin < 135.0)
		leg_spin += 5.0;
 	glutPostRedisplay();
}

int
main (int argc, char **argv)
{
	time_t t;
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
	glutCreateWindow(argv[0]);
	init();
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutIdleFunc(spin);
		
	time(&t);
	srand(t);
	threshold = rand() % 30 + 5;
	height = rand() % 50 + 20;
	
	glutMainLoop();
	return 0;
}

