/*********************************************************/
/* premier exemple de programme OpenGL / GLUT            */
/* Benoît Piranda          Université de Marne La Vallée */
/*********************************************************/
/* - Utilisation de GLUT (GL Utility Toolkit) pour ouvrir*/
/*   une fenêtre OpenGL et gérer les intervensions de    */
/*   l'utilisateur.                                      */
/* - Utilisation des opérateurs sur les matrices de      */
/*   visualisation pour placer un objet et la caméra dans*/
/*   l'espace.                                           */
/*********************************************************/

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>

GLint id_teapot,id_plan,id_fleche;

/*********************************************************/
/* fonction de dessin de la scène à l'écran              */
static void drawFunc(void)
{ /* initialisation des buffers : couleur et ZBuffer */
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  /* modification de la matrice de la scène */
  glMatrixMode(GL_MODELVIEW);

  glPushMatrix();
  /*[3]*/ glRotated(-150.0,0.0,0.0,1.0);

  /* affichage de l'objet fleche */
  glPushMatrix();
  glCallList(id_fleche);
  glPopMatrix();

  /* affichage de la théière */
  glPushMatrix();
  glCallList(id_teapot);
  glPopMatrix();

  glPopMatrix();

  /* fin de la définition de la scène */
  glFlush();
  /* changement de buffer d'affichage */
  glutSwapBuffers();
}

/*********************************************************/
/* fonction de changement de dimension de la fenetre     */
/* paramètres :                                          */
/* - width : largeur (x) de la zone de visualisation     */
/* - height : hauteur (y) de la zone de visualisation    */
static void reshapeFunc(int width,int height)
{ GLfloat  h = (GLfloat) height / (GLfloat) width;

  /* dimension de l'écran GL */
  glViewport(0, 0, (GLint)width, (GLint)height);
  /* construction de la matrice de projection */
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  /* définition de la camera */
  glFrustum( -1.0, 1.0, -h, h, 5.0, 60.0 );
  /*[1] placement de la caméra */
  /*[1]*/ glTranslatef( 0.0, 0.0, -15.0 );
  /*[1]*/ glRotatef(-90.0,1.0,0.0,0.0);

  /* initialisation de la matrice de la scène */
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

/*********************************************************/
/* fonction associée au clique de la souris              */
/* paramètres :                                          */
/* - button : nom du bouton pressé GLUT_LEFT_BUTTON,     */
/*   GLUT_MIDDLE_BUTTON ou GLUT_RIGHT_BUTTON             */
/* - state : état du bouton button GLUT_DOWN ou GLUT_UP  */
/* - x,y : coordonnée du curseur dans la fenêtre         */
static void mouseFunc(int button, int state, int x, int y)
{ 
}

/*********************************************************/
/* fonction associée au déplacement de la souris bouton  */
/* enfoncé.                                              */
/* paramètres :                                          */
/* - x,y : coordonnée du curseur dans la fenêtre         */
static void motionFunc(int x, int y)
{ 
}

/*********************************************************/
/* fonction associée aux interruptions clavier           */
/* paramètres :                                          */
/* - c : caractère saisi                                 */
/* - x,y : coordonnée du curseur dans la fenêtre         */
static void kbdFunc(unsigned char c, int x, int y)
{
}

/*********************************************************/
/* fonction associée aux interruptions clavier étendu.   */
/* paramètres :                                          */
/* - code : code de la touche enfoncée                   */
/* - x,y : coordonnée du curseur dans la fenêtre         */
static void kbdSpecialFunc(int code, int x, int y)
{ 
}

/*********************************************************/
/* fonction d'initialisation des paramètres de rendu et  */
/* des objets de la scènes.                              */
static void init()
{ GLfloat pos[4] = {-2.0f, -1.0f,5.0f, 0.0f};
  GLfloat c1[4] =  { 0.8f, 0.8f, 0.2f, 0.7f};
  GLfloat c2[4] =  { 1.0f, 0.2f, 0.2f, 1.0f};
  GLfloat cr[4] =  { 1.0f, 0.0f, 0.0f, 1.0f};
  GLfloat cv[4] =  { 0.0f, 1.0f, 0.0f, 1.0f};
  GLfloat cb[4] =  { 0.0f, 0.0f, 1.0f, 1.0f};

  /* activation du modèle d'illuminaion */
  glEnable(GL_LIGHTING);
  /* activation de la source n°0 */
  glEnable(GL_LIGHT0);
  /* placement de la source n°0 */
  glLightfv(GL_LIGHT0, GL_POSITION, pos );
  /* couleur du fond (noir) */
  glClearColor(0.1,0.1,0.1,0.0);
  /* activation du ZBuffer */
  glEnable( GL_DEPTH_TEST);
  /* ZBuffer actif pour les objets non convexes */
  glDisable(GL_CULL_FACE);

  /* activation de la transparence */
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  /* construction de l'objet id_teapot */
  id_teapot = glGenLists(1);
  glNewList(id_teapot, GL_COMPILE);
  /* couleur de l'objet */
  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,c1);
  /* la théière */
  glPushMatrix();
  glRotated(90,1.0,0.0,0.0);
  glutSolidTeapot(1.0);
  glPopMatrix();
  glEndList();

  /*[2] construction de l'objet id_fleche */
  /*[2]*/ id_fleche = glGenLists(1);
  /*[2]*/ glNewList(id_fleche, GL_COMPILE);
  /*[2]*/ glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,cr);
  /*[2]*/ glPushMatrix();
  /*[2]*/ glRotated(90,0.0,1.0,0.0);
  /*[2]*/ glutSolidCone(0.15,2.5, 50, 10);
  /*[2]*/ glPopMatrix();
  /*[2]*/ glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,cv);
  /*[2]*/ glPushMatrix();
  /*[2]*/ glRotated(-90,1.0,0.0,0.0);
  /*[2]*/ glutSolidCone(0.15,2.5, 50, 10);
  /*[2]*/ glPopMatrix();
  /*[2]*/ glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,cb);
  /*[2]*/ glutSolidCone(0.15,2.5, 50, 10);
  /*[2]*/ glEndList();

  /* construction de l'objet id_plan */
  /* plan horizontal (O,X,Y) de normale Z*/
  id_plan = glGenLists(1);
  glNewList(id_plan, GL_COMPILE);
  /* couleur de l'objet */
  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,c2);
  /* normale : vecteur Z */
  glNormal3d(0.0,0.0,1.0);
  /* construction d'un quadrilataire */
  glBegin(GL_QUADS);
    glVertex3d(0.0,0.0,0.0);
    glVertex3d(0.0,1.0,0.0);
    glVertex3d(1.0,1.0,0.0);
    glVertex3d(1.0,0.0,0.0);
  glEnd();
  glEndList();

  /* lissage des couleurs sur les facettes */
  glShadeModel(GL_SMOOTH);
}

int main(int argc, char** argv)
{ /* traitement des paramètres du programme propres à GL */
  glutInit(&argc, argv);
  /* initialisation du mode d'affichage :                */
  /* RVB + ZBuffer + Double buffer.                      */
  glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE);
  /* placement et dimentions originales de la fenêtre */
  glutInitWindowPosition(0, 0);
  glutInitWindowSize(500, 500);
  /* ouverture de la fenêtre */
  if (glutCreateWindow("Exemple 1") == GL_FALSE)
  { return 1;
  }

  init();
  
  /* association de la fonction de dimensionnement */
  glutReshapeFunc(reshapeFunc);
  /* association de la fonction d'affichage */
  glutDisplayFunc(drawFunc);
  /* association de la fonction d'événement souris */
  glutMouseFunc(mouseFunc);
  /* association de la fonction de DRAG */
  glutMotionFunc(motionFunc);
  /* association de la fonction d'événement du clavier */
  glutKeyboardFunc(kbdFunc);
  /* association de la fonction de traitement des touches*/
  /* spéciales du clavier                                */ 
  glutSpecialFunc(kbdSpecialFunc);

  /* boucle principale de gestion des événements */
  glutMainLoop();

  return 0;
}

unsigned char *LecturePPM(char *titre)
{ FILE *fichier;
  char chaine[255];
  unsigned char *image=NULL;
  int dx,dy;

  if (!(fichier = fopen(titre, "rt")))
  { printf("fichier %s introuvable\n",titre);
    return NULL;;
  }
  fscanf(fichier,"%s\n",chaine);
  printf("%s\n",chaine);
  do
  { fgets(chaine,255,fichier);
  } while (chaine[0]=='#');
  sscanf(chaine,"%d %d",&dx,&dy);
  printf("%d,%d\n",dx,dy);
  fscanf(fichier,"%s\n",chaine);
  image = (unsigned char *) malloc (dx*dy*3*sizeof(unsigned char));
  if (image==NULL)
  { printf("erreur d'allocation de l'image de texture\n");
    return NULL;
  }
  fread (image, sizeof (unsigned char), dx*dy * 3, fichier);
  fclose(fichier);

  return image;
}
