Bitmapy, wczytywanie plików, double buffer 1 Wstęp teoretyczny
Transkrypt
Bitmapy, wczytywanie plików, double buffer 1 Wstęp teoretyczny
Grafika komputerowa 2D Instrukcja laboratoryjna 5 Temat: Bitmapy, wczytywanie plików, double buffer Przygotował: dr inż. Grzegorz Łukawski, mgr inż. Maciej Lasota, mgr inż. Tomasz Michno 1 Wstęp teoretyczny Biblioteka Allegro wraz z wywołaniem funkcji set_gfx_mode tworzy w pamięci bitmapę o nazwie screen, reprezentującą obszar ekranu na którym można rysować. Biblioteka dostarcza również możliwość tworzenia własnych bitmap przez użytkownika. Możemy je podzielić na: • Memory Bitmap (standardowa bitmapa przechowywana w pamięci RAM) • Sub Bitmap (bitmapa potomna, będąca częścią bitmapy-rodzica) • Video Memory Bitmap (specjalny rodzaj bitmap, wykorzystywany np. w grach, dostosowany do sprzętowego wspomagania niektórych operacji) • System Bitmap (specjalny rodzaj bitmap, który zawiera część cech zwykłych bitmap (np. przechowywanie w pamięci RAM) oraz bitmap typu video) Więcej o różnicach pomiędzy powyższymi typami bitmap: http://www.allegro.cc/manual/4/api/bitmap-objects/ Każda bitmapa w Allegro jest reprezentowana przez typ BITMAP, który ma następującą strukturę: typedef struct BITMAP int w, h; int clip; int cl, cr, ct, cb; clip !=) unsigned char *line[]; - rozmiar bitmapy w pikselach (w- szer., h- wys.) - !=0, jeśli włączono obcinanie - współrzędne prostokąta obcinającego (używane jeśli - wskaźniki na początek każdej linii obrazu 1.1 Tworzenie bitmap Bitmapy można tworzyć wywołując funkcję CreateBitmap: BITMAP *create_bitmap(int width, int height); gdzie: width – szerokość height – wysokość 1/6 Jeśli tworzenie zakończyło się pomyślnie, funkcja zwraca wskaźnik na bitmapę, w przeciwnym wypadku wartość NULL. Utworzone bitmapy należy zawsze usuwać z pamięci za pomocą funkcji destroy_bitmap: void destroy_bitmap(BITMAP *bitmap); Inne przydatne funkcje: BITMAP *create_bitmap_ex(int color_depth, int Utworzenie zwykłej bitmapy o podanej width, int height); w parametrze color_depth głębi kolorów BITMAP *create_sub_bitmap(BITMAP Utworzenie sub-bitmapy, jako parametry *parent, int x, y, width, height); należy podać: wskaźnik na bitmapę- rodzica, oraz prostokąt obcinający - punkt startowy (x,y) oraz rozmiar (width, height) BITMAP *create_video_bitmap(int width, int Utworzenie bitmapy typu video-bitmap height); BITMAP *create_system_bitmap(int width, int Utworzenie bitmapy systemowej height); void set_clip_rect(BITMAP *bitmap, int x1, int Ustawienie prostokąta obcinającego dla y1, int x2, int y2); bitmapy void set_color_depth(int depth); Ustawienie głębi bitowej dla ekranu aplikacji i bitmap, należy wywoływać ją przed funkcją set_gfx_mode() (na początku aplilacji) 1.2 Obsługa plików graficznych Biblioteka Allegro posiada zaimplementowane funkcje służące do odczytu i zapisu plików graficznych. Obsługiwane formaty to: BMP, PCX, TGA i LBM. Do wczytywania bitmapy służy funkcja load_bitmap: BITMAP *load_bitmap(const char *filename, RGB *pal); gdzie: filename – ścieżka dostępu do pliku 2/6 pal – tablica (o rozmiarze 256), która będzie przechowywała paletę obrazu; można użyć zmiennej typu PALETTE. Każdą wczytaną bitmapę należy po użyciu usuwać z pamięci za pomocą destroy_bitmap. Przykład użycia (zaczerpnięty z dokumentacji: http://www.allegro.cc/manual/4/api/loading-imagefiles/load_bitmap): BITMAP *bmp; PALETTE palette; ... bmp = load_bitmap("image.pcx", palette); if (!bmp) abort_on_error("Couldn't load image.pcx!"); ... destroy_bitmap(bmp); Bitmapy można zapisywać do pliku za pomocą save_bitmap: int save_bitmap(const char *filename, BITMAP *bmp, const RGB *pal); gdzie: filename – ścieżka do pliku do zapisu bmp – wskaźnik na bitmapę, która ma zostać zapisana pal – paleta (można ją uzyskać za pomocą funkcji get_palette(PALETTE p)). 1.3 Kopiowanie prostokątnych obszarów pomiędzy bitmapami W celu skopiowania prostokątnego obszaru jednej bitmapy do drugiej bitmapy, wywołujemy funkcję blit: void blit(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height); gdzie: source – bitmapa źródłowa dest – bitmapa docelowa (bitmapa źródłowa i docelowa może też być tą samą bitmapą) source_x, source_y – lewy górny punkt kopiowanego obszaru dest_x, dest_y – lewy górny punkt obszaru docelowego width, height – szerokość i wysokość prostokąta Funkcja blit jest wykorzystywana w technice Doble Buffering'u (Podwójnego Buforowania). Polega ona na używaniu do płynnego wyświetlania obrazu na ekranie dwóch buforów o tym samym 3/6 rozmiarze. Bufory wyświetlane są na ekranie naprzemiennie, przy czym rysowanie klatki odbywa się zawsze na niewidocznym buforze. Dzięki temu unika się m. in. migotania obrazu i artefaktów. W bibliotece Allegro jednym buforem może być bitmapa screen, a drugim dowolna bitmapa o rozmiarze ekranu. Obraz rysowany jest na drugiej bitmapie, a następnie za pomocą funkcji blit jest kopiowany na ekran (pierwszą bitmapę – screen). 1.4 Duszki – Sprite'y Sprite'y są specjalnymi rodzajami bitmap, które najczęściej służą do tworzenia postaci lub innych elementów wyświetlanych na ekranie (np. z wykorzystaniem transformacji 2D). W bibliotece Allegro obsługuje się je identycznie jak zwykłe bitmapy. Dodatkowo udostępnione są następujące funkcje: void draw_sprite(BITMAP *bmp, BITMAP Rysuje sprite'a na bitmapie bmp w punkcie *sprite, int x, int y); określonym przez x oraz y void stretch_sprite(BITMAP *bmp, BITMAP Pozwala narysować sprite'a, zmieniając jego *sprite, int x, int y, int w, int h); rozmiar. Parametry: w – nowa szerokość h – nowa wysokość void rotate_sprite(BITMAP *bmp, BITMAP Rysuje sprite'a obróconego o kąt angle *sprite, int x, int y, fixed angle); void pivot_sprite(BITMAP *bmp, BITMAP Rysuje sprite'a obróconego *sprite, int x, int y, int cx, int cy, fixed angle); względem punktu cx, cy o kąt void draw_sprite_v_flip(BITMAP BITMAP *sprite, int x, int y); *bmp, Rysuje sprite'a z obróceniem pionowym void draw_sprite_h_flip(BITMAP BITMAP *sprite, int x, int y); *bmp, Rysuje sprite'a z obróceniem poziomym void draw_sprite_vh_flip(BITMAP BITMAP *sprite, int x, int y); *bmp, Rysuje sprite'a i poziomym z obróceniem angle pionowym void rotate_scaled_sprite(BITMAP *bmp, Rysuje sprite'a obróconego o kąt angle oraz BITMAP *sprite, int x, int y, fixed angle, fixed przeskalowanego przez współczynnik scale scale); void pivot_scaled_sprite(BITMAP *bmp, Rysuje sprite'a obróconego o kąt angle BITMAP *sprite, int x, int y, int cx, int cy, fixed względem punktu cx, cy oraz przeskalowanego angle, fixed scale); przez współczynnik scale 4/6 void stretch_blit(BITMAP *source, BITMAP Funkcja blit z możliwością zmiany rozmiaru *dest, int source_x, source_y, source_width, prostokąta na bitmapie docelowej source_height, int dest_x, dest_y, dest_width, dest_height); W powyższych funkcjach przy obrotach pojawia się typ fixed, który przyjmuje wartości od 0 do 256 (0 – brak obrotu, 256 – pełny obrót). Aby ułatwić sobie zadanie, warto zadeklarować zmienną typu float, przechowującą kąt, a następnie użyć funkcji itofix(liczba), która zamieni ją na typ fixed, np.: float kat = 0; // ... rotate_sprite(screen, bitmapa, 0, 0, itofix(kat)); Zmienną kat możemy zwiększać lub zmniejszać o małe kroki, dzięki czemu uzyskamy płynny obrót (należy pamiętać, że kąt może mieć wartości tylko z przedziału od 0 do 256), np.: kat += 0.5; if (kat > 256) kat = 0; Przezroczystość tła sprite'a: Często sprite'y służą do przechowywania np. postaci lub innych elementów planszy w grach. Pojawia się wtedy problem z tłem, które po wstawieniu obrazka do aplikacji przesłania elementy za postacią. Twórcy biblioteki Allegro wymyślili bardzo prosty sposób na ten problem – uznali, że kolor różowy (255, 0, 255) będzie tak rzadko używany, że uznają go za domyślny kolor przezroczystości przy rysowaniu sprite'a Jak widać na przykładzie – sprite biegnącego konia ma różowe tło, po narysowaniu go w programie 5/6 z użyciem draw_sprite, jest ono automatycznie usuwane. 2 Zadania 1. Napisz program, który będzie: ◦ wyświetlał obraz wczytany z pliku w całym oknie aplikacji ◦ wyświetlał na tle pierwszego obrazka dowolny sprite wczytany z dysku ◦ sprite powinien być przesuwany po ekranie w dowolny sposób (automatycznie, bez interakcji użytkownika) 2. Napisz program który będzie: ◦ wczytywał dowolny plik z dysku ◦ pozwalał z użyciem dowolnie wybranego zestawu klawiszy na wykonywanie jednej z podanych operacji: obrotu, skalowania lub odwrócenia poziomego i pionowego ◦ zapisywał zawartość ekranu do dowolnego pliku 6/6