/* objects.c display many glu and glut objects */
/* eye movement in  x, X, y, Y, z, Z */

/* We use the keyboard 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;
GLUquadricObj *obj;

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

static void eyeView()
{
  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]);
}

static void display(void)
{
  char text[]="move eye using x, X, y, Y, z, Z";
  char text2[]="roll, pitch, heading  r, R, p, P, h, H";
  char text3[]="objects.c showing wireframe versions";
  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); */
  glPushMatrix();
  eyeView();
  glTranslatef(5.0, 0.0, 0.0);
  glutWireCone(1.0, 1.0, 10, 10);
  /* glutSolidCone(1.0, 1.0, 10, 10); */
  glTranslatef(-3.5, 0.0, 0.0);
  glutWireCube(1.0);
  /* glutSolidCube(1.0); */
  glTranslatef(-3.5, 0.0, 0.0);
  glutWireDodecahedron();
  /* glutSolidDodecahedron(); */
  glTranslatef(-3.5, 0.0, 0.0);
  glutWireIcosahedron();
  /* glutSolidIcosahedron(); */
  glTranslatef(0.0, 3.5, 0.0);
  glutWireOctahedron();
  /* glutSolidOctahedron(); */
  glTranslatef(3.5, 0.0, 0.0);
  glutWireSphere(1.0, 10, 10);
  /* glutSolidSphere(1.0, 10, 10); */
  glTranslatef(3.5, 0.0, 0.0);
  glutWireTeapot(1.0);
  /* glutSolidTeapot(1.0); */
  glTranslatef(3.5, 0.0, 0.0);
  glutWireTetrahedron();
  /* glutSolidTetrahedron(); */
  glTranslatef(0.0, 3.5, 0.0);
  glutWireTorus(0.5, 1.0, 10, 10);
  /* glutSolidTorus(0.5, 1.0, 10, 10); */

  glTranslatef(-3.5, 0.0, 0.0);
  gluSphere(obj, 1.0, 12, 12);
  glTranslatef(-3.5, 0.0, 0.0);
  gluCylinder(obj, 1.0, 0.5, 1.0, 12, 12);
  glTranslatef(-3.5, 0.0, 0.0);
  gluDisk(obj, 0.5, 1.0, 10, 10);
  glTranslatef(3.5, 3.5, 0.0);
  gluPartialDisk( obj, 0.5, 1.0, 10, 10, 0.0, 45.0);

  glPopMatrix();
  
  glPushMatrix();
  glLoadIdentity();
  glColor3f(1.0, 1.0, 1.0);
  glTranslatef(-1.5, 1.85, -nearv);
  glScalef(0.001, 0.001, 1.0);
  for(p=text; *p; p++)
    glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
  glPopMatrix();
  
  glPushMatrix();
  glColor3f(1.0, 1.0, 1.0);
  glTranslatef(-1.5, 1.7, -nearv);
  glScalef(0.001, 0.001, 1.0);
  for(p=text2; *p; p++)
    glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
  glPopMatrix();
  
  glPushMatrix();
  glColor3f(1.0, 1.0, 1.0);
  glTranslatef(-1.7, -1.9, -nearv);
  glScalef(0.0015, 0.0015, 1.0);
  for(p=text3; *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);
  obj = gluNewQuadric();
  gluQuadricDrawStyle(obj, GLU_LINE);
  glutMainLoop();
  return 0;
}

