/* Lumieres et materiaux                         */
/*                                               */
/* Auteur: Nicolas JANEY                         */
/* nicolas.janey@univ-fcomte.fr                  */
/* Fevrier 2019                                  */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>

/* Fonction d'initialisation des parametres      */
/* OpenGL ne changeant pas au cours de la vie    */
/* du programme                                  */

static void init(void) {
  const float noir[] = { 0.0F,0.0F,0.0F,1.0F };
  glClearColor(0.0F,0.0F,0.0F,1.0F);
  glDepthFunc(GL_LESS);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT,noir);
}

static const float blanc[]       = { 1.0F,1.0F,1.0F,1.0F };
static const float jaune[]       = { 1.0F,1.0F,0.0F,1.0F };
static const float cyan[]        = { 0.0F,1.0F,0.0F,1.0F };
static const float magenta[]     = { 1.0F,0.0F,1.0F,1.0F };
static const float rouge[]       = { 1.0F,0.0F,0.0F,1.0F };
static const float vert[]        = { 0.0F,1.0F,0.0F,1.0F };
static const float bleu[]        = { 0.0F,0.0F,1.0F,1.0F };
static const float noir[]        = { 0.0F,0.0F,0.0F,1.0F };
static const float grisMoyen[]   = { 0.5F,0.5F,0.5F,1.0F };

/* Scene dessinee 1                              */

static void configurationMaterielTore1(void) {
  glMaterialfv(GL_FRONT,GL_DIFFUSE,vert);
  glMaterialfv(GL_FRONT,GL_SPECULAR,jaune);
  glMaterialf(GL_FRONT,GL_SHININESS,15.0F);
}

static void configurationMaterielTore2(void) {
  glMaterialfv(GL_FRONT,GL_DIFFUSE,bleu);
  glMaterialfv(GL_FRONT,GL_SPECULAR,blanc);
  glMaterialf(GL_FRONT,GL_SHININESS,100.0F);
}

static void configurationMaterielTore3(void) {
  glMaterialfv(GL_FRONT,GL_DIFFUSE,rouge);
  glMaterialfv(GL_FRONT,GL_SPECULAR,bleu);
  glMaterialf(GL_FRONT,GL_SHININESS,64.0F);
}

static void scene() {
  glPushMatrix();
  configurationMaterielTore1();
  glutSolidTorus(0.5,4.5,36,36);
  glRotatef(90.0F,1.0F,0.0F,0.0F);
  configurationMaterielTore2();
  glutSolidTorus(0.5,4.5,36,36);
  glRotatef(90.0F,0.0F,1.0F,0.0F);
  configurationMaterielTore3();
  glutSolidTorus(0.5,4.5,36,36);
  glPopMatrix();
}

/* Fonction de configuration de la lumiere 0     */

static void configurationLumiere0() {
  const GLfloat pos[] = { 2.0,2.0,2.0,1.0 };
  glLightfv(GL_LIGHT0,GL_POSITION,pos);
  glLightfv(GL_LIGHT0,GL_DIFFUSE,blanc);
  glLightfv(GL_LIGHT0,GL_SPECULAR,noir);
  glLightfv(GL_LIGHT0,GL_AMBIENT,noir);
  glEnable(GL_LIGHT0);
}

/* Fonction de configuration de la lumiere 1     */

static void configurationLumiere1() {
  const GLfloat pos[] = { -2.0,0.0,-4.0,0.0 };
  glLightfv(GL_LIGHT1,GL_POSITION,pos);
  glLightfv(GL_LIGHT1,GL_DIFFUSE,blanc);
  glLightfv(GL_LIGHT1,GL_SPECULAR,blanc);
  glLightfv(GL_LIGHT1,GL_AMBIENT,noir);
  glEnable(GL_LIGHT1);
}

/* Fonction de configuration des lumieres        */

static void configurationLumieres(void) {
  glPushMatrix();
  glEnable(GL_LIGHTING);
  configurationLumiere0();
  configurationLumiere1();
  glPopMatrix();
}

/* Fonction executee lors d'un rafraichissement  */
/* de la fenetre de dessin                       */

static void display(void) {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glPushAttrib(GL_LIGHTING_BIT);
  glPushMatrix();
  glTranslatef(-2.0F,-4.0F,6.0F);
  configurationLumieres();
  scene();
  glPopMatrix();
  glPopAttrib();
  glFlush();
  glutSwapBuffers();
  int error = glGetError();
  if ( error != GL_NO_ERROR )
    printf("Erreur OpenGL: %d\n",error);
}

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

#ifndef M_PI
  #define M_PI 3.14159
#endif

#define EPSILON 1.0

/* Fonction executee lors d'un changement        */
/* de la taille de la fenetre OpenGL             */
/* -> Ajustement de la camera de visualisation   */

static void reshape(int tx,int ty) {
  glViewport(0,0,tx,ty); 
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  double ratio =(double) tx/ty;
  gluPerspective(2.0*asin(5.0/15.0)*180/M_PI,ratio,10.0-EPSILON,20.0+EPSILON);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(-4.0,6.0,-5.0,-2.0,-4.0,6.0,0.0,1.0,0.0);
}

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

/* Fonction executee lors de la frappe           */
/* d'une touche du clavier                       */

static void keyboard(unsigned char key,int x,int y) {
  switch ( key ) {
      break;
    case 0x1B :
      exit(0); 
      break; }
}

/* Fonction principale                           */

int main(int argc,char **argv) {
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE);
  glutInitWindowSize(360,360); 
  glutInitWindowPosition(50,50); 
  glutCreateWindow("Epreuve n°2"); 
  init();
  glutKeyboardFunc(keyboard);
  glutReshapeFunc(reshape);
  glutDisplayFunc(display);
  glutMainLoop();
  return(0);
}
