/*
  gcc -Wall -lglut -lGLU -lGL -lXm -lXi -lX11 unproject0.c -o unproject0
*/

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

void Display();
void Reshape(int w,int h);
void Mouse(int button,int state,int x,int y);

int main(int argc,char **argv) {
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
  glutInitWindowSize(500,500);
  glutInitWindowPosition(100,100);
  glutCreateWindow(argv[0]);
  glutDisplayFunc(Display);
  glutReshapeFunc(Reshape);
  glutMouseFunc(Mouse);

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_DEPTH_TEST);

  glutMainLoop();
  return 0;
}

GLdouble ox=0.0,oy=0.0,oz=0.0;
void Display() {
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();
  gluLookAt(10.0,0.0,20.0,0.0,0.0,0.0,0.0,1.0,0.0);

  glPushMatrix();
  glRotatef(45,1.0,0.0,0.0);
  glutSolidTorus(4.0,5.0,20,20);
  glPopMatrix();

  glPushMatrix();
  glDepthMask(GL_FALSE);
  glTranslated(ox,oy,oz);
  glutSolidSphere(0.5,15,15);
  glDepthMask(GL_TRUE);
  glPopMatrix();

  glFlush();
}

void Reshape(int w,int h) {
  glViewport(0,0,w,h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0,(float)w/(float)h,5.0,30.0);
  glMatrixMode(GL_MODELVIEW);
}

void Unproject(int x, int y,
			   GLdouble *x3d_ret, GLdouble *y3d_ret, GLdouble *z3d_ret)
{
  GLint viewport[4];
  GLdouble modelview[16],projection[16];
  GLfloat wx = x, wy, wz;
  glGetIntegerv(GL_VIEWPORT,viewport);
  wy = y = viewport[3]-y;
  glGetDoublev(GL_MODELVIEW_MATRIX,modelview);
  glGetDoublev(GL_PROJECTION_MATRIX,projection);
  glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&wz);
  /* wx, wy, and wz are ready now */
  gluUnProject(wx,wy,wz,modelview,projection,viewport,
			   x3d_ret, y3d_ret, z3d_ret);
  printf("coörds: %f, %f, %f\n", *x3d_ret, *y3d_ret, *z3d_ret);
}

void Mouse(int button,int state,int x,int y) {
  if(state!=GLUT_DOWN)
    return;
  if(button==GLUT_RIGHT_BUTTON)
    exit(0);
  Unproject(x, y, &ox, &oy, &oz);
  glutPostRedisplay();
}

