Como interrompo o alongamento durante o redimensionamento da janela no XNA?

8

No meu jogo XNA no modo janela, quando o usuário redimensiona a janela, o jogo para de atualizar a janela e o último quadro desenhado é esticado e distorcido até que o usuário libere o mouse e o redimensionamento seja concluído.

Existe alguma maneira de o jogo continuar rodando "normalmente", atualizando quadros e redesenhando a tela durante o evento de redimensionamento?

Sei que manter o loop de renderização durante o redimensionamento pode não ser possível ou recomendado, porque os recursos gerenciados por hardware são continuamente criados e destruídos, mas existe alguma maneira de interromper o alongamento feio? Idealmente, deixando o quadro existente sem escala no canto superior esquerdo ou com uma tela preta, se isso não for possível.

Bradley Uffner
fonte
Registre um evento para o redimensionamento da janela e atualize a resolução GraphicsDevice. Isso pode atualizar a proporção e corrigir o alongamento.
Gustavo Maciel
Eu não sei sobre C # / XNA, mas em C ++ / D3D eu só tinha o loop de renderização em execução em um thread separado do thread principal com o loop de mensagens. O encadeamento principal executa o redimensionamento do buffer quando ocorre um evento de redimensionamento, sincronizado por meio de um mutex.
11
Gustavo, eu já lido com esse evento para outros fins no jogo. Infelizmente, ele não é acionado até que o usuário libere o mouse quando o redimensionamento estiver concluído.
Bradley Uffner
Esse par de perguntas / respostas pode ser útil. Ele mostra como continuar a renderização (embora não conserte o alongamento).
Andrew Russell

Respostas:

3

Há pelo menos três mensagens que você pode acompanhar.

  • WM_SIZE- redimensionamento de janelas, mini / maximização, comutação em tela cheia / janelas. Você deve ler o wParam para descobrir o que exatamente aconteceu e lParam para o tamanho atual.
  • WM_ENTERSIZEMOVE - inicia o redimensionamento da janela no modo janela
  • WM_EXITSIZEMOVE - redimensionar a janela final no modo de janela

Geralmente, você não deseja redimensionar seu aplicativo a cada quadro entre WM_ENTERSIZEMOVE e WM_EXITSIZEMOVE, porque é muito lento e feio. Mas tente, certamente é mais do que alongar, talvez você goste =)

case WM_SIZE:
    // Save the new client area dimensions.
    m_ptViewportSize.x  = LOWORD(lParam);
    m_ptViewportSize.y = HIWORD(lParam);
    if( wParam == SIZE_MINIMIZED )
    {
        m_bAppSuspended = true;
        m_bMinimized = true;
        m_bMaximized = false;
    }
    else if( wParam == SIZE_MAXIMIZED )
    {
        m_bAppSuspended = false;
        m_bMinimized = false;
        m_bMaximized = true;
        OnResize();
    }
    else if( wParam == SIZE_RESTORED )
    {
        // Restoring from minimized state
        if( m_bMinimized )
        {
            m_bAppSuspended = false;
            m_bMinimized = false;
            OnResize();
        }
        // Restoring from maximized state
        else if( m_bMaximized )
        {
            m_bAppSuspended = false;
            m_bMaximized = false;
            OnResize();
        }
        else if( m_bResizing )
        {
            // Resizing in processs
            // You woldn't wanto to handle a massive stream of
            // WM_SIZE here because buffers resizing is very slow
        }
        else
        {
            // Resizing finished and you can handle it. For ex. with 
            // m_SwapChain->SetFullscreenState
            OnResize();
        }

    }
    return 0;

// WM_EXITSIZEMOVE is sent when the user grabs the resize bars.
case WM_ENTERSIZEMOVE:
    m_bAppSuspended = true;
    m_bResizing  = true;
    g_pTimer->Stop();
    return 0;
// WM_EXITSIZEMOVE is sent when the user releases the resize bars.
// Here we reset everything based on the new window dimensions.
case WM_EXITSIZEMOVE:
    m_bAppSuspended = false;
    m_bResizing  = false;
    g_pTimer->Start();
    OnResize();
    return 0;
Ivan Aksamentov - Saque
fonte
11
O tratamento de mensagens do Windows no .NET envolve a substituição System.Windows.Forms.Form.WndProc(). Ao trabalhar no XNA, você não tem acesso direto a Formpara substituir esse método. Embora seja possível, não é uma quantidade trivial de trabalho e teria que contornar o design do XNA.
Cypher
Alguém deve optar por tomar este caminho, esta lista de WM_ * constantes devem revelar-se útil: pinvoke.net/default.aspx/Constants/WM.html
Cypher
Como outros já disseram, eu ainda precisaria de uma maneira de causar um curto-circuito no "mecanismo" do XNA e fazê-lo desenhar novamente durante os eventos corretos. Pelo que posso dizer, o XNA meio que "dorme" durante o procedimento de redimensionamento.
Bradley Uffner