Question

Je veux mettre en œuvre mon propre curseur dans une fenêtre OpenGL / GLUT. La manière habituelle de faire est de geler le curseur (donc il ne peut pas frapper les bords de l'écran) et de garder trace de sa position vous-même. Je peux faire le curseur à l'écran invisible en utilisant

glutSetCursor(GLUT_CURSOR_NONE);

et puis à l'intérieur de mon rappel glutPassiveMotionFunc déplacer le pointeur vers le milieu de la fenêtre en utilisant

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

Cela fonctionne en ce qu'elle maintient le pointeur coincé au milieu de la fenêtre. Le problème est que quand je dessine la souris « OpenGL » (à l'intérieur de la fonction de rappel glutDisplayFunc ()) il est extrêmement saccadé.

Je l'ai regardé en ligne et a constaté que d'un problème où glutWarpPointer () il peut y avoir fait le rappel glutPassiveMotionFunc être appelé à nouveau, ce qui entraîne dans une boucle, mais cela ne semble pas se produire ici.

Je suis sous Mac OS X et j'ai trouvé un poste en disant que CGDisplayMoveCursorToPoint était un meilleur ajustement pour cela. L'appel CGDisplayMoveCursorToPoint fonctionne, mais le mouvement est encore très saccadé (et je semble avoir beaucoup d'événements où x et y sont tous deux 0). Dans tous les cas, je voudrais que cela fonctionne sur Linux, si bien que Mac seule solution est pas idéale (mais je vais bien devoir faire des choses différentes sur les différents systèmes).

Je l'ai réduit à un 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;
}
Était-ce utile?

La solution

Merci BAI pour les conseils. Tu me as à la recherche dans le démontage de glutWarpPointer et il est devenu évident ce qui se passait. Appel glutWarpPointer CGPostMouseEvent qui se traduit par un tas d'événements non-sens (et il n'y a aucun moyen de les ignorer, puisque vous obtenez seulement des événements de la souris une fois par trame, les nouveaux événements « réels » seront en retard). La solution que j'ai trouvé est que la chaîne lorsque le pointeur se trouve au bord de l'écran (le point, après tout, est de prétendre que le point ne peut jamais atteindre le bord de l'écran). Dans tous les cas, le code est ici.

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

Autres conseils

J'ai trouvé une meilleure approche. Ce qui se passe est que le système d'exploitation supprime les événements pendant environ 0,25 secondes après que vous téléporter la souris. Ainsi, au lieu simplement appeler:

#ifdef __APPLE__
CGSetLocalEventsSuppressionInterval(0.0);
#endif

Alors tout ira smoothy sans bégayer.

Vous devrez peut-être inclure:

#include <ApplicationServices/ApplicationServices.h>

et ajouter ce cadre à votre projet ou à vos options de compilateur.

Notez que vous pouvez obtenir un événement pour la souris en mouvement au centre de l'écran, donc j'ignorer un événement si elle est au milieu de l'écran.

Je n'ai pas trop d'expérience avec surabondance, sauf exemples rouge-livre, mais est-ce saccadée à cause de ce que vous dessinez pour le curseur ou la fréquence à laquelle vous le dessiner? Si vous venez de dessiner un point où le curseur est censé être en utilisant des appels OpenGL, est-il encore saccadé? Pourrait votre code de synchronisation est un problème?

Quel est le code que vous appelez de mettre à jour le pointeur chaque tic-tac? Je suppose que ce n'est pas le code répertorié comme vous calculera le point central à chaque fois, au lieu d'un événement resize.

Mes excuses pour répondre à l'aveuglette ici (à savoir avec une expérience limitée rassasiement).

Je devine ici, mais je pense que le mouvement est saccadé parce que le curseur est dessiné en fonction de tirage de votre application (affichage ()), plutôt que géré par le système d'exploitation.

Un pointeur de souris normale est traitée au niveau du pilote par XOR l'image du curseur avec le contenu du tampon de trame - ainsi foudre rapide, et traité avec une très haute priorité par le système d'exploitation dans une routine de service d'interruption (pour maintenir l'illusion de la réactivité ).

Lorsque vous dessinez vous-même, vous êtes soumis au mécanisme de programmation régulière de votre système d'exploitation et passer par le régulier clair et redessiner l'ensemble rigamarole de fenêtre. Dans ce cas, il est rapide mais pas aussi vite que nous sommes habitués avec un pointeur de la souris en raison de ce qui précède.

En bref, je ne suis pas sûr que vous obtiendrez jamais à être aussi vite que vous attendez qu'il soit (en particulier en fonction de votre affichage et la logique application est plus complexe).

Bonne chance!

Êtes-vous le calcul de la moyenne mouvement de la souris sur quelques images? Je ne peux pas trouver mon code pour mon projet précédent parce que je suis au travail. Mais je pense que je les mouvements de la moyenne de la souris sur quelques images, avant je l'ai fait que le mouvement était très saccadé.

Serait-ce parce que vous êtes la permutation des tampons sur une fenêtre tampon non double?

Votre exemple ne fonctionne pas sur mon système Win32, à moins que j'ajouter à GLUT_DOUBLE glutInitDisplayMode ().

Edit:

Vous avez raison. Appel glutWarpPointer () à partir de la fonction de mouvement semble provoquer une boucle sur mon système [win32]. La minuterie n'a même pas la chance de tirer à moins que je clique sur un bouton ou quelque chose. Je parie la file d'attente de messages est inondé avec des événements de mouvement.

Affichage d'appel () à droite de la fonction de mouvement ne semble pas fonctionner, que ce soit -. Cette fois, il ne s'enregistre tout type de mouvement

La seule façon que je pouvais obtenir votre exemple au travail était en changeant la passif rappel de mouvement à une actif rappel de mouvement et d'appeler display () directement à partir de cette fonction. Je sais que cela est loin de ce que vous avez initialement prévu, mais au moins je suis certain mouvement en douceur de cette façon.

Avez-vous essayé d'utiliser un glutIdleFunc () pour déclencher vos mises à jour d'affichage pour vous? Il peut ne pas fonctionner avec une file d'attente de messages inondé, mais il peut être la peine d'essayer. Vous pouvez également regarder dans la capture de la souris à l'aide d'un appel API au lieu d'envelopper manuellement le curseur au centre de la fenêtre à chaque mouvement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top