/* pilot.c                                          */
/* plane at x, X, y, Y, z, Z */

/* We use the pilot view function in the display callback to point
   the eye, whose position can be altered by the
   x,X,y,Y,z and Z keys for eye position
   r,R,p,P,h and H keys for rool, pitch and heading
   The perspective view is set in the reshape callback */
   
#include <stdlib.h>
#include <GL/glut.h>

static GLfloat nearv=2.0;
static GLfloat farv=100.0;
static GLfloat roll=0.0;
static GLfloat pitch=0.0;
static GLfloat heading=0.0;

/* initial eye location */
static GLdouble eye[]= {0.0, 5.0, 10.0}; 

void pilotView()
{
  glRotatef(roll, 0.0, 0.0, 1.0);
  glRotatef(pitch, 1.0, 0.0, 0.0);
  glRotatef(heading, 0.0, 1.0, 0.0);
  glTranslatef(-eye[0], -eye[1], -eye[2]);
}

void display(void)
{
  char text[]="move plane using x, X, y, Y, z, Z";
  char text2[]="roll, pitch, heading  r, R, p, P, h, H";
  char *p;
  
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  /* Update eye position in modelview matrix */
  glLoadIdentity();
  /* from eye to center of scene */
  /* gluLookAt(eye[0],eye[1],eye[2],*/ /* a hack, not good */
            /* heading, pitch, -5.0, roll, 1.0, 0.0); */
  pilotView();
  /* draw runway */
  glBegin(GL_POLYGON);
  glColor3f(0.5, 0.5, 0.5); /* gray */
    glVertex3f(-1.0, 0.0, -5.0);
    glVertex3f(-1.0, 0.0,  5.0);
    glVertex3f( 1.0, 0.0,  5.0);
    glVertex3f( 1.0, 0.0, -5.0);
  glEnd();
  glBegin(GL_POLYGON); /* center line */
  glColor3f(1.0, 1.0, 1.0); /* white */
    glVertex3f(-0.05, 0.01, -5.0);
    glVertex3f(-0.05, 0.01,  5.0);
    glVertex3f( 0.05, 0.01,  5.0);
    glVertex3f( 0.05, 0.01, -5.0);
  glEnd();
  glBegin(GL_POLYGON); /* grass */
  glColor3f(0.0, 0.5, 0.0); /* green */
    glVertex3f(-10.0, -0.1, -50.0);
    glVertex3f(-10.0, -0.1,  50.0);
    glVertex3f( 10.0, -0.1,  50.0);
    glVertex3f( 10.0, -0.1, -50.0);
  glEnd();
  glBegin(GL_POLYGON); /* grass */
  glColor3f(0.0, 0.0, 1.0); /* blue background */
    glVertex3f(-200.0, -200.0,  -50.0);
    glVertex3f(-200.0,  200.0,  -50.0);
    glVertex3f( 200.0,  200.0,  -50.0);
    glVertex3f( 200.0, -200.0,  -50.0);
  glEnd();
  
  glPushMatrix();
  glLoadIdentity(); /* need view matrix after this */
  pilotView();
  glColor3f(1.0, 1.0, 1.0);
  glTranslatef(-7.0, 6.0, 0.0);
  glScalef(0.005, 0.005, 1.0);
  for(p=text; *p; p++)
    glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
  glPopMatrix();
  
  glPushMatrix(); /* just hide this codes matrix changes */
  glColor3f(1.0, 1.0, 1.0);
  glTranslatef(-7.0, 5.0, 0.0);
  glScalef(0.005, 0.005, 1.0);
  for(p=text2; *p; p++)
    glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
  glPopMatrix();

  glFlush();
  glutSwapBuffers();
}

void keys(unsigned char key, int x, int y)
{
  /* Use x, X, y, Y, z, and Z keys to move eye */
  if(key == 'x') eye[0] -= 1.0;
  if(key == 'X') eye[0] += 1.0;
  if(key == 'y') eye[1] -= 0.5; /* could clamp at zero */
  if(key == 'Y') eye[1] += 0.5;
  if(key == 'z') eye[2] -= 1.0;
  if(key == 'Z') eye[2] += 1.0;
  /* Use r, R, p, P, h, and H keys to move roll, pitch, heading */
  if(key == 'r') roll    -= 2.0;
  if(key == 'R') roll    += 2.0;
  if(key == 'p') pitch   -= 2.0;
  if(key == 'P') pitch   += 2.0;
  if(key == 'h') heading -= 2.0;
  if(key == 'H') heading += 2.0;
  display();
}

void myReshape(int w, int h)
{
  glViewport(0, 0, w, h);
  /* Use a perspective view */
  glMatrixMode(GL_PROJECTION); 
  glLoadIdentity();
  if(w<=h)
    glFrustum(-2.0, 2.0, -2.0 * (GLfloat) h/ (GLfloat) w,
              2.0* (GLfloat) h / (GLfloat) w, nearv, farv);
  else
    glFrustum(-2.0, 2.0, -2.0 * (GLfloat) w/ (GLfloat) h, 
              2.0* (GLfloat) w / (GLfloat) h, nearv, farv);
  /* Or we can use gluPerspective */
  /* gluPerspective(45.0, w/h, -10.0, 10.0); */
  glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char *argv[])
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(500, 500);
  glutCreateWindow(argv[0]);
  glutReshapeFunc(myReshape);
  glutDisplayFunc(display);
  glutKeyboardFunc(keys);
  glEnable(GL_DEPTH_TEST);
  glutMainLoop();
  return 0;
}

