D3D device release bei DestroyWindow notwendig?



  • Hey!

    Ich möchte zur Laufzeit mein d3dPP.hDeviceWindow ändern. Das wollte ich so machen:

    DestroyWindow(hWnd);
    hWnd = CreateWindow("Main", 0, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0);
    d3dPP.hDeviceWindow = hWnd;
    d3dDev->Reset(&d3dPP);
    

    Funktioniert aber nicht richtig, wahrscheinlich weil das Fenster geändert wird, obwohl das device noch nicht released wurde. Komme ich also nicht darum herum?

    d3dDev->Release();
    DestroyWindow(hWnd);
    hWnd = CreateWindow("Main", 0, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0);
    d3dPP.hDeviceWindow = hWnd;
    d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dPP, &d3dDev);
    

    ?

    Und muss ich das hier schreiben:

    UnregisterClass("Main", 0);
    DestroyWindow(hWnd);
    RegisterClass(&windowClass);
    

    Oder ist das egal?

    Danke!
    MfG



  • Waere nicht eine andere Reihenfolge sinnvoller?

    - neues Fenster erstellen
    - D3D freigeben
    - D3D neu erstellen in neuen Fenster
    - altes Fenster schliessen

    f'`8k

    Autocogito

    Gruß, TGGC (making great games since 1992)



  • Schreib das ganze Modular, so hab ichs mit meinem OpenGL-Framework auch gemacht.
    Die Vorteile:
    Du kannst einzelne Steps besser ausführen oder wiederholen.
    Debuggen fällt einfacher (finde ich).
    Du kannst später ohne Probleme z.Bsp. auch OpenGL einbinden und den "alten" Code wiederverwenden.
    Mein Aufbau:

    Klasse Window:
    CreateWindow(): Erstellt das blanke Win32-Fenster. Nimmt einen Zeiger auf das Interface 3DFactory als Parameter
    KilLWindow(): Löscht die WndClass und gibt das Fenster frei

    Klasse 3DGLFactory, abgeleitet von 3DFactory:
    Create(): Erzeugt den OpenGL-Context und übernimmt Initialisierungen wie Antialising und VSync.
    Kill(): Zerstört nur den OpenGL-Context.
    In C kannst du es ja mit einzelnen Funktionen machen.

    Mit diesem Konstrukt ist es relativ einfach, das Fenster zu zerstören und neu aufzubauen. Aber generell würde ich einfach das Fenster komplett zerstören und neu basteln.
    rya.



  • Danke für die Tips.

    MfG

    EDIT:
    Hmm @TGGC, scheint nicht hinzuhauen, danach kann ich nicht mehr minimieren, der Desktop flackert nur hindurch:

    wc.lpfnWndProc = MsgProc;
    	wc.lpszClassName = "Main2";
    
    	RegisterClass(&wc);
    
    	d3dPP.hDeviceWindow = CreateWindow("Main2", 0, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0);
    
    	d3dDev->Reset(&d3dPP);
    
    	UnregisterClass("Main", 0);
    	DestroyWindow(windowHandle);
    

    Meine Frage war ja, ob ein Reset bei einem window change ausreichen würde, oder ob man um ein Release & Create nicht herumkommt...

    MfG



  • Ok dann nehm ich mal an, dass es ohne erneutem CreateDevice nicht geht.
    Noch eine Frage:

    Wird d3dPP.hDeviceWindow benötigt? Werd aus der msdn Hilfe ned ganz schlau. Wenn ich es nicht initialisiere, passt trotzdem alles, zumindest im fullscreen mode.

    MfG



  • So bisschen Fehlercodes abfragen usf. waere sicher nicht verkehrt. f'`8k

    Autocogito

    Gruß, TGGC (making great games since 1992)



  • Bezieht sich vermutlich nicht auf die letzte Frage. CreateDevice gibt keinen Fehlercode zurück, wenn ich d3dPP.hDeviceWindow weglasse.



  • Reset reicht zum wechseln zw. FullScreen und Windowed modus. Jedoch nicht wenn Du z.B. während der Fenstermodus läuft die Auflösung ändern willst. Denn beim erstellen des Direct3D Devices musst Du ja das Handle vom Fenster übergeben, das ist natürlich beim neu-erstellen eines Fensters nichtmehr valid. Edit: Mit Reset() wird ja nicht das ganze Direct3DDevice neu erstellt und so wird wahrscheinlich ein neues Window-Handle einfach ignoriert. Leider ist das soviel ich weiss nicht dokumentiert.

    Du kannst auch versuchen mit MoveWindow zu arbeiten, das ist aber meines erachtens nicht so eine schöne Angelegenheit.

    Da ich sowieso relativ API-Unabhänig programmiere mach ich da so:

    Direct3D Surfaces etc. releasen.
    Direct3D runterfahren (komplett).
    Fenster zerstören.
    Fenster neu erstellen.
    Direct3D mit neuem Fenster-Handle neu initialisieren.
    Direct3D Surfaces etc. neu laden.

    Gruss, Andi

    Edit:

    TGGC:

    - neues Fenster erstellen
    - D3D freigeben
    - D3D neu erstellen in neuen Fenster
    - altes Fenster schliessen

    Ich denke nicht dass es sinvoll ist, kurzzeitig zwei Fenster zu haben wenn man doch nur eines braucht. Weil da muss man dann zwei Handles speichern und aufpassen mit der Window-Prozedur.



  • hier stand müll



  • Jo danke Andi. Aber sobald ich DestroyWindow() aufrufe, schließt sich auch mein Programm...

    Deshalb:

    while(message.message != WM_QUIT)
        Hauptschleife
    

    Wie könnte ich das am elegantesten verhindern?

    MfG



  • Hast du nen WinProc (Message-Handler)?
    Dann füg das WM_QUIT dort ein und benachrichtige eine Funktion einer Klasse, dass das Fenster geschlossen hat. Dann prüfst du ne Variable, ob das Programm geschlossen werden soll, oder nur das Fenster neu gebaut wird. Und für die while-Schleife nimmst eine andere Bedingung.
    rya.



  • Das versteh ich nicht. WM_QUIT wird doch von PeekMessage() in der Hauptschleife empfangen. In meinem MessageHandler hat das doch nix zu suchen? Da wird ja nur auf WM_DESTROY reagiert.

    Globale Variablen oder nen Singleton möchte ich eben vermeiden.

    MfG



  • Andi001 schrieb:

    Ich denke nicht dass es sinvoll ist, kurzzeitig zwei Fenster zu haben wenn man doch nur eines braucht.

    Wenn man nur eines braucht, warum will man es dann ueberhaupt wechseln? f'`8k

    Autocogito

    Gruß, TGGC (making great games since 1992)



  • Jo hast recht... hab mich vertan -.- Naja nimm halt einfach ne andere abfrage für deine schleife und lass WM_QUIT raus...

    EDIT: Aber WM_QUIT wird doch nur durch ::PostQuitMessage() ausgelöst? Warum beendet sich dann deine Anwendung wenn du das Fenster zerstörst?

    The WM_QUIT message is not associated with a window and therefore will never be received through a window's window procedure. It is retrieved only by the GetMessage or PeekMessage functions.
    rya.



  • @TGGC
    Um die Fenstergröße zu ändern, wenn man in den Fenstermodus geht. Der Benutzer könnte ja die Desktop-Auflösung geändert haben.

    @Scorcher24

    LRESULT WINAPI MsgProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	if(message == WM_DESTROY)
    		PostQuitMessage(0);
    
    	return DefWindowProc(windowHandle, message, wParam, lParam);
    }
    

    Ich werd wohl einfach PeekMessage() in meiner Hauptklasse aufrufen.

    int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
    {
        Game game;
        game.Tick();
    }
    

    MfG

    EDIT:
    Ich weiß grad echt nicht, warum ich nicht einfach MoveWindow() verwende. Sollte doch funktionieren... 🙄



  • Man braucht keine neues Fenster, um die Größe zu verändern. Warum probierst du es nicht einfach aus, mit der Maus das Fenster auseinander zu ziehen und stellst fest, dass es geht, einfach so? Um die Auflösung anzupassen reicht dann auch ein Reset.



  • Ich mein aber die Fenstergröße und Position anzupassen, wenn die Anwendung im Fenstermodus ist, damit das Fenster dann in der Mitte liegt.

    Achja, warum funktioniert das nicht:

    SetWindowLong(windowHandle, GWL_STYLE, WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE);
    SetWindowPos(windowHandle, HWND_NOTOPMOST, 0, 0, 640, 480, SWP_FRAMECHANGED);
    

    Der STYLE wird nicht verändert.

    MfG



  • Weiß ich doch nicht. Ich benutze .Net und kenne nicht die äquivalenten Windows API aufrufe. Ich kann mein Form resizen und verschieben. Du musst dafür kein neues Fenster erstellen.



  • Jo hab ich auch eben rausgefunden 🙄
    Die Frage war ja ned direkt an dich gerichtet.

    MfG

    EDIT:
    Ich frag das lieber im WINAPI Forum



  • TGGC schrieb:

    Andi001 schrieb:

    Ich denke nicht dass es sinvoll ist, kurzzeitig zwei Fenster zu haben wenn man doch nur eines braucht.

    Wenn man nur eines braucht, warum will man es dann ueberhaupt wechseln? f'`8k

    Autocogito

    Gruß, TGGC (making great games since 1992)

    Aus dem Grund wie ich weiter oben in meinem Post geschrieben habe. Z.B. OpenGL<->Direct3D Renderer-Wechsel, nicht zu vergessen Window-Style änderungen (Fullscreen ohne Border, Fenstermodus mit Border etc.). Sollte Dir eigentlich klar sein, weil Du ja schon so lange hier bist...

    Wegen dem anderen Problem: Das Programm schliesst sich, weil Du wahrscheinlich die WM_DESTORY-Message abfängst. Immer wenn Du mit DestroyWindow() ein Fenster zerstörst, bekommt dessen Window-Prozedur natürlich die WM_DESTROY-Nachricht. Reagiert deine WindowProzedur mit dem Beendes des Programms darauf, ist dann natürlich nicht nur das Fenster geschlossen 🙂

    Edit:

    Hier ein kleines Schnippsel aus meinem Prog was bei der Lösung helfen könnte:

    case WM_DESTROY:
             // Wenn die Auflösung gewechselt wird, wird das Fenster zerstört.
             // Dies wird jedoch von Platform::createWindow()/Platform::destroyWindow()
             // schon richtig gehandhabt. Also mache ich einfach nichts, da das Fenster
             // schon richtig zerstört wurde. So wird keine PostQuitMessage(0) geschickt,
             // die das ganze Programm beenden würde.
             break;
          case WM_CLOSE:
             // Löst ein QuitEvent aus.
             PostQuitMessage(0);
             return 0;
    

    Edit 2: (uhm bin heute nur am Editieren^^)

    Also das mit der PostQuitMessage(0) ist halt so, dass man normalerweise in der Schleife guckt ob die Message == WM_QUIT ist und reagiert darauf mit dem beenden des Programms. Sendet man also bei WM_DESTROY ein Quit-Signal, wird das ganze Programm beendet. Bei mir wird dabei halt dann ein QuitEvent an die Applikation gesendet.


Anmelden zum Antworten