/* L15.c
           OpenGL Framework using GLUT 3.7 

           Rob Fletcher  2001

           Draw a Solid cube and make the faces observe
           their 3D depth (the "d/D" keys toggle the
           OpenGL depth testing state variable).

           Code to stop updates when icon or obscured.

           We now also include a timer function to give us
           a required frame rate.

           We also show how to use the "value" argument to
           the timer function callback to control the
           drawing (or not) which in turn is dependent on
           the visibility of the graphics.

           Felix Genicio 2009
           
           Added some code to the original in orde to allow
           launch the app in full screen mode and to correct
           a but with yangle rotation.

*/

#include <stdio.h>
#include <stdlib.h>     /* For "exit" prototype */
#include <GL/glut.h>    /* Header File For The GLUT Library */


/* ASCII code for the escape key. */
#define ESCAPE 27

GLint window;           /* The number of our GLUT window */
GLint Xsize=400;
GLint Ysize=400;


GLfloat xangle=0.0,yangle=0.0,zangle=0.0;   /* axis angles */
GLfloat xinc=0.0,yinc=0.0,zinc=0.0;         /* Axis increments */

/* Simple window transformation routine */
GLvoid Transform(GLfloat Width, GLfloat Height)
{
  glViewport(0, 0, Width, Height);              /* Set the viewport */
  glMatrixMode(GL_PROJECTION);                  /* Select the projection matrix */
  glLoadIdentity();				/* Reset The Projection Matrix */
  gluPerspective(45.0,Width/Height,0.1,100.0);  /* Calculate The Aspect Ratio Of The Window */
  glMatrixMode(GL_MODELVIEW);                   /* Switch back to the modelview matrix */
}


/* A general OpenGL initialization function.  Sets all of the initial parameters. */
GLvoid InitGL(GLfloat Width, GLfloat Height)	
{
  glClearColor(0.0, 0.0, 0.0, 0.0);		/* This Will Clear The Background Color To Black */
  Transform( Width, Height );                   /* Perform the transformation */
}

/* The function called when our window is resized  */
GLvoid ReSizeGLScene(GLint Width, GLint Height)
{
  if (Height==0)    Height=1;                   /* Sanity checks */
  if (Width==0)      Width=1;
  Transform( Width, Height );                   /* Perform the transformation */
}


/* The main drawing function

   In here we put all the OpenGL and calls to routines which manipulate
   the OpenGL state and environment.

   This is the function which will be called when a "redisplay" is requested.
*/

GLvoid DrawGLScene()
{

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	/* Clear The Screen And The Depth Buffer */

  glPushMatrix();
  glLoadIdentity();
  glTranslatef(0.0,0.0,-6.0);
  glRotatef(xangle,1.0,0.0,0.0);
  glRotatef(yangle,0.0,1.0,0.0);
  glRotatef(zangle,0.0,0.0,1.0);

  glBegin(GL_QUADS);                /* start drawing the cube.*/
  
  /* top of cube*/
  glColor3f(0.0,1.0,0.0);            /* Set The Color To Blue*/
  glVertex3f( 1.0, 1.0,-1.0);        /* Top Right Of The Quad (Top)*/
  glVertex3f(-1.0, 1.0,-1.0);        /* Top Left Of The Quad (Top)*/
  glVertex3f(-1.0, 1.0, 1.0);        /* Bottom Left Of The Quad (Top)*/
  glVertex3f( 1.0, 1.0, 1.0);        /* Bottom Right Of The Quad (Top)*/

  /* bottom of cube*/
  glColor3f(1.0,0.5,0.0);            /* Set The Color To Orange*/
  glVertex3f( 1.0,-1.0, 1.0);        /* Top Right Of The Quad (Bottom)*/
  glVertex3f(-1.0,-1.0, 1.0);        /* Top Left Of The Quad (Bottom)*/
  glVertex3f(-1.0,-1.0,-1.0);        /* Bottom Left Of The Quad (Bottom)*/
  glVertex3f( 1.0,-1.0,-1.0);        /* Bottom Right Of The Quad (Bottom)*/

  /* front of cube*/
  glColor3f(1.0,0.0,0.0);            /* Set The Color To Red*/
  glVertex3f( 1.0, 1.0, 1.0);        /* Top Right Of The Quad (Front)*/
  glVertex3f(-1.0, 1.0, 1.0);        /* Top Left Of The Quad (Front)*/
  glVertex3f(-1.0,-1.0, 1.0);        /* Bottom Left Of The Quad (Front)*/
  glVertex3f( 1.0,-1.0, 1.0);        /* Bottom Right Of The Quad (Front)*/

  /* back of cube.*/
  glColor3f(1.0,1.0,0.0);            /* Set The Color To Yellow*/
  glVertex3f( 1.0,-1.0,-1.0);        /* Top Right Of The Quad (Back)*/
  glVertex3f(-1.0,-1.0,-1.0);        /* Top Left Of The Quad (Back)*/
  glVertex3f(-1.0, 1.0,-1.0);        /* Bottom Left Of The Quad (Back)*/
  glVertex3f( 1.0, 1.0,-1.0);        /* Bottom Right Of The Quad (Back)*/

  /* left of cube*/
  glColor3f(0.0,0.0,1.0);            /* Blue*/
  glVertex3f(-1.0, 1.0, 1.0);        /* Top Right Of The Quad (Left)*/
  glVertex3f(-1.0, 1.0,-1.0);        /* Top Left Of The Quad (Left)*/
  glVertex3f(-1.0,-1.0,-1.0);        /* Bottom Left Of The Quad (Left)*/
  glVertex3f(-1.0,-1.0, 1.0);        /* Bottom Right Of The Quad (Left)*/

  /* Right of cube */
  glColor3f(1.0,0.0,1.0);            /* Set The Color To Violet*/
  glVertex3f( 1.0, 1.0,-1.0);        /* Top Right Of The Quad (Right)*/
  glVertex3f( 1.0, 1.0, 1.0);        /* Top Left Of The Quad (Right)*/
  glVertex3f( 1.0,-1.0, 1.0);        /* Bottom Left Of The Quad (Right)*/
  glVertex3f( 1.0,-1.0,-1.0);        /* Bottom Right Of The Quad (Right)*/
  glEnd();                              /* Done Drawing The Cube*/

  glPopMatrix();

  glFlush();
  glutSwapBuffers();                    /* Swap the buffers ! */
 
  xangle = xangle + xinc;                /* Add any x increment */
  if( xangle > 360.0 || xangle < 0.0 )   /* fix up silly angles! */
      xangle = 0.0;

  yangle = yangle + yinc;                /* Add any y increment */
  if( yangle > 360.0 || yangle < 0.0 )   /* fix up silly angles! */
      yangle = 0.0;

  zangle = zangle + zinc;                /* Add any z increment */
  if( zangle > 360.0 || zangle < 0.0 )   /* fix up silly angles! */
      zangle = 0.0;


}


/*  The function called whenever a "normal" key is pressed. */
void NormalKey(GLubyte key, GLint x, GLint y) 
{
    switch ( key )    { 
     case ESCAPE :
        printf("escape pressed. exit.\n");
	glutDestroyWindow(window);	/* Kill our window */
	exit(0); 			/* Very dirty exit */                  
        break;				/* Do we need this??? */

     case 'x':
        xinc += 0.2;
        break;
     case 'X':
        xinc -= 0.2;
        break;

     case 'y':
        yinc += 0.2;
        break;

     case 'Y':
        yinc -= 0.2;
        break;

     case 'z':
        zinc += 0.2;
        break;

     case 'Z':
        zinc -= 0.2;
        break;

     case 'd':
        glEnable(GL_DEPTH_TEST);
        break;

     case 'D':
        glDisable(GL_DEPTH_TEST);
        break;

     default:
	break;
    }

}

GLvoid Timer( int value )
{
   if( value ) glutPostRedisplay();
   glutTimerFunc(10,Timer,value);
}

GLvoid Viz(int state)
{
 switch (state)
 {
   case GLUT_VISIBLE:
             Timer(1);
             break;
   case GLUT_NOT_VISIBLE:
             Timer(0);
             break;
   default:
             break;
 }
}

/*************************** Main ***************************************************************/


int main(int argc, char **argv) 
{  

/* Initialisation and window creation */

  glutInit(&argc, argv);               /* Initialize GLUT state. */

  glutInitDisplayMode(GLUT_RGBA |      /* RGB and Alpha */
                      GLUT_DOUBLE |     /* Single buffer */
                      GLUT_DEPTH);     /* Z buffer (depth) */

  if (argc == 2){
    if (strcmp(argv[1],"-f") == 0){
      char parameters[20];
      sprintf(parameters,"%dx%d",glutGet(GLUT_SCREEN_WIDTH),glutGet(GLUT_SCREEN_HEIGHT));
      glutGameModeString(parameters);
      glutEnterGameMode();
    }else{
      printf("Unknown command option.\n");
    }
  }else{
    glutInitWindowSize(Xsize,Ysize);         /* set initial window size. */
    glutInitWindowPosition(0,0);         /* upper left corner of the screen. */
  
    window = glutCreateWindow("L15");     /* Open a window with a title. */ 
    InitGL(Xsize,Ysize);                     /* Initialize our window. */
  }

/* Now register the various callback functions */

  glutDisplayFunc(DrawGLScene);        /* Function to do all our OpenGL drawing. */
  glutReshapeFunc(ReSizeGLScene);
  glutKeyboardFunc(NormalKey);         /*Normal key is pressed */
  glutTimerFunc(10,Timer,1);
  glutVisibilityFunc(Viz);

/* Now drop into the event loop from which we never return */

  glutMainLoop();                      /* Start Event Processing Engine. */  
  return 1;
}

