Grafika 3D
 
  Zarejestruj się
::  Newsy  ::  Pliki  ::  Twoje Konto  ::  Forum  ::
Menu
· Strona główna
· Forum
· Linki
· Lista u?ytkowników
· O nas...
· Pliki
· Statystyki
· Twoje Konto
Tutoriale
· API
· Matematyka
· Teoria
· Direct3D
· OpenGL
· Techniki
Kto Jest Online
Aktualnie jest 37 gość(ci) i 0 użytkownik(ów) online.

Jesteś anonimowym użytkownikiem. Możesz się zarejestrować za darmo klikając tutaj
Tutoriale - Techniki - Fullscreen

Witam. W sprawie trybów pełnoekranowych przy programowaniu grafiki 3D napłynęło chyba ostatnio najwięcej listów z całego świata więc aby sprostać waszym oczekiwaniom i pocieszyć tych najbardziej sfrustrowanych dzisiaj dowiemy się, jak tryb pełnoekranowy włączyć i jak z niego korzystać. Na samym początku wyjaśnijmy sobie, skąd bierze się problem większości dotyczący niemożności programowania pełnoekranowych aplikacji korzystających z Direct3D czy OpenGL pod systemem Windows. Zaznaczam od razu na początku także, że będzie to treść skierowana głównie do programistów pracujących na tym właśnie systemie, ponieważ co do innych - nie znam się za bardzo, więc nie będę się tutaj wymądrzał. Przechodząc zaś do sedna problemu...

Starzy wyjadacze robiący grafikę jeszcze za czasów starego, dobrego DOS-a doskonale wyczuwają różnicę pomiędzy trybem tekstowym a graficznym. Wiedzą czym charakteryzował się jeden i drugi tryb pracy karty graficznej i bez problemu potrafią sobie takie tryby na pewno wywołać. Programiści młodego pokolenia, przeważnie korzystający i piszący pod systemy Windows z serii 95 i następnymi takiej różnicy mogą już nie odczuwać i nawet nie do końca wiedzieć w czym tak naprawdę tkwi problem. A ponieważ kontakt z tymi starymi wyjadaczami jakiś tam maja więc zaczynają się nieporozumienia. Starzy programiści przyzwyczajeni do tego, że musieli sobie pod systemem DOS sami inicjalizować grafikę nie mogą się przyzwyczaić do systemu Windows a młodzi, którzy nasłuchali się od starych jakich to trzeba sztuczek, żeby przełączyć kartę w odpowiedni tryb graficzny szybko załamują ręce. Ból jednych i drugich tkwi często w bardzo prostej rzeczy a mianowicie nieświadomości, że - tutaj uwaga! Bo to ważne! Nieświadomości tego, że Windows po załadowaniu swojego całego środowiska pracuje już w trybie graficznym! Wiem, że to banał i każdy oczywiście będzie wiedział że Windows to grafika - pewnie nawet pani układająca pasjansa w wolnych chwilach w biurze. Ale wiedza ta jak na razie nie jest wystarczająca do tego, aby programować aplikacje graficzne pracujące i korzystające z dobrodziejstw pełnego ekranu. W czym tkwi zagadka? Otóż Windows jest systemem bardzo specyficznym, w którym nic nie da się narysować bez udziału tytułowych okien. Dla wyjadaczy, przyzwyczajonych do inicjalizowania trybu graficznego na piechotę okna są niepojęte jeśli chodzi o tryb pełnoekranowy - Jak to? pytają - tryb pełnoekranowy w oknie??? Młodych zapewne łatwiej będzie przekonać, ale ich często przeraża tryb pełnoekranowy i niemożliwość podglądnięcia sobie okien kompilatora, przy których czują się tak bezpiecznie. Tym artykułem jednak spróbujemy zaradzić na te bolączki, obawy i niewiedze.

Pytanie postawione na początku - czy da się pod Windows osiągnąć tryb pełnoekranowy? Oczywiście że tak, widzieliście przecież nie raz grając w najbanalniejsza grę korzystającą czy to z OpenGL czy z Direct3D. Nawet niektóre aplikacje, takie jak Corel, Intrernet Explorer czy nawet poczciwy VC++ potrafią korzystać z trybu pełnoekranowego ;). Żeby dobrze zrozumieć co i jak, trzeba sobie odpowiedzieć na podstawowe pytanie - czym jest tryb pełnoekranowy? Odpowiedz narzuca się natychmiast sama i jest zupełnie oczywista. W trybie pełnoekranowym, aplikacja, która akurat pracuje ma cały ekran dla siebie, nie udostępnia żadnego kawałka dla innego okna - można powiedzieć, że ma ekskluzywny dostęp do ekranu. Każda aplikacja, która będzie potrafiła cos takiego zrobić, zagarnąć cały ekran dla siebie będzie pracować w trybie pełnoekranowym, którego wszyscy tak bardzo pożądamy. W systemach takich jak DOS osiąganie trybu pełnoekranowego było zupełnie banalne - wystarczyło zainicjalizować dla karty jakikolwiek tryb graficzny i aplikacja od razu dostawała się do ekranu. Było o tyle łatwiej, że pod DOS-em, raczej nie było aplikacji, które pracowały jednocześnie - był to system, w którym bez stosowania rożnych sztuczek nie dawało się odpalać kilku programów na raz. W Windows jest to już możliwe bez większego problemu ale to niesie za sobą oczywiście problem dostępu do ekranu. Dostęp wielu programów na raz powoduje oczywiście to, że wszystko nam gwałtownie zwalnia, bo system musi obsłużyć wszystkie aplikacje i każdej dać jakiś kawałek. Jeśli jednak aplikacja uzyska ekskluzywny dostęp do ekranu, wtedy śpiewka już jest inna - koniec z dzieleniem się i aplikacja może w pełni wykorzystać możliwości takieg sposobu dostępu. Pod DOS-em istniała także inna ważna kwestia - możliwość bezpośredniego dostępu do pamięci video karty graficznej - można było do niej pisać bez pośredników i bardzo zyskiwać na wydajności pracy aplikacji rysującej. Pod Windows sprawa zmieniła się diametralnie, ponieważ brak jest już możliwości dostania się do pamięci video bezpośrednio (no może nie tak do końca), a przynajmniej nie należy tego robić w sposób zupełnie beztroski. Dzisiaj wszystko za nas załatwiają sterowniki urządzeń, dzięki którym nie musimy się martwic o to, jakie urządzenie mamy i które rejestry karty trzeba przeprogramować, żeby osiągnąć zamierzony efekt. Oczywiście odbija się to głęboką rysa na wydajności naszych aplikacji, ale nie ma co załamywać rak. Stopień komplikacji współczesnych urządzeń wyświetlających, takich jak akceleratory grafiki 3D i tak skutecznie powinien zniechęcić do bezpośredniego programowania zaawansowanych funkcji, ale jednocześnie daje do ręki potężna narzędzia, które są w wielu przypadkach o wiele szybsze niż najszybszy dostęp, idziemy więc na pewnego rodzaju kompromis - część obowiązków zawiązanych z wyświetlaniem i obliczaniem grafiki przejmie za nas akcelerator, pod warunkiem, że my nie będziemy już grzebać mu w pamięci.

Niestety wyboru wielkiego nie mamy i jeśli chcemy wydajnie programować pod Windows pozostaje nam się zgodzić na właśnie takie rozwiązanie. Tak więc nie będziemy się upierać przy ręcznym inicjowaniu trybu graficznego za pomocą bezpośredniego programowania sterownika karty graficznej (zwłaszcza że prawdopodobnie pod Windows 2000 czy XP i tak nam się nie uda bez pisania specjalnych sterowników) a skupimy się raczej na tym, jak osiągnąć efekt pełnego ekranu z tym co mamy, czyli z oknami. Zobaczycie sami ocenicie, czy takie rozwiązanie wam odpowiada.
Jak więc ruszyć tryb pełnoekranowy pod Widnows? Jak wiemy, każda aplikacja rysująca cos na ekranie korzysta w tym celu z okna. Dostaje się do karty poprzez interfejs urządzenia GDI, który pozwala się skupić na tym, co rysujemy a nie jak rysujemy dając nam uniwersalny dostęp do każdej karty graficznej na świecie. Jak zdajemy sobie doskonale sprawę nie będziemy rysować za pomocą GDI, bo szybszy byłby w takim przypadku pewnie i tak nasz stary 286 wyposażony w kartę VGA i oprogramowywany za pomocą bezpośredniego dostępu. My oczywiście zajmiemy się naszymi bibliotekami do grafiki trójwymiarowej czyli Direct3D i OpenGL. Te zaś mają bardzo interesującą właściwość - otóż, jeśli ustalić dla nich taki tryb pracy, że aplikacja będzie miała ekran tylko dla siebie zaczynają pracować o wiele bardziej wydajnie niż współdzieląc ekran z innymi aplikacjami, pomimo, że same pracują w oknie. Tak, tak moi drodzy - w oknie, a jednak na pełnym ekranie! A jak?

Otóż, żeby osiągnąć efekt pełnego ekranu wystarczy odpowiednio skonstruować dla naszej aplikacji okno. Okno takie będzie musiało spełniać kilka podstawowych cech:
  • po pierwsze - skoro ma być pełny ekran, to musi mieć ono rozmiary dokładnie takie, jakie ma ustawiony aktualny tryb graficzny,
  • po drugie - okno nie może posiadać menu, belki tytułowej oraz innych atrybutów typowych dla zwykłej aplikacji Windows,
  • po trzecie - okno takie musi się znajdować na samym szczycie z-porządku okien na pulpicie - po prostu musi być niejako najbliżej nas,
  • po czwarte - okno nie może być dzieckiem innego okna, musi być głównym oknem aplikacji.
Po zainicjalizowaniu takiego okna poinformujemy odpowiednio pakiet do grafiki trójwymiarowej, że może uzyskać bezpośredni dostęp do ekranu i już nasza aplikacja będzie pracować w sposób przez nas wymarzony - bez innych okien w tle, wypełniając nam cały ekran bajecznie kolorową animacją. Sprawa nie wygląda na skomplikowaną i taka też jest w istocie. Zmian wymaga głównie okno, które będzie musiało sprostać naszym wymaganiom no i pozostaje jeszcze kwestia rozdzielczości. Otóż doskonale wiemy, że każda szanująca się gra w 3D umożliwia rozgrywkę na ekranie w różnorakich rozdzielczościach, które użytkownik ustawia sobie na miarę możliwości własnego sprzętu i upodobania. Oczywistym faktem jest, że im większa rozdzielczość tym większe wymagania co do użytkowanego sprzętu. Z każdym wyższym trybem graficznym trzeba narysować na ekranie więcej pikseli i przepchać więcej danych przez magistrale danych. Ale w niektórych przypadkach efekt i ogólny wygląd scen jest oczywiście wart zachodu.

Wspomniałem na początku, że Windows po starcie swojego środowiska zaczyna pracować w trybie graficznym. Tryb ten ma ustawioną pewną rozdzielczość, która jest obsługiwana przez kartę. Rozdzielczość czym jest, każdy wie - charakteryzuje się dwoma, a w zasadzie dzisiaj już trzema parametrami: szerokością i wysokością ekranu w pikselach oraz ilością bitów na piksel ekranu określającą ilość możliwych do wyświetlenia kolorów. Rozdzielczości nie są dowolne - każda karta na świecie powinna przestrzegać pewnego standardu, który określa jakie rozdzielczości karta powinna obsługiwać. Są dopuszczalne dla różnych egzemplarzy pewne egzotyczne kombinacje wyżej wymienionych parametrów, ale dzisiaj nie są już praktykowane, ponieważ stanowią one tylko problem przy konstrukcji karty a i tak nie są przez nikogo używane. Te rozdzielczości, które są niejako "w standardzie" (VGA, SVGA) wynikają głównie z ułatwień w konstrukcji kart graficznych i tego, że takie a nie inne liczby pomagają na różne sposoby przyspieszyć transfery danych, co dla kart grafiki jest bardzo ważne. Większość standardowych rozdzielczości wszyscy znamy doskonale - 320x200, 640x480, 800x600, 1024x768, 1280x720 itd. Pierwszy tryb - 320x200 to już legenda. Pierwsze gry, które pokazały się na PC korzystały właśnie z niego. Był on bardzo prosty w obsłudze i na jego bazie powstało wiele gier i dem scenowych, które i dzisiaj wzbudzają zachwyt.
Windows zaraz po zainstalowaniu i uruchomieniu się standardowo używa trybu 640x480x16. Był to standard, który pojawił wraz z pierwszymi kartami VGA i jak na owe czasy był olbrzymim skokiem jakościowym w grafice komputerowej. Dzisiaj doskonale wiemy, że prawie nikt go nie używa ponieważ wygląda... zbyt brzydko! Po zainstalowaniu odpowiednich sterowników do karty graficznej, jeśli ona sama umożliwia przełączenie się w jakiś wyższy tryb graficzny każdy natychmiast wyciska z karty ile tylko może. I dzisiaj już standardową rozdzielczością dla mniejszych monitorów (<15") jest 800x600, dla większych 1024x768 i więcej - w zależności od wielkości monitora. Jeśli zaś chodzi o kolory to każdy już także używa więcej niż 256 kolorów (8 bitów na piksel). W zależności o możliwości karty graficznej dla określonego trybu można sobie włączyć 16, 24 albo najbardziej dzisiaj popularne 32 bity na piksel. Dlaczego tak trąbię o tych rozdzielczościach? Otóż pewnie każdy chciałby wiedzieć czy da się jakoś w Windows takie rozdzielczości przełączać - gry przecież to robią, więc czemu nie my? -jak stworzymy sobie już aplikację na pełnym ekranie to oczywistym staje się, że chcielibyśmy móc jeszcze sobie zmienić i rozdzielczość ekranu. Oczywiście, taka możliwość istnieje - a jak się do tego wszystkiego już zabrać już teraz i tylko u nas (jak w porządnej reklamie ;-)). No to startujemy, zapiąć pasy, wyrzucić fajki i przygotować kompilatory.

Po pierwsze - Okno

Jak wspominałem podstawą stworzenia aplikacji pełnoekranowej w Windows jest odpowiednio przygotowane okno. Poniżej przedstawiam przykładowy fragment kodu, który utworzy nam takiego cosia zgodne z naszymi wymaganiami:
// Register the window class
WNDCLASSEX wc;

wc.cbSize        = sizeof( WNDCLASSEX );
wc.style         = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc   = MsgProc;
wc.cbClsExtra    = 0L;
wc.cbWndExtra    = 0L;
wc.hInstance     = GetModuleHandle( NULL );
wc.hIcon         = NULL;
wc.hCursor       = NULL;
wc.hbrBackground = (HBRUSH) ( 2 );
wc.lpszMenuName  = NULL;
wc.lpszClassName = WND_FULLSCREEN_CLASS_NAME;
wc.hIconSm       = NULL;

RegisterClassEx( &wc );

HWND  hWnd = CreateWindowEx( 0, WND_FULLSCREEN_CLASS_NAME,
                             WND_FULLSCREEN_NAME,
                             WS_POPUP,
                             0, 0, 640, 480,
                             NULL, NULL,
                             wc.hInstance, NULL );
Te kawałki kodu powinny być nam już dosyć dobrze znane. Na początku wypełniany strukturę odpowiedzialną za klasę okna a następnie rejestrujemy ją w systemie. Nic nowego nam się tutaj nie pojawia a jeśli ktoś nie kojarzy co do czego, to wszystko jest pięknie wytłumaczone w lekcji z działu "API". Po zarejestrowaniu klasy okna przystępujemy do jego stworzenia. Tutaj najważniejszą rzeczą będzie czwarty parametr funkcji CreateWindowEx(). Jest to styl, z jakim tworzymy okno, u nas WM_POPUP. Utworzenie okna z takim stylem powoduje to, że nie będzie ono posiadało ani paska tytułowego (pomimo, że tytuł podajemy jako parametr funkcji), żadnych klawiszy do zamykania, maksymalizowania itp. oraz że nie będzie posiadało ramki. Po uruchomieniu programu po prostu otrzymamy na ekranie czarny prostokąt (ponieważ takie tło mamy ustawione w zarejestrowanej klasie okna). Rozmiary okna podane jako cztery następne parametry muszą ściśle odpowiadać parametrom trybu graficznego, jaki ustawimy do pracy dla naszej aplikacji, przy czym okno powinno się zaczynać w samym rogu ekranu (lewa góra - 0, 0) i mieć odpowiednią szerokość i wysokość (u nas dla przykładu 640 i 480). Za pomocą klasy okna jak i funkcji do jego tworzenia pozbawiamy okno menu, ikon i całej zbędnej w tym przypadku reszty.

Po drugie - rozdzielczość

Tryb pełnoekranowy kojarzy się z tym, że możemy sobie ustawić na karcie określony tryb graficzny, uruchomić i wyświetlić okno no i coś sobie rysować na ekranie bez udziału innych aplikacji. A jak przestawić w Windows tryb graficzny? - nic bardziej banalnego, robimy to jedną funkcją!
DEVMODE dmScreenSettings
memset( &dmScreenSettings, 0, sizeof( dmScreenSettings ));
dmScreenSettings.dmSize       = sizeof( dmScreenSettings );
dmScreenSettings.dmPelsWidth  = width;
dmScreenSettings.dmPelsHeight = height;
dmScreenSettings.dmBitsPerPel = color;
dmScreenSettings.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

if( ChangeDisplaySettings( &dmScreenSettings, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
{
  MessageBox( NULL,"Couldn't set video mode, program close", "ERROR", MB_OK | MB_ICONSTOP );

  return false;
}
Wspomniałem o jednej funkcji a tutaj mamy niezły kawał kodu - ale nie zrażajmy się tym - jak za chwilę będziemy mieli okazje się przekonać nic strasznego tak naprawdę się tutaj nie dzieje i tylko tak groźnie to wszystko wygląda. Naszą główną bohaterką w tym fragmencie jest funkcja Windows API o sugerującej wszystko nazwie - ChangeDisplaySettings(). Za jej pomocą będziemy mogli wyczyniać cuda z rozdzielczością w Windows. Przyjmuje ona tylko dwa parametry - przyjrzyjmy się zatem im bliżej. Pierwszy z nich to adres struktury DEVMODE, która będzie w swoich polach zawierać informacje niezbędne do uruchomienia pożądanego przez nas trybu graficznego. Jak spojrzeć do dokumentacji to opis a w szczególności ilość pól tej struktury może naprawdę przerazić najwytrwalszych i zaciętych maniaków. Na szczęście my nie musimy być za bardzo skrupulatni, ponieważ na początek wystarczy nam zaledwie inicjalizacja kilku pól, aby osiągnąć to, o co nam chodzi. A pól tych dokładnie będzie pięć:
memset( &dmScreenSettings, 0, sizeof( dmScreenSettings ) );
dmScreenSettings.dmSize       = sizeof( dmScreenSettings );
dmScreenSettings.dmPelsWidth  = width;
dmScreenSettings.dmPelsHeight = height;
dmScreenSettings.dmBitsPerPel = color;
dmScreenSettings.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
Pierwszą rzeczą jaką robimy z naszą strukturą jest wyczyszczenie jej zawartości, aby nie spotkały nas żadne niespodzianki podczas naszej zabawy z rozdzielczością. Robimy to znaną nam już poniekąd funkcją memset() - wypełnia ona po prostu obszar pamięci zajmowany przez strukturę wartościami 0. Następnie polu dmSize struktury DEVMODE przypisujemy jej rozmiar - pole to powinno zostać wypełnione aby funkcja zadziałała nam poprawnie. Mając tak przygotowaną strukturę można przystąpić do właściwej zabawy czyli ustalania konkretnych parametrów trybu graficznego, który mamy zamiar ustawić. Z opisu i kawałku kodu chyba jasno wynika co i do czego. Kolejno podajemy oczywiście szerokość ekranu w pikselach (dmPelsWidth), wysokość (dmPelsHeight) oraz ilość bitów przypadających na jeden piksel ekranu, określających ilość kolorów jakie piksel taki może przyjąć (pole dmBitsPerPel). Oczywiście wartości tutaj podane muszą posiadać jakiś sens i pochodzić niejako ze standardu, który definiuje poszczególne tryby graficzne możliwe do wyświetlenia. Podanie wartości bez sensu spowoduje po prostu błędne działanie funkcji ChangeDisplaySettings(), co chyba oczywiste i nic nam się nie zmieni. Dlatego też tutaj trzeba uważać co się podaje. Najlepiej wszystkie dostępne tryby sobie wyliczyć i ustawiać te, które można dla naszej karty. Ostatnim polem wypełnianym przez nas przy ustawianiu trybu graficznego jest pole o nazwie dmFields, które zawiera kombinację bitową określającą, które pola w strukturze, przy przetwarzaniu jej przez funkcję mają tak naprawdę znaczenie - po prostu jeśli wypełnili byśmy inne pola naszej struktury a nie ustawili w tym miejscu flagi, że pola te mają zostać wzięte pod uwagę to funkcja by je zignorowała - nie muszę mówić, że stałoby się podobnie z naszymi wcześniej ustawionymi wartościami nowego trybu graficznego. Dlatego też robimy odpowiednią kombinację takich flag - ich pełny spis oczywiście w dokumentacji Windwos API. Znaczenia poszczególnych flag przez nas użytych chyba nie muszę wyjaśniać.

Po ustawieniu wszystkich potrzebnych pól w naszej strukturze (dodajmy, że oczywiście nie musimy ustawiać wszystkich możliwych - tylko te, które będą miały istotne znaczenie, określone są wspomnianymi przed momentem flagami) możemy przystąpić do zmieniania parametrów naszego obrazu. Jak już wiemy służy do tego funkcja ChangeDisplaySettings(). Pierwszy z parametrów już sobie omówiliśmy, czas więc na drugi - tym razem będzie to flaga mówiąca o sposobie dokonywanej zmiany i co ma się z nią później stać. Możemy sobie więc na stałe zapamiętać naszą zmienioną rozdzielczość w rejestrach systemu, możemy sobie na przykład tylko przetestować czy nasza funkcja z podanymi parametrami zadziała poprawnie (funkcja bardzo przydatna). Nam przyda się jednak flaga o nazwie CDS_FULLSCREEN, czyli coś, co brzmi już bardzo przyjemnie. Jak wynika z dokumentacji, oznacza ona, że jeśli wykonanie funkcji zmieniającej rozdzielczość się powiedzie to ta zmiana będzie tymczasowa - do czasu zmiany parametrów ekranu po raz kolejny lub do czasu restartu systemu - wtedy zostaną przywrócone domyślne, zapamiętane gdzieś w rejestrze parametry obrazu. Dobrym zwyczajem powinno się stać przy pierwszym podejściu najpierw przetestowanie, czy nasza funkcja wykona się i zakończy sukcesem - dokonamy tego ustawiając najpierw flagę CDS_TEST i wywołując funkcję z adresem naszej struktury. Jeśli operacja zakończy się powodzeniem, możemy zastąpić drugi argument wartością CDS_FULLSCREEN, wywołać funkcję ponownie i przystąpić do działań na pełną skalę.

Czasami w naszej karierze programisty zdarza się, że napiszemy program w miarę poprawnie i uda się nam wyjść z niego w miarę normalny sposób, nie zakończony totalnym crashem systemu i twardym resetem ;). Zapewne też, jeśli mowa o grafice 3D i aplikacjach pełnoekranowych to zdarzy nam się zmienić rozdzielczość. Jak łatwo się domyśleć przy zamykaniu naszej aplikacji powstanie problem jeśli nasza aplikacja podczas pracy ustawiła sobie inny tryb graficzny niż normalnie był w Windows przed startem naszego programu - wyobraźmy sobie chociażby sytuację, kiedy na co dzień pracujemy w rozdzielczości 1024x768 a nasza aplikacja przy starcie przełączyła się w 640x480 dla przykładu. Jeśli zamkniemy okno i zostawimy to samemu sobie to łatwo sobie wyobrazić co ujrzymy na ekranie - niezłą kaszanę mówiąc najprościej i coś, z czym nie da się pracować. Sytuacji takiej trzeba jakoś zaradzić - wystarczy oczywiście przywrócić tryb graficzny, jaki panował przed uruchomieniem naszej aplikacji. Dróg jest wiele - możemy na przykład zapamiętać tryb pracy przed startem a następnie go przy powrocie z aplikacji ustawić znaną nam już metodą, możemy brutalnie zrestartować komputer i liczyć, że samo się zrobi... ale ponieważ jesteśmy porządni i lubimy wychodzić elegancko z opresji, więc i tym razem sobie poradzimy. Nic nie będziemy musieli zapamiętywać ani restartować. Wystarczy, że posłużymy się naszą funkcją do zmiany rozdzielczości ponownie, ale zamiast zapamiętywać jakieś parametry to po prostu przywrócimy domyślny tryb, który system ma zapisany w rejestrach. Wystarczy tylko zamiast adresu struktury zawierającej dane trybu graficznego podać jako pierwszy argument funkcji ChangeDisplaySettings() wartość NULL i po sprawie. Ktoś może zapytać, co z flagą w takim razie - tutaj wartość tak naprawdę nie będzie miała znaczenia, ponieważ chcemy raczej, żeby było, jak było. Dla bezpieczeństwa więc najlepiej ustawić ten sam tryb co poprzednio - czyli CDS_FULLSCREEN. Niby ustawienia te będą tymczasowe, ale ponieważ i tak po restarcie będzie to samo, więc nikt nie zauważy różnicy. Ale flag możecie oczywiście tutaj użyć całą gamę.

I to w zasadzie byłoby wszystko jeśli chodzi o samo API systemu Windows - jak widać poradziliśmy sobie zupełnie bez pomocy Direct3D czy OpenGL bo tak naprawdę ich pomoc nie była nam tutaj zupełnie do niczego potrzebna, poza tym daremnie u nich szukać takiej, ponieważ jej po prostu nie oferują. Jeśli zaś chodzi o tryb pełnoekranowy z wykorzystaniem tych bibliotek to pewnej uwagi wymaga w zasadzie tylko Direct3D, który paradoksalnie tym razem sprawia niejakie kłopoty, choć to wyrób tej samej firmy jakby na to nie patrzeć co samo API systemu, OpenGL za to poradzi sobie tutaj bez problemu - jemu wystarczy tylko odpowiednio ustawić klasę okna, o której mówiliśmy na samym początku.

Z Direct3D natomiast trzeba się będzie trochę pobawić w momencie tworzenia obiektu urządzenia renderującego. Funkcja CreateDevice() obiektu Direct3D jako jeden z parametrów przyjmuje strukturę o nazwie D3DPRESENT_PARAMETERS. Jednym z pól tej struktury jest twór o nazwie Windowed. Jemu, w zależności od tego, w jakim trybie będzie pracować nasza aplikacja trzeba odpowiednio ustawić wartość - pole to może przyjmować wartości TRUE lub FALSE, więc wielkiego problemu raczej nie ma... po prostu jeśli ma być fullscreen to dajemy FALSE (lub na odwrót jeśli zajdzie potrzeba). Oczywiście w momencie tworzenia urządzenia musimy także znać rozdzielczość, w jakiej przyjdzie nam pracować - pociąga to za sobą ustawienie kolejnych pól wyżej wspomnianej struktury, BackBufferWidth, BackBufferHeight, BackBufferFormat. Należy zauważyć, że są to rozmiary bufora tylnego, do którego renderujemy i potem wrzucamy na ekran widoczny dla nas, ale dla porządku i żeby obyło się bez problemu ustawimy tutaj poprawne i oczekiwane wartości, no chyba że chcemy osiągnąć jakieś specjalne efekty - wtedy droga wolna, ale co się będzie działo? Kto to może wiedzieć ;). Można się również pobawić polami FullScreen_RefreshRateInHz oraz FullScreen_PresentationInterval, które niewątpliwie będą miały wpływ na szybkość działania naszej aplikacji, jednak używanie domyślnych wartości na sam początek do nauki zupełnie wystarczy - jak już opanujecie podstawy to można kombinować z lepszym lub gorszym skutkiem. My nie będziemy się zajmowali w tym artykule takimi szczegółowymi analizami, bo to nie jest naszym celem - my tylko nakreślamy na co należy zwrócić uwagę i gdzie szukać ewentualnych kłopotów, co przy fullscreenie nie będzie wcale takie proste.

I to będzie w zasadzie tyle, jeśli chodzi o Direct3D - jak widać nie jest tego wiele, ale zawsze to coś, co przeszkadza. Przypominam oczywiście o odpowiednim typie okna dla danego trybu pracy aplikacji - znaczenie ma tutaj oczywiście tylko tryb fullscreen w którym obowiązuje tylko jeden styl okna - WS_POPUP. Jeśli chodzi o aplikacje okienkowe to macie zupełną dowolność i możecie zrobić praktycznie co wam się żywnie podoba. Na sam koniec może pozostać jedynie pytanie w jakiej kolejności dokonywać poszczególnych operacji. Tutaj nie ma jakiegoś jasno określonego schematu i tak jak uznamy, tak będzie dobrze, byle działało i przynosiło zamierzony skutek. Najwięcej możliwości może budzić kwestia najzupełniej banalna - czyli czy najpierw tworzyć odpowiedniego rozmiaru okno a potem zmieniać rozdzielczość czy odwrotnie. Tutaj musicie sami zdecydować, co wam się bardziej będzie podobało - ja nie pomogę.

I to byłoby na tyle - mam nadzieję, że choć trochę przybliżyłem fam tajemnice trybu fullscreen w Windows, który budzi ogromne emocje, sądzą po ilości próśb o artykuł. Mam teraz nadzieję na chwilę oddechu ;)

Na sam koniec przypomnijmy jeszcze o czym należy pamiętać:
  • po pierwsze - klasa okna, szczególnie ważna przy trybie fullscreen,
  • po drugie - w przypadku Direct3D należy uważać w momencie tworzenia obiektu urządzenia renderującego i ustawić mu odpowiednie parametry za pomocą struktury D3DPRESENT_PARAMETERS,
  • po trzecie - debug. Ponieważ w trybie fullscreen będzie on raczej niemożliwy do zrealizowania, więc od razu na samym początku trzeba przemyśleć sprawę jakiegoś systemu informacji o błędach, z tym, że od razu odradzam okna dialogowe, ponieważ w Direct3D mogą wystąpić - hm... powikłania ;). Najlepiej mieć jakim system trace-ów, który będzie wpisywał odpowiednie komunikaty do plików na dysku,
  • po czwarte zmiana rozdzielczości - pamiętajmy, że po powrocie z programu trzeba po sobie posprzątać i przywrócić to co było.
Oczywiście odpowiednie kody przykładowe znajdziecie w projekcie w dziale z plikami - zarówno dla OpenGL jak i Direct3D. Zapraszam do ściągania i analizowania. A potem - do dzieła!


Kod źródłowy (glFullscreen.zip)

Kod źródłowy (dxFullscreen.zip)

©Copyright by Robal   



Tutoriale - Techniki
Nasze newsy s� w RSS: backend.php
PHP-Nuke Copyright © 2005 by Francisco Burzi. This is free software, and you may redistribute it under the GPL. PHP-Nuke comes with absolutely no warranty, for details, see the license.
Tworzenie strony: 0.04 sekund

:: Layout strony został stworzony przez www.nukemods.com w oparciu o styl phpbb2 Helius, którego autorem jest Cyberalien ::