#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>       /* for cos(), sin(), and sqrt() */
#include <GL/glut.h>    /* OpenGL Utility Toolkit header */

/* Some <math.h> files do not define M_PI... */
/*********************************************/
#ifndef M_PI
#define M_PI 3.14159265
#endif

#define NB_BOULE_LIGHTS 3 // nbre de lumieres qui tournent au dessus du gars

/* Variable de controle des differents mode de rendus */
/******************************************************/

static int stencilShadow = 1;
static int offsetShadow = 1;
static int renderShadow = 0;
static int renderBarman = 1;
static int renderBoule = 1;
static int renderMirror = 0;
static int linearFiltering = 0; 
static int useMipmaps = 0;
static int useTexture = 1;
static int reportSpeed = 0;
static int animation = 0;
static GLboolean lightSwitch1 = GL_TRUE;
static GLboolean lightSwitch2 = GL_TRUE;
static GLboolean lightSwitch3 = GL_TRUE;
static int directionalLight1 = 1;
static int directionalLight2 = 1;
static int directionalLight3 = 1;
static GLfloat l=0.0;

static int enfle = 0;

static int fog = 0;
static GLfloat fogMode[] = {GL_EXP};
static GLfloat fogDensity[] = {0.03};
static GLfloat fogIndex[] = {0.7};
static GLfloat fogColor[] = {0.5,0.5,0.5,1.0};

static int antialiasing = 0;

static int forceExtension = 0;
static int signe = 1;
static int cpteur = 0;
static float vitesse = 500.0;
enum {WIREFRAME,FLAT,DOT,SMOOTH};
static int mode=SMOOTH;



/* Variable de controle du temps */
/*********************************/

static float move = 0.0;
static float move_old = 0.0;

GLfloat angle = -150;   /* in degrees */
GLfloat angle2 = 30;   /* in degrees */

int moving;
int startx;
int starty;
int angleBoule;


int polygonOffsetVersion;

enum {
  MISSING, EXTENSION, ONE_DOT_ONE
};

/* Definition des lumieres de la boule */  
/***************************************/

static int lights_enabled[NB_BOULE_LIGHTS] = {1, 1, 1};
static GLfloat lightBoulePosition[NB_BOULE_LIGHTS][4];

/* Stroboscope */
/***************/
static int renderStrobo = 0;
static int strobo;


/* Variable de controle des lumieres et couleurs */
/*************************************************/

static GLfloat light1Position[4] = {1.0, 1.0, 0.0, 0.0};
static GLfloat light1Color[] = {1.0, 1.0, 1.0, 1.0}; 

static GLfloat light2Position[4] = {1.0,1.0,1.0,0.0};
static GLfloat light2Color[] = {0.2, 1.0, 0.8, 1.0};

static GLfloat light3Position[4] = {1.0,1.0,1.0,0.0};
static GLfloat light3Color[] = {0.5, 0.0, 1.0, 1.0};

static GLfloat light4Position[4] = {10.0, 0.0, -10.0, 1.0};
static GLfloat light4Color[] = {0.1, 0.0, 1.0, 1.0}; 

static GLfloat light5Position[4] = {0.0, -10.0, 0.0, 1.0};
static GLfloat light5Color[] = {0.2, 1.0, 0.6, 1.0}; 

static GLfloat light6Position[4] = {-10.0, 0.0, 0.0, 1.0};
static GLfloat light6Color[] = {0.5, 0.0, 1.0, 1.0}; 

static GLfloat light7Position[4] = {1.0, 0.0, 0.0, 1.0};
static GLfloat light7Color[] = {1.0, 1.0, 1.0, 0.0}; 

static GLfloat nullEmission[] = {0.0,0.0,0.0,1.0};	
static GLfloat nullSpecular[] = {0.0,0.0,0.0,1.0};
static GLfloat nullShininess = 0.0;
static GLfloat skinColor[] = {0.1, 0.5, 1.0, 1.0};
static GLfloat blackSkinColor[] = {0.1, 0.1, 0.1, 0.5};
static GLfloat skinSpecular[] = {0.1,0.2,0.5,0.1};
static GLfloat skinShininess = 100.0;
static GLfloat skinEmission[] = {0.2,0.5,0.8,0.1};
static GLfloat eyeColor[] = {1.0, 0.2, 0.2, 1.0};
static GLfloat barColor[] = {0.6,0.2,0.1,0.7};
static GLfloat glassBottleColor[] = {0.9,0.9,0.9,0.4};
static GLfloat bottleShininess[] = {1000.0};
static GLfloat bottleEmission[] = {1.0,1.0,1.0,0.0};	
static GLfloat bottleSpecular[] = {1.0,1.0,1.0,0.5};
static GLfloat mirrorColor[] = {0.9,0.9,0.9,0.4};   
static GLfloat mirrorSpecular[] = {1.0,1.0,1.0,1.0};
static GLfloat mirrorBackColor[] = {0.8,0.3,0.2,0.7};

/* Enumeration des variables de la display list. */
/**************************************************/
enum {
  RESERVED, BACK_SIDE_BAR, SIDE_BAR, HEAD, HALF_A_BODY, BODY, CLAVI, BRAS, AVANT_BRAS, PEC, ABDO,
	  CALE, JAMBE, PIED, BOUTEILLE, VERRE, NOEUD
};

/* *INDENT-ON* */

/* Definition d'une texture pour le sol */
/****************************************/

static char *circles[] = {
  "****************",
  "****************",
  "****        ****",
  "***          ***",
  "**            **",
  "**            **",
  "*              *",
  "*              *",
  "*              *",
  "*              *",
  "**            **",
  "**            **",
  "***          ***",
  "****        ****",
  "****************",
  "****************",
};

/* Definition du sol */
/*********************/

static GLfloat floorVertices[4][3] = {
  { -30.0, 0.0, 30.0 },
  { 30.0, 0.0, 30.0 },
  { 30.0, 0.0, -30.0 },
  { -30.0, 0.0, -30.0 },
};

/* Affichage du sol */
/********************/

static void drawFloor(void)
{
  glEnable(GL_LIGHTING);
	
  if (useTexture) {
    glEnable(GL_TEXTURE_2D);
  }

  glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex3fv(floorVertices[0]);
    glTexCoord2f(0.0, 16.0);
    glVertex3fv(floorVertices[1]);
    glTexCoord2f(16.0, 16.0);
    glVertex3fv(floorVertices[2]);
    glTexCoord2f(16.0, 0.0);
    glVertex3fv(floorVertices[3]);
  glEnd();

  if (useTexture) {
    glDisable(GL_TEXTURE_2D);
  }

  glDisable(GL_LIGHTING);
}

static GLfloat floorPlane[4];
static GLfloat floorShadow[4][4];


/* gestion de la texture */
/*************************/

static void makeFloorTexture(void)
{
  GLubyte floorTexture[16][16][3];
  GLubyte *loc;
  int s, t;

  /* Setup RGB image for the texture. */
  loc = (GLubyte*) floorTexture;
  for (t = 0; t < 16; t++) {
    for (s = 0; s < 16; s++) {
      if (circles[t][s] == '*') {
        /* Nice green. */
        loc[0] = 0x1f;
        loc[1] = 0x8f;
        loc[2] = 0x1f;
      } else {
        /* Light gray. */
        loc[0] = 0xaa;
        loc[1] = 0xaa;
        loc[2] = 0xaa;
      }
      loc += 3;
    }
  }

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  if (useMipmaps) {
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
      GL_LINEAR_MIPMAP_LINEAR);
    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
      GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
  } else {
    if (linearFiltering) {
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    } else {
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    }
    glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
      GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
  }
}

enum {
  X, Y, Z, W
};
enum {
  A, B, C, D
};

/* Create a matrix that will project the desired shadow. */
void shadowMatrix(GLfloat shadowMat[4][4],
  GLfloat groundplane[4],
  GLfloat light1pos[4])
{
  GLfloat dot;

  /* Find dot product between light1 position vector and ground plane normal. */
  dot = groundplane[X] * light1pos[X] +
    groundplane[Y] * light1pos[Y] +
    groundplane[Z] * light1pos[Z] +
    groundplane[W] * light1pos[W];

  shadowMat[0][0] = dot - light1pos[X] * groundplane[X];
  shadowMat[1][0] = 0.f - light1pos[X] * groundplane[Y];
  shadowMat[2][0] = 0.f - light1pos[X] * groundplane[Z];
  shadowMat[3][0] = 0.f - light1pos[X] * groundplane[W];

  shadowMat[X][1] = 0.f - light1pos[Y] * groundplane[X];
  shadowMat[1][1] = dot - light1pos[Y] * groundplane[Y];
  shadowMat[2][1] = 0.f - light1pos[Y] * groundplane[Z];
  shadowMat[3][1] = 0.f - light1pos[Y] * groundplane[W];

  shadowMat[X][2] = 0.f - light1pos[Z] * groundplane[X];
  shadowMat[1][2] = 0.f - light1pos[Z] * groundplane[Y];
  shadowMat[2][2] = dot - light1pos[Z] * groundplane[Z];
  shadowMat[3][2] = 0.f - light1pos[Z] * groundplane[W];

  shadowMat[X][3] = 0.f - light1pos[W] * groundplane[X];
  shadowMat[1][3] = 0.f - light1pos[W] * groundplane[Y];
  shadowMat[2][3] = 0.f - light1pos[W] * groundplane[Z];
  shadowMat[3][3] = dot - light1pos[W] * groundplane[W];

}

/* Find the plane equation given 3 points. */
void findPlane(GLfloat plane[4],
  GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])
{
  GLfloat vec0[3], vec1[3];

  /* Need 2 vectors to find cross product. */
  vec0[X] = v1[X] - v0[X];
  vec0[Y] = v1[Y] - v0[Y];
  vec0[Z] = v1[Z] - v0[Z];

  vec1[X] = v2[X] - v0[X];
  vec1[Y] = v2[Y] - v0[Y];
  vec1[Z] = v2[Z] - v0[Z];

  /* find cross product to get A, B, and C of plane equation */
  plane[A] = vec0[Y] * vec1[Z] - vec0[Z] * vec1[Y];
  plane[B] = -(vec0[X] * vec1[Z] - vec0[Z] * vec1[X]);
  plane[C] = vec0[X] * vec1[Y] - vec0[Y] * vec1[X];

  plane[D] = -(plane[A] * v0[X] + plane[B] * v0[Y] + plane[C] * v0[Z]);
}

/* Fonction de conception d'objets geometriques */
/************************************************/

void cylindreH(GLfloat x1,GLfloat y1,GLfloat z1,GLfloat x2,GLfloat z2,double d)
{
  static GLUquadricObj *quadObj=NULL;

  double a=atan2(z2-z1,x2-x1)*180/M_PI;

  double h=sqrt((x2-x1)*(x2-x1)+(z2-z1)*(z2-z1));

  if (!quadObj)
    quadObj=gluNewQuadric();

  glPushMatrix();
  glTranslatef(x2,y1,0);
  glTranslatef(0,0,-h/2);
  glRotatef(a,1,0,0);
  glRotatef(90,1,0,0);
  gluQuadricDrawStyle(quadObj,GLU_FILL);
  gluQuadricNormals(quadObj,GLU_SMOOTH);
  gluCylinder(quadObj,d,d,h,20,5);
  glPopMatrix();
}

/* Definition des structures*/
/****************************/

static GLfloat FrontBarVertices[4][3] = {
  { 0.0, 0.0, 15.0 },
  { 0.0, 10.0, 15.0 },
  { 0.0, 10.0, -15.0 },
  { 0.0, 0.0, -15.0 },
};

static GLfloat mirrorBackVertices[4][3] = {
  { 0.0, 10.0, -15.0 },
  { 0.0, 10.0, 15.0 },
  { 0.0, 30.0, 15.0 },
  { 0.0, 30.0, -15.0 }
};

static GLfloat mirrorVertices[4][3] = {
  { 0.0, 12.0, -13.0 },
  { 0.0, 12.0, 13.0 },
  { 0.0, 28.0, 13.0 },
  { 0.0, 28.0, -13.0 }
};

static GLfloat WorkFieldVertices[4][3] = {
  { -4.0, 10.0, -15.0 },
  { -4.0, 10.0, 15.0 },
  { 0.0, 10.0, 15.0 },
  { 0.0, 10.0, -15.0 },
};

static GLfloat BackWorkFieldVertices[4][3] = {
  { -8.0, 10.0, -15.0 },
  { -8.0, 10.0, 15.0 },
  { 0.0, 10.0, 15.0 },
  { 0.0, 10.0, -15.0 },
};

static GLfloat SideBarVertices[4][3] = {
  { 0.0, 10.0, 0.0 },
  { -15.0, 10.0, 0.0 },
  { -15.0, 0.0, 0.0 },
  { 0.0, 0.0, 0.0 },
};

static GLfloat BackSideBarVertices[4][3] = {
  { 0.0, 10.0, 0.0 },
  { -8.0, 10.0, 0.0 },
  { -8.0, 0.0, 0.0 },
  { 0.0, 0.0, 0.0 },
};


/* Fonction de creation du bar */
/*******************************/

static void makeBar(void)
{
	// cotes du bar
	// creation de la liste
	glNewList(SIDE_BAR,GL_COMPILE);
	glBegin(GL_QUADS);
    glVertex3fv(SideBarVertices[0]);
    glVertex3fv(SideBarVertices[1]);
    glVertex3fv(SideBarVertices[2]);
    glVertex3fv(SideBarVertices[3]);
	glEnd();
	glEndList();

	glNewList(BACK_SIDE_BAR,GL_COMPILE);
	glBegin(GL_QUADS);
    glVertex3fv(BackSideBarVertices[0]);
    glVertex3fv(BackSideBarVertices[1]);
    glVertex3fv(BackSideBarVertices[2]);
    glVertex3fv(BackSideBarVertices[3]);
	glEnd();
	glEndList();
}

/* Fonction d'affichage du miroir */
/**********************************/

static void drawMirror(void)
{
  glEnable(GL_LIGHTING);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  
  
  glMaterialfv(GL_FRONT, GL_DIFFUSE,mirrorColor);
  glMaterialfv(GL_FRONT, GL_SPECULAR,mirrorSpecular);
  glMaterialfv(GL_FRONT,GL_DIFFUSE,mirrorColor);

  glPushMatrix();
	glTranslatef(-15.9,0.0,0.0);

  glBegin(GL_QUADS);
    glVertex3fv(mirrorVertices[0]);
    glVertex3fv(mirrorVertices[1]);
    glVertex3fv(mirrorVertices[2]);
    glVertex3fv(mirrorVertices[3]);
  glEnd();

  glPopMatrix();
  
  
  //glEnable(GL_CULL_FACE);
  	
  glDisable(GL_BLEND);
  glDisable(GL_LIGHTING);
  glMaterialfv(GL_FRONT,GL_SPECULAR,nullSpecular);
  glMaterialfv(GL_FRONT,GL_DIFFUSE,nullSpecular);

}

static void drawBackMirror(void)
{
  glEnable(GL_LIGHTING);
  glMaterialfv(GL_FRONT, GL_DIFFUSE,mirrorBackColor);

  glPushMatrix();
  glTranslatef(-16.0,0.0,0.0);

  glBegin(GL_QUADS);
    glVertex3fv(mirrorBackVertices[0]);
    glVertex3fv(mirrorBackVertices[3]);
    glVertex3fv(mirrorBackVertices[2]);
    glVertex3fv(mirrorBackVertices[1]);
  glEnd();

  glPopMatrix();
  glDisable(GL_LIGHTING);
}

static void drawFrontMirror(void)
{
  glEnable(GL_LIGHTING);
  glPushMatrix();
  glTranslatef(-16.0,0.0,0.0);

  glBegin(GL_QUADS);
    glVertex3fv(mirrorBackVertices[0]);
    glVertex3fv(mirrorBackVertices[1]);
    glVertex3fv(mirrorBackVertices[2]);
    glVertex3fv(mirrorBackVertices[3]);
  glEnd();

  glPopMatrix();
  glDisable(GL_LIGHTING);
}


/* Fonction d'affichage du bar */
/**********************************/

static void drawBar(void)
{
	glEnable(GL_LIGHTING);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, barColor);
	glDisable(GL_CULL_FACE);

	// panneau avant
	glPushMatrix();
	glTranslatef(15.0,0.0,0.0);  
	glBegin(GL_QUADS);
    glVertex3fv(FrontBarVertices[0]);
    glVertex3fv(FrontBarVertices[1]);
    glVertex3fv(FrontBarVertices[2]);
    glVertex3fv(FrontBarVertices[3]);
	glEnd();
	glPopMatrix();

	//panneaux arrières avant
	glPushMatrix();
	glTranslatef(-8.0,0.0,0.0);  
	glBegin(GL_QUADS);
    glVertex3fv(FrontBarVertices[0]);
    glVertex3fv(FrontBarVertices[1]);
    glVertex3fv(FrontBarVertices[2]);
    glVertex3fv(FrontBarVertices[3]);
	glEnd();
	glPopMatrix();

	//panneaux arrières arriere
	glPushMatrix();
	glTranslatef(-16.0,0.0,0.0);  
	glBegin(GL_QUADS);
    glVertex3fv(FrontBarVertices[0]);
    glVertex3fv(FrontBarVertices[1]);
    glVertex3fv(FrontBarVertices[2]);
    glVertex3fv(FrontBarVertices[3]);
	glEnd();
	glPopMatrix();

	//plan de travail arriere
	glPushMatrix();
	glTranslatef(-8.0,0.0,0.0);
	glBegin(GL_QUADS);
    glVertex3fv(BackWorkFieldVertices[0]);
    glVertex3fv(BackWorkFieldVertices[1]);
    glVertex3fv(BackWorkFieldVertices[2]);
    glVertex3fv(BackWorkFieldVertices[3]);
	glEnd();
	glPopMatrix();

	//plan de travail
	glPushMatrix();
	glTranslatef(15.0,0.0,0.0);
	glBegin(GL_QUADS);
    glVertex3fv(WorkFieldVertices[0]);
    glVertex3fv(WorkFieldVertices[1]);
    glVertex3fv(WorkFieldVertices[2]);
    glVertex3fv(WorkFieldVertices[3]);
	glEnd();
	glPopMatrix();

	// cote droit arriere
	glPushMatrix();
	glTranslatef(-8.0,0.0,-15.0);
	glCallList(BACK_SIDE_BAR);
	glPopMatrix();

	// cote gauche arriere
	glPushMatrix();
	glTranslatef(-8.0,0.0,15.0);
	glCallList(BACK_SIDE_BAR);
	glPopMatrix();

	// cote droit
	glPushMatrix();
	glTranslatef(15.0,0.0,-15.0);
	glCallList(SIDE_BAR);
	glPopMatrix();

	// cote gauche
	glPushMatrix();
	glTranslatef(15.0,0.0,15.0);
	glCallList(SIDE_BAR);
	glPopMatrix();

	glEnable(GL_CULL_FACE);
	glDisable(GL_BLEND);
    glDisable(GL_LIGHTING);
}
/* Fonction de creation du Barman */
/**********************************/

static void makeBarman(void)
{
	/* tete */
	glNewList(HEAD,GL_COMPILE);
	glPushMatrix();
		//glTranslatef(0.0,21.0,0.0);
		glPushMatrix();
		glEnable(GL_NORMALIZE);
		glScalef(1.0,2.0,1.0);
		glutSolidSphere(1.5,10.0,10.0);
		glDisable(GL_NORMALIZE);
		glPopMatrix();
		glTranslatef(-1.0,2.0,0.0);
		glutSolidSphere(2.5,10.0,10.0);
	glPopMatrix();
	glEndList();

	/* une clavicule */
	glNewList(CLAVI,GL_COMPILE);
	glPushMatrix();
		glRotatef(10.0,1.0,0.0,0.0);
		cylindreH(0.0,0.0,-3.0,0.0,0.0,0.3);
	glPopMatrix();
	glEndList();

	/* un bras */
	glNewList(BRAS,GL_COMPILE);
	glPushMatrix();
		glutSolidSphere(0.8,10.0,10.0);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(0.0,-1.5,-0.5);
		glRotatef(110.0,1.0,0.0,0.0);
		cylindreH(0.0,0.0,0.0,0.0,-3.0,0.4);
	glPopMatrix();
	glEndList();

	/* un avant bras */
	glNewList(AVANT_BRAS,GL_COMPILE);
	glPushMatrix();
		glutSolidSphere(0.7,10.0,10.0);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(0.0,-1.5,-0.3);
		glRotatef(100.0,1.0,0.0,0.0);
		cylindreH(0.0,0.0,0.0,0.0,-2.5,0.3);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(0.0,-3.5,-0.6);
		glEnable(GL_NORMALIZE);
		glScalef(2.0,2.5,1.0);
		glutSolidSphere(0.5,10.0,10.0);
		glDisable(GL_NORMALIZE);
	glPopMatrix();
	glEndList();

	/* un pec */
	glNewList(PEC,GL_COMPILE);
	glPushMatrix();
		glTranslatef(0.0,-0.3,0.0);
		glRotatef(80.0,1.0,0.0,0.0);
		cylindreH(0.0,0.0,-3.0,0.0,0.0,0.3);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(0.0,1.0,3.0);
		cylindreH(0.0,0.0,-2.3,0.0,0.0,0.3);
	glPopMatrix();
	glEndList();

	/* une moitie d'abdos */
	glNewList(ABDO,GL_COMPILE);
	glPushMatrix();
		glTranslatef(0.0,0.0,1.0);
		glRotatef(80.0,1.0,0.0,0.0);
		cylindreH(0.0,0.0,-2.0,0.0,0.0,0.3);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(0.0,1.0,3.0);
		cylindreH(0.0,0.0,-1.5,0.0,0.0,0.3);
	glPopMatrix();
	glEndList();

	/* une moitie de calebar */
	glNewList(CALE,GL_COMPILE);
	glPushMatrix();
		glTranslatef(0.0,0.0,0.8);
		glRotatef(40.0,1.0,0.0,0.0);
		cylindreH(0.0,0.0,-2.0,0.0,0.0,0.3);
	glPopMatrix();
	glEndList();

	/* une jambe */
	glNewList(JAMBE,GL_COMPILE);
	glPushMatrix();
		glTranslatef(0.0,-6.5,0.0);
		glutSolidSphere(0.7,10.0,10.0);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(0.0,-10.0,-0.8);
		glutSolidSphere(0.7,10.0,10.0);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(0.0,-4.5,0.5);
		glRotatef(110.0,1.0,0.0,0.0);
		cylindreH(0.0,0.0,0.0,0.0,-4.0,0.4);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(0.0,-8.5,-0.5);
		glRotatef(100.0,1.0,0.0,0.0);
		cylindreH(0.0,0.0,0.0,0.0,-3.5,0.3);
	glPopMatrix();
	glEndList();

	/* un pied */
	glNewList(PIED,GL_COMPILE);
	glPushMatrix();
		glEnable(GL_NORMALIZE);
		glScalef(4.0,2.0,2.0);
		glutSolidSphere(0.5,10.0,10.0);
		glDisable(GL_NORMALIZE);
	glPopMatrix();
	glEndList();

	/* corps */
	glNewList(HALF_A_BODY,GL_COMPILE);
	glPushMatrix();
		/* clavicules */
		glPushMatrix();
		glTranslatef(0.0,16.5,1.0);
		glCallList(CLAVI);
		glPopMatrix();

		/* pecs */
		glPushMatrix();
		glTranslatef(0.0,12.5,-2.5);
		glCallList(PEC);
		glPopMatrix();

		/* abdos */
		glPushMatrix();
		glTranslatef(0.0,10.0,-2.0);
		glCallList(ABDO);
		glPopMatrix();

		/* calebar */
		glPushMatrix();
		glTranslatef(0.0,9.0,0.0);
		glCallList(CALE);
		glPopMatrix();

		/* jambe */
		glPushMatrix();
		glTranslatef(0.0,12.5,-2.5);
		glCallList(JAMBE);
		glPopMatrix();

		/* pied */
		glPushMatrix();
		glTranslatef(0.0,1.0,-3.6);
		glCallList(PIED);
		glPopMatrix();

		

	glPopMatrix();
	glEndList();

	glNewList(BODY,GL_COMPILE);
	glPushMatrix();
		glTranslatef(-1.0,0.0,0.0);
		glCallList(HALF_A_BODY);
		glRotatef(180.0,0.0,1.0,0.0);
		glCallList(HALF_A_BODY);
	glPopMatrix();
	glEndList();

	/* une bouteille */
	glNewList(BOUTEILLE,GL_COMPILE);
	glPushMatrix();
		glRotatef(45.0,-1.0,0.0,0.0);
		cylindreH(0.0,0.0,0.0,0.0,-3.5,1.0);
		glTranslatef(0.0,0.0,2.0);
		cylindreH(0.0,0.0,0.0,0.0,-3.5,0.6);
	glPopMatrix();
	glEndList();

	/* un verre */
	glNewList(VERRE,GL_COMPILE);
	glPushMatrix();
		glRotatef(80.0,1.0,0.0,0.0);
		cylindreH(0.0,0.0,0.0,0.0,-3.5,0.9);
	glPopMatrix();
	glEndList();
}

/* Fonction d'affichage du barman */
/**********************************/

static void drawBarman()
{
	/* Translate the barman at (0,8,0). */
	glEnable(GL_LIGHTING);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
	glMaterialfv(GL_FRONT,GL_SPECULAR, skinSpecular);
	//glMaterialf(GL_FRONT,GL_SHININESS, skinShininess);
	//glMaterialfv(GL_FRONT,GL_EMISSION, skinEmission);

	if (animation == 0)
	{
		glPushMatrix();
		glPushMatrix();
		glTranslatef(0.0,21.0,0.0);
		glCallList(HEAD);
		glPopMatrix();
		glCallList(BODY);

		/* bras */
		glPushMatrix();
		glTranslatef(-1.0,17.0,-4.0);
		glCallList(BRAS);
		glPopMatrix();

		/* avant bras */
		glPushMatrix();
		glTranslatef(-1.0,14.0,-5.0);
		glCallList(AVANT_BRAS);
		glPopMatrix();

		/* une bouteille */
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, glassBottleColor);
		glPushMatrix();
		glTranslatef(0.0,10.0,-5.0);
		glPushMatrix();
		glRotatef(0.0,1.0,0.0,0.0);
		glCallList(BOUTEILLE);
		glPopMatrix();
		glPopMatrix();

		/* verre */
		glPushMatrix();
		glTranslatef(-0.5,11.0,5.0);
		glCallList(VERRE);
		glPopMatrix();

		glDisable(GL_BLEND);
		
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, skinColor);
		glRotatef(180.0,0.0,1.0,0.0);

		/* bras */
		glPushMatrix();
		glTranslatef(1.0,17.0,-4.0);
		glCallList(BRAS);
		glPopMatrix();

		/* avant bras */
		glPushMatrix();
		glTranslatef(1.0,14.0,-5.0);
		glCallList(AVANT_BRAS);
		glPopMatrix();

		glPopMatrix();
	}
	else
	{
		glPushMatrix();
		
		if(!enfle) {
			glPushMatrix();
			glTranslatef(0.0,21.0,0.0);
			glPushMatrix();
			glRotatef(4.0*move,1.0,0.0,0.0);
			glRotatef(2.0*move,0.0,0.0,1.0);
			glCallList(HEAD);
			glPopMatrix();
			glPopMatrix();
		} else {
			glPushMatrix();
			glTranslatef(0.0,21.0,0.0);
			glPushMatrix();
			glRotatef(4.0*move,1.0,0.0,0.0);
			glRotatef(2.0*move,0.0,0.0,1.0);
			glEnable(GL_NORMALIZE);
			glScalef(1.0,move/4.0,1.0);
			glCallList(HEAD);
			glDisable(GL_NORMALIZE);
			glPopMatrix();
			glPopMatrix();
		}
		glPushMatrix();
		glRotatef(0.0,0.0,1.0,0.0);
		glCallList(BODY);
		glPopMatrix();

		/* bras */
		glPushMatrix();
		glTranslatef(-1.0,17.0,-4.0);
		glPushMatrix();
		glRotatef(12*move,1.0,0.0,0.0);
		glCallList(BRAS);
		glPopMatrix();
		glPopMatrix();

		/* avant bras */
		glPushMatrix();
		glTranslatef(-1.0,14.0+move/2.3,-5.0-move/2.0);
		glPushMatrix();
		glRotatef(4*move,1.0,0.0,0.0);
		glCallList(AVANT_BRAS);
		glPopMatrix();
		glPopMatrix();

		/* une bouteille */
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, glassBottleColor);
		glPushMatrix();
		glTranslatef(0.0,10.0+move/2.4,-5.0-move/1.3);
		glPushMatrix();
		glRotatef(12.0*move,1.0,0.0,0.0);
		glCallList(BOUTEILLE);
		glPopMatrix();
		glPopMatrix();

		/* verre */
		glPushMatrix();
		glTranslatef(-0.5,11.0,5.0-1.2*move);
		glPushMatrix();
		glRotatef(12.0*move,-1.0,0.0,0.0);
		glCallList(VERRE);
		glPopMatrix();
		glPopMatrix();
		glDisable(GL_BLEND);

		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, skinColor);
		glRotatef(180.0,0.0,1.0,0.0);

		/* bras */
		glPushMatrix();
		glTranslatef(1.0,17.0,-4.0);
		glPushMatrix();
		glRotatef(9.0*move,-1.0,0.0,0.0);
		glCallList(BRAS);
		glPopMatrix();
		glPopMatrix();

		/* avant bras */
		glPushMatrix();
		glTranslatef(1.0,14.0,-5.0+move/2.0);
		glPushMatrix();
		glRotatef(9.0*move,-1.0,0.0,0.0);
		glCallList(AVANT_BRAS);
		glPopMatrix();
		glPopMatrix();
		glPopMatrix();

	}
	glMaterialfv(GL_FRONT,GL_SPECULAR,nullSpecular);
	//glMaterialf(GL_FRONT,GL_SHININESS,nullShininess);
	//glMaterialfv(GL_FRONT,GL_EMISSION, nullEmission);
	//glDisable(GL_LIGHTING);
}


/********************/
/*    LE Redraw     */
/********************/

static void redraw(void)
{
  int start, end;

  switch(mode) {
  case WIREFRAME:
	glShadeModel(GL_SMOOTH);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
	break;
  case DOT:
	glShadeModel(GL_SMOOTH);
	glPolygonMode(GL_FRONT_AND_BACK,GL_POINT);
	break;
  case FLAT:
	glShadeModel(GL_FLAT);
	glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
	break;
  case SMOOTH:
	glShadeModel(GL_SMOOTH);
	glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
	break;
  }

  if (reportSpeed) {
    start = glutGet(GLUT_ELAPSED_TIME);
  }

  /* Remise a zero des stencil */
  /****************************/

  if ((renderMirror) || (stencilShadow && renderShadow)) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  } else {
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  }

  // stroboscope
  if(renderStrobo) {
	if(strobo) 
		glEnable(GL_LIGHT7);
	else 
		glDisable(GL_LIGHT7);
  }

// pour le mouvement des lumieres dans la boule
  if (renderBoule)
  {
	glPushMatrix();

	glTranslatef(0.0, 30.0,4.0);
	//Positionnement des lumiere de la boule
	glLightfv(GL_LIGHT4, GL_POSITION, light4Position);

	glLightfv(GL_LIGHT5, GL_POSITION, light5Position);

	glLightfv(GL_LIGHT6, GL_POSITION, light6Position);
	
	glPopMatrix();

	if(lights_enabled[0]==1)
	{
	  glEnable(GL_LIGHT4);
	  light4Position[0] = 10.0 * sin(angleBoule);
	  light4Position[1] = -10.0;
	  light4Position[2] = 10.0 * cos(angleBoule);;
	  light4Position[3] = 1.0;
	} else 
		glDisable(GL_LIGHT4);

	if(lights_enabled[1]==1)
	{
	  glEnable(GL_LIGHT5);
	  light5Position[0] = 10.0 * sin(angleBoule);
	  light5Position[1] = 10.0 * cos(angleBoule);
	  light5Position[2] = 0.0;
	  light5Position[3] = 1.0;
	} else 
		glDisable(GL_LIGHT5);

	if(lights_enabled[2]==1)
	{
	  glEnable(GL_LIGHT6);
	  light6Position[0] = 0.0;
	  light6Position[1] = 10.0 * cos(angleBoule);
	  light6Position[2] = 10.0 * sin(angleBoule);
	  light6Position[3] = 1.0;
	  
	  //glPushMatrix();
	  //glTranslatef(lightBoulePosition[2][0], lightBoulePosition[2][1], lightBoulePosition[2][2]);
	  //glutSolidSphere(1.0, 5, 5);
	  //glPopMatrix();
	} else 
		glDisable(GL_LIGHT6);
  }

  else {
	glDisable(GL_LIGHT4);
	glDisable(GL_LIGHT5);
	glDisable(GL_LIGHT6);
  }


  /* Gestion du brouillard */
  /*************************/
  if(fog) {
	  glEnable(GL_FOG);
	  glFogfv(GL_FOG_MODE,fogMode);
	  glFogfv(GL_FOG_DENSITY,fogDensity);
	  glFogfv(GL_FOG_COLOR,fogColor);

  } else 
	  glDisable(GL_FOG);

  /* Gestion de l'antialiasing */
  /*****************************/
  if(antialiasing) {
	  glEnable(GL_BLEND);
	  glBlendFunc(GL_SRC_ALPHA,GL_ONE);

	  //glEnable(GL_LINE_SMOOTH);
	  glEnable(GL_POLYGON_SMOOTH);
	  //glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
	  //glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
	  glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
  } else {
	  glDisable(GL_BLEND);
	  glDisable(GL_POLYGON_SMOOTH);
	  glDisable(GL_POINT_SMOOTH);
	  glDisable(GL_LINE_SMOOTH);
  }

  /* Gestion de la position des sources de lumiere */
  /************************************************/

  if (directionalLight1) {
    light1Position[3] = 0.0;
  } else {
    light1Position[3] = 1.0;
  }

  if (directionalLight2) {
    light2Position[3] = 0.0;
  } else {
    light2Position[3] = 1.0;
  }

  if (directionalLight3) {
    light3Position[3] = 0.0;
  } else {
    light3Position[3] = 1.0;
  }

  shadowMatrix(floorShadow, floorPlane, light1Position);

  glPushMatrix();
    // Perform scene rotations based on user mouse input.
    glRotatef(angle2, 1.0, 0.0, 0.0);
    glRotatef(angle, 0.0, 1.0, 0.0);
     
    // Tell GL new light source position.
    glLightfv(GL_LIGHT0, GL_POSITION, light1Position);
	glPushMatrix();
	glTranslatef(0.0,0.0,-28.0);
	glLightfv(GL_LIGHT1, GL_POSITION, light2Position);
	glPopMatrix();
	glPushMatrix();
	glTranslatef(0.0,0.0,-11.0);
	glLightfv(GL_LIGHT2, GL_POSITION, light3Position);
	glPopMatrix();



	/* Gestion du miroir */
	/*********************/

	if (renderMirror) {
	  /* Don't update color or depth. */
      glDisable(GL_DEPTH_TEST);
      glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

      /* Draw 1 into the stencil buffer. */
      glEnable(GL_STENCIL_TEST);
      glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
      glStencilFunc(GL_ALWAYS, 1, 0xffffffff);

      /* Now render floor; floor pixels just get their stencil set to 1. */
	  glFrontFace(GL_CW);
	  glMaterialfv(GL_FRONT, GL_SPECULAR,mirrorSpecular);
      drawMirror();
		//glFrontFace(GL_CCW);

      /* Re-enable update of color and depth. */ 
      glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
      glEnable(GL_DEPTH_TEST);

	  /* Now, only render where stencil is set to 1. */
      glStencilFunc(GL_EQUAL, 1, 0xffffffff);  /* draw if ==1 */
      glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    
	  glPushMatrix();

      /* The critical reflection step: Reflect barman through the floor
         (the Y=0 plane) to make a relection. */
      glScalef(-1.0, 1.0, 1.0);
  	  glTranslatef(20.0,0.0,0.0);

      /* Reflect the light position. */
      glLightfv(GL_LIGHT0, GL_POSITION, light1Position);
	  glLightfv(GL_LIGHT1, GL_POSITION, light2Position);
      glLightfv(GL_LIGHT2, GL_POSITION, light3Position);
	  /* To avoid our normals getting reversed and hence botched lighting
         on the reflection, turn on normalize.  */
      glEnable(GL_NORMALIZE);
      glCullFace(GL_FRONT);

      /* Draw the reflected barman. */
      drawBarman();

      /* Disable normalize again and re-enable back face culling. */
      glDisable(GL_NORMALIZE);
      glCullFace(GL_BACK);

      glPopMatrix();

      /* Switch back to the unreflected light position. */
      glLightfv(GL_LIGHT0, GL_POSITION, light1Position);
	  glLightfv(GL_LIGHT1, GL_POSITION, light2Position);
	  glLightfv(GL_LIGHT2, GL_POSITION, light3Position);
      
      glDisable(GL_STENCIL_TEST);
    }
    
    /* Affichage du sol */
	/********************/

    glFrontFace(GL_CW);  /* Switch face orientation. */
    glColor4f(0.1, 0.1, 0.7, 1.0);
    drawFloor();
    
	if (renderMirror) {
		glMaterialfv(GL_FRONT, GL_SPECULAR,mirrorSpecular);
		drawMirror();
		glMaterialfv(GL_FRONT, GL_SPECULAR,nullSpecular);
	}
	drawBackMirror();
	drawFrontMirror();

	glFrontFace(GL_CCW);
	
	
	/* Gestion des ombres */
	/**********************/

    if (renderShadow) {
      if (stencilShadow) {
        /* Draw the floor with stencil value 3.  This helps us only 
           draw the shadow once per floor pixel (and only on the
           floor pixels). */
        glEnable(GL_STENCIL_TEST);
        glStencilFunc(GL_ALWAYS, 3, 0xffffffff);
        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
      }
    

    /* Draw "top" of floor.  Use blending to blend in reflection. */
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor4f(1.0, 1.0, 1.0, 0.3);
    //drawFloor();
    //drawBarman();
	//drawBar();
	glDisable(GL_BLEND);
	}
    if (renderBarman) {
		/* Draw "actual" barman, not its reflection. */
		drawFloor();
		drawBarman();
		drawBar();
		//drawBarman();
			
    }

    if (renderShadow) {

      /* Render the projected shadow. */

      if (stencilShadow) {

        /* Now, only render where stencil is set above 2 (ie, 3 where
           the top floor is).  Update stencil with 2 where the shadow
           gets drawn so we don't redraw (and accidently reblend) the
           shadow). */
        glStencilFunc(GL_LESS, 2, 0xffffffff);  /* draw if ==1 */
        glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
      }

      /* To eliminate depth buffer artifacts, we use polygon offset
         to raise the depth of the projected shadow slightly so
         that it does not depth buffer alias with the floor. */
      if (offsetShadow) {
        switch (polygonOffsetVersion) {
        case EXTENSION:
	
	#ifdef GL_EXT_polygon_offset
          glEnable(GL_POLYGON_OFFSET_EXT);
          break;
	#endif
	#ifdef GL_VERSION_1_1
        case ONE_DOT_ONE:
          glEnable(GL_POLYGON_OFFSET_FILL);
          break;
	#endif
        case MISSING:
          /* Oh well. */
          break;
        }
      }

      /* Render 50% black shadow color on top of whatever the
         floor appareance is. */
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glDisable(GL_LIGHTING);  /* Force the 50% black. */
      glColor4f(0.0, 0.0, 0.0, 1.0);

      glPushMatrix();
        /* Project the shadow. */
		glMultMatrixf((GLfloat*)floorShadow);
        drawBarman();
      glPopMatrix();

      glDisable(GL_BLEND);
      glEnable(GL_LIGHTING);

      if (offsetShadow) {
        switch (polygonOffsetVersion) {
	#ifdef GL_EXT_polygon_offset
        case EXTENSION:
          glDisable(GL_POLYGON_OFFSET_EXT);
          break;
	#endif
	#ifdef GL_VERSION_1_1
        case ONE_DOT_ONE:
          glDisable(GL_POLYGON_OFFSET_FILL);
          break;
	#endif
        case MISSING:
          /* Oh well. */
          break;
        }
      }
      if (stencilShadow) {
        glDisable(GL_STENCIL_TEST);
      }
    }
	glPopMatrix();
  if (reportSpeed) {
    glFinish();
    end = glutGet(GLUT_ELAPSED_TIME);
    printf("Speed %.3g frames/sec (%d ms)\n", 1000.0/(end-start), end-start);
  }

  glutSwapBuffers();
}


/* Gestion des actions de la souris */
/************************************/

static void mouse(int button, int state, int x, int y)
{
  if (button == GLUT_LEFT_BUTTON) {
    if (state == GLUT_DOWN) {
      moving = 1;
      startx = x;
      starty = y;
    }
    if (state == GLUT_UP) {
      moving = 0;
    }
  }
  if (button == GLUT_MIDDLE_BUTTON) {
    if (state == GLUT_DOWN) {
    }
    if (state == GLUT_UP) {
    }
  }
}

/* Gestion des movements de la souris */
/**************************************/

static void motion(int x, int y)
{
  if (moving) {
    angle = angle + (x - startx);
    angle2 = angle2 + (y - starty);
    startx = x;
    starty = y;
    glutPostRedisplay();
  }
}


/* Variation des paramètres pour les divers mouvements   */
/*********************************************************/

static void idle(void)
{
  static float time = 0.0;
  move_old = move;

  time = glutGet(GLUT_ELAPSED_TIME) / vitesse;

  move = 10.0 * fabs(sin(time)*0.5);

  angleBoule += 1;

  strobo = (strobo==1)?0:1;

  glutPostRedisplay();
}

/* Enumeration des fonctions accessibles a l'utilisateur */
/*********************************************************/

enum {
  M_NONE, M_MOTION, M_LIGHT1, M_LIGHT2, M_LIGHT3, M_LIGHT123, M_TEXTURE, M_SHADOWS, M_MIRROR, M_BARMAN, M_BOULE,
  M_STENCIL_SHADOW, M_OFFSET_SHADOW,
  M_POSITIONAL1, M_DIRECTIONAL1, M_POSITIONAL2, M_DIRECTIONAL2, M_POSITIONAL3, M_DIRECTIONAL3, M_PERFORMANCE
};


/* Controle de la lumiere */
/**************************/

static void controlLights(int value)
{
  switch (value) {
  case M_NONE:
    return;
  case M_MOTION:
	animation = (animation==1)?0:1;
    break;
  case M_LIGHT1:
    lightSwitch1 = !lightSwitch1;
    if (lightSwitch1) 
		glEnable(GL_LIGHT0);
    else 
		glDisable(GL_LIGHT0);
    break;
  case M_LIGHT2:
		lightSwitch2 = !lightSwitch2;
		if (lightSwitch2) 
			glEnable(GL_LIGHT1);
		else
			glDisable(GL_LIGHT1);
		break;
  case M_LIGHT3:
		lightSwitch3 = !lightSwitch3;
		if (lightSwitch3) 
			glEnable(GL_LIGHT2);
		else
			glDisable(GL_LIGHT2);
		break;
  case M_LIGHT123:
		if (lightSwitch1 || lightSwitch2 || lightSwitch3)
		{
			lightSwitch1 = GL_FALSE;
			glDisable(GL_LIGHT0);
			lightSwitch2 = GL_FALSE;
			glDisable(GL_LIGHT1);
			lightSwitch3 = GL_FALSE;
			glDisable(GL_LIGHT2);
		}
		else {
			lightSwitch1 = GL_TRUE;
			glEnable(GL_LIGHT0);
			lightSwitch2 = GL_TRUE;
			glEnable(GL_LIGHT1);
			lightSwitch3 = GL_TRUE;
			glEnable(GL_LIGHT2);
		}
		break;

/* controle des fonctions accessibles à l'utilisateur */
/******************************************************/

  case M_TEXTURE:
    useTexture = !useTexture;
    break;
  case M_SHADOWS:
    renderShadow = 1 - renderShadow;
	break;
  case M_MIRROR:
    renderMirror = 1 - renderMirror;
    break;
  case M_BOULE:
	  renderBoule = (renderBoule==1)?0:1;
	break;
  case M_BARMAN:
    renderBarman = 1 - renderBarman;
    break;
  case M_STENCIL_SHADOW:
    stencilShadow = 1 - stencilShadow;
    break;
  case M_OFFSET_SHADOW:
    offsetShadow = 1 - offsetShadow;
    break;
  case M_POSITIONAL1:
    directionalLight1 = 0;
    break;
  case M_DIRECTIONAL1:
    directionalLight1 = 1;
    break;
  case M_POSITIONAL2:
    directionalLight2 = 0;
    break;
  case M_DIRECTIONAL2:
    directionalLight2 = 1;
    break;
  case M_POSITIONAL3:
    directionalLight3 = 0;
    break;
  case M_DIRECTIONAL3:
    directionalLight3 = 1;
    break;
  case M_PERFORMANCE:
    reportSpeed = 1 - reportSpeed;
    break;
  }
  glutPostRedisplay();
}


/* When not visible, stop animating.  Restart when visible again. */
/******************************************************************/
static void visible(int vis)
{
  if (vis == GLUT_VISIBLE) {
    if (animation)
      glutIdleFunc(idle);
  } else {
    if (!animation)
      glutIdleFunc(NULL);
  }
}


/* Gestion des touches du clavier */
/**********************************/

static void keyboard(unsigned char c, int x, int y)
{
	switch(c) {
	case 'q':
	case 27:
		exit(0);
		break;
	case 'f':
		mode=FLAT; 
		break;
	case 's':
		mode=SMOOTH;
		break;
	case 'd':
		mode=DOT;
		break;
	case 'w':
		mode=WIREFRAME;
		break;
	case 'r':
		renderMirror = 1 - renderMirror;
		break;
	case 'a':
		animation=(animation==1)?0:1;
		break;
	case 'b':
		fog = (fog==1)?0:1;
		break;
	case '+': 
		//augmente la vitesse du mouvement
		if(vitesse>100)
			vitesse-=50.0;
		break;
	case '-':
		// baisse la vitesse du mouvement
		if(vitesse<1000.0)
			vitesse+=50.0;
		break;
	case 'p':
		// augmente la densite du brouillard
		if(fogDensity[0]<0.1)
			fogDensity[0]+=0.002;
		break;
	case 'm':
		// diminue la densite du brouillard
		if(fogDensity[0]>0.0)
			fogDensity[0]-=0.002;
		break;
	case 'z':
		// antialiasing
		// produit des lignes un peu bizarres 
		// (probablement dues au blending)
		antialiasing=(antialiasing==1)?0:1;
		break;
	/* la partie entre commentaires ne sert a rien */
	/***********************************************/
	case 'o':
		l++;
		printf("%f",l);
		break;
	case 'l':
		l--;
		printf("%f",l);
		break;
	/***********************************************/
	case '1': // 1ère lumière
		if (renderBoule)
		{
			if(lights_enabled[0]==0)
			{
				glEnable(GL_LIGHT4);
				lights_enabled[0] = 1;
			}
			else {
				glDisable(GL_LIGHT4);
				lights_enabled[0] = 0;
			}
		}
		break;
	case '2': // 2ème lumière
		if (renderBoule)
		{
			if(lights_enabled[1]==0)
			{
				glEnable(GL_LIGHT5);
				lights_enabled[1] = 1;
			}
			else {
				glDisable(GL_LIGHT5);
				lights_enabled[1] = 0;
			}
		}
		break;
	case '3': // 3ème lumière
		if (renderBoule)
		{
			if(lights_enabled[2]==0)
			{
				glEnable(GL_LIGHT6);
				lights_enabled[2] = 1;
			}
			else {
				glDisable(GL_LIGHT6);
				lights_enabled[2] = 0;
			}
		}
		break;
	case 'E':
		enfle = (enfle==1)?0:1;
		break;
	case 'S':
		renderStrobo = (renderStrobo==1)?0:1;
		if(renderStrobo) {
			renderBoule = 0;
			lightSwitch1 = GL_FALSE;
			lightSwitch2 = GL_FALSE;
			lightSwitch3 = GL_FALSE;
		} else {
			glDisable(GL_LIGHT7);
			renderBoule = 1;
			lightSwitch1 = GL_TRUE;
			lightSwitch2 = GL_TRUE;
			lightSwitch3 = GL_TRUE;
			glEnable(GL_LIGHT0);
			glEnable(GL_LIGHT1);
			glEnable(GL_LIGHT2);
		}

		break;
	default:
		break;

	}
	glutPostRedisplay();
}


/* creation du menu des fonction accessible du bouton droit de la souris */
  /*************************************************************************/

static void createMenu(void) 
{
  glutCreateMenu(controlLights);

  glutAddMenuEntry("Toggle motion", M_MOTION);
  glutAddMenuEntry("-----------------------", M_NONE);
  glutAddMenuEntry("Toggle light 1", M_LIGHT1);
  glutAddMenuEntry("Toggle light 2", M_LIGHT2);
  glutAddMenuEntry("Toggle light 3", M_LIGHT3);
  glutAddMenuEntry("Toggle light 1,2,3", M_LIGHT123);
  glutAddMenuEntry("Toggle SphereLight", M_BOULE);
  glutAddMenuEntry("Toggle texture", M_TEXTURE);
  glutAddMenuEntry("Toggle shadows", M_SHADOWS);
  glutAddMenuEntry("Toggle mirror", M_MIRROR);
  glutAddMenuEntry("Toggle barman", M_BARMAN);
  glutAddMenuEntry("-----------------------", M_NONE);
  glutAddMenuEntry("Toggle shadow stenciling", M_STENCIL_SHADOW);
  glutAddMenuEntry("Toggle shadow offset", M_OFFSET_SHADOW);
  glutAddMenuEntry("----------------------", M_NONE);
  glutAddMenuEntry("Positional light 1", M_POSITIONAL1);
  glutAddMenuEntry("Directional light 1", M_DIRECTIONAL1);
  glutAddMenuEntry("Positional light 2", M_POSITIONAL2);
  glutAddMenuEntry("Directional light 2", M_DIRECTIONAL2);
  glutAddMenuEntry("Positional light 3", M_POSITIONAL3);
  glutAddMenuEntry("Directional light 3", M_DIRECTIONAL3);

  glutAddMenuEntry("-----------------------", M_NONE);
  glutAddMenuEntry("Toggle performance", M_PERFORMANCE);
  glutAttachMenu(GLUT_RIGHT_BUTTON);
}

/* fonctions speciales */
/***********************/

static void special(int k, int x, int y)
{
  glutPostRedisplay();
}

static int supportsOneDotOne(void)
{
  const char *version;
  int major, minor;

  version = (char *) glGetString(GL_VERSION);
  if (sscanf(version, "%d.%d", &major, &minor) == 2)
    return major >= 1 && minor >= 1;
  return 0;            /* OpenGL version string malformed! */
}


	/********************************/
	/*    Fonction principale       */
	/********************************/

int main(int argc, char **argv)
{
  int i;

  glutInit(&argc, argv);

  for (i=1; i<argc; i++) {
    if (!strcmp("-linear", argv[i])) {
      linearFiltering = 1;
    } else if (!strcmp("-mipmap", argv[i])) {
      useMipmaps = 1;
    } else if (!strcmp("-ext", argv[i])) {
      forceExtension = 1;
    }
  }

  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL | GLUT_MULTISAMPLE);
	
#if 1
  /* In GLUT 4.0, you'll be able to do this an be sure to
     get 2 bits of stencil if the machine has it for you. */
  glutInitDisplayString("samples stencil>=2 rgb double depth");
#endif
	
  glutInitWindowSize(500,500);
  glutCreateWindow("Blue Boy Bar");
  glClearColor(0.1,0.1,0.1,1.0);
  if (glutGet(GLUT_WINDOW_STENCIL_SIZE) <= 1) {
    printf("Barman: Sorry, I need at least 2 bits of stencil.\n");
    exit(1);
  }

  /* Register GLUT callbacks. */
  glutDisplayFunc(redraw);
  glutMouseFunc(mouse);
  glutMotionFunc(motion);
  glutKeyboardFunc(keyboard);
  glutVisibilityFunc(visible);
  glutSpecialFunc(special);
  glutIdleFunc(idle);
#ifdef GL_VERSION_1_1
  if (supportsOneDotOne() && !forceExtension) {
    polygonOffsetVersion = ONE_DOT_ONE;
    glPolygonOffset(-2.0, -1.0);
  } else
#endif
  {
#ifdef GL_EXT_polygon_offset
  /* check for the polygon offset extension */
  if (glutExtensionSupported("GL_EXT_polygon_offset")) {
    polygonOffsetVersion = EXTENSION;
    glPolygonOffsetEXT(-0.1, -0.002);
  } else 
#endif
    {
      polygonOffsetVersion = MISSING;
      printf("\nbarman: Missing polygon offset.\n");
      printf("           Expect shadow depth aliasing artifacts.\n\n");
    }
  }

  glEnable(GL_CULL_FACE);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_TEXTURE_2D);
  glLineWidth(0.5);

  glMatrixMode(GL_PROJECTION);
  gluPerspective( /* field of view in degree */ 40.0,
  /* aspect ratio */ 1.0,
    /* Z near */ 20.0, /* Z far */ 120.0);
  glMatrixMode(GL_MODELVIEW);
  gluLookAt(0.0, 8.0, 80.0,  /* eye is at (0,8,60) */
    0.0, 8.0, 0.0,      /* center is at (0,8,0) */
    0.0, 1.0, 0.);      /* up is in postivie Y direction */

	glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light1Color);
	glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.03);
	glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.01);
	glEnable(GL_LIGHT0);

	glLightfv(GL_LIGHT1, GL_DIFFUSE, light2Color);
	glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.03);
	glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.01);
	glEnable(GL_LIGHT1);

	glLightfv(GL_LIGHT2, GL_DIFFUSE, light3Color);
	glLightf(GL_LIGHT2, GL_CONSTANT_ATTENUATION, 0.03);
	glLightf(GL_LIGHT2, GL_LINEAR_ATTENUATION, 0.01);
	glEnable(GL_LIGHT2);

	glLightfv(GL_LIGHT4, GL_DIFFUSE, light4Color);
	glLightf(GL_LIGHT4, GL_CONSTANT_ATTENUATION, 0.01);
	glLightf(GL_LIGHT4, GL_LINEAR_ATTENUATION, 0.01);
	glEnable(GL_LIGHT4);

	glLightfv(GL_LIGHT5, GL_DIFFUSE, light5Color);
	glLightf(GL_LIGHT5, GL_CONSTANT_ATTENUATION, 0.01);
	glLightf(GL_LIGHT5, GL_LINEAR_ATTENUATION, 0.01);
	glEnable(GL_LIGHT5);

	glLightfv(GL_LIGHT6, GL_DIFFUSE, light6Color);
	glLightf(GL_LIGHT6, GL_CONSTANT_ATTENUATION, 0.01);
	glLightf(GL_LIGHT6, GL_LINEAR_ATTENUATION, 0.01);
	glEnable(GL_LIGHT6);

	glLightfv(GL_LIGHT7, GL_DIFFUSE, light7Color);
	glLightfv(GL_LIGHT7, GL_SPECULAR, light7Color);
	glLightfv(GL_LIGHT7, GL_EMISSION, light7Color);
	glLightf(GL_LIGHT7, GL_CONSTANT_ATTENUATION, 0.01);
	glLightf(GL_LIGHT7, GL_LINEAR_ATTENUATION, 0.01);

	glEnable(GL_LIGHTING);

  makeFloorTexture();
  createMenu();
  makeBar();
  makeBarman();

  /* Setup floor plane for projected shadow calculations. */
  findPlane(floorPlane, floorVertices[1], floorVertices[2], floorVertices[3]);

  glutMainLoop();
  return 0;             /* ANSI C requires main to return int. */
}
