我想在OpenGL/GLUT窗口中实现自己的光标。这样做的通常方法是卡住光标(这样光标就不会碰到屏幕的边缘)并自己跟踪其位置。我可以使用来使屏幕上的光标不可见
glutSetCursor(GLUT_CURSOR_NONE);
然后在我的glutPassiveMotionFunc回调内部,使用
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 );
这样做的原因是它使指针停留在窗口的中间。问题是,当我绘制“OpenGL”鼠标(在glutDisplayFunc()回调内部)时,它非常生涩。
我在网上查看,发现可能存在一个问题,其中glutWarpPointer()导致再次调用glutPassiveMotionFunc回调,从而导致循环,但这似乎没有发生。
我在Mac OS X上,发现一个帖子说CGDisplayMoveCursorToPoint更适合此操作。调用CGDisplayMoveCursorToPoint可以,但是运动仍然非常不稳定(而且我似乎收到很多x和y均为0的事件)。无论如何,我也希望它也可以在Linux上运行,因此,仅Mac的解决方案不是理想的选择(但是我可以在不同的系统上做不同的事情)。
我已经将其简化为一个测试用例。
#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;
}
最佳答案
感谢aib的提示。您让我调查了glutWarpPointer的反汇编,发现发生了什么变得很明显。调用glutWarpPointer CGPostMouseEvent会导致一堆无意义的事件(并且没有任何方法可以跳过它们,因为每帧只获得一次Mouse Events,新的“真实”事件将延迟)。我发现的解决方案是仅在指针位于屏幕边缘时才弯曲(毕竟,该点要装作好像该点永远无法到达屏幕边缘)。无论如何,这是代码。
int lastX = 150;
int lastY = 150;
void passivemotion( int x, int y ) {
int deltaX = x - lastX;
int deltaY = y - lastY;
lastX = x;
lastY = y;
if( deltaX == 0 && deltaY == 0 ) return;
int windowX = glutGet( GLUT_WINDOW_X );
int windowY = glutGet( GLUT_WINDOW_Y );
int screenWidth = glutGet( GLUT_SCREEN_WIDTH );
int screenHeight = glutGet( GLUT_SCREEN_HEIGHT );
int screenLeft = -windowX;
int screenTop = -windowY;
int screenRight = screenWidth - windowX;
int screenBottom = screenHeight - windowY;
if( x <= screenLeft+10 || (y) <= screenTop+10 || x >= screenRight-10 || y >= screenBottom - 10) {
lastX = 150;
lastY = 150;
glutWarpPointer( lastX, lastY );
// If on Mac OS X, the following will also work (and CGwarpMouseCursorPosition seems faster than glutWarpPointer).
// CGPoint centerPos = CGPointMake( windowX + lastX, windowY + lastY );
// CGWarpMouseCursorPosition( centerPos );
// Have to re-hide if the user touched any UI element with the invisible pointer, like the Dock.
// CGDisplayHideCursor(kCGDirectMainDisplay);
}
curX += deltaX;
curY -= deltaY;
}
关于macos - glutPassiveMotionFunc和glutWarpMousePointer,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/728049/