/**********************************************************************
* EINFUEHRUNG IN DIE COMPUTERGRAFIK                      BEISPIEL 6.1 *
*                                                                     *
* Kalchmair Franz-Helmut                                     Gruppe 4 *
*                                                                     *
* Date: June/10/2001                                                  *
*                                                                     *
* Bauernstubn mit Kuckucksuhr                                         *
**********************************************************************/

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

GLfloat mat_specular[]={0.8, 0.8, 0.8, 0.0};
GLfloat mat_diffuse[]={0.8f, 0.8f, 0.8f, 0.0f};
GLfloat mat_ambient[]={0.6f, 0.6f, 0.6f, 0.0f};
GLfloat mat_shininess[] = {0};

GLfloat LightAmbient[]= { 0.3f, 0.3f, 0.3f, 1.0f };
GLfloat LightDiffuse[]= { 0.8f, 0.8f, 0.8f, 1.0f };
GLfloat LightSpecular[]={ 0.2f, 0.2f, 0.2f, 1.0f };
GLfloat LightPosition[]={ 0.0f, 0.0f, -2.3f, 1.0f };

GLdouble dist=-1.475;
GLfloat deg=-30;
GLfloat change=+4;
int azimut=-352,elevation=-85;

double dx,dy;

enum MouseMovement {NONE, MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE};
enum MouseMovement mmove=NONE;
int mposx, mposy;


void avtPendulum(void){
	deg+=change;
	if(deg>=30.0) change=(-3);
	if(deg<=-30.0) change=3;
	glutPostRedisplay();
}

void showPendulum(){
	GLUquadricObj *stab;
	glColor3f(0.7f,0.7f,1.0f);
	glRotatef(-deg,0.0f,1.0f,0.0f);
	glTranslatef(0.0f,0.0f,0.30f);
	glutSolidSphere(0.04,15,15);
	glTranslatef(0.0f,0.0f,-0.30f);
	stab=gluNewQuadric();
	gluQuadricOrientation(stab,GLU_OUTSIDE);
	gluCylinder(stab,0.005,0.005,0.30,15,1);	// Licht
	glRotatef(deg,0.0f,1.0f,0.0f);
}
void showRoom(void) {
	GLUquadricObj *zylinder;
	glRotatef(-90.0f,1.0f,0.0f,0.0f);
	glTranslatef(0.0f,0.0f,2.35f);
	glRotatef(90.0f,1.0f,0.0f,0.0f);
	showPendulum();
	glTranslatef(0.0f,0.0f,-0.15f);
	glColor3f(0.0f,1.0f,1.0f);
	glRotatef(-45.0f,0.0f,0.0f,1.0f);
	glRotatef(-180.0f,1.0f,0.0f,0.0f);
	glutSolidCone(0.22,0.20,4,10);		// Uhrdach
	glColor3f(0.0f,0.0f,1.0f);
	glRotatef(180.0f,1.0f,0.0f,0.0f);
	glRotatef(45.0f,0.0f,0.0f,1.0f);
	glTranslatef(0.0f,0.0f,0.15f);
	glRotatef(-90.0f,1.0f,0.0f,0.0f);
	glutSolidCube(0.30f);				// Uhr
	glTranslatef(0.0f,0.0f,-2.35f);
	glRotatef(90.0f,1.0f,0.0f,0.0f);
	glTranslatef(0.0f,0.0f,-1.0f);
	glColor3f(1.0f,1.0f,1.0f);
	glutSolidSphere(0.1f,15.0f,15.0f);		// Licht
	glTranslatef(0.0f,0.0f,-0.3f);
	glColor3f(1.0f,1.0f,1.0f);
	zylinder=gluNewQuadric();
	gluQuadricOrientation(zylinder,GLU_OUTSIDE);
	gluCylinder(zylinder,0.05,0.05,0.25,15,1);	// Licht
	glTranslatef(0.0f,0.0f,+1.3f);
	glRotatef(-90.0f,1.0f,0.0f,0.0f);
	glTranslatef(0.0f,0.0f,2.5f);
	glColor3f(0.5f,0.5f,0.0f);
	glRectf(-2.0f,-1.3f,2.0f,1.3f);		// Wände
	glTranslatef(0.0f,0.0f,-2.5f);
	glRotatef(90.0f,0.0f,1.0f,0.0f);
	glTranslatef(0.0f,0.0f,2.0f);
	glRectf(-2.5f,-1.3f,2.5f,1.3f);
	glTranslatef(0.0f,0.0f,-2.0f);
	glRotatef(90.0f,0.0f,1.0f,0.0f);
	glTranslatef(0.0f,0.0f,2.5f);
	glRectf(-2.0f,-1.3f,2.0f,1.3f);
	glTranslatef(0.0f,0.0f,-2.5f);
	glRotatef(90.0f,0.0f,1.0f,0.0f);
	glTranslatef(0.0f,0.0f,2.0f);
	glRectf(-2.5f,-1.3f,2.5f,1.3f);
	glTranslatef(0.0f,0.0f,-2.0f);
	glRotatef(90.0f,1.0f,0.0f,0.0f);
	glTranslatef(0.0f,0.0f,-1.3f);
	glColor3f(0.7f,0.3f,0.8f);		// Decke
	glRectf(-2.5,-2.0,2.5,2.0);
	glTranslatef(0.0f,0.0f,2.6f);
	glColor3f(0.4f,0.2f,0.8f);		// Boden
	glRectf(-2.5,-2.0,2.5,2.0);
}

void display (void) {

  glClearColor(1.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  glOrtho(-dist, dist, -dist, dist, 0, 100);
  glTranslatef(0,0,dist);
  glRotated(elevation,1,0,0);
  glRotated(azimut,0,0,1);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  showRoom();

  glutSwapBuffers ();
}


void KeyKlicks(int key, int x, int y){
  switch(key){
  case GLUT_KEY_LEFT:
	azimut=azimut<=0?355:azimut-5;break;
  case GLUT_KEY_RIGHT:
	azimut=azimut>=355?0:azimut+5;break;
  case GLUT_KEY_UP:
	  elevation=elevation>=180?180:elevation+5;break;
  case GLUT_KEY_DOWN:
	elevation=elevation<=-180?-180:elevation-5;break;
  case GLUT_KEY_PAGE_UP:
	dist+=0.01;break;
  case GLUT_KEY_PAGE_DOWN:
	dist-=0.01;break;
  default:break;
  }
  glutPostRedisplay();
}

void MouseClick(int button, int state, int x, int y){
  if(mmove!=NONE){
	if(state==GLUT_UP){
	  if(button==GLUT_MIDDLE_BUTTON&&mmove==MOUSE_MIDDLE ||
		 button==GLUT_LEFT_BUTTON&&mmove==MOUSE_LEFT ||
		 button==GLUT_RIGHT_BUTTON&&mmove==MOUSE_RIGHT){
		  mmove=NONE;
	  }
	}
  }
  else{
	if(state==GLUT_DOWN){
	  mposx=x;
	  mposy=y;
	  switch(button){
	  case GLUT_MIDDLE_BUTTON: mmove=MOUSE_MIDDLE;break;
	  case GLUT_LEFT_BUTTON: mmove=MOUSE_LEFT;break;
	  case GLUT_RIGHT_BUTTON: mmove=MOUSE_RIGHT;break;
	  }
	}
  }
}

void MouseMove(int x, int y){
  if(mmove!=NONE){
	switch(mmove){
	case MOUSE_LEFT:
		azimut+=x-mposx;
		if(azimut<0)azimut+=360;
		if(azimut>=0)azimut-=360;
		mposx=x;
		break;
	case MOUSE_RIGHT:
		dist+=0.01*(mposy-y);
		mposy=y;
		break;
	case MOUSE_MIDDLE:

		break;
	}
    glutPostRedisplay();
  }
}



void myInit (void) {
  glEnable (GL_DEPTH_TEST);

  glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
  glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpecular);
  glLightfv(GL_LIGHT0, GL_POSITION,LightPosition);
  glEnable(GL_LIGHT0);
  glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 1.0);

  glEnable(GL_COLOR_MATERIAL);
  glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS,mat_shininess);

  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();



}


void initialGLUT (void) {
  glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

  glutInitWindowSize (400, 400);
  glutInitWindowPosition (0, 0);
  glutCreateWindow ("Bauernstube");

  myInit();
  glEnable(GL_LIGHTING);
  glutDisplayFunc (display);
  glutSpecialFunc(KeyKlicks);
  glutMouseFunc(MouseClick);
  glutMotionFunc(MouseMove);
  glutIdleFunc(avtPendulum);
}




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

  initialGLUT ();
  glutMainLoop ();
  return 0;
}
