DirectDraw - pierwsze starcie

Naukę budowania aplikacji Windows z wykorzystaniem biblioteki DirectX powinniśmy rozpocząć od poznania metod tworzenia grafiki 2D. Przedstawiamy zatem obiekt DirectDraw i piszemy pierwszą aplikację.

Naukę budowania aplikacji Windows z wykorzystaniem biblioteki DirectX powinniśmy rozpocząć od poznania metod tworzenia grafiki 2D. Przedstawiamy zatem obiekt DirectDraw i piszemy pierwszą aplikację.

DirectDraw jest tylko jednym z wielu obiektów składających się na całą funkcjonalność biblioteki, ale to właśnie od niego najczęściej rozpoczyna się pracę z DirectX. Wszystkim, którzy przed zgłębieniem tajników programowania DirectDraw chcieliby się więcej dowiedzieć o bibliotece DirectX oraz technologii COM, która stanowi jej podstawę, polecamy tekst "Wprowadzenie do DirectX", zamieszczony w miniportalu PCWK_PROG 5/2004 na naszych płytach.

Tworzenie grafiki i animacji 2D możemy zrealizować kilkoma metodami, w zależności od wersji wykorzystywanej biblioteki DirectX: używać modułu DirectDraw z siódmej wersji biblioteki DirectX, gdzie DirectDraw pojawił się po raz ostatni (ale za to w najlepszym wydaniu), albo wykorzystać moduł Direct3D z nowszych wersji DirectX.

Każde z rozwiązań ma wady i zalety, różnią się też stopniem zaawansowania. My na początek wybierzemy moduł DirectDraw, bo jego obsługa jest bardzo prosta, wystarczy umiejętność tworzenia szkieletu aplikacji okienkowej. A to przecież już potrafimy robić po lekturze wcześniejszych tekstów o programowaniu aplikacji Windows.

Zagadnienia, które poznamy przy okazji odkrywania możliwości DirectDraw, w znacznej mierze ułatwią późniejszą pracę z modułem Direct3D, zbudowanym na podstawie DirectDraw. Obecnie mamy utworzyć aplikację, która przejmie kontrolę nad pracą głównej karty graficznej, a następnie narysuje coś na ekranie za pomocą funkcji GDI. Program nie będzie tworzyć okna, ponieważ nie jest ono nam jeszcze potrzebne. Funkcji DirectDraw nie obudujemy też specjalną klasą, lecz umieścimy je bezpośrednio w ciele funkcji WinMain, aby na początku nie zaciemniać kodu programu.

DirectDraw i jego budowa

Moduł DirectDraw stanowi rdzeń graficznej części biblioteki DirectX.

Rysunek 1. Obiekty modułu DirectDraw.

Rysunek 1. Obiekty modułu DirectDraw.

W przeciwieństwie do modułu Direct3D, jest jej integralną częścią od chwili pojawienia się pierwszej wersji biblioteki. Na jego funkcjonalność składają się obiekty COM (rys. 1). Pierwszy i najważniejszy to DirectDraw. Tworzy go niemal każda aplikacja, która korzysta z biblioteki DirectX, a już na pewno wszystkie, które zajmują się wyświetlaniem grafiki za jej pomocą. Mówimy tu o starszych programach. W nowszych wersjach biblioteki, gdzie moduł DirectDraw i Direct3D zostały połączone, inicjalizowanie graficznego środowiska aplikacji przebiega nieco inaczej. Obiekt DirectDraw często jest utożsamiany z kartą graficzną. Zostaje utworzony z uwzględnieniem konkretnego sterownika, a do funkcji pracujących na rzecz obiektu DirectDraw mamy zapewniony dostęp przez interfejsy. Do momentu pojawienia się biblioteki DirectX 7.0 mieliśmy do czynienia zaledwie z trzema odsłonami obiektu DirectDraw. Pierwszy reprezentowany był przez interfejs IDirectDraw, kolejny przez IDirectDraw2, następny przez IDirectDraw4, aż do najnowszego - IDirectDraw7.

Powierzchnie

Rysunek 2. Budowa i uruchomienie aplikacji wykorzystującej DirectDraw.

Rysunek 2. Budowa i uruchomienie aplikacji wykorzystującej DirectDraw.

Kolejny obiekt modułu DirectDraw to DirectDrawSurface, najczęściej nazywany po prostu powierzchnią (surface). Reprezentuje ciągły fragment pamięci systemowej lub pamięci wideo (pamięć karty graficznej), w którym możemy umieszczać grafikę wyświetlaną później na ekranie. Powierzchni używamy do przechowywania grafiki najróżniejszego typu i formatu, od zwyczajnych obrazów stosowanych w grach 2D, po tekstury o bardzo różnych formatach pikseli. Wyróżniamy także powierzchnie specjalnego rodzaju, jak bufory wyświetlania, bufory głębokości czy powierzchnie nakładkowe. Z obiektem powierzchni pracujemy za pośrednictwem interfejsu IDirectDrawSurface7.

Obszary obcinające

Następny obiekt to DirectDrawClipper. Możemy podłączyć go do wybranej powierzchni. Jego zadanie polega na obcinaniu grafiki kopiowanej na powierzchnię, gdy wychodzi częściowo poza jej obszar. Jest szczególnie przydatny w przypadku aplikacji okienkowych. Pozwala bowiem uniknąć zamalowania pulpitu, gdy odnosimy się do całego obszaru głównej powierzchni. Działa wyłącznie z funkcjami kopiującymi DirectDraw - funkcje GDI z niego nie korzystają. Z obiektem komunikujemy się za pomocą interfejsu IDirectDrawClipper.

Palety kolorów

Czwartym obiektem jest DirectDrawPalette. Używamy go, gdy pracujemy w trybach paletowych, w których na jeden piksel przypada nie więcej niż osiem bitów. Paleta składa się z wzorców koloru wysyłanych do karty graficznej i może ich zawierać 2, 4, 16 lub 256, co odpowiada 1-, 2-, 4- i 8-bitowemu trybowi graficznemu. Każdy wzorzec to grupa czterech bajtów, odpowiednio po jednym bajcie dla czerwonego, zielonego i niebieskiego elementu składowego koloru. Czwarty bajt może zawierać informację o danym wzorcu lub zostać użyty do przenoszenia wartości kanału alfa (przezroczystości). Paletę można podłączać do dowolnej powierzchni, ale najczęściej jest podłączana do powierzchni głównej. Paletowa powierzchnia nie przenosi informacji o kolorze poszczególnych pikseli. Wartość piksela określa numer wzorca koloru, który ma zostać użyty do jego narysowania. Z obiektem DirectDrawPalette pracujemy za pomocą interfejsu IDirectDrawPalette. Obecnie paletowych trybów wyświetlania już się w zasadzie nie używa, jednak palety nadal się stosuje m.in. do tekstur.

Wszystkie obiekty modułu DirectDraw potrafią ze sobą współpracować. Ich poprawne działanie zależy od sposobu utworzenia i dalszego sterowania właściwościami. Podstawowym obiektem jest DirectDraw, który daje początek pozostałym trzem. Obszar obcinający możemy także - w razie konieczności - utworzyć w sposób niezależny, tj. z pominięciem obiektu DirectDraw.

Obiekt DirectDraw

Dzięki DirectDraw Test Application z pakietu SDK można poznać zasady wykorzystywania biblioteki DirectX bez potrzeby pisania własnych aplikacji testowych.

Dzięki DirectDraw Test Application z pakietu SDK można poznać zasady wykorzystywania biblioteki DirectX bez potrzeby pisania własnych aplikacji testowych.

Każda aplikacja wykorzystująca bibliotekę DirectX do wyświetlania obrazu musi utworzyć obiekt DirectDraw. Reprezentuje on kartę graficzną i to za jego pomocą przełączamy tryby graficzne, decydujemy o sposobie współpracy aplikacji z systemem, sprawdzamy właściwości karty, pobieramy informacje o aktualnych współrzędnych plamki monitora i wykonujemy mnóstwo innych operacji. Chcąc powołać do życia obiekt DirectDraw, stosujemy funkcje DirectDrawCreate lub DirectDrawCreateEx. Wybór ma w tym wypadku bardzo duże znaczenie dla programu, który musi dostęp do urządzenia renderującego grafikę 3D. Obiekt DirectDraw utworzony za pomocą pierwszej funkcji nie zawiera interfejsu IDirect3D7, za to pozwala pobrać jeden z czterech interfejsów obiektu DirectDraw. Druga funkcja umożliwia utworzenie obiektu DirectDraw, do którego uzyskamy dostęp wyłącznie za pomocą interfejsu IDirectDraw7, jednak w zamian uzyskujemy z jego poziomu możliwość pobrania interfejsu IDirect3D7. Strata starszych interfejsów DirectDraw jest bez znaczenia. Najnowszy udostępnia opcje poprzednich interfejsów i wiele nowych rozwiązań. Ostatecznie zdecydujemy się na wykorzystanie funkcji DirectDrawCreateEx, ze względu na to, iż z biegiem czasu pokażemy sobie, jak wzbogacić grafikę 2D za pomocą modułu Direct3D. Poniżej pokażemy jednak, jak użyć i jednej, i drugiej funkcji do utworzenia obiektu DirectDraw i pobrania interfejsu IDirectDraw7. W ten sposób łatwiej będzie zrozumieć ideę interfejsów obiektów COM. Oto nagłówki funkcji, które możemy znaleźć w pliku ddraw.h:

HRESULT WINAPI DirectDrawCreate(

GUID FAR *lpGUID

LPDIRECTDRAW FAR *lplpDD

IUnknown FAR *pUnkOuter);

HRESULT WINAPI DirectDrawCreateEx(

GUID FAR *lpGUID

LPVOID *lplpDD

REFIID iid

IUnknown FAR *pUnkOuter);

DirectX Caps Viewer z pakietu SDK pozwala zbadać, jaką funkcjonalność oferuje karta graficzna i jakie operacje dostarczane są przez bibliotekę DirectX.

DirectX Caps Viewer z pakietu SDK pozwala zbadać, jaką funkcjonalność oferuje karta graficzna i jakie operacje dostarczane są przez bibliotekę DirectX.

Jako parametr lpGUID podajemy adres struktury GUID określającej globalny, unikatowy identyfikator sterownika karty graficznej, na podstawie którego zostanie utworzony obiekt DirectDraw. Jeżeli podamy wartość NULL, zostanie użyty aktualnie aktywny, podstawowy sterownik ekranu. Możemy podać również identyfikator DDCREATE_HARDWAREONLY, który oznacza, że żadna z operacji wykonywanych przez DirectDraw nie będzie emulowana. Gdy żądana operacja nie jest obsługiwana sprzętowo przez kartę, po prostu nie zostanie wykonana (będzie pominięta). Drugi identyfikator to DDCREATE_EMULATIONONLY. Oznacza on, że DirectDraw będzie emulował wszystkie operacje i nawet wtedy, gdy mogą być wykonywane wielokrotnie szybciej za pomocą sprzętowych układów karty graficznej. Jako parametr lplpDD pierwszej funkcji podajemy adres wskaźnika mogącego przechowywać adres interfejsu IDirectDraw. Najlepiej, gdy taki wskaźnik jest typu LPDIRECTDRAW, zdefiniowanego w następujący sposób:

typedef struct IDirectDraw FAR *LPDIRECTDRAW;


Zobacz również