I want to implement my own cursor in an OpenGL / GLUT window. The usual way to do this is to freeze the cursor (so it can't hit the edges of the screen) and keep track of its position yourself. I can make the onscreen cursor invisible using
glutSetCursor(GLUT_CURSOR_NONE);
and then inside of my glutPassiveMotionFunc callback move the pointer to the middle of the window using
int centerX = (float)kWindowWidth / 2.0;
int centerY = (float)kWindowHeight / 2.0;
int deltaX = (x - centerX);
int deltaY = (y - centerY);
mouseX += deltaX / (float)kWindowWidth;
mouseY -= deltaY / (float)kWindowHeight;
glutWarpPointer( centerX, centerY );
This works in that it keeps the pointer stuck to the middle of the window. The problem is that when I am drawing the 'OpenGL' mouse (inside of the glutDisplayFunc() callback) it is extremely jerky.
I have looked online and found that there can be an issue where glutWarpPointer() causes the glutPassiveMotionFunc callback to be called again, resulting in a loop, but this doesn't seem to happen here.
I'm on Mac OS X and I found a post saying that CGDisplayMoveCursorToPoint was a better fit for this. Calling CGDisplayMoveCursorToPoint works but the movement is still very jerky (and I seem to get a lot of events where x and y are both 0). In any case, I'd like this to work on Linux as well so a Mac only solution is not ideal (but I'm okay having to do different things on the different systems).
I've reduced this to a testcase.
#include <stdio.h>
#include <OpenGL/OpenGL.h>
#include <GLUT/GLUT.h>
int curX = 0;
int curY = 0;
void display() {
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glClear( GL_COLOR_BUFFER_BIT );
float vx = (float)curX / 300.0 + 0.5;
float vy = (float)curY / 300.0 + 0.5;
glColor3f( 1.0, 0.0, 0.0 );
glBegin( GL_POINTS );
glVertex3f( vx, vy, 0.0 );
glEnd();
glutSwapBuffers();
}
void passivemotion( int x, int y ) {
int centerX = 150;
int centerY = 150;
int deltaX = x - centerX;
int deltaY = y - centerY;
curX += deltaX;
curY -= deltaY;
glutWarpPointer( centerX, centerY );
}
void timer( int val ) {
glutTimerFunc( 16, &timer, 0);
glutPostRedisplay();
}
int main (int argc, char * argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(300,300);
glutCreateWindow("FPS Mouse Sample");
glutDisplayFunc(&display);
glutPassiveMotionFunc(&passivemotion);
glutSetCursor( GLUT_CURSOR_NONE );
glutTimerFunc( 16, &timer, 0 );
glutMainLoop();
return 0;
}