Pregunta

Quiero aplicar mi propio cursor en una ventana de OpenGL / GLUT. La forma habitual de hacer esto es congelar el cursor (por lo que no puede golpear los bordes de la pantalla) y realizar un seguimiento de su posición a sí mismo. Puedo hacer que el cursor en pantalla invisible utilizando

glutSetCursor(GLUT_CURSOR_NONE);

y luego dentro de mi devolución de llamada glutPassiveMotionFunc mover el puntero a la mitad de la ventana utilizando

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 );

Esto funciona en el que se mantiene el puntero pegado a la mitad de la ventana. El problema es que cuando estoy dibujando el ratón 'OpenGL' (en el interior de la devolución de llamada glutDisplayFunc ()) es extremadamente desigual.

He mirado en línea y se encontró que no puede haber un problema en el glutWarpPointer () hace que la devolución de llamada glutPassiveMotionFunc a ser llamado de nuevo, lo que resulta en un bucle, pero esto no parece suceder aquí.

Estoy en Mac OS X y me encontré con un post diciendo que CGDisplayMoveCursorToPoint era una mejor opción para esto. Llamando CGDisplayMoveCursorToPoint funciona pero el movimiento sigue siendo muy desigual (y me parece conseguir una gran cantidad de eventos en los que X e Y son ambos 0). En cualquier caso, me gustaría que esto funcione en Linux, así que la única solución Mac no es lo ideal (pero estoy bien tener que hacer cosas diferentes en los distintos sistemas).

He reducido a un caso de prueba.

#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;
}
¿Fue útil?

Solución

Gracias por los consejos AIB. Usted me mira en el desmontaje de glutWarpPointer y se hizo evidente lo que estaba pasando. Llamando glutWarpPointer CGPostMouseEvent que se traduce en un montón de eventos sin sentido (y no hay ninguna forma de omitir ellos, ya que sólo recibe eventos del ratón una vez por cuadro, los nuevos acontecimientos "reales" será tarde). La solución que he encontrado es que solamente urdimbre cuando el puntero está en el borde de la pantalla (el punto, después de todo, es pretender que el punto nunca puede alcanzar el borde de la pantalla). En cualquier caso, aquí está el código.

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;
}

Otros consejos

He encontrado un mejor enfoque. Lo que está sucediendo es que el sistema operativo suprime eventos durante aproximadamente 0,25 segundos después de deformar el ratón. Así, en lugar de simplemente llamar a:

#ifdef __APPLE__
CGSetLocalEventsSuppressionInterval(0.0);
#endif

A continuación, todo irá colado sin ningún tartamudeo.

Es posible que deba incluir:

#include <ApplicationServices/ApplicationServices.h>

y añadir este marco para su proyecto o de sus opciones de compilación.

Tenga en cuenta que usted puede conseguir un evento para el ratón se mueve hacia el centro de la pantalla, por lo que sólo ignorar un evento si es a la mitad de la pantalla.

No tengo demasiada experiencia con exceso, con excepción de ejemplos de color rojo-libro, pero ¿es desigual debido a lo que está dibujando para el cursor, o con qué frecuencia va a dibujar ella? Si sólo dibuja un punto donde se supone que el cursor a ser mediante llamadas de OpenGL, se sigue cecina? Podría su código de tiempo será un problema?

¿Qué código está llamando para actualizar el puntero cada pulso? Asumo que no es el código que aparece a medida que estaría calculando el punto central cada vez, en lugar de en un evento de cambio de tamaño.

Mis disculpas por responder a ciegas aquí (es decir, con experiencia limitada exceso).

Estoy adivinando, pero sospecho que el movimiento es desigual debido a que el cursor se dibuja en función de drenaje de la aplicación (pantalla ()), más bien que se maneja por el sistema operativo.

Un puntero de ratón normal se maneja en el nivel de controlador por XORing la imagen del cursor con el contenido del búfer de marco - por lo tanto rápido como un rayo, y manejado con prioridad muy alta por el sistema operativo en una rutina de servicio de interrupción (para mantener la ilusión de la capacidad de respuesta ).

Cuando se dibuja usted mismo, usted está sujeto al mecanismo de programación regular de su sistema operativo y pasar por la clara regular y volver a dibujar todo el galimatías ventana. En este caso, es rápido pero no tan rápido como estamos acostumbrados con un puntero de ratón debido a lo anterior.

En resumen, no estoy seguro de que conseguirá siempre que sea lo más rápido que esperar que sea (en particular, su función y aplicación lógica de visualización se vuelve más complejo).

Buena suerte!

¿Está promediando el movimiento del ratón sobre una serie de imágenes? No puedo encontrar mi código para mi proyecto anterior, porque estoy en el trabajo. Pero creo que un promedio de los movimientos del ratón más de unos pocos fotogramas, antes i hizo que el movimiento era muy desigual.

Podría ser porque estás cambiando de tampones en una ventana de doble búfer no?

Su ejemplo no funciona en mi sistema Win32, a menos que agrego a GLUT_DOUBLE glutInitDisplayMode ().

Editar:

Usted está correcto. Llamando glutWarpPointer () desde dentro de la función de movimiento parece ser la causa de un bucle en mi sistema [Win32]. El temporizador ni siquiera tienen la oportunidad de disparar a menos que haga clic en un botón o algo. Estoy apostando a la cola de mensajes está siendo inundado de eventos de movimiento.

No parece Calling pantalla () desde la función de movimiento para trabajar, ya sea -. Esta vez no se registra ningún tipo de movimiento

La única manera de que pudiera obtener su ejemplo de trabajo fue cambiando el pasiva de devolución de llamada movimiento a un activa de devolución de llamada de movimiento y llamar a la pantalla () directamente de esa función. Sé que esto está lejos de lo que ha sido fabricado, pero al menos tengo algo de movimiento suave de esta manera.

¿Ha intentado utilizar un glutIdleFunc () para activar sus actualizaciones de pantalla para usted? Todavía no se puede trabajar con una cola de mensajes inundado pero puede valer la pena probar. También podría mirar en la captura del ratón usando una llamada a la API en lugar de envolver manualmente el cursor hasta el centro de la ventana en cada movimiento.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top