![]() |
![]() ![]()
Autor artykułu: mgr Jerzy Wałaszek, wersja1.0 |
©2010 mgr
Jerzy Wałaszek |
Grafika komputerowa ma olbrzymie zastosowanie w informatycznie - praktycznie całe współczesne oprogramowanie użytkowe pracuje w trybie graficznym. Naukę programowania grafiki rozpoczniemy od biblioteki SDL (ang. Simple Directmedia Library), która jest darmowo dostępna w Internecie. Biblioteka ta udostępnia środowisko graficzne dla programów. Jednakże nie posiada zdefiniowanych funkcji do tworzenia grafiki na poziomie pikseli. Dlatego bibliotekę SDL uzupełnimy opracowaną w naszej szkole biblioteką newgfx.
Dla celów zajęć na kole informatycznym przygotowałem następującą procedurę instalacji:
Ściągnij na swój dysk archiwum
SDL z naszego serwera i rozpakuj je.
Wewnątrz znajdziesz katalog SDL. Otwórz go. Zawartość będzie następująca:
Katalogi include i lib skopiuj do katalogu MinGW wewnątrz instalacji CodeBlocks.
Plik biblioteki dynamicznej SDL.dll skopiuj do katalogu Windows/System32. Jeśli katalog ten jest dla ciebie niedostępny, to plik SDL.dll musi być w tym samym katalogu co program exe korzystający z biblioteki SDL. W przypadku Code::Blocks jest to katalog bin/Debug lub bin/Release wewnątrz katalogu projektowego.
Uruchom Code::Blocks, wybierz Create a new project, w okienku dialogowym zaznacz kategorię jako Win32 GUI Project i dalej postępuj standardowo. Na koniec w edytorze powinieneś mieć szablon programu okienkowego Windows - nie przejmuj się tym, gdyż zaraz zastąpimy go czymś innym.
Do katalogu projektowego skopiuj z archiwum SDL 2 pliki newgfx (jeden jest programem w C++ z kodem biblioteki, drugi jest plikiem nagłówkowym).
Wybierz z menu opcję Project/Build options. W oknie dialogowym kliknij w zakładkę Linker settings i przekopiuj do prawego pola Other linker options poniższy tekst:
-lmingw32
-mwindows
-lSDLmain
-lSDL
Wybierz z menu opcję Project/Add files i za jego pomocą dodaj pliki newgfx.h oraz newgfx.cpp.
Usuń z edytora tekst programu Windows i wklej poniższy kod, który stanie się szablonem programu SDL:
// Plik szablonowy SDL // (C)2011 Koło Informatyczne // I LO w Tarnowie //------------------------------- #include "newgfx.h" int main(int argc, char *argv[]) { if(!SDL_Init(SDL_INIT_VIDEO)) { atexit(SDL_Quit); SDL_Surface * screen = SDL_SetVideoMode(320, 240, 32, SDL_HWSURFACE); if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen); // tutaj wstawiamy program graficzny for(Sint32 y = 0; y < screen->h; y++) for(Sint32 x = 0; x < screen->w; x++) if((x % 10) && (y % 10)) gfxPlot(screen,x,y,0xff0000); else gfxPlot(screen,x,y,0x00ffff); if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); SDL_UpdateRect(screen, 0, 0, 0, 0); // oczekujemy klawisza ESC int waiting = 0; do { SDL_Event event; while (SDL_PollEvent(&event)) if ((event.type == SDL_QUIT) || ((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_ESCAPE))) waiting = 1; } while(!waiting); } return 0; } |
Skompiluj i uruchom program. Jeśli nie popełniłeś żadnego błędu, to dostaniesz poniższe okienko z motywem kraty:
Na koniec z menu wybierz opcję File/Save project as template i w okienku dialogowym podaj nazwę dla szablonu SDL. Od tej pory dostęp do projektu SDL będziesz miał poprzez opcję Create a new project/User templates.
Program szablonowy został tak zaprojektowany, aby umożliwiał tworzenie prostej, statycznej grafiki w SDL. Poniżej krótko opisujemy jego podstawowe bloki funkcjonalne.
#include "newgfx.h" |
Plik nagłówkowy newgfx.h daje nam dostęp do wszystkich funkcji SLD oraz do procedur graficznych biblioteki newgfx. | ||||||||||||||||
int main(int argc, char *argv[]) |
Funkcja główna musi posiadać dokładnie taką postać, chociaż nie korzystamy z jej argumentów. | ||||||||||||||||
if(!SDL_Init(SDL_INIT_VIDEO)) |
Na początku programu wywołujemy funkcję inicjalizacji
biblioteki SDL. Jako parametr przekazuje się, które z jej podsystemów
mają być inicjowane. Tutaj inicjujemy podsystem wideo. Wszystkie
możliwości, to:
|
||||||||||||||||
atexit(SDL_Quit); |
Tutaj ustawiamy funkcję, która zostanie wywołana przy zakończeniu programu. SDL_Quit wykonuje sprząta po bibliotece SDL. | ||||||||||||||||
SDL_Surface * screen = SDL_SetVideoMode(320,240,32,SDL_HWSURFACE); |
SDL_Surface to najważniejsza struktura SDL. Zawiera ona
informacje o powierzchni graficznej, po której program rysuje.typedef struct { Uint32 flags; SDL_PixelFormat * format; int w, h; Uint16 pitch; void * pixels; SDL_Rect clip_rect; int refcount; } SDL_Surface; Powierzchnię rysunkową inicjujemy za pomocą funkcji SDL_SetVideoMode(). Kolejne parametry tej funkcji określają rozmiary okna w poziomie i pionie, liczbę bitów na piksel oraz parametry powierzchni graficznej. |
||||||||||||||||
if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen); ... if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); |
Pomiędzy wywołaniami tych funkcji umieszczamy nasz program graficzny, który dokonuje rysowania. Ich zadaniem jest sprawdzenie, czy powierzchnia rysunkowa musi być zablokowana dla innych wątków. Jeśli tak, to ją blokują przed rysowaniem i zwalniają po rysowaniu. | ||||||||||||||||
SDL_UpdateRect(screen, 0, 0, 0, 0); |
Wywołanie tej funkcji powoduje przeniesienie zmian w powierzchni graficznej na ekran. | ||||||||||||||||
// oczekujemy klawisza ESC int waiting = 0; do { SDL_Event event; while (SDL_PollEvent(&event)) if ((event.type == SDL_QUIT) || ((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_ESCAPE))) waiting = 1; } while(!waiting); } return 0; } |
Ta część programu wykorzystuje system obsługi zdarzeń w SDL do czekania aż użytkownik naciśnie klawisz ESC. Wtedy program się kończy - w dalszej części kursu, gdy nasze umiejętności wzrosną, będziemy mogli inaczej obsługiwać zdarzenia. |
Rysowanie rozpoczniemy od stawiania punktów graficznych, czyli pikseli. Wszystkie podane tutaj programy wstawiamy do naszego szablonu pod komentarzem. Biblioteka newgfx posiada funkcję zaprojektowaną dokładnie w tym celu (nazwy wszystkich funkcji rozpoczynają się od gfx):
gfxPlot(s,x,y,c);
s - wskaźnik do struktury SDL_Surface, która określa parametry
powierzchni graficznej
x - współrzędna x w oknie graficznym
y - współrzędna y w oknie graficznym (uwaga, oś OY jest skierowana w dół - punkt
0,0 leży w lewym górnym narożniku okna)
c - kolor punktu
Pierwsze trzy parametry są w miarę proste do zrozumienia. Opisu wymaga ostatni parametr c - kolor. Każdy piksel jest reprezentowany na powierzchni graficznej przez 32 bity, czyli 4 bajty. Najstarszy bajt określa przeźroczystość powierzchni - nie używamy go. Trzy kolejne bajty określają tzw. składowe koloru:
R - czerwoną
G - zieloną
B - niebieską
Jeśli masz pod ręką lupę, to oglądnij przez nią powierzchnię ekranu monitora. Zobaczysz, że obraz zbudowany jest z siatki punktów czerwonych, zielonych i niebieskich.
Kolory pośrednie otrzymujemy regulując natężenie świecenia kolorów podstawowych:
W kodzie piksela każdy z kolorów podstawowych zajmuje pole o szerokości 8 bitów. Z tego powodu kolory podstawowe mogą przyjmować intensywności od 0 do 255. Wartość 0 oznacza brak świecenia, 255 - świecenie z maksymalną intensywnością. Do określania kolorów najlepiej nadaje się system szesnastkowy - każda składowa jest wtedy zapisywana przy pomocy dwóch cyfr szesnastkowych. Poniżej są typowe wartości:
00 - brak
40 - 1/4 intensywności
80 - 1/2 intensywności
C0 - 3/4 intensywności
FF - pełna intensywność
W szablonie programu usuń kod spod komentarza pomiędzy instrukcjami if(SDL_MUSTLOCK... i wpisz poniższy tekst, po czym skompiluj i uruchom program:
gfxPlot(screen,10,10,0xff0000); // piksel czerwony gfxPlot(screen,20,20,0x00ff00); // piksel zielony gfxPlot(screen,30,30,0x0000ff); // piksel niebieski |
Efektem działania powyższego programu są trzy punkty w kolorach czerwonym, zielonym i niebieskim:
Kolory pośrednie otrzymamy mieszając barwy podstawowe. Do poprzedniego kodu dopisz:
gfxPlot(screen,40,40,0xffff00); // piksel żółty gfxPlot(screen,50,50,0xff00ff); // piksel buraczkowy gfxPlot(screen,60,60,0xffffff); // piksel biały |
Aktualną szerokość powierzchni graficznej odczytujemy ze struktury SDL_Surface. Wskaźnik do tej struktury w naszym programie nazywa się screen.
screen->w - szerokość w pikselach
screen->h - wysokość w pikselach
Poprawne współrzędne punktów na powierzchni graficznej leżą w przedziałach:
x → 0 ... screen->w - 1
y → 0 ... screen->h - 1
Kolejny kod wypełnia całe okno graficzne jednolitym kolorem czerwonym (zastąp nim poprzedni kod):
Sint32 x,y; for(y = 0; y < screen->h; y++) for(x = 0; x < screen->w; x++) gfxPlot(screen,x,y,0xff0000); |
Typ Sint32 w bibliotece SDL oznacza daną 32 bitową ze znakiem. Dane 32 bitowa bez znaku posiada typ Uint32 - typy te wprowadzono, aby zapewnić przenośność programów na inne platformy sprzętowe.
Dla ćwiczenia uzyskaj wypełnienie zielone, niebieskie, żółte, białe. Poeksperymentuj z różnymi wartościami dla składowych kolorów.
Ciekawy efekt kolorystyczny uzyskamy przez uzależnienie koloru piksela od jego pozycji na powierzchni graficznej. Zaczniemy od koloru niebieskiego, który będzie się zmieniał w osi OX:
dla x = 0 składowa niebieska ma wartość 0
dla x = screen->w - 1 składowa niebieska ma wartość 255
Układamy proporcję:
Z proporcji wyznaczamy wartość składowej niebieskiej b:
Wpisz poniższy kod (stary kod usuń!):
Sint32 x,y; Uint32 b; for(y = 0; y < screen->h; y++) for(x = 0; x < screen->w; x++) { b = (255 * x) / (screen->w - 1); // składowa niebieska gfxPlot(screen,x,y,b); } |
Składową zieloną g uzależnimy od położenia pionowego y:
Aby wstawić ją do kodu koloru piksela, musimy wykonać przesunięcie o 8 bitów w lewo - wtedy bity wartości składowej zielonej znajdą się na właściwej pozycji. Uzupełnij kod programu:
Sint32 x,y; Uint32 b,g; for(y = 0; y < screen->h; y++) for(x = 0; x < screen->w; x++) { b = (255 * x) / (screen->w - 1); // składowa niebieska g = (255 * y) / (screen->h - 1); // składowa zielona gfxPlot(screen,x,y,b | (g << 8)); } |
Składową czerwoną uzależnimy od iloczynu współrzędnych x i y:
Składową czerwoną należy w kodzie koloru przesunąć o 16 bitów w lewo.
Sint32 x,y; Uint32 b,g,r; for(y = 0; y < screen->h; y++) for(x = 0; x < screen->w; x++) { b = (255 * x) / (screen->w - 1); // składowa niebieska g = (255 * y) / (screen->h - 1); // składowa zielona r = (255 * x * y) / (screen->w-1) / (screen->h-1); // składowa czerwona gfxPlot(screen,x,y,b | (g << 8) | (r << 16); } |
W lewym górnym narożniku wszystkie trzy składowe mają wartość 0 -
kolor czarny.
W prawym górnym narożniku składowa niebieska ma wartość 255, pozostałe składowe
mają wartości 0, kolor wynikowy niebieski.
W lewym dolnym narożniku składowa zielona ma wartość 255, pozostałe mają
wartości 0, kolor wynikowy zielony.
W prawym dolnym narożniku wszystkie trzy składowe otrzymują wartość 255, kolorem
wynikowym zostaje kolor biały.
W innych miejscach okienka składowe mieszają się ze sobą i otrzymujemy barwy
pośrednie.
Ciekawy efekt kolorystyczny uzyskamy, odejmując składową czerwoną r od 255 - wtedy wartości się odwrócą i maksimum barwy czerwonej będzie w lewym górnym narożniku, czyli tam, gdzie pozostałe dwie składowe, zielona i niebieska, mają wartość 0:
Sint32 x,y; Uint32 b,g,r; for(y = 0; y < screen->h; y++) for(x = 0; x < screen->w; x++) { b = (255 * x) / (screen->w - 1); // składowa niebieska g = (255 * y) / (screen->h - 1); // składowa zielona r = 255 - (255 * x * y) / (screen->w-1) / (screen->h-1); // składowa czerwona gfxPlot(screen,x,y,b | (g << 8) | (r << 16); } |
Biblioteka newgfx posiada kilka funkcji do rysowania linii.
gfxHLine(s,x,y,c,len) - rysuje linię poziomą od strony lewej do
prawej
s - wskaźnik do struktury SDL_Surface
x,y - punkt początkowy linii
c - kolor linii
len - długość linii
gfxVLine(s,x,y,c,len) - rysuje linię pionową od góry w dół
s - wskaźnik do struktury SDL_Surface
x,y - punkt początkowy linii
c - kolor linii
len - długość linii
Uwaga: dla tych wersji funkcji rysowane linie muszą w całości mieścić się na powierzchni graficznej. W przeciwnym razie program zostanie zatrzymany z błędem dostępu do pamięci.
Uruchom poniższy program:
gfxHLine(screen,0,screen->h/2,0xff0000,screen->w/2); gfxHLine(screen,screen->w/2,screen->h/2,0x00ff00,screen->w/2); gfxVLine(screen,screen->w/2,0,0x0000ff,screen->h/2); gfxVLine(screen,screen->w/2,screen->h/2,0xffff00,screen->h/2); |
Kolejna funkcja rysuje dowolną linię pomiędzy dwoma punktami o podanych współrzędnych - w tej wersji linia w całości musi się mieścić na powierzchni graficznej:
gfxLine(s,x1,y1,x2,y2,c)
s - wskaźnik do struktury SDL_Surface
x1,y1 - współrzędne punktu startowego
x2,y2 - współrzędne punktu końcowego
c - kolor linii
Dopisz do poprzedniego kodu:
gfxLine(screen,0,0,screen->w-1,screen->h-1,0xff00ff); gfxLine(screen,0,screen->h-1,screen->w-1,0,0x00ffff); |
Łamana jest krzywą zbudowaną z odcinków połączonych końcami. Poniższe dwie funkcje przydają się przy rysowaniu łamanych:
gfxMoveTo(x,y) - ustawia punkt początkowy łamanej
x,y - współrzędne początku łamanej
gfxLineTo(s,x,y,c) - rysuje linie od punktu ustawionego przez gfxMoveTo() lub
punkt końcowy poprzedniego wywołania gfxLineTo() do punktu o współrzędnych x,y.
Linia w całości musi się mieścić na powierzchni graficznej.
s - wskaźnik do struktury SDL_Surface
x,y - punkt końcowy linii
c - kolor
Dopisz do poprzedniego programu poniższy kod:
gfxMoveTo(0,screen->h/2); gfxLineTo(screen,screen->w/2,0,0xffffff); gfxLineTo(screen,screen->w-1,screen->h/2,0xffffff); gfxLineTo(screen,screen->w/2,screen->h-1,0xffffff); gfxLineTo(screen,0,screen->h/2,0xffffff); |
gfxPlot(s,x,y,c) - rysuje punkt w kolorze c na współrzędnych x,y.
s - wskaźnik do struktury SDL_Surface
x,y - współrzędne punktu
c - kolor punktu
gfxHLine(s,x,y,c,len) - rysuje linię poziomą od strony lewej do
prawej, poczynając od punktu x,y.
s - wskaźnik do struktury SDL_Surface
x,y - punkt początkowy linii
c - kolor linii
len - długość linii
gfxVLine(s,x,y,c,len) - rysuje linię pionową od góry w dół,
poczynając od punktu x,y.
s - wskaźnik do struktury SDL_Surface
x,y - punkt początkowy linii
c - kolor linii
len - długość linii
gfxLine(s,x1,y1,x2,y2,c)
- rysuje linię od x1,y1 do x2,y2.
s - wskaźnik do struktury SDL_Surface
x1,y1 - współrzędne punktu startowego
x2,y2 - współrzędne punktu końcowego
c - kolor linii
gfxMoveTo(x,y) - ustawia punkt początkowy łamanej na pozycji x,y
x,y - współrzędne początku łamanej
gfxLineTo(s,x,y,c) - rysuje linie do punktu x,y. Punkt początkowy jest określany
przez gfxMoveTo() lub poprzednią funkcję gfxLineTo().
s - wskaźnik do struktury SDL_Surface
x,y - punkt końcowy linii
c - kolor
![]() | I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe