|
Autor: Worm
Data: 4 Marzec 2001
Intro
Tym artykułem chciałbym rozpocząć pierwszą część serii artykułów na
temat programowania z wykorzystaniem bibliotek DirectX w Visual C++. Seria
adresowana jest dla początkujących, więc wszystko będę dokładnie opisywał.
W pierwszej lekcji zajmiemy sie DirectDraw i grafiką 2D.
Do dzieła!
Spróbujemy napisać program który wyświetli nam plik graficzny (bitmapę)
w trybie DirectDraw. Utwórz nowy Obszar Roboczy i nazwij go 'Kurs DirectX',
utwórz w nim nowy projekt i nazwij go 'Lekcja1'. Następnie dodaj pliki
'ddraw.lib', 'dxguid.lib', 'lekcja1.cpp' i 'tlo.bmp'. Po obejrzeniu działania
programu możemy przejść do analizy kodu.
#include <windows.h>
#include <ddraw.h>
//Dodajemy dwa pliki
nagłówkowe wymagane abyśmy mogli korzystać z większości funkcji
LPDIRECTDRAW lpDD; //Deklarujemy
obiekt DirectDraw
LPDIRECTDRAW4 lpDD4; //Deklarujemy
obiekt DirectDraw4
LPDIRECTDRAWSURFACE4 lpDDSEkran; //Deklarujemy
powierzchnię podstawową
HWND okno; //Deklarujemy okno do inicjalizacji programu
HDC kontekst; //Deklarujemy kontekst
urządzenia
LRESULT CALLBACK PetlaKomunikatow(HWND, UINT, WPARAM,
LPARAM);
//Deklarujemy funkcję 'PetlaKomunikatow"
której użyjemy do przechwytywania zdarzeń
char klasa[] = "nazwa_klasy";
//Aby się nie powtarzać w dalszej części kodu, tworzymy
sobie zmienną w której przechowujemy nazwę klasy okna
int WINAPI WinMain(HINSTANCE naszprogram, HINSTANCE,
LPSTR, int tryb)
{
//WinMain to główna funkcja programu, uruchamiana
razem z nim.
//W parametrze pierwszym (tzn. HINSTANCE naszprogram) deklarujemy instancję
naszego programu.
WNDCLASS KlasaOkna;
KlasaOkna.lpszClassName = klasa;
KlasaOkna.hInstance = naszprogram;
KlasaOkna.lpfnWndProc = PetlaKomunikatow;
KlasaOkna.style = CS_OWNDC;
KlasaOkna.lpszMenuName = NULL;
KlasaOkna.hIcon = LoadIcon(NULL, IDI_WINLOGO);
KlasaOkna.hCursor = LoadCursor(NULL, IDC_ARROW);
KlasaOkna.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
KlasaOkna.cbClsExtra = 0;
KlasaOkna.cbWndExtra = 0;
//Tu ustawiamy poszczególne parametry okna.
RegisterClass(&KlasaOkna);
//Rejestrujemy klasę okna (trzeba to zrobić)
okno = CreateWindow( klasa,
"Programowanie DirectX",
WS_EX_TOPMOST|WS_POPUP,
0,
0,
800,
600,
NULL,
NULL,
naszprogram,
NULL
);
//Używamy funkcji CreateWindow aby stworzyć okno
programu...
ShowWindow(okno, tryb);
//...i wyświetlamy je na ekranie
/v/ Tutaj zaczyna się
inicjalizacja DirectDraw! \v\
DirectDrawCreate(NULL, &lpDD, NULL); //Tworzymy
obiekt DirectDraw o nazwie lpDD
lpDD->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpDD4);
//Pobieramy interfejs DirectDraw4 (aby wykorzystać
możliwości DirectX'a od wersji 6.0)
lpDD->Release(); //Zwalniamy obiekt lpDD,
bo nie będzie już potrzebny
lpDD4->SetCooperativeLevel(okno, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
//Ustawiamy tryb współpracy przed chwilą stworzonego
obiektu lpDD4 z naszym programem
lpDD4->SetDisplayMode (800, 600, 16, 0, NULL);
// Ustawiamy tryb pracy 800x600x16 bit
DDSURFACEDESC2 ddsd;
//Deklarujemy opis powierzchni na której będziemy
wyświetlać grafikę
ZeroMemory(&ddsd, sizeof(ddsd));
//Zerujemy zakres pamięci wykorzystywany przez
opis powierzchni ddsd
ddsd.dwSize = sizeof(ddsd);
//Ustawiamy właściwość .dwSize tak, żeby miała
rozmiar opisu powierzchni ddsd
ddsd.dwFlags = DDSD_CAPS;
//Włączamy flagę mówiącą o tym, że wykorzystamy
strukturę DDSD_CAPS
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
//informujemy, że opis powierzchni ddsd odnosi
się do powierzchni podstawowej
if (DD_OK==lpDD4->CreateSurface(&ddsd,&lpDDSEkran, NULL))
MessageBox(okno,
"Powierzchnia stworzona :)","Powierzchnia",MB_OK);
//Tworzymy powierzchnię podstawową lpDDSEkran
z wykorzystaniem opisu powierzchni ddsd,
//następnie wyświetlamy komunikat jeśli operacja zakończy się sukcesem
HDC hdcmem;
HBITMAP hbmp;
//Deklarujemy kontekst 'hdcmem' oraz bitmapę 'hbmp'
hdcmem=CreateCompatibleDC(NULL);
//Ta linia kodu tworzy drugi kontekst, o takiej
strukturze jak nasz podstawowy o nazwie 'kontekst'
hbmp=(HBITMAP)LoadImage(naszprogram, "tlo.bmp", IMAGE_BITMAP,
800, 600, LR_LOADFROMFILE);
//Ładowanie pliku 'tlo.bmp', rozciągnięcie go
do rozmiaru 800x600 oraz zapamiętanie go w hbmp
SelectObject(hdcmem, hbmp); //Skopiowanie zawartości
hbmp do kontekstu hdcmem
lpDDSEkran->GetDC(&kontekst); //Pobranie
kontekstu urządzenia, aby dało się go za chwilę użyć
BitBlt(kontekst,0,0,800,600,hdcmem,0,0,SRCCOPY);
//Skopiowanie zawartości kontekstu 'hdcmem'
do kontekstu 'kontekst' - czyli wyświetlenie obrazka
DeleteObject(hbmp); //Usunięcie
obiektu 'hbmp', aby już nam nie przeszkadzał
DeleteDC(hdcmem); //Usunięcie kontekstu 'hdcmem'
- nie będzie już potrzebny
lpDDSEkran->ReleaseDC(kontekst); //Zwolnienie
głównego kontekstu
MSG komunikat;
for(;;)
{
if (PeekMessage(&komunikat,NULL,0,0,PM_REMOVE))
{
if (komunikat.message==WM_QUIT
|| komunikat.message==WM_KEYDOWN) break;
TranslateMessage(&komunikat);
DispatchMessage(&komunikat);
}
} //To jest pętla komunikatów, dzięki której
komputer reaguje na nasze polecenia
lpDDSEkran->Release();
lpDD4->RestoreDisplayMode();
lpDD4->Release();
//Zwolnienie powierzchni ekranu, przywrócenie
trybu graficznego, zwolnienie obiektu lpDD4
return komunikat.wParam; //Wartość
którą zwraca funkcja WinMain
} //Koniec funkcji WinMain
LRESULT CALLBACK PetlaKomunikatow (HWND okno, UINT
komunikat, WPARAM wParam, LPARAM lParam)
{
switch (komunikat)
{
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return( DefWindowProc (okno, komunikat, wParam,
lParam));
}
return 0;
}
//Pętla komunikatów odpowiadająca na nasze reakcje
//====THE
END czyli KONIEC====\\
\v/ (Stąd możesz skopiować kod bezpośrednio do edytora) \v/
\v/ (Tak wygląda efekt działania naszego programu) \v/
Zakończenie
Dzięki powyższemu kodowi zainicjalizowaliśmy i zwolniliśmy tryb DirectDraw.
Myślę, że wyświetlenie bitmapy na ekranie po przejrzeniu tego arta nie
będzie już stwarzało problemu. Już wkrótce następna część serii programowania
z wykorzystaniem DirectX. Acha - program wymaga zainstalowanych bibliotek
DirectX w wersji przynajmniej 5.0.
!
Materiały
wykorzystane w tym artykule: lekcja1.zip
!
|