title: glutPassiveMotionFunc and glutWarpMousePointer
body: <p>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 </p>
  
  <pre><code>glutSetCursor(GLUT_CURSOR_NONE);
  </code></pre>
  
  <p>and then inside of my glutPassiveMotionFunc callback move the pointer to the middle of the window using</p>
  
  <pre><code>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 );
  </code></pre>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>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).</p>
  
  <p>I've reduced this to a testcase.</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;OpenGL/OpenGL.h&gt;
  #include &lt;GLUT/GLUT.h&gt;
  
  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, &amp;timer,  0);
      glutPostRedisplay();
  }
  
  int main (int argc, char * argv[]) {
      glutInit(&amp;argc, argv);
      glutInitDisplayMode(GLUT_RGB);
      glutInitWindowSize(300,300);
      glutCreateWindow("FPS Mouse Sample");
      glutDisplayFunc(&amp;display);
      glutPassiveMotionFunc(&amp;passivemotion);
      glutSetCursor( GLUT_CURSOR_NONE );
      glutTimerFunc( 16, &amp;timer, 0 );
      glutMainLoop();
      return 0;
  }
  </code></pre>