////////////////////////////////////////////////////////
//Jason Kim
//CSE 581 Lab 3
//Open GL

//
// For more View Readme
//

//Keys: w = wireframe, a = animate, f = forward, t = turn,  q = quit,  o = move robot head up,  p =  move robot head down
//
//Lab 3 Keys:
// l = turn left , r = turn right,  f = forward , b = back , U =  move camera up, D = move camera down, left arrow = move COI left, right arrow =  move COI right, h = reset camera angle,  
// 1 = turn light 1 on (point light / white ),  2 = turn light 2 on (headlight / blue) ,  3  = turn light 3 on (spotlight / green),  s = smooth/flat shading
// bonus:
// m = First Person mode on Robot,   v =  animate camera
//
////////////////////////////////////////////////////////

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

//scene variables
int press_x, press_y; 
int release_x, release_y; 
float x_angle = 0.0; 
float y_angle = 0.0; 
float scale_size = 1; 

int xform_mode = 0; 

int forward = 0;
int forwardx = 0;
int forwardz = 0;
int turn = 0;
int turnK = 1;
int wireframe=0;
int headangle=0;
int anim=0;
int animcam=0;
int fps=0;
int flip=0;

//camera variables

int ex=0;
int ey=2;
int ez=15;

int cx=0;
int cy=0;
int cz=0;

int ux=0;
int uy=3;
int uz=0;


//light variables

int light1=0;
int light2=0;
int light3=0;
int shiny=0;
int shade=0;

#define XFORM_NONE    0 
#define XFORM_ROTATE  1
#define XFORM_SCALE 2 


////////////////////////////////////////////// 

void animate()
{
	turn=turn+10;

	glutPostRedisplay();
	//spins robot around


}
void animcamera()
{
	ex++;
	ez++;
	glutPostRedisplay();
	//animate zoom camera away 

}
void donothing()
{
	//donothing
}

void resetrobot()
{
	ex=0;
	ez=15;
	turn=0;
	glutPostRedisplay();

}
void draw_cube(float r, float g, float b)
{
  if(wireframe==0)
  {

	glColor3f(r, g, b); 
	glutSolidCube(1.0);   // draw a solid cube 
  }
  else if(wireframe==1)
  {
	  glColor3f(r,g,b);
	  glutWireCube(1.0);
  }

}

void draw_floor(float r, float g, float b)
{
  //make yellow floor
  glBegin(GL_POLYGON);
  glColor4f(1,1,0,1);
  glVertex3f(-10,-0.5,-10);
  glVertex3f(-10,-0.5,10);
  glVertex3f(10,-0.5,10);
  glVertex3f(10,-0.5,-10);
  glEnd();

  //make yellow wall
  glBegin(GL_POLYGON);
  glColor4f(1,1,0,1);
  glVertex3f(-10,0,-15);
  glVertex3f(-10,10,-15);
  glVertex3f(10,0,-15);
  glVertex3f(10,10,-15);
  glEnd();



  //makes a red table
  if(wireframe==0)
  {
   
	glScalef(15, 0.1, 15);
	glColor3f(r, g, b); 
	glutSolidCube(1.0);   
  }
  else if(wireframe==1)
  {
	  glScalef(15, 0.1, 15);
	  glColor3f(r,g,b);
	  glutWireCube(1.0);
  }

}

void draw_teapot(float r, float g, float b)
{
  if(wireframe==0)
  {
	glColor3f(r, g, b); 
	glutSolidTeapot(0.5); // draw a solid cube 
  }
  else if(wireframe==1)
  {
	glColor3f(r, g, b); 
	glutWireTeapot(0.5); // draw a solid cube 
  }

}


//Draw The Head of the Robot, which is a Green Cone
void draw_cone(float r, float g, float b)
{

	if(wireframe==0)
	{
		glTranslatef(1,1,2);
		glColor3f(r, g, b); 
		glutSolidCone(1,2,4,4); // draws the head
		glColor3f(0,0,0);
		glutPostRedisplay();
	}
	else if(wireframe==1)
	{
		glTranslatef(1,1,2);
		glColor3f(r, g, b); 
		glutWireCone(1,2,4,4); // draws the head
		glColor3f(0,0,0);
		glutPostRedisplay();
	}

}


//Draw the Legs of the Robot
void draw_legs(float r, float g, float b)
{
	if(wireframe==0)
	{
		glTranslatef(1,1,2);
		glTranslatef(-1,-1,0);
		glScalef(0.5, 2, 0.5);
		glColor3f(r, g, b); 
		glutSolidCube(1.0);   // left leg
		glTranslatef(4,0,0);
		glutSolidCube(1.0);   // right leg
		glutPostRedisplay();
	}
	else if(wireframe==1)
	{
		glTranslatef(1,1,2);
		glTranslatef(-1,-1,0);
		glScalef(0.5, 2, 0.5);
		glColor3f(r, g, b); 
		glutWireCube(1.0);   // left leg
		glTranslatef(4,0,0);
		glutWireCube(1.0);   // right leg
		glutPostRedisplay();
	}
}


//Draw the Eyes of the Robot which are Red cubes
void draw_eyes(float r, float g, float b)
{
	if(wireframe==0)
	{

		glTranslatef(-0.5,0,1);
		glScalef(0.1, 0.1, 0.1);
		glColor3f(r, g, b); 
		glutSolidCube(1.0);  
		glTranslatef(10,0,0);
		glutSolidCube(1.0); // draw eyes
	}
	else if(wireframe == 1)
	{

		glTranslatef(-0.5,0,1);
		glScalef(0.1, 0.1, 0.1);
		glColor3f(r, g, b); 
		glutWireCube(1.0);  
		glTranslatef(10,0,0);
		glutWireCube(1.0); // draw eyes
	}
}

//////////////////////////////////////////////////////

void getcamera()
{
	gluLookAt(ex,ey,ez,cx,cy,cz,ux,uy,uz);
}
void display()
{
  glEnable(GL_DEPTH_TEST); 
  glClearColor(0,0,0,1); 
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
  
  glMatrixMode(GL_PROJECTION); 
  glLoadIdentity(); 
  gluPerspective(60, 1, .1, 100); 


  glMatrixMode(GL_MODELVIEW); 
  glLoadIdentity(); 

  //Camera Control
  //gluLookAt(0,2,15,0,0,0,0,3,0); 
  getcamera();



  glRotatef(x_angle, 0, 1,0); 
  glRotatef(y_angle, 1,0,0); 
  glScalef(scale_size, scale_size, scale_size); 
	


  //initialize scene


  //Point Light
 if(light1==1)
 {
   GLfloat mat_specular[] = { 0.0, 1.0, 0.0, 0.0 };
   GLfloat mat_ambient[] = {0.0, 0.0, 1.0, 0.0}; 
   GLfloat  mat_diffuse[] = {0.0, 1.0, 0.0, 0.0}; 
   GLfloat mat_shininess[] = { shiny };//shinyness
   GLfloat light_position[] = { 1.0, 1.0, 1.0, 1.0 };

   glMaterialfv(GL_LIGHT0, GL_AMBIENT, mat_ambient);
   glMaterialfv(GL_LIGHT0,GL_DIFFUSE,mat_diffuse);
   glMaterialfv(GL_LIGHT0, GL_SPECULAR, mat_specular);
   glMaterialfv(GL_LIGHT0, GL_SHININESS, mat_shininess);
   glLightfv(GL_LIGHT0, GL_POSITION, light_position);

   
   glEnable(GL_LIGHT0);
 }
 else if(light1==0)
 {
	 
	 glDisable(GL_LIGHT0);
 }

 glEnable(GL_COLOR_MATERIAL);
 glEnable(GL_LIGHTING);
   //shade
   if(shade==0)
	   glShadeModel(GL_FLAT);
   else if(shade==1)
		glShadeModel(GL_SMOOTH);


   
   //Spotlight


   //Headlight from camera

if(light2==1)
 {
   GLfloat matt_specular[] = { 0.0, 1.0, 0.0, 1.0 };
   GLfloat matt_ambient[] = {0.0, 0.0, 1.0, 1.0}; 
   GLfloat  matt_diffuse[] = {0.0, 1.0, 0.0, 0.0}; 
   GLfloat matt_shininess[] = { shiny };//shinyness

   GLfloat light2_position[] = { ex, ey, ez, 1.0 }; //Light coming from the Camera Eye

   glLightfv(GL_LIGHT2, GL_AMBIENT, matt_ambient);
   glLightfv(GL_LIGHT2,GL_DIFFUSE,matt_diffuse);
   glLightfv(GL_LIGHT2, GL_SPECULAR, matt_specular);
   glLightfv(GL_LIGHT2, GL_SHININESS, matt_shininess);
   glLightfv(GL_LIGHT2, GL_POSITION, light2_position);
   glEnable(GL_LIGHT2);
 }
 else if(light2==0)
 {
	 
	 glDisable(GL_LIGHT2);
 }


  //create scene


   //discoball!
   glPushMatrix();
   glTranslatef(0,5,0);
   glColor3f(1,1,1);
   if(wireframe==0)
		glutSolidSphere (1.0, 20, 16);
   else if(wireframe==1)
	   glutWireSphere (1.0, 20, 16);

   glPopMatrix();

  glPushMatrix();
  draw_cube(0,0,1);
  draw_floor(1,0,0);
  glPopMatrix();
  glPushMatrix();
  glTranslatef(3,0,0);
  draw_cube(0,0,1);
  glPopMatrix();
  glTranslatef(0,1,0);
  draw_teapot(0,0,1);
  glPopMatrix();


  //Add some more objects to the Scene to Enhance it
  glPushMatrix();
  glTranslatef(-3,0,7);
   
  if(wireframe==0)
		glutSolidSphere (1.0, 20, 16);
   else if(wireframe==1)
	   glutWireSphere (1.0, 20, 16);
 glTranslatef(0,1,0);
      if(wireframe==0)
		glutSolidSphere (1.0, 20, 16);
   else if(wireframe==1)
	   glutWireSphere (1.0, 20, 16);

  glTranslatef(7,0,0);
  glTranslatef(0,-1,0);
   if(wireframe==0)
		glutSolidSphere (1.0, 20, 16);
   else if(wireframe==1)
	   glutWireSphere (1.0, 20, 16);
   glTranslatef(0,1,0);
        if(wireframe==0)
		glutSolidSphere (1.0, 20, 16);
   else if(wireframe==1)
	   glutWireSphere (1.0, 20, 16);

   glTranslatef(0,0,-10);
   glTranslatef(0,-1,0);
   if(wireframe==0)
		glutSolidSphere (1.0, 20, 16);
   else if(wireframe==1)
	   glutWireSphere (1.0, 20, 16);

   glTranslatef(0,1,0);
   if(wireframe==0)
		glutSolidSphere (1.0, 20, 16);
   else if(wireframe==1)
	   glutWireSphere (1.0, 20, 16);

  glTranslatef(-7,0,0);
  glTranslatef(0,-1,0);
  if(wireframe==0)
		glutSolidSphere (1.0, 20, 16);
   else if(wireframe==1)
	   glutWireSphere (1.0, 20, 16);
  glTranslatef(0,1,0);
       if(wireframe==0)
		glutSolidSphere (1.0, 20, 16);
   else if(wireframe==1)
	   glutWireSphere (1.0, 20, 16);

  glPopMatrix();



  //Spotlight on Object
  if(light3==1)
 {
   GLfloat matr_specular[] = { 0.0, 1.0, 0.0, 0.0 };
   GLfloat matr_ambient[] = {0.0, 0.0, 1.0, 0.0}; 
   GLfloat  matr_diffuse[] = {0.0, 1.0, 0.0, 0.0}; 
   GLfloat matr_shininess[] = { shiny };//shinyness
   GLfloat light3_position[] = { forwardx-1, 1, forwardz+3, 1.0 };

   //glMaterialfv(GL_LIGHT3, GL_AMBIENT, matr_ambient);
   //glMaterialfv(GL_LIGHT3,GL_DIFFUSE,matr_diffuse);
   //glMaterialfv(GL_LIGHT3, GL_SPECULAR, matr_specular);
   //glMaterialfv(GL_LIGHT3, GL_SHININESS, matr_shininess);
   glLightfv(GL_LIGHT3,GL_DIFFUSE,matr_diffuse);
   glLightfv(GL_LIGHT3,GL_SPECULAR,matr_specular);
   glLightfv(GL_LIGHT3, GL_POSITION, light3_position);

   
   glEnable(GL_LIGHT3);
 }
 else if(light3==0)
 {
	 
	 glDisable(GL_LIGHT3);
 }
 glEnable(GL_COLOR_MATERIAL);

	//Object Motion
	glTranslatef(forwardx,0,forwardz);
    glRotatef(turn,0,1,0);


	//create object,  Green 2 legged Robot with a Cone for a head and Red eyes
	glPushMatrix();
	//3 Levels of Heirarchy
	glRotatef(headangle,1,0,0);
	draw_cone(0,1,0);//Head
	draw_eyes(1,0,0);//Eyes
	glPopMatrix();
	glPushMatrix();
	draw_legs(0,1,0);//Legs
	
	
	glPopMatrix();
	//create Object

  glutSwapBuffers(); 
}

///////////////////////////////////////////////////////////

void mymouse(int button, int state, int x, int y)
{
  if (state == GLUT_DOWN) {
    press_x = x; press_y = y; 
    if (button == GLUT_LEFT_BUTTON)
      xform_mode = XFORM_ROTATE; 
	 else if (button == GLUT_RIGHT_BUTTON) 
      xform_mode = XFORM_SCALE; 
  }
  else if (state == GLUT_UP) {
	  xform_mode = XFORM_NONE; 
  }
}

/////////////////////////////////////////////////////////

void mymotion(int x, int y)
{
    if (xform_mode==XFORM_ROTATE) {
      x_angle += (x - press_x)/5.0; 
      if (x_angle > 180) x_angle -= 360; 
      else if (x_angle <-180) x_angle += 360; 
      press_x = x; 
	   
      y_angle += (y - press_y)/5.0; 
      if (y_angle > 180) y_angle -= 360; 
      else if (y_angle <-180) y_angle += 360; 
      press_y = y; 
    }
	else if (xform_mode == XFORM_SCALE){
      float old_size = scale_size;
      scale_size *= (1+ (y - press_y)/60.0); 
      if (scale_size <0) scale_size = old_size; 
      press_y = y; 
    }
	glutPostRedisplay(); 
}

///////////////////////////////////////////////////////////////

void mykey(unsigned char key, int x, int y)
{
        switch(key) {
		case 'q': exit(1);
			break; 

			//Move Forward 
		case 'f':
			{

				if(turnK==1)
				{
					
					if(fps==1)
					{
						ez++;
					}
				    forwardz++;


				}
				if(turnK==2)
				{
					
					forwardx++;
					if(fps==1)
					{
						ex++;
					}

				}
				if(turnK==3)
				{

	
						forwardz--;
	
					if(fps==1)
					{
						ez--;
					}

				}
				if(turnK==4)
				{
				
				
					if(fps==1)
					{
						ex--;
					}
	
						forwardx--;
		
				}

				//forward
			}
			break;
					//Move backward
		case 'b':
			{
				if(turnK==1)
				{
					
					if(fps==1)
					{
						ez--;
					}

					forwardz--;
				}
				if(turnK==2)
				{
					
					forwardx--;
					if(fps==1)
					{
						ex--;
					}

				}
				if(turnK==3)
				{
						forwardz++;
					
					if(fps==1)
					{
						ez++;
					}

				}
				if(turnK==4)
				{
				
					
					if(fps==1)
					{	
						ex++;
					}

					forwardx++;
	

				}

				//forward
			}
			break;

			//Turn 90 degrees to the left
		case 'l':
			{
				turn=turn+90;
				if(turnK==1)
				{
				
					//forwardx=0;
					turnK=2;
					if(fps==1)
					{
						cx=cx+800;
					}

				}
				else if(turnK==2)
				{
					
					//forwardz=0;
					turnK=3;
					if(fps==1)
					{
						cz=cz+800;
					}

				}
				else if(turnK==3)
				{
					
					//forwardx=0;
					turnK=4;
					if(fps==1)
					{
						cx=cx+800;
					}

				}
				else if(turnK==4)
				{
					
					//forwardx=0;
					turnK=1;
					if(fps==1)
					{
						cz=cz+800;
					}

				}


			}
			break;

					//Turn 90 degrees to the right
		case 'r':
			{
				turn=turn-90;
				if(turnK==1)
				{
					
				
					//forwardx=0;
					turnK=4;
					if(fps==1)
					{
						cx=cx-800;
					}

				}
				else if(turnK==2)
				{
					
					
					//forwardz=0;
					turnK=3;
					if(fps==1)
					{
						cz=cz-800;
					}

				}
				else if(turnK==3)
				{
					
					//forwardx=0;
					turnK=4;
					
					if(fps==1)
					{
						cx=cx-800;
					}

				}
				else if(turnK==4)
				{
					
					//forwardx=0;
					turnK=1;
					
					if(fps==1)
					{
						cz=cz-800;
					}
				}
			


			}
			break;

			//Toggles Animation.  Makes Robot Spin in a circle
		case 'a':
			{
				//animate
				if(anim==0)
				{
					glutIdleFunc(animate);
					anim=1;
				}
				else
				{

					//toggles Animation off and resets Robot to Start Position.
					anim=0;
					glutIdleFunc(donothing);
					resetrobot();
					
				}


			}
			break;
	
		//Part 3 Keys to move the moveable parts of Robot.  Moves the Cone Head up and Down with u for down and h for up
		case 'o':
			{
				if(headangle < 30)
					headangle=headangle+10;
				//Move Head Down
			}
			break;

	
		case 'p':
			{
				if(headangle >-30)
					headangle=headangle-10;
				//Move Head Up
			}
			break;

			//Toggle WireFrame Mode
		case 'w':
			{
				if(wireframe==0)//wireframe mode
					wireframe=1;
				else
					wireframe=0;
			}
			break;

			//move camera without moving COI

		case 'L':
			{
				ex--;
				glutPostRedisplay();

			}
			break;
			
		case 'R':
			{
				ex++;
				glutPostRedisplay();

			}
			break;
		case 'U':
			{
				ey++;
				glutPostRedisplay();

			}
			break;
		case 'D':
			{
				ey--;
				glutPostRedisplay();

			}
			break;
			
		//reset camera

		case 'h':
			{
				ex=0;
				ey=2;
				ez=15;
				cx=0;
				cy=0;
				cz=0;
				glutPostRedisplay();

			}
			break;

			//shading/shiny/light controls
		
		
			//toggles shading flat/smooth
		case 's':
			{
				if(shade==0)
					shade=1;
				else if(shade==1)
					shade=0;
				glutPostRedisplay();
			}
			break;

			//increase/decrease shinyness

		case '+':
			{
				shiny++;
				glutPostRedisplay();

			}
			break;

		case '-':
			{
				shiny--;
				glutPostRedisplay();
			}
			break;

		case '1':
			{
				if(light1==0)
					light1=1;
				else if (light1==1)
					light1=0;

			}
			break;
			
		case '2':
			{
				if(light2==0)
					light2=1;
				else if (light2==1)
					light2=0;

			}
			break;
		case '3':
			{
				if(light3==0)
					light3=1;
				else if (light3==1)
					light3=0;

			}
			break;

		case 'y': //swing camera around.
			{
				double a=30;
				ez = ez*sin(a);

			}
			break;

			
		case 'm': //FPS mode
			{
				if(fps==0)
				{
					fps=1;
					cx = 0;
					cy = 5;
					cz = 20;

					ex = 1;
					ey = 3;
					ez = 0;
				}
				else if (fps ==1)
				{
					ex=0;
					ey=2;
					ez=15;
					cx=0;
					cy=0;
					cz=0;
					fps = 0;
				}


			}
			break;
		case 'v': //Animate Camera Zoom Away
			{
				if(animcam==0)
				{
					animcam=1;
					glutIdleFunc(animcamera);

				}
				else 
				{
					animcam=0;
					glutIdleFunc(donothing);
					resetrobot();
				}
			}
			break;
		  
		}



		
}

//Special Function Keys
void arrowkey(int key, int x, int y)
{
	//Move COI

	switch(key){
				case GLUT_KEY_LEFT:
			{
				cx--;
				glutPostRedisplay();

			}
			break;

		case GLUT_KEY_RIGHT:
			{
				cx++;

			}
			break;

		case GLUT_KEY_UP:
			{
				cy++;
				glutPostRedisplay();

			}
			break;
		case GLUT_KEY_DOWN:
			{
				cy--;
				glutPostRedisplay();

			}
			break;
	}
}

///////////////////////////////////////////////////////////////

int main(int argc, char** argv) 
{
  glutInit(&argc, argv); 
  glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); 
  glutInitWindowSize(600,600); 
  
  glutCreateWindow("Jason Kim CSE581 Lab2"); 
  glutDisplayFunc(display); 
  glutMouseFunc(mymouse); 
  glutMotionFunc(mymotion);
  glutKeyboardFunc(mykey); 
  glutSpecialFunc(arrowkey);
  glutMainLoop(); 
}



