/* Un programme OpenGL de deplacement            */
/* d'une camera au sein d'une scene              */
/* par utilisation du clavier                    */
/*                                               */
/* Auteur: Nicolas JANEY                         */
/* nicolas.janey@univ-fcomte.fr                  */
/* Fevrier 2017                                  */

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

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

#include "Scene.h"

/* Variables globales                           */

static int l = 1;

static float px = 0.0F;
static float py = 2.5F;
static float pz = -30.0F;
static float angle = 0.0F;
static float vy = 0.0F;
static float vz = 0.0F;
static float ouv = 60.0F;

static void initGL(void) {
  glEnable(GL_LIGHT0);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
}

/* Fonction executee lors d'un changement       */
/* de la taille de la fenetre OpenGL            */
/* Configuration d'une camera de visualisation  */
/* en projection en perspective                 */

static void reshape(int tx,int ty) {
  /* Configuration du viewport d'affichage      */
  glViewport(0,0,tx,ty);
  /* Choix et configuration de la camera        */
  /* de visualisation                           */
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(ouv,(double) tx/ty,0.1,1000.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

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

static void display(void) {
  glClearColor(0.6F,0.6F,0.6F,1.0F) ;
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) ;
  glPushMatrix();
  gluLookAt(px,py,pz,
            px+sin(angle),py,pz+cos(angle),
            0.0,1.0,0.0);
  /* Configuration de l'éclairage               */
  const GLfloat l_pos[] = { 1.0F,10.0F,-1.0F,1.0F };
  if ( l )
    glEnable(GL_LIGHTING);
    else
    glDisable(GL_LIGHTING);
  glLightfv(GL_LIGHT0,GL_POSITION,l_pos);
  /* Affichage de la scene                      */
  for ( int x = -1 ; x <= 1 ; x++ ) {
    for ( int z = -1 ; z <= 1 ; z++ ) {
      glPushMatrix();
      glTranslatef(20.0F*x,0.0,20.0F*z);
      scene(l);
      glPopMatrix(); } }
  glPopMatrix();
  glFlush();
  glutSwapBuffers();
  int error = glGetError();
  if ( error != GL_NO_ERROR )
    printf("Attention, erreur OpenGL %d\n",error);
}

/* Fonction executee en tache de fond           */

static void idle(void) {
  px += vz*0.01F*sin(angle);
  pz += vz*0.01F*cos(angle);
  py += vy*0.0001F;
  if ( py < 0.01F )
    py = 0.01F;
  glutPostRedisplay();
}

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

static void keyboard(unsigned char key,int x,int y) {
  switch ( key ) {
    case 'f' :  { static int fullScreen = 0;
                  static int tx;
                  static int ty;
                  static int px;
                  static int py;
                  fullScreen = !fullScreen;
                  if ( fullScreen ) {
                    px = glutGet(GLUT_WINDOW_X);
                    py = glutGet(GLUT_WINDOW_Y);
                    tx = glutGet(GLUT_WINDOW_WIDTH);
                    ty = glutGet(GLUT_WINDOW_HEIGHT);
                    glutFullScreen(); }
                    else
                    glutPositionWindow(px,py);
                    glutReshapeWindow(tx,ty); }
                break;
    case 0x0D : l = !l ;
                glutPostRedisplay();
                break;
    case 0x20 : { static int anim = 0;
                  anim = !anim;
                  glutIdleFunc(( anim && ( vz != 0 )) ? idle : NULL); }
                break;
    case 0x1B : exit(0); }
}

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

static void special(int key,int x,int y) {
  switch ( key ) {
    case GLUT_KEY_UP        : vz += 1.0F;
                              glutIdleFunc(idle);
                              break;
    case GLUT_KEY_DOWN      : vz -= 1.0F;
                              if ( vz < 0.0F ) {
                                vz = 0.0F;
                                glutPostRedisplay();
                                glutIdleFunc(NULL); }
                              break;
    case GLUT_KEY_PAGE_UP   : vy += 1.0F;
                              glutIdleFunc(idle);
                              break;
    case GLUT_KEY_PAGE_DOWN : vy -= 1.0F;
                              if ( vz < 0.0F ) {
                                vz = 0.0F;
                                glutPostRedisplay();
                                glutIdleFunc(NULL); }
                              break;
    case GLUT_KEY_RIGHT     : angle -= 0.03F;
                              glutPostRedisplay();
                              break;
    case GLUT_KEY_LEFT      : angle += 0.03F;
                              glutPostRedisplay();
                              break; }
}

/* Fonction principale                          */

int main(int argc,char **argv) {
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
  glutInitWindowSize(900,400); 
  glutInitWindowPosition(50,50); 
  glutCreateWindow("Deplacement au clavier");
  initGL();
  glutReshapeFunc(reshape);
  glutKeyboardFunc(keyboard);
  glutSpecialFunc(special);
  glutDisplayFunc(display);
  glutIdleFunc(idle);
  glutMainLoop();
  return(0);
}
