Domanda

Voglio realizzare il mio cursore in una finestra OpenGL / GLUT. Il solito modo per farlo è quello di congelare il cursore (in modo che non può colpire i bordi dello schermo) e tenere traccia della sua posizione da soli. Posso fare il cursore sullo schermo invisibile utilizzando

glutSetCursor(GLUT_CURSOR_NONE);

e poi all'interno della mia glutPassiveMotionFunc richiamata spostare il puntatore al centro della finestra utilizzando

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

Questo funziona in quanto mantiene il puntatore attaccato al centro della finestra. Il problema è che quando sto disegnando il mouse 'OpenGL' (all'interno della richiamata glutDisplayFunc ()) è estremamente scatti.

Ho guardato online e ha scoperto che non ci può essere un problema in cui glutWarpPointer () fa sì che il callback glutPassiveMotionFunc di essere chiamato di nuovo, con conseguente in un ciclo, ma questo non sembra accadere qui.

Sono su Mac OS X e ho scoperto dicendo che CGDisplayMoveCursorToPoint era una misura migliore per questo un post. Chiamando CGDisplayMoveCursorToPoint funziona, ma il movimento è ancora molto a scatti (e mi sembra di avere un sacco di eventi in cui X e Y sono entrambi 0). In ogni caso, mi piacerebbe questo per lavorare su Linux e quindi una unica soluzione per Mac non è ideale (ma sto bene di dover fare cose diverse sui diversi sistemi).

Ho ridotto ad 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;
}
È stato utile?

Soluzione

Grazie AIB per i suggerimenti. You got me esaminando lo smontaggio di glutWarpPointer ed è diventato evidente che cosa stava succedendo. Chiamando glutWarpPointer CGPostMouseEvent che si traduce in una serie di eventi senza senso (e non c'è alcun modo di saltare loro in quanto si ottiene solo gli eventi di mouse una volta per frame, i nuovi eventi "reali" saranno in ritardo). La soluzione che ho trovato è solo ordito quando il puntatore si trova al bordo dello schermo (il punto, dopo tutto, è quello di far finta come il punto non può mai raggiungere il bordo dello schermo). In ogni caso, ecco il codice.

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

Altri suggerimenti

Ho trovato un approccio migliore. Che cosa sta succedendo è che il sistema operativo sopprime gli eventi per circa 0,25 secondi dopo di deformare il mouse. Così, invece basta chiamare:

#ifdef __APPLE__
CGSetLocalEventsSuppressionInterval(0.0);
#endif

Poi tutto andrà frullato senza balbuzie.

Potrebbe essere necessario includere:

#include <ApplicationServices/ApplicationServices.h>

e aggiungere questo quadro al progetto o alle opzioni del compilatore.

Si noti che si può ottenere un evento per il mouse in movimento al centro dello schermo, quindi ho semplicemente ignorare un evento se è al centro dello schermo.

Non ho troppa esperienza con sovrabbondanza, salvo per gli esempi rosso-book, ma è a scatti a causa di ciò che si sta disegnando per il cursore, o quanto spesso si sta disegnando? Se hai appena disegna un punto in cui si suppone che il cursore di utilizzare le chiamate OpenGL, è ancora a scatti? Potrebbe il codice tempi essere un problema?

Quale codice sta chiamando per aggiornare il puntatore ogni tick? Suppongo che non è il codice elencato come si sarebbe calcolando il punto centrale ogni volta, invece che su un evento resize.

Le mie scuse per rispondere alla cieca qui (vale a dire con l'esperienza sovrabbondanza limitata).

Sto indovinando qui, ma ho il sospetto che il movimento è a scatti, perché il cursore è disegnata in funzione draw dell'applicazione (display ()), piuttosto che gestito dal sistema operativo.

Un puntatore normale mouse viene gestita a livello di driver come XOR l'immagine del cursore con la cornice contenuto del buffer - così fulmine veloce, e maneggiato con la massima priorità dal sistema operativo in una routine di servizio di interruzione (per mantenere l'illusione di reattività ).

Quando si disegna da soli, sei soggetto al meccanismo di programmazione regolare del vostro sistema operativo e passare attraverso la chiara regolare e ridisegnare l'intera finestra manfrina. In questo caso, è veloce, ma non così rapidamente come siamo abituati a con un puntatore del mouse a causa di quanto sopra.

In breve, io non sono sicuro che potrai mai avere di essere veloce come si aspetta che sia (in particolare per quanto la vostra logica di funzionamento e applicazione di visualizzazione diventa più complesso).

In bocca al lupo!

Stai con una media il movimento del mouse sopra un paio di frame? Non riesco a trovare il mio codice per il mio progetto precedente perché io sono al lavoro. Ma penso che la media dei movimenti del mouse più di un paio di fotogrammi, prima di ho fatto che il movimento era molto a scatti.

Potrebbe essere perché si sta scambiando i buffer su una finestra non-doppio buffer?

Il tuo esempio non funziona sul mio sistema Win32, a meno che non aggiungo GLUT_DOUBLE a glutInitDisplayMode ().

Modifica:

Hai ragione. Chiamata glutWarpPointer () all'interno della funzione di movimento sembra causare un loop sul mio sistema [Win32]. Il timer non ha nemmeno avuto la possibilità di sparare a meno che non si fa clic su un pulsante o qualcosa del genere. Sto scommettendo la coda dei messaggi viene invaso da eventi di movimento.

display () proprio dalla funzione di movimento di chiamata non sembra funzionare, o -. Questa volta non riesce a registrare qualsiasi tipo di moto

L'unico modo ho potuto ottenere il vostro esempio a lavoro è stato modificando il passiva richiamata mozione per una diretta attiva di movimento richiamata e chiamando display () da quella funzione. So che questo è lontano da quello che hai originariamente previsto, ma almeno ho avuto qualche buon movimento in questo modo.

Hai provato a usare un glutIdleFunc () per attivare gli aggiornamenti di visualizzazione per te? Esso non può ancora lavorare con una coda di messaggi allagato, ma può essere la pena di provare. Si potrebbe anche prendere in considerazione la cattura il mouse utilizzando una chiamata API, invece di manualmente avvolgere il cursore al centro della finestra ad ogni movimento.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top