Dobra, panowie, bo już sam zacząłem off-top ciągnąć. Nie wiem do tej pory dlaczego SFML tak posysa, ale nie będę go używał — nie chce mi się szukać przyczyny, a robię wszystko tak jak to stoi w tutorialach. Zresztą po wynikach waszych testów jasno widać, że coś jest ewidentnie z nim nie tak.
Skorzystam z SDL, bo ten nie dość że działa wydajnie u wszystkich, to w dodatku da się w nim normalnie programować — lepiej napisać 5x więcej kodu i mieć wszystko z głowy, niż rwać włosy z głowy kombinując jak działa ta obiektowa, SFML-owa abominacja. Reasumując — problem rozwiązany, dzięki wielkie za pomoc i testy. ;)
Niżej jeszcze wyjaśnienia wcześniej podanych problemów z SDL (i rozwiązania).
Wcześniej podałem, że SDL ma problem z dezaktywacją (np. za pomocą Alt+Tab
) programu odpalonego w trybie wideo (np. 640x480). Okno powinno się zminimalizować, a po przywróceniu tryb wideo powinien zostać również przywrócony (tak działają normalne gry czy emulatory), natomiast ten zapętla minimalizację i przywracanie, powodując niekończące się miganie ekranów i trzeba zamknąć program, aby to szaleństwo się skończyło.
Można to rozwiązać na dwa sposoby. Pierwszy to przechwycenie zdarzenia SDL_WINDOWEVENT_MINIMIZED
, wyłączenie trybu fullscreen funkcją SDL_SetWindowFullScreen
, zmiana rozmiaru okna na jakiś własny i ustawienie nowej pozycji. Natomiast drugi sposób to wyłączenie opcji SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS
:
Kopiuj
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, '0');
Dzięki temu, SDL po dezaktywacji okna odpalonego w trybie wideo nie będzie próbował go minimalizować, a więc nie zapętli minimalizacji i przywracania. System sam zminimalizuje okno i zmieni rozdzielczość na desktopową, a po ponownej aktywacji okna programu (Alt+Tab
lub po kliknięciu w przycisk programu na pasku zadań), ładnie przywróci tryb wideo.
Miałem też problem z implementacją funkcji toggle fullscreen
. Po wyłączeniu trybu wideo, zmieniałem rozmiar okna na własny i centrowałem okno na głównym ekranie. Niestety SDL ani nie zmieniał rozmiaru okna (zostawało 640x480), ani nie centrował okna (zostawała pozycja 0,0
). Doszedłem jednak do takiego rozwiązania, że wyjście z trybu wideo centruje okno na ekranie i w większości przypadków rozmiar okna faktycznie się zmienia. W większości przypadków.
Okno chcę mieć bez obramowania, z możliwością przeciągania łapiąc za jego klienta. Do tego użyłem funkcji SDL_SetWindowHitTest
, podając własny callback, który zawsze zwraca SDL_HITTEST_DRAGGABLE
. Okazuje się, że jeśli jest ustawiony callback, to nie da się ukryć kursora — nawet w trybie wideo. Dlatego aby móc w trybie okienkowym pokazać kursor, należy podłączyć callback:
Kopiuj
SDL_SetWindowHitTest(AWindow, @MyHitTestCallback, nil);
a ustawiając okno na pełny ekran, odpinać go:
Kopiuj
SDL_SetWindowHitTest(AWindow, nil, nil);
Śmieszne jest też to, że gdy callback jest podłączony i program działa w trybie wideo, jego okno można nadal przeciągać na inny ekran. Nie wiem dlaczego SDL/Windows na to pozwala. Dlatego lepiej ten callback odpinać przy przejściu na fullscreen, a w nim dodatkowo sprawdzać swoje flagi i zwracać wartość SDL_HITTEST_NORMAL
, jeśli okno nie może być przeciągane. Czyli callback powinien wyglądać tak:
Kopiuj
function MyHitTestCallback(AWindow: PSDL_Window; const APoint: PSDL_Point; AData: Pointer): TSDL_HitTestResult; cdecl;
begin
if DisplaySize in [DISPLAY_FULL, DISPLAY_VIDEO] then
Result := SDL_HITTEST_NORMAL
else
Result := SDL_HITTEST_DRAGGABLE;
end;
DisplaySize
to moja zmienna przechowująca obecny tryb wyświetlania. DISPLAY_FULL
oznacza desktopowy tryb pełnoekranowy (zwykłe okno rozciągnięte na cały ekran), a DISPLAY_VIDEO
to ekskluzywny tryb wideo — w obu tych przypadkach przeciąganie ma być zablokowane.
W razie gdyby ktoś chciał się pobawić to w załączniku dorzucam swój testowy programik, w którym wszystko powyższe jest użyte. Kod jest napisany byle jak, byle sprawdzić czy wszystko czego potrzebuję działa poprawnie. Obsługa:
Esc — zamknięcie programu,
F11 — toggle fullscreen, przejście do trybu wideo 640x480 lub powrót do trybu okienkowego,
S, R, T — odpalenie różnych dźwięków na trzech różnych kanałach audio.
Rolką myszy zmienia się rozmiar okna — 1x, 2x, 3x oraz desktopowy pełny ekran. Mała uwaga — testowałem obsługę klawiatury, czytając stan klawiszy bezpośrednio z bufora (nie zdarzeniami). Dlatego jak się przytrzyma S
, R
lub T
, to dźwięk będzie w kółko puszczany od początku, a po zwolnieniu klawisza będzie się odgrywał do końca. Tak że to nie bug, to feature. :]