/****************************************************************************
 * file:      survival-kit-extended.c
 * status:    17-aug-2011, wlm.
 * functie:   OpenGL survival kit with variable windows and a
 *            larger number of examples
 ****************************************************************************/

#ifdef __APPLE__
  #include <GLUT/glut.h>
#else
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glut.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* Default grootte en positie van door OpenGL te maken venster. */
int WINSIZE_X = 600;    /* grootte in X-richting in pixels          */
int WINSIZE_Y = 400;    /* grootte in Y-richting in pixels          */
int WINPOS_X  = 100;    /* standaardpositie van linker              */
int WINPOS_Y  = 100;    /*                      boven  hoek         */

int WINSIZE_X_S = 600;  /* standaardgrootte in X-richting in pixels */
int WINSIZE_Y_S = 400;  /* standaardgrootte in Y-richting in pixels */
int current_size = 0;   /* current window size 0 at start of the program */

/* Default grenzen van gebruikerscoordinaten in door OpenGL te maken venster. */
float XMIN    = -3.0;   /* linksonder  */
float XMAX    =  3.0;   /* rechtsboven */
float YMIN    = -2.0;   /* linksonder  */
float YMAX    =  2.0;   /* rechtsboven */

void progReshape (int  w, int h);
void progInit (void);
void printText (float x, float y, char s[]);
void drawLine (float x1, float y1, float x2, float y2);
void drawPoint (float x1, float y1, float pointsize);
void progDisplay (void);
void progReshape (int  w, int h);
void progKeyboard (unsigned char key, int x, int y);
/* Zie commentaar in main
void berekeningPlot (int argc, char** argv);  */

#define FRAME_TITLE  "Voorbeeld: OpenGL survival kit"

/****************************************************************************
 * Hoofdprogramma.
 ****************************************************************************/
int main (int argc, char** argv)
{
/*  Plaats HIER je eigen code nodig VOORDAT je naar de grafisch mode gaat
 *  Te preferen is een call naar een zelfgemaakte functie: bijvoorbeeld:
 *
 *       berekeningPlot(argc,argv);
 *
 *   met als declaratie:
 *
 *   void berekeningPlot (int argc, char** argv);
 *                                                                           */

  /* Initialisatie van de OpenGL Utility Toolkit (glut). */
  glutInit (&argc, argv);
  /* Initialisatie van vensterparameters. */
  glutInitDisplayMode    (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize     (WINSIZE_X, WINSIZE_Y);
  glutInitWindowPosition (WINPOS_X, WINPOS_Y);
  /* Maak venster. */
  glutCreateWindow (FRAME_TITLE);
  /* Initialisatie van dit programma. */
  progInit ();
  /* Declaratie van functies om "events" af te handelen. */
  glutDisplayFunc  (progDisplay);   /* hier wordt getekend! */
  glutReshapeFunc  (progReshape);   /* na vormverandering van venster */
  glutKeyboardFunc (progKeyboard);  /* na typen van toets op toetsenbord */
  /* Event handling loop. */
  glutMainLoop ();
  return 0;
}
/****************************************************************************
 * Met de onderstaande progDisplay functie kun je je eigen plot
 * creeren.
 ****************************************************************************/
void progDisplay (void)
{
  int i;
  /* Maakt venster schoon, d.w.z. geef het de achtergrondkleur (zwart). */
  glClear (GL_COLOR_BUFFER_BIT);
  glLoadIdentity();

  /* Hieronder vind je aantal eenvoudige voorbeelden met OpenGL
     Voor je eigen programma: VERWIJDER al deze voorbeelden en zet je
     eigen code er voor in de plaats
   */

  /**********  BEGIN VOORBEELDEN  *********/

  /* Paars kader. */
  glColor3f (1.0, 0.0, 1.0);
  drawLine (XMIN+0.1, YMIN+0.1, XMAX-0.1, YMIN+0.1);
  drawLine (XMAX-0.1, YMIN+0.1, XMAX-0.1, YMAX-0.1);
  drawLine (XMAX-0.1, YMAX-0.1, XMIN+0.1, YMAX-0.1);
  drawLine (XMIN+0.1, YMAX-0.1, XMIN+0.1, YMIN+0.1);

  /* Gele tekst bovenaan. */
  glColor3f (1.0, 1.0, 0.0);
  printText (XMIN+0.2, YMAX-0.3,
          "In dit venster worden verschillende grafische objecten getekend.");

  /* Lijnen met verschillende attributen. */

  /* Dubbeldik. */
  glColor3f (0.5, 0.5, 1.0);
  glLineWidth (2.0);
  drawLine (XMIN+0.2, YMAX-0.4, XMAX-0.2, YMAX-0.4);

  /* Vier maal zo dik als normaal. */
  glColor3f (0.4, 0.4, 1.0);
  glLineWidth (4.0);
  drawLine (XMIN+0.2, YMAX-0.5, XMAX-0.2, YMAX-0.5);

  /* Zet stippelen van lijnen aan.
   * Stippelen/strepen wordt gedaan met behulp van een 16-bits patroon,
   * bit=1 om te tekenen, bit=0 om niet te tekenen.
   * Bits worden van achter naar voor geinterpreteerd!
   * Een herhalingsfacter (1e argument) herhaald de bits van het patroon,
   * dus 1010 wordt 11001100 en niet 10101010. */
  glEnable (GL_LINE_STIPPLE);

  /* Stip: 1111 0000 1111 0000 -> 0000 1111 0000 1111 */
  glColor3f (0.3, 0.3, 1.0);
  glLineStipple (1, (GLushort) 0x0F0F);
  drawLine (XMIN+0.2, YMAX-0.6, XMAX-0.2, YMAX-0.6);

  /* Streep: 1111 1111 1111 0000 -> 0000 1111 1111 1111 */
  glColor3f (0.2, 0.2, 1.0);
  glLineStipple (1, (GLushort) 0x0FFF);
  drawLine (XMIN+0.2, YMAX-0.7, XMAX-0.2, YMAX-0.7);

  /* Lange streep, verdubbeld: 1111 1111 1111 1000 -> 0001 1111 1111 1111 */
  glColor3f (0.3, 0.3, 1.0);
  glLineStipple (2, (GLushort) 0x1FFF);
  drawLine (XMIN+0.2, YMAX-0.8, XMAX-0.2, YMAX-0.8);

  /* Stip-streep: 1110 0011 1111 1000 -> 0001 1111 1100 0111 */
  glColor3f (0.4, 0.4, 1.0);
  glLineStipple (1, (GLushort) 0x1FC7);
  drawLine (XMIN+0.2, YMAX-0.9, XMAX-0.2, YMAX-0.9);

  /* Tekent een aantal punten op een rij, met grootte 10 */
  glColor3f (0.4, 1.0, 0.4);
  for ( i = 0; i< 11; i++)
    drawPoint (XMIN+0.5*(i+1), YMAX-1.0,10.);

  /* Zet stippelen van lijnen uit. */
  glDisable (GL_LINE_STIPPLE);

  /* Vijf maal zo dik als normaal. */
  glLineWidth (5.0);
  glColor3f (0.5, 1.0, 1.0);
  glBegin (GL_LINE_STRIP);
    glVertex2f (XMIN+0.5, YMIN+1.3);
    glVertex2f (XMIN+1.2, YMIN+1.3);
    glVertex2f (XMIN+0.5, YMAX-1.2);
    glVertex2f (XMIN+1.2, YMAX-1.2);
    glVertex2f (XMIN+0.5, YMIN+1.3);
  glEnd ();

  /* Zet lijndikte terug op "normaal". */
  glLineWidth (1.0);

  /* Lichtgroene theepot rond oorsprong (uit glut-bibliotheek). */
  glColor3f (0.4, 1.0, 0.4);
  glutWireTeapot (1.0);

  /* Vijf maal zo dik als normaal. */
  glColor3f (1.0, 0.5, 1.0);
  glLineWidth (5.0);
  glEnable (GL_LINE_STIPPLE);
  glLineStipple (1, (GLushort) 0x0F0F);
  glBegin (GL_LINE_LOOP);
    glVertex2f (XMAX-0.5, YMIN+1.3);
    glVertex2f (XMAX-1.2, YMIN+1.3);
    glVertex2f (XMAX-0.85, YMAX-1.2);
  glEnd ();
  glDisable (GL_LINE_STIPPLE);
  glLineWidth (1.0);

  /* Oranje rechthoek met rode rechthoek erin. */
  glColor3f (1.0, 0.5, 0.0);
  glRectf (XMIN+0.2, YMIN+0.4, XMAX-0.2, YMIN+1.1);
  glColor3f (1.0, 0.0, 0.0);
  glRectf (XMIN+0.6, YMIN+0.6, XMAX-0.6, YMIN+0.9);

  /* Turquoise tekst onderaan. */
  glColor3f (0.0, 0.9, 0.9);
  printText (XMIN+0.2, YMIN+0.2,
             "Type 'e' of 'q' om te stoppen; ESC om window size te veranderen.");

  /**********  EINDE VOORBEELDEN  *********/

  /* Zorgt dat alles getekend wordt. */
  glutSwapBuffers();
}

/****************************************************************************
 * Afhandelen van toetsinterrupt:
 *   programma stopt als e of q in venster ingetikt is.
 *   Bij ESC wordt window gereshaped
 ****************************************************************************/
void progKeyboard (unsigned char key, int x, int y)
{
  switch (key)
  { case 'e': exit (0);
              break;
    case 'q': exit (0);
              break;
    case 27:
              if (current_size == 1 ) {
                WINSIZE_X = WINSIZE_X_S;
                WINSIZE_Y = WINSIZE_Y_S;
                current_size = 0;
              }
              else {
                WINSIZE_X = (int) ((float) WINSIZE_X * 1.5);
                WINSIZE_Y = (int) ((float)WINSIZE_Y * 0.75);
                current_size = 1;
              }
              progReshape (WINSIZE_X, WINSIZE_Y);
              glutPostRedisplay();
              break;
  }
}

/****************************************************************************
 * Initialisatie voor het programma.
 ****************************************************************************/
void progInit (void)
{
  /* Zet achtergrondkleur van door OpenGL te maken venster (zwart). */
  glClearColor (0.0, 0.0, 0.0, 0.0);

  /* Geef instructies voor gebruiker in commandovenster. */
  printf
    ("\n  %s\n  Type 'e' of 'q' in OpenGL venster om te stoppen; ESC om de grootte van het venster te veranderen.\n",
     FRAME_TITLE);
}

/****************************************************************************
 * Druk tekst in "s" af beginnend op positie (x,y).
 ****************************************************************************/
void printText (float x, float y, char s[])
{
  int i, length;
  char c;

  /* Ga naar gewenste beginpositie. */
  glRasterPos2f (x, y);
  length = strlen (s);
  for (i=0; i<length; i++)
  { c = s[i];
    glutBitmapCharacter (GLUT_BITMAP_8_BY_13, c);
  }
}

/****************************************************************************
 * Teken lijn van (x1,y1) naar (x2,y2) in gebruikerscoordinaten.
 ****************************************************************************/
void drawLine (float x1, float y1, float x2, float y2)
{
  glBegin (GL_LINES);
    glVertex2f (x1, y1);
    glVertex2f (x2, y2);
  glEnd ();
}

/****************************************************************************
* Teken een punt op (x1,y1) in gebruikerscoordinaten.
****************************************************************************/
void drawPoint (float x1, float y1, float pointsize)
{
       glEnable(GL_POINT_SMOOTH);
       glPointSize(pointsize);
       glBegin (GL_POINTS);
          glVertex2f (x1, y1);
       glEnd ();
}

/****************************************************************************
 * Afhandelen van verandering van venstergrootte:
 *   w en h zijn de nieuwe breedte en hoogte van het venster in
 *   venstercoordinaten, het oude venster wordt geheel in het nieuwe
 *   afgebeeld, waardoor de X/Y-verhoudingen niet bewaard hoeven te blijven.
 *
 *   Je kunt met behulp van XMIN, XMAX, YMIN en YMAX (Globale parameters)
 *   de gebruikers assen aanpassen
 ****************************************************************************/
void progReshape (int  w, int h)
{
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glutReshapeWindow(w, h);
  glViewport (0, 0, w, h);
  gluOrtho2D (XMIN, XMAX, YMIN, YMAX);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}
