I've tried to put together some c code to show the problem.
Up to now, what I achieved is when I click on a point on the white line, the sheet rotate around that point, but if I click not on the white line, the sheet will rotate around a point on the white line, and that point is aligned vertically with the point I click.
Not sure if I have made myself clear, maybe the code explains better.
(You can press ESC to reset the scene)
#include <GL/gl.h>#include <GL/glu.h>#include <glut.h>#include <math.h>int mWidth, mHeight;float mZTrans;float mYAngle;int mMouseX, mMouseY;double mPosX, mPosY, mPosZ;int mMouseMove;void getClickCoord(int x, int y, double *posX, double *posY, double *posZ){ int viewport[4]; double modelview[16]; double projection[16]; float winX, winY, winZ; glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, projection); glGetIntegerv(GL_VIEWPORT, viewport); winX = (float)x; winY = (float)(viewport[3] - y - 1); glReadPixels((int)winX, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ ); gluUnProject(winX, winY, winZ, modelview, projection, viewport, posX, posY, posZ);}float normalizeAngle(float angle){ angle -= (360*(int)(angle/360)); if (angle < 0) angle += 360; return angle;}void glOrthoBegin(){ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, mWidth, 0, mHeight, -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();}void glOrthoEnd(){ glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix();}void paintCircle(float radius, GLint xoffset, GLint yoffset){ float delta = 0.05; glPushAttrib(GL_CURRENT_BIT); glColor3f(0.0, 1.0, 0.0); glBegin(GL_LINE_LOOP); float theta; for (theta = 0; theta < 2*M_PI; theta += delta) { glVertex2i((int)(radius*cos(theta))+xoffset, (int)(radius*sin(theta))+yoffset); } glEnd(); glPopAttrib();}void paintQuads(){ int row, col; float xoffset, zoffset; glPushAttrib(GL_CURRENT_BIT); glBegin(GL_QUADS); for (row = 0; row < 10; row++) { zoffset = 1*row+0.5 - 5; for (col = 0; col < 10; col++) { xoffset = 1*col+0.5 - 5; glColor3f(row*0.1, col*0.1, 0.0); glVertex3f(-0.5+xoffset, 0, -0.5+zoffset); glVertex3f(-0.5+xoffset, 0, 0.5+zoffset); glVertex3f( 0.5+xoffset, 0, 0.5+zoffset); glVertex3f( 0.5+xoffset, 0, -0.5+zoffset); } } glEnd(); glPopAttrib();}void reset(){ mZTrans = -15.0; mYAngle = 0.0; mMouseX = mMouseY = 0; mMouseMove = 0;}void init() { glClearColor(0.0, 0.0, 0.0, 1.0); glClearDepth(1.0); glShadeModel(GL_SMOOTH); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); float ambient[] = {0.5, 0.5, 0.5, 1.0}; float diffuse[] = {0.8, 0.8, 0.8, 1.0}; float specular[] = {1.0, 1.0, 1.0, 1.0}; float position[] = {0.0, 0.0, 0.0, 1.0}; glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); glLightfv(GL_LIGHT0, GL_POSITION, position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL);}void display(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0, 0, mZTrans); if (mMouseMove) glTranslatef(mPosX, mPosY, mPosZ); glRotatef(45.0, 1, 0, 0); glRotatef(mYAngle, 0, 1, 0); if (mMouseMove) glTranslatef(-mPosX, -mPosY, -mPosZ); paintQuads(); if (mMouseMove) { glOrthoBegin(); paintCircle(20.0, mMouseX, (mHeight-mMouseY-1)); glOrthoEnd(); } mMouseMove = 0; glutSwapBuffers();}void reshape(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); mWidth = width; mHeight = height; float aspect = (float)width/(float)height; float top, bottom, left, right; top = 0.1*tan(20.0/180.0*M_PI); if (aspect < 1.0) top *= (1.0/aspect); bottom = -top; right = top*aspect; left = -right; glFrustum(left, right, bottom, top, 0.1, 100); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}void mouse(int button, int state, int x, int y){ if (state == GLUT_DOWN) { mMouseX = x; mMouseY = y; getClickCoord(x, y, &mPosX, &mPosY, &mPosZ); } else if (state == GLUT_UP) { glutPostRedisplay(); }}void motion(int x, int y){ mYAngle = normalizeAngle(mYAngle + 5); mMouseMove = 1; glutPostRedisplay();}void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: reset(); glutPostRedisplay(); break; case '=': case '+': mZTrans /= 1.2; glutPostRedisplay(); break; case '-': case '_': mZTrans *= 1.2; glutPostRedisplay(); break; case 'Q': case 'q': exit(0); break; default: break; }}int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(640, 480); glutInitWindowPosition(100, 60); glutCreateWindow(argv[0]); reset(); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMotionFunc(motion); glutKeyboardFunc(keyboard); glutMainLoop(); return 0;}