Hi, all
I’d like to do something like Gooogle earth e.g., if I click on an arbitrary location on the map and drag the mouse, the whole map should rotate about the location where mouse is clicked at.
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;
}