¿Cómo detengo el estiramiento durante el cambio de tamaño de la ventana en XNA?

8

En mi juego XNA en modo ventana, cuando el usuario cambia el tamaño de la ventana, el juego deja de actualizar la ventana y el último cuadro dibujado se estira y distorsiona hasta que el usuario suelta el mouse y se completa el cambio de tamaño.

¿Hay alguna manera de que el juego continúe ejecutándose "normalmente", actualizando marcos y redibujando la pantalla, durante el evento de cambio de tamaño?

Me doy cuenta de que mantener el bucle de renderizado mientras se cambia el tamaño puede no ser posible o recomendado debido a que los recursos administrados por hardware se crean y destruyen continuamente, pero ¿hay alguna forma de detener el feo estiramiento? Lo ideal sería dejar el marco existente sin escala en la esquina superior izquierda, o con una pantalla negra si eso no es posible.

Bradley Uffner
fuente
Registre un evento para cambiar el tamaño de la ventana y actualice la resolución de GraphicsDevice. Esto puede actualizar la relación de aspecto y corregir el estiramiento.
Gustavo Maciel
No sé acerca de C # / XNA, pero en C ++ / D3D solo tenía el bucle de renderizado ejecutándose en un hilo separado del hilo principal con el bucle de mensajes. El subproceso principal realiza el cambio de tamaño del búfer cuando se produce un evento de cambio de tamaño, sincronizado a través de un mutex.
1
Gustavo, ya manejo ese evento para otros propósitos en el juego. Desafortunadamente, no se dispara hasta que el usuario suelta el mouse cuando se completa el cambio de tamaño.
Bradley Uffner
Este par de preguntas / respuestas puede ser útil. Le indica cómo continuar renderizando (aunque no soluciona el estiramiento).
Andrew Russell

Respuestas:

3

Hay al menos 3 mensajes que puede rastrear.

  • WM_SIZE- cambio de tamaño de ventana, mini / maximización, cambio de pantalla completa / ventana. Deberá leer en wParam para averiguar qué sucedió exactamente y en lParam para el tamaño actual.
  • WM_ENTERSIZEMOVE - comienza a cambiar el tamaño de la ventana en modo ventana
  • WM_EXITSIZEMOVE - finaliza el cambio de tamaño de la ventana en modo ventana

Por lo general, no querrá cambiar el tamaño de su aplicación cada fotograma entre WM_ENTERSIZEMOVE y WM_EXITSIZEMOVE porque es demasiado lento y feo. Pero pruébalo, seguramente es mejor que estirar, tal vez te guste =)

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 - Drop
fuente
1
El manejo de mensajes de Windows en .NET implica la anulación System.Windows.Forms.Form.WndProc(). Cuando trabajas en XNA, no tienes acceso directo a a Formpara anular ese método. Si bien es posible hacerlo, no es una cantidad de trabajo trivial y tendría que eludir el diseño de XNA.
Cypher
Si alguien elige tomar este camino, esta lista de constantes wm_ * debería resultar útil: pinvoke.net/default.aspx/Constants/WM.html
Cypher
Como otros han dicho, aún necesitaría una forma de cortocircuitar el "motor" XNA y hacer que se vuelva a dibujar durante los eventos correctos. Por lo que puedo decir, XNA "se duerme" durante el procedimiento de cambio de tamaño.
Bradley Uffner