Frage

Ich möchte meine eigene Cursor in einem OpenGL / GLUT-Fenster implementieren. Der übliche Weg, dies zu tun ist, um den Cursor gefrieren (so kann sie die Ränder des Bildschirms nicht getroffen) und behalten ihre Position selbst. Ich kann den Bildschirm Cursor unsichtbar machen mit

glutSetCursor(GLUT_CURSOR_NONE);

und dann in meinem glutPassiveMotionFunc Rückruf die Zeiger auf die Mitte des Fensters bewegen Sie mit

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

Das funktioniert, dass sie den Zeiger auf die Mitte des Fensters fest halten. Das Problem ist, dass, wenn ich die ‚OpenGL‘ Maus an Zeichnung (innerhalb des glutDisplayFunc () Callback) ist es extrem ruckelt.

Ich habe Online gesucht und gefunden, dass es ein Problem sein, wo glutWarpPointer (), um den glutPassiveMotionFunc Rückruf verursacht erneut aufgerufen werden, in einer Schleife führt, aber dies scheint nicht hier zu geschehen.

Ich bin auf Mac OS X und ich einen Beitrag gefunden sagen, dass CGDisplayMoveCursorToPoint besser dafür geeignet war. CGDisplayMoveCursorToPoint Aufruf funktioniert, aber die Bewegung ist immer noch sehr abgehackt (und ich scheinen viele Ereignisse zu bekommen, wo x und y beide 0 sind). Auf jeden Fall würde ich dies gerne auch auf Linux arbeiten, so ein Mac einzige Lösung nicht ideal ist (aber ich bin okay verschiedene Dinge auf den verschiedenen Systemen zu tun haben).

Ich habe dies reduziert auf einen Testfall.

#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;
}
War es hilfreich?

Lösung

Danke aib für die Tipps. Du hast mich in die Demontage von glutWarpPointer suchen und es wurde klar, was los war. Der Aufruf glutWarpPointer CGPostMouseEvent, die in einem Haufen Unsinn Ereignisse ergibt (und es gibt keine Möglichkeit, sie zu überspringen, da Sie nur Mausereignisse erhalten einmal pro Rahmen, werden die neuen „echten“ Ereignisse zu spät). Die Lösung, die ich gefunden habe, ist nur Kette, wenn der Zeiger am Rande des Bildschirms ist (der Punkt, schließlich ist wie der Punkt so zu tun, kann niemals den Rand des Bildschirms erreichen). Auf jeden Fall hier ist der Code.

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

Andere Tipps

Ich fand einen besseren Ansatz. Was ist da los ist, dass das Betriebssystem für etwa 0,25 Sekunden Ereignisse unterdrückt, nachdem Sie die Maus verziehen. Also, statt nur nennen:

#ifdef __APPLE__
CGSetLocalEventsSuppressionInterval(0.0);
#endif

Dann wird alles gehen Smoothy ohne Stottern.

Sie müssen enthalten:

#include <ApplicationServices/ApplicationServices.h>

und fügen Sie diesen Rahmen zu einem Projekt oder zu Ihren Compiler-Optionen.

Beachten Sie, dass Sie ein Ereignis für die Maus in der Mitte des Bildschirms in Bewegung bringen können, so dass ich nur ein Ereignis ignorieren, wenn es in der Mitte des Bildschirms ist.

ich zu viel Erfahrung nicht mit Schwemme haben, rot-Buch Beispiele sparen für, aber ist es ruckelt, weil von dem, was Sie für den Cursor sind zeichnen, oder wie oft es Sie zeichnen? Wenn Sie nur einen Punkt ziehen, wo der Cursor soll OpenGL Anrufe zu verwenden, ist es immer noch ruckelt? Könnte Ihr Timing-Code ein Problem sein?

Welcher Code rufen Sie den Zeiger jeden Tick zu aktualisieren? Ich nehme an, es nicht der Code ist aufgelistet, wie Sie den Mittelpunkt jedes Mal, würde die Berechnung, statt auf einem Resize-Ereignis.

Ich entschuldigt sich für blind hier beantworten (das heißt mit begrenzten Schwemme Erfahrung).

Ich vermute hier, aber ich vermute, dass die Bewegung ruckartig ist, weil der Cursor in Ihrer Anwendung Zeichenfunktion (display ()) gezogen wird, und nicht von dem O behandelt.

Ein normaler Mauszeigers auf Treiberebene gehandhabt wird durch XOR-Verknüpfung des Cursor-Bildes mit dem Pufferinhalt Rahmen - also blitzschnell und mit sehr hohen Priorität durch das Betriebssystem in einer Interrupt-Serviceroutine verarbeitet (um die Illusion von Ansprechbarkeit beibehalten ).

Wenn Sie es sich ziehen, sind Sie auf der regulären Scheduling-Mechanismus Ihres OS Thema & gehen durch die regelmäßige klar und das gesamte Fenster rigamarole neu zu zeichnen. In diesem Fall ist es schnell, aber nicht so schnell, wie wir es mit einer Maus gewohnt sind aufgrund der oben.

Kurz gesagt, ich bin nicht sicher, ob Sie jemals bekommen werde es so schnell sein, wie Sie es erwarten, dass (vor allem als Anzeigefunktion & app Logik komplexer wird).

Viel Glück!

sind durchschnittlich Sie die Bewegung der Maus über ein paar Frames? Ich kann nicht meinen Code für mein vorheriges Projekt finden, weil ich bei der Arbeit bin. Aber ich glaube, ich gemittelt, um die Mausbewegungen über ein paar Frames, bevor ich habe, dass die Bewegung sehr ruckartig war.

Könnte es sein, weil Sie Puffer auf einem nicht doppelt gepuffert Fenster sind Swapping?

Ihr Beispiel funktioniert nicht auf meinem Win32-System, es sei denn, ich GLUT_DOUBLE zu glutInitDisplayMode hinzufügen ().

Edit:

Sie sind richtig. Der Aufruf glutWarpPointer () aus der Bewegungsfunktion scheint eine Schleife auf meinem [win32] System zu verursachen. Der Timer wird nicht einmal eine Chance zu schießen, wenn ich einen Knopf oder etwas klicken. Ich wette, die Nachrichtenwarteschlange mit Bewegungsereignissen überflutet wird.

Beim display () rechts von der Motion-Funktion scheint nicht zu funktionieren, entweder -. Diesmal ist es, jede Art von Bewegung registrieren versagt

Die einzige Art, wie ich Ihr Beispiel an der Arbeit konnte nur durch eine Änderung der passiv Bewegung Rückruf zu einem aktiv Bewegung Rückruf und Anrufanzeige () direkt aus dieser Funktion. Ich weiß, das ist weit davon entfernt, was Sie ursprünglich gedacht haben, aber zumindest ich habe einige glatte Bewegung auf diese Weise.

Haben Sie versucht, eine glutIdleFunc () mit Ihrer Anzeige-Updates für Sie auslösen? Es kann immer noch nicht mit einer überfluteten Nachrichtenwarteschlange arbeiten, aber es kann einen Versuch wert sein. Sie können auch den Cursor in die Mitte des Fensters Einwickeln bei jeder Bewegung einen API-Aufruf anstelle von manuell suchen in der Maus zu erfassen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top