Przełączanie trybu fullscreen-window - źle odtwarza rozmiar okna


#1

Witam!
Mam grę napisaną w C++ w DirectX. Przełączanie między oknem a full screen robiłem do tej pory “offline”, czyli gdy użytkownik wybrał opcję “przejdź do trybu full screen” wyświetlałem informację, że musi wyjść z gry i ponownie ją uruchomić, aby mieć full screen. Podobnie przy powrocie z full screen do okna.
Obecnie chciałbym zmienić tę procedurę i przełączać się między oknem a full screen “online”, czyli zaraz po kliknięciu przez użytkownika opcji. Gra po prostu od razu się przełączy do odpowiedniego trybu graficznego i nie trzeba z niej wychodzić.
Napisałem funkcję i ogólnie działa poprawnie - za wyjątkiem jednej rzeczy. Po powrocie z full screen okno rysuje się mniejsze niż powinno być. Gra działa w rozdzielczości 800x600 i taki też rozmiar obszaru klienta w oknie mam po jej uruchomieniu. Gdy jednak wrócę z full screen, to rozmiar obszaru klienta wynosi 784x562 (sprawdzam przez ::GetClientRect).
Nie mam za bardzo pomysłu, jak odtwarzać oryginalny rozmiar klienta, czyli 800x600 - proszę o pomoc.

Poniżej kod funkcji zmieniającej rozdzielczość. Funkcja jest wywoływana z innej funkcji, która po tym usuwa zasoby, robi reset urządzenia DirectX i odtwarza zasoby (jeśli trzeba, dołączę również tę nadrzędną funkcję).
Pozdr
Yazilim

void CGUI::ChangeWindowStyle(bool bFullScreen)
{
	HWND hwnd = CGUI::GetGUI()->GetMainWindowHandle();

	LONG lWndStyle = ::GetWindowLong(hwnd, GWL_STYLE);

	if (bFullScreen)
	{
		RECT rect;
		::GetClientRect(hwnd, &rect);
		lWndStyle = WS_POPUP | WS_VISIBLE;
		::SetWindowLong(hwnd, GWL_STYLE, lWndStyle);
	}
	else // powrot do window
	{
		// nowy styl
		lWndStyle &= ~WS_POPUP;
		lWndStyle |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;

		// zmiana stylu
		::SetWindowLong(hwnd, GWL_STYLE, lWndStyle);

		// BŁĄD: okno po odtworzeniu jest mniejsze - trzeba go powiększyć do 800x600 - w jaki sposób? 

		// obszar klienta 800 x 600
		RECT rect = { 0, 0, 800, 600 };
		AdjustWindowRect(&rect, lWndStyle, false);

		SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 800,
			600, SWP_NOMOVE | SWP_NOACTIVATE);
	}
}

ChangeDisplaySettings vs SetFullscreenState
#2

Nie piszę w DirectX i winapi, ale zmiana z 800x600 na 784x562 brzmi jakby była różnica w dodatkowej przestrzeni okna (np górna belka).

To:


Mówi o różnicy pomiędzy client rect a window rect.

Workaround to pewnie zapisanie sobie window/client rect przed zmianą i wpisanie tego (w dobre miejsce) po zmianie, ale pewnie ktoś kto się na tym zna powie Ci, że używasz złych funkcji lub flag.

Przynajmniej wiesz gdzie zacząć poszukiwania :smiley:


#3

Dzięki za podpowiedź! Zrobiłem następujące zmiany:

  • Dodałem testową instrukcję sprawdzającą rozmiar obszaru window - wyszło mi 816 x 638.
  • Usunąłem AdjustWindowRect (nie jest potrzebne)
  • W instrukcji SetWindowPos wpisałem 816 i 638 zamiast 800 i 600, co było wcześniej (w opisie funkcji jest informacja, że mają to być wymiary window, a nie klienta).
    Niestety teraz sytuacja jest taka, że po powrocie z full screen otrzymuję rozmiar klienta 796 x 564, a okna 812 x 612, czyli jakieś dziwne rozmiary. Co prawda lepiej niż było poprzednio (przedtem klient był 784x562), ale jednak trochę brakuje do 800x600. Co ciekawe, wyliczyłem sobie różnice i takie też wartości dodałem do 816 i 638, ale to nic nie dało, tak jakby rozmiar okna był cały czas przez coś wymuszany.

#4

OK sam sobie odpowiadam :slight_smile: Procedura po moich poprawkach była już dobra, ale trzeba ją było wywołać po operacjach DirectX (usunięciu zasobów, resecie urządzenia i odtworzeniu zasobów).