Comment arrêter l'étirement pendant le redimensionnement de la fenêtre dans XNA?

8

Dans mon jeu XNA en mode fenêtré, lorsque l'utilisateur redimensionne la fenêtre, le jeu cesse de mettre à jour la fenêtre et la dernière image dessinée est étirée et déformée jusqu'à ce que l'utilisateur relâche la souris et que le redimensionnement soit terminé.

Existe-t-il un moyen de faire fonctionner le jeu "normalement", en mettant à jour les cadres et en redessinant l'écran, pendant l'événement de redimensionnement?

Je me rends compte que garder la boucle de rendu en cours pendant le redimensionnement peut ne pas être possible ou recommandé car les ressources gérées par le matériel sont-elles continuellement créées et détruites, mais y a-t-il un moyen d'arrêter l'étirement laid? Idéalement, en laissant le cadre existant non mis à l'échelle en haut à gauche, ou avec un écran noir si ce n'est pas possible.

Bradley Uffner
la source
Enregistrez un événement pour le redimensionnement de la fenêtre et mettez à jour la résolution GraphicsDevice. Cela peut mettre à jour le rapport hauteur / largeur et corriger l'étirement.
Gustavo Maciel
Je ne connais pas C # / XNA, mais en C ++ / D3D je viens de faire tourner la boucle de rendu dans un thread séparé du thread principal avec la boucle de message. Le thread principal effectue le redimensionnement du tampon lorsqu'un événement de redimensionnement se produit, synchronisé via un mutex.
1
Gustavo, je gère déjà cet événement à d'autres fins dans le jeu. Malheureusement, il ne se déclenche qu'après que l'utilisateur a relâché la souris lorsque la redimensionnement est terminé.
Bradley Uffner
Cette paire question / réponse pourrait être utile. Il vous indique comment continuer le rendu (bien qu'il ne corrige pas l'étirement).
Andrew Russell

Réponses:

3

Il y a au moins 3 messages que vous pouvez suivre.

  • WM_SIZE- redimensionnement de la fenêtre, mini / maximisation, commutation plein écran / fenêtre. Vous devez lire dans wParam pour savoir ce qui s'est exactement passé et lParam pour la taille actuelle.
  • WM_ENTERSIZEMOVE - commencer le redimensionnement de la fenêtre en mode fenêtré
  • WM_EXITSIZEMOVE - fin de redimensionnement de la fenêtre en mode fenêtré

Habituellement, vous ne voudrez pas redimensionner votre application à chaque image entre WM_ENTERSIZEMOVE et WM_EXITSIZEMOVE parce que c'est trop lent et laid. Mais essayez-le, c'est sûrement bien que l'étirement, peut-être que vous l'aimerez =)

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
la source
1
La gestion des messages Windows dans .NET implique la substitution System.Windows.Forms.Form.WndProc(). Lorsque vous travaillez dans XNA, vous n'avez pas d'accès direct à un Formpour remplacer cette méthode. Bien qu'il soit possible de le faire, ce n'est pas une quantité de travail insignifiante et devrait contourner la conception de XNA.
Cypher
Si quelqu'un choisit de prendre ce chemin, cette liste de constantes wm_ * devrait s'avérer utile: pinvoke.net/default.aspx/Constants/WM.html
Cypher
Comme d'autres l'ont dit, j'aurais toujours besoin d'un moyen de court-circuiter le "moteur" XNA et de le faire dessiner à nouveau lors des événements corrects. D'après ce que je peux dire, XNA "s'endort" pendant la procédure de redimensionnement.
Bradley Uffner