Pergunta

Eu quero implementar meu próprio cursor em uma janela OpenGL / GLUT. A maneira usual de fazer isso é para congelar o cursor (para que ele não pode bater as bordas da tela) e manter o controle de sua posição a si mesmo. Eu posso fazer o cursor na tela invisível usando

glutSetCursor(GLUT_CURSOR_NONE);

e, em seguida, dentro da minha glutPassiveMotionFunc callback mover o ponteiro para o meio da janela usando

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

Isso funciona em que ele mantém o ponteiro preso ao meio da janela. O problema é que quando estou desenhando o mouse 'OpenGL' (dentro do callback glutDisplayFunc ()) é extremamente irregular.

Eu olhei online e descobriu que pode haver um problema onde glutWarpPointer () faz com que o retorno de chamada glutPassiveMotionFunc para ser chamado novamente, resultando em um loop, mas isso não parece acontecer aqui.

Eu estou no Mac OS X e eu encontrei um post dizendo que CGDisplayMoveCursorToPoint foi um ajuste melhor para isso. Chamando CGDisplayMoveCursorToPoint funciona, mas o movimento ainda é muito jerky (e me parece ter um monte de eventos onde X e Y são ambos 0). Em qualquer caso, eu gostaria que isso funcione no Linux, bem assim a única solução Mac não é ideal (mas estou bem ter que fazer coisas diferentes em diferentes sistemas).

Eu reduzi a um 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;
}
Foi útil?

Solução

aib Obrigado pelas dicas. Você me pegou olhando para a desmontagem de glutWarpPointer e tornou-se óbvio o que estava acontecendo. Chamando glutWarpPointer CGPostMouseEvent o que resulta em um monte de eventos sem sentido (e não há nenhuma maneira de ignorá-los desde que você só obter eventos do mouse uma vez por quadro, os novos eventos "reais" será tarde). A solução que eu encontrei é a única urdidura quando o ponteiro está na borda da tela (o ponto, afinal, é fingir que o ponto nunca pode alcançar a borda da tela). Em todo caso, aqui está o 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;
}

Outras dicas

Eu encontrei uma abordagem melhor. O que está acontecendo é que o OS suprime eventos para cerca de 0,25 segundos depois de deformar o mouse. Então, ao invés de apenas chamar:

#ifdef __APPLE__
CGSetLocalEventsSuppressionInterval(0.0);
#endif

Então tudo vai smoothy sem qualquer gagueira.

Você pode precisar incluem:

#include <ApplicationServices/ApplicationServices.h>

e adicione essa estrutura para seu projeto ou a seus opções do compilador.

Note que você pode receber um evento para o rato mover-se para o centro da tela, então eu simplesmente ignorar um evento, se é para o meio da tela.

Eu não tenho muita experiência com excesso, para salvar exemplos vermelho-book, mas é acelerado porque o que você está desenhando para o cursor, ou quantas vezes você está desenhando-lo? Se você acabou de desenhar um ponto onde o cursor é suposto ser usando chamadas OpenGL, ainda é jerky? Poderia seu código de tempo ser um problema?

O código está ligando para atualizar o ponteiro cada tick? Presumo que não é o código listado como você seria calcular o ponto central de cada vez, em vez de em um evento de redimensionamento.

As minhas desculpas por cegamente responder aqui (ou seja, com a experiência excesso limitada).

Eu estou supondo aqui, mas eu suspeito que o movimento é irregular porque o cursor é desenhado em função empate do seu aplicativo (display ()), em vez de tratado pelo OS.

Um ponteiro de rato normal é feita ao nível do controlador por XORing a imagem do cursor com o conteúdo do buffer de quadro - assim relâmpago rápido, e tratadas com prioridade muito elevada pela OS numa rotina de serviço de interrupção (para manter a ilusão de responsividade ).

Quando você desenha-lo sozinho, você está sujeito ao mecanismo de escalonamento regular de seu OS & atravessar a clara regular e redesenhar toda a janela rigamarole. Neste caso, é rápido, mas não tão rápido como estamos acostumados com um ponteiro do mouse devido ao acima.

Em suma, eu não tenho certeza que você jamais vai conseguir que ele seja tão rápido quanto você espera que ele seja (particularmente como sua função de exibição e aplicação lógica se torna mais complexa).

Boa sorte!

Você está em média o movimento do mouse sobre alguns quadros? Não consigo encontrar meu código para o meu projeto anterior, porque eu estou no trabalho. Mas acho que em média os movimentos do mouse sobre alguns quadros, antes i fez que o movimento era muito irregular.

Poderia ser porque você está trocando buffers em uma janela não-double buffer?

Seu exemplo não funciona no meu sistema Win32, a menos que eu adicione GLUT_DOUBLE para glutInitDisplayMode ().

Editar:

Você está correto. Chamando glutWarpPointer () dentro da função de movimento parece causar um loop no meu sistema [win32]. O temporizador nem sequer ter a chance de fogo a menos que eu clicar em um botão ou algo assim. Eu estou apostando que a fila de mensagens está sendo inundado com eventos de movimento.

Chamar display () desde a função de movimento não parece trabalho, ou -. Neste momento ele deixa de registar qualquer tipo de movimento

A única maneira que eu poderia obter o seu exemplo ao trabalho foi alterando o passiva movimento de retorno a um ativa callback movimento e tela do telefone () diretamente essa função. Eu sei que isso está longe de ser o que você inicialmente previsto, mas pelo menos eu tenho algum movimento suave desta forma.

Você já tentou usar um glutIdleFunc () para acionar suas atualizações de exibição para você? Ele ainda não pode trabalhar com uma fila de mensagens inundada, mas pode valer a pena uma tentativa. Você também pode olhar para a captura do mouse usando uma chamada de API em vez de manualmente envolvendo o cursor para o centro da janela em cada movimento.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top