/* Auteur: Nicolas JANEY                */
/* nicolas.janey@univ-fcomte.fr         */
/* Avril 2015                           */
/* Calculs de projection pour affichage */

#include <stdio.h>
#include <math.h>
#include <sys/timeb.h>
#include <time.h>

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

#include "BSpline\LignePolygonale3D.h"
#include "BSpline\Position3D.h"
#include "BSpline\LookAt.h"

static LignePolygonale3D *lps;
static int image = 0;
const static int nbImages = 10000;

static const int nbP = 30;
static float pts[nbP][4] =
  { { -20.0F,  0.0F, 15.0F, 1.0F },{  20.0F,  0.0F, 15.0F, 1.0F },
    {  20.0F, 20.0F, 15.0F, 1.0F },{ -20.0F, 20.0F, 15.0F, 1.0F },
    { -20.0F,  0.0F,-15.0F, 1.0F },{  20.0F,  0.0F,-15.0F, 1.0F },
    {  20.0F, 20.0F,-15.0F, 1.0F },{ -20.0F, 20.0F,-15.0F, 1.0F },
    {  20.0F, 30.0F,  0.0F, 1.0F },{ -20.0F, 30.0F,  0.0F, 1.0F },
    {  20.0F,  0.0F,  4.0F, 1.0F },{  20.0F, 15.0F,  4.0F, 1.0F },
    {  20.0F, 15.0F, -4.0F, 1.0F },{  20.0F,  0.0F, -4.0F, 1.0F },
    {   5.0F,  7.0F, 15.0F, 1.0F },{  -5.0F,  7.0F, 15.0F, 1.0F },
    {  -5.0F, 15.0F, 15.0F, 1.0F },{   5.0F, 15.0F, 15.0F, 1.0F },
    {  15.0F,  7.0F,-15.0F, 1.0F },{   5.0F,  7.0F,-15.0F, 1.0F },
    {   5.0F, 15.0F,-15.0F, 1.0F },{  15.0F, 15.0F,-15.0F, 1.0F },
    {  -5.0F,  7.0F,-15.0F, 1.0F },{ -15.0F,  7.0F,-15.0F, 1.0F },
    { -15.0F, 15.0F,-15.0F, 1.0F },{  -5.0F, 15.0F,-15.0F, 1.0F },
    { -20.0F,  7.0F,  5.0F, 1.0F },{ -20.0F, 15.0F,  5.0F, 1.0F },
    { -20.0F, 15.0F, -5.0F, 1.0F },{ -20.0F,  7.0F, -5.0F,1.0F } }; 
static const int nbS = 34;
static int sgmts[nbS][2] =
  { {  0, 1 },{  1, 2 },{  2, 3 },{  3, 0 },{  4, 5 },
    {  5, 6 },{  6, 7 },{  7, 4 },{  0, 4 },{  1, 5 },
    {  8, 9 },{  8, 6 },{  9, 3 },{  8, 2 },{  9, 7 },
    { 10,11 },{ 11,12 },{ 12,13 },{ 14,15 },{ 15,16 },
    { 16,17 },{ 17,14 },{ 18,19 },{ 19,20 },{ 20,21 },
    { 21,18 },{ 22,23 },{ 23,24 },{ 24,25 },{ 25,22 },
    { 27,26 },{ 28,27 },{ 29,28 },{ 26,29 } };
static const int nbT = 18;
static float ptT[nbT][4] =
  { {  200.0F,  60.0F, 120.0F, 1.0F },{  200.0F,  60.0F, 120.0F, 1.0F },
    {  200.0F,  60.0F, 120.0F, 1.0F },{  170.0F, 100.0F, 120.0F, 1.0F },
    {  120.0F,  90.0F, 200.0F, 1.0F },{  120.0F,  60.0F, 200.0F, 1.0F },
    { -100.0F,  90.0F, 200.0F, 1.0F },{ -150.0F, 130.0F, 150.0F, 1.0F },
    { -200.0F, 180.0F,   0.0F, 1.0F },{ -180.0F, 230.0F,-150.0F, 1.0F },
    { -150.0F,   0.0F,-160.0F, 1.0F },{    0.0F,   0.0F,-200.0F, 1.0F },
    {   50.0F,  30.0F,-180.0F, 1.0F },{  150.0F,  60.0F,  60.0F, 1.0F },
    {  200.0F,  60.0F, 120.0F, 1.0F },{    0.0F,   0.0F,   0.0F, 1.0F },
    {    0.0F,   0.0F,   0.0F, 1.0F },{    0.0F,   0.0F,   0.0F, 1.0F } }; 

static struct timeb     t_deb ;
static struct timeb     t_fin ;
static int              j_deb ;
static int              j_fin ;

void debutChrono(void)
  { time_t deb ;
    struct tm *d_deb ;
    deb = time(NULL) ;
    d_deb = gmtime(&deb) ;
    j_deb = d_deb->tm_mday ;
    ftime(&t_deb) ;
  }

long tempsEcoule(void)
  { time_t fin ;
    long temps ;
    struct tm *d_fin ;
    fin = time(NULL) ;
    d_fin = gmtime(&fin) ;
    j_fin = d_fin->tm_mday ;
    ftime(&t_fin) ;
    temps =(long) t_fin.millitm -(long) t_deb.millitm ;
    temps += ((long) t_fin.time -(long) t_deb.time) * 1000L ;
    temps += ((long) j_fin -(long) j_deb) * 86400000L ;
    return(temps) ; 
  }

void clean(void) {
  delete(lps);
}

void init(void) {
}

void scene(void) {
  Position3D pv(0.0,0.0,0.0);
  LookAt lkAt(&lps->t[image],&pv);
  glPushMatrix();
  glScalef(1000.0F,1000.0F,1000.0F);
  glBegin(GL_LINES);
  for ( int i = 0 ; i < nbS ; i++ ) {
    Position3D p1(pts[sgmts[i][0]][0],pts[sgmts[i][0]][1],pts[sgmts[i][0]][2]);
    Position3D p2(pts[sgmts[i][1]][0],pts[sgmts[i][1]][1],pts[sgmts[i][1]][2]);
    lkAt.transforme(&p1);
    lkAt.transforme(&p2);
    p1.c[0] /= -p1.c[2];
    p1.c[1] /= -p1.c[2];
    p2.c[0] /= -p2.c[2];
    p2.c[1] /= -p2.c[2];
    glVertex2dv((double *) &p1);
    glVertex2dv((double *) &p2); }
  glEnd();
  glPopMatrix();
}

/* Fonction executee lors d'un changement       */
/* de la taille de la fenetre OpenGL            */

void reshape(int x,int y) {
  glViewport(0,0,x,y); 
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
//  gluPerspective(90.0,(double) x/y,0.1,500.0);
  glOrtho(-x/2.0,-x/2.0+x,-y/2.0,-y/2.0+y,-10.0,10.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

void idle(void) {
  image =(int) ((tempsEcoule()/2) % nbImages);
  glutPostRedisplay();
}

void display(void) {
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  glPushMatrix() ;
  scene();
  glPopMatrix();
  glFlush();
  glutSwapBuffers();
}

void key(unsigned char key,int x,int y) {
  switch ( key ) {
    case 45   : image -= 10;
                if ( image < 0 )
                  image = 0;
                glutPostRedisplay();
                break;
    case 43   : image += 10;
                if ( image >= nbImages )
                  image = nbImages-1;
                glutPostRedisplay();
                break;
    case 0x20 : { static int anim = 1;
                  anim = !anim;
                  glutIdleFunc((anim) ? idle : NULL); }
                break;
    case 0x0D : image = 0;
                glutPostRedisplay();
                break;
    case 0x1B : exit(0);
                break; }
}

int main(int argc,char **argv) {
  atexit(clean);
  LignePolygonale3D *lp = new LignePolygonale3D(18);
  for ( int i = 0 ; i < nbT ; i++ ) { 
  lp->set( i,&Position3D(ptT[i][0],ptT[i][1],ptT[i][2])); }
  lps = new LignePolygonale3D(nbImages,lp,(MatriceDeBase *) &NRUBS);
  delete(lp);
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE);
  glutInitWindowSize(400,400); 
  glutInitWindowPosition(50,50); 
  glutCreateWindow("Projection pour visualisation");
  init();
  glutIdleFunc(idle);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(key);
  glutDisplayFunc(display);
  debutChrono();
  glutMainLoop();
  return(0);
}
