/****************************************************************************
 * file:      vb-02-interaction.c
 * status:    17-apr-2001, pfk.
 *            07-sep-2010, pfk:  English version.
 * function:  Sample program with mouse interaction.
 * description:
 *            Click with mouse in output window, a colored line will be drawn 
 *            form the origin (lower left corner) to the position indicated.
 *            If the size of the output window is changed, the user
 *            coordinates are adapted to maintain the original size and
 *            orientation of objects. 
 *
 * NB: Watch the difference between the use of user and window coordinates!
 ****************************************************************************/

#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define WINSIZE_X    300   /* size in X in pixels */
#define WINSIZE_Y    300   /* size in Y in pixels */
#define WINPOS_X     100   // position top
#define WINPOS_Y     100   //              left corner

// Boundaries of user coordinates in OpenGL output window.
#define XMIN       -11.0
#define XMAX        11.0
#define YMIN       -11.0
#define YMAX        11.0

// Window title.
#define FRAME_TITLE  "Sample program:  Mouse interaction"

// Global variables.
GLsizei frameWidth, frameHeight;

/****************************************************************************
 * Initialise.
 ****************************************************************************/
void progInit (void) 
{
  /* Zet achtergrond (zwart). */
  glClearColor (0.0, 0.0, 0.0, 0.0);

  frameWidth  = WINSIZE_X;
  frameHeight = WINSIZE_Y;
}


/****************************************************************************
 * Print text variable "s", starting at position (x,y).
 ****************************************************************************/
void printText (float x, float y, char s[])
{
  int  i,       // loop variabele
       length;  // number of characters, length of "s"
  char c;       // single character

  glRasterPos2f (x, y);

  length = strlen (s);
  for (i=0; i<length; i++)
  { c = s[i];
    glutBitmapCharacter (GLUT_BITMAP_8_BY_13, c);
  }
}


/****************************************************************************
 * Draw line from (x1,y1) to (x2,y2).
 * Coordinate values are in user coordinates.
 ****************************************************************************/
void drawLine (float x1, float y1, float x2, float y2)
{
  glBegin (GL_LINES);
    glVertex2f (x1, y1);
    glVertex2f (x2, y2);
  glEnd ();
}


/****************************************************************************
 * Draw square along the edge of the original output window.
 * Function uses user coordinates.
 ****************************************************************************/
void progDisplay (void)
{
  glClear (GL_COLOR_BUFFER_BIT);
  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);

  glColor3f (1.0, 1.0, 1.0);
  printText (XMIN+0.5, YMAX-1.0,
             "Click with mouse in the window.");
  printText (XMIN+0.5, YMAX-2.0,
             "Type 'e', 'q', 's' or ESC in");
  printText (XMIN+0.5, YMAX-3.0,
             "this window to terminate.");

  glFlush ();
}


/****************************************************************************
 * Handle change in size of output window:
 *   "w" and "h" are the new width and height of the output window in window 
 *   coordinates,
 *   "shift_x" and "shift_y" are the shifts in X and Y in user coordinates.
 ****************************************************************************/
void progReshape (GLsizei w, GLsizei h)
{
  float shift_x, shift_y;

  frameWidth  = w;
  frameHeight = h;

  shift_x = ( (float)(w-WINSIZE_X) / (float)WINSIZE_X ) * (XMAX-XMIN);
  shift_y = ( (float)(h-WINSIZE_Y) / (float)WINSIZE_Y ) * (YMAX-YMIN);

  glViewport (0, 0, w, h);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  gluOrtho2D (XMIN, XMAX + shift_x, YMIN, YMAX + shift_y);

  glFlush ();
}


/****************************************************************************
 * Handle keyboard interrupt:
 * terminate program if "e", "q", "s" or ESC is entered in the output window.
 ****************************************************************************/
void progKeyboard (unsigned char key, int x, int y)
{
  switch (key)   // only the following keys are allowed
  { case 'e': 
    case 'q': 
    case 's': 
    case  27: exit (0);  // escape key ESC
              break;
  }
}


/****************************************************************************
 * Handle mouse interrupt and draw line: 
 *   "button" indicates which button is pushed or released,
 *   "state" returns status of the button,
 *   "x" and "y" are in window coordinates 
 *     (pixel positions with origin top left!),
 *   "xx" and "yy" are in user coordinates.
 ****************************************************************************/
void progMouse (int button, int state, int x, int y)
{
  float xx, yy;

  if ( (button == GLUT_LEFT_BUTTON) && (state == GLUT_UP) )
  { 
    xx = (float)x / (float)frameWidth *
         (XMAX - XMIN)*((float)frameWidth / (float)WINSIZE_X) + XMIN;
    yy = (float)(frameHeight - y) / (float)frameHeight *
         (YMAX - YMIN)*((float)frameHeight / (float)WINSIZE_Y) + YMIN;

    /* Set random line color. */
    glColor3f (((float)rand()/(float)RAND_MAX),   /* red component   */
               ((float)rand()/(float)RAND_MAX),   /* green component */
               ((float)rand()/(float)RAND_MAX));  /* blue component  */

    /* Set random line width between 1 and 4. */
    glLineWidth (((float)rand()/(float)RAND_MAX+1.0)*4.0);

    /* Draw line. */
    drawLine (XMIN, YMIN, xx, yy);

    /* Back to default values for color and line width. */
    glColor3f (1.0, 1.0, 1.0);
    glLineWidth (1.0);

    glFlush ();
  }
}


/****************************************************************************
 * Main program function.
 ****************************************************************************/
int main (int argc, char** argv)
{
  /* Initialise OpenGL Utility Toolkit. */
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
  glutInitWindowSize (WINSIZE_X, WINSIZE_Y); 
  glutInitWindowPosition (WINPOS_X, WINPOS_Y);
  glutCreateWindow (FRAME_TITLE);

  /* Event handling functions. */
  glutDisplayFunc (progDisplay); 
  glutReshapeFunc (progReshape);
  glutKeyboardFunc (progKeyboard);
  glutMouseFunc (progMouse);

  progInit ();

  /* Event handling loop. */
  glutMainLoop ();

  return 0;
}
