#include <cmath>
#include <cstdlib>
#include <GL/glut.h>
#include "gettime.h"

#include "CImageGL.h"

const float MOVEMENTSIZE   = 10.0f;
const float RADIUS         = 3.0f;
const float BOXSIZE        = MOVEMENTSIZE+RADIUS;
const int   WINDOW_WIDTH   = 500;
const int   WINDOW_HEIGHT  = 500;
const float MINSPEED       = 1.0f;
const float MAXSPEED       = 1.5f;
const float CENTERDISTANCE = 4*BOXSIZE;

CImageGL image;


void init(void)
{
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glEnable(GL_DEPTH_TEST);
  image.SetPattern("images/patron01.bmp");
}

void idle(void)
{
  glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y)
{
  switch (key)
    {
    case 'Q':
    case 'q':
      exit(0);
      break;
    default:
      break;
    }
}

void murs(void)
{
  glColor3f(1.0f, 1.0f, 1.0f);

  glBegin(GL_QUADS);
  glVertex3f(-BOXSIZE , -BOXSIZE , -BOXSIZE);
  glVertex3f(-BOXSIZE ,  BOXSIZE , -BOXSIZE);
  glVertex3f(-BOXSIZE ,  BOXSIZE ,  BOXSIZE);
  glVertex3f(-BOXSIZE , -BOXSIZE ,  BOXSIZE);
  glEnd();

  glBegin(GL_QUADS);
  glVertex3f(-BOXSIZE , -BOXSIZE , -BOXSIZE);
  glVertex3f(-BOXSIZE , -BOXSIZE ,  BOXSIZE);
  glVertex3f( BOXSIZE , -BOXSIZE ,  BOXSIZE);
  glVertex3f( BOXSIZE , -BOXSIZE , -BOXSIZE);
  glEnd();

  glBegin(GL_QUADS);
  glVertex3f(-BOXSIZE ,  BOXSIZE , -BOXSIZE);
  glVertex3f( BOXSIZE ,  BOXSIZE , -BOXSIZE);
  glVertex3f( BOXSIZE ,  BOXSIZE ,  BOXSIZE);
  glVertex3f(-BOXSIZE ,  BOXSIZE ,  BOXSIZE);
  glEnd();

  glBegin(GL_QUADS);
  glVertex3f(-BOXSIZE , -BOXSIZE , -BOXSIZE);
  glVertex3f( BOXSIZE , -BOXSIZE , -BOXSIZE);
  glVertex3f( BOXSIZE ,  BOXSIZE , -BOXSIZE);
  glVertex3f(-BOXSIZE ,  BOXSIZE , -BOXSIZE);
  glEnd();

  glBegin(GL_QUADS);
  glVertex3f(-BOXSIZE , -BOXSIZE ,  BOXSIZE);
  glVertex3f(-BOXSIZE ,  BOXSIZE ,  BOXSIZE);
  glVertex3f( BOXSIZE ,  BOXSIZE ,  BOXSIZE);
  glVertex3f( BOXSIZE , -BOXSIZE ,  BOXSIZE);
  glEnd();
}

void display(void)
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  static float
    x  = 0,
    y  = 0,
    z  = 0,
    vx = 0.5*(MINSPEED + MAXSPEED),
    vy = 0.5*(MINSPEED + MAXSPEED),
    vz = 0.5*(MINSPEED + MAXSPEED);

  static int temps1 = GetTime();
  int temps2 = GetTime();
  float inc = (temps2 - temps1) / 1000000.0f;
  temps1 = temps2;

  if (x + vx*inc < -MOVEMENTSIZE)
    vx =  ((rand() / (float) RAND_MAX) * (MAXSPEED-MINSPEED) + MINSPEED);
  else if (x + vx*inc >  MOVEMENTSIZE)
    vx = -((rand() / (float) RAND_MAX) * (MAXSPEED-MINSPEED) + MINSPEED);
  if (y + vy*inc < -MOVEMENTSIZE)
    vy =  ((rand() / (float) RAND_MAX) * (MAXSPEED-MINSPEED) + MINSPEED);
  else if (y + vy*inc >  MOVEMENTSIZE)
    vy = -((rand() / (float) RAND_MAX) * (MAXSPEED-MINSPEED) + MINSPEED);
  if (z + vz*inc < -MOVEMENTSIZE)
    vz =  ((rand() / (float) RAND_MAX) * (MAXSPEED-MINSPEED) + MINSPEED);
  else if (z + vz*inc >  MOVEMENTSIZE)
    vz = -((rand() / (float) RAND_MAX) * (MAXSPEED-MINSPEED) + MINSPEED);

  x += vx*inc;
  y += vy*inc;
  z += vz*inc;

  glLoadIdentity();
  gluLookAt( CENTERDISTANCE, 0, 0, // eye
             0, 0, 0,       // center
             0, 0, 1);      // up

  murs();

  glPushMatrix();
  glTranslatef(x, y, z);
  glColor3f(0,0,1);
  glutSolidSphere(RADIUS, 40, 40);
  glPopMatrix();

  image.GenerateStereogram();

  glutSwapBuffers();
}

void reshape(int w, int h)
{
  glViewport(0, 0, (GLsizei) w, (GLsizei) h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(50.0, (GLfloat) w / (GLfloat) h,
                 0.9*(CENTERDISTANCE-BOXSIZE),
                 1.1*(CENTERDISTANCE+BOXSIZE+0.1));
  glMatrixMode(GL_MODELVIEW);

  image.SetDimension(w, h);
}

int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
  glutCreateWindow("Stereo");
  glutFullScreen();
  glutSetCursor(GLUT_CURSOR_NONE);

  init();
  glutKeyboardFunc(&keyboard);
  glutDisplayFunc(&display);
  glutReshapeFunc(&reshape);
  glutIdleFunc(&idle);
  glutMainLoop();

  return 0;
}
