Serwis Edukacyjny Nauczycieli w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy
Wałaszek |
©2024 mgr Jerzy Wałaszek
|
SPIS TREŚCI |
Podrozdziały |
Współczesny młody człowiek nie zdaje sobie sprawy, jak bardzo rozwinął się sprzęt komputerowy w ciągu ostatnich 30 lat. Ma wypasiony telefon komórkowy, w domu gra na komputerze w gry prezentujące obraz w jakości filmowej, na telewizorze ogląda programy w jakości HD (ang. high definition – wysoka jakość) nadawane cyfrowo, itd. Nie ma w tym nic złego. Rozwój nie jest zły (o ile nie dotyczy techniki wojennej). Bez niego wciąż biegalibyśmy z maczugami wokół jaskini (co również nie było takie całkiem złe).
Mój pierwszy komputer (rok 1983, ZX-81) nie posiadał wcale grafiki w dzisiejszym rozumieniu.
Potrafił jedynie wyświetlać literki, a i to nie wszystkie. Na przykład wykres funkcji wyglądał na ekranie ZX-81 tak:
Punkty i linie były tworzone ze znaków o specjalnych kształtach (tzw. semigrafika znakowa). Związane to było z kilkoma czynnikami:
Dobra grafika wymaga szybkiego procesora do przetwarzania danych. Pierwsze procesory nie należały do demonów szybkości, zatem obsługa obrazu o dużej liczbie kolorów i o dużej rozdzielczości była czasochłonna. Pamiętam, jak w latach 80-tych byłem na giełdzie elektronicznej w Krakowie. Widziałem tam "nowoczesne" komputery wyświetlające obrazy o jakości fotograficznej. Lecz zmiana takiego obrazu trwała kilka sekund i widać było, jak obrazek był rysowany linia po linii.
Dobra grafika wymaga odpowiednio zaawansowanej elektroniki. W pierwszych komputerach stosowano tanie rozwiązania, aby zwiększyć sprzedaż.
Powodów można by znaleźć więcej, ale to nie jest nasz problem.
Tryb tekstowy wciąż jest obecny na współczesnych komputerach, niekiedy w czasie startu system pracuje właśnie w trybie tekstowym. Nowsze komputery stosują już wyłącznie tryb graficzny, a Windows 10 blokuje możliwość przełączenia karty w ten tryb. Nie wróży mu to dobrze i pewnie niedługo tryb tekstowy zniknie z kart graficznych.
Zasada działania trybu tekstowego jest w miarę prosta:
Obraz na ekranie monitora składa się z linii (tutaj przesadnie pokazanych):
Linie te są wyświetlane kolejno z góry na dół, aż zostanie wyświetlona cała ramka obrazu (ang. frame), po czym rysowana jest kolejna. Na sekundę tych ramek jest kilkadziesiąt (parametr nosi nazwę fps = frames per second, czyli ramki na sekundę). Nasze oczy nie widzą tego procesu, ponieważ odbywa się zbyt szybko.
Dane do wyświetlenia na ekranie przechowywane są w pamięci RAM (ang. Random Access Memory, czyli pamięć o dostępie swobodnym, traci zawartość po wyłączeniu zasilania) w tzw. buforze ekranu (ang. display buffer). Układ graficzny odczytuje kody znaków z bufora ekranu, a następnie na podstawie matryc znakowych (przechowują kształt znaków w postaci punktów zwanych pikselami) i numerów linii generuje treść kolejnych linii obrazowych:
Zwróć uwagę, iż obraz każdego znaku tworzony jest w siatce n x m punktów. Punkty te nazywamy pikselami. Tutaj mogą być jasne lub ciemne. Skoro tak, to piksele w matrycach da się przedstawić za pomocą bitów. Zatem każda taka matryca, to kilka kolejnych bajtów w pamięci:
Matryce mogą być przechowywane w pamięci RAM komputera (wtedy komputer może zmienić sobie kształt literek lub zastąpić nieużywane znaki innymi, które są mu akurat potrzebne – tak początkowo odbywało się spolszczanie programów) lub w pamięci ROM (ang. Read Only Memory, czyli pamięć tylko do odczytu, pamięć stała, nie traci zawartości po wyłączeniu zasilania) układu graficznego (wtedy kształt literek jest stały i użytkownik nie może go sobie zmieniać).
Zaletą trybu tekstowego jest niskie zapotrzebowanie na pamięć i duża szybkość działania programów, ponieważ obraz zawiera niewiele danych. W trybach znakowych wciąż działają niektóre wyświetlacze stosowane w mikrokontrolerach:
Elektronicy chętnie je stosują z uwagi na proste sterowanie. Jak widzisz, są obszary zastosowań informatyki, gdzie stare rozwiązania wciąż jeszcze dobrze się mają.
Ludzie się czasami dobrze bawią w trybie tekstowym: https://s3.eu-central-1.amazonaws.com/ascii-art-history/ascii-the_incredibles1.htm.
Po okresie wyświetlaczy monochromatycznych ludzie pracujący na komputerach zapragnęli coś więcej niż tylko jednokolorowe literki. Dodano zatem kolor do trybu tekstowego. Rozwiązań było kilka, ale skupmy się na tym, co działo się w komputerach PC, ponieważ współczesne karty wciąż to mogą zawierać.
Kolor zrealizowano w ten sposób, iż w obszarze ekranu oprócz kodów znaków umieszczano dodatkowe informacje. Każda pozycja znakowa (obszar wyświetlający literę) składała się teraz z dwóch bajtów: bajtu z kodem znaku oraz tzw. bajtu atrybutu, w którym zawarty był kolor znaku i kolor jego tła. Spójrz jeszcze raz na matrycę literki A:
Matryca definiuje jedynie punkty białe i czarne. Kolory te można zastąpić innymi przez określenie kolorów wynikowych dla punktów białych i czarnych matrycy:
Jak widzisz, już jest ciekawiej.
Wyświetlanie kolorowych literek działa podobnie do monochromatycznego tryby znakowego.
Układ graficzny pobiera z bufora ekranu kolejno: bajt kodu znaku i bajt atrybutu. Na podstawie kodu znaku i numeru linii obrazu pobiera z pamięci matryc znaków bajt matrycy znakowej. Kolor biały i czarny zastępuje kolorami zdefiniowanymi w atrybucie koloru i wynik przesyła na wyjście do monitora. W efekcie na ekranie monitora powstaje kolorowy obraz:
Aby zrozumieć kodowanie kolorów, musisz wiedzieć jak monitory wyświetlają kolorowy obraz. Zdobądź dobrą lupę i spójrz z bliska na ekran swojego komputera (może też być smartfon). Zauważysz, że obraz utworzony jest z małych punktów w kolorach czerwonym, zielonym i niebieskim:
Układ tych punktów może być różny, niemniej zawsze występują w trzech podanych kolorach. Trójka kolorowych punktów nosi nazwę triady RGB (ang. R - red, czerwony; G - green, zielony; B - blue, niebieski). Triada tworzy jeden punkt obrazu, który nazywamy pikselem (ang. pixel = picture element, element obrazu). Regulując natężenie świecenia kolorów triady uzyskuje się różne kolory piksela:
R | G | B | RGB |
Atrybut koloru składa się z 8 bitów. Bity te są podzielone na dwie grupy po 4 bity. Dolna grupa określa kolor znaku. Górna grupa określa kolor tła:
kolor tła | kolor liter | ||||||
---|---|---|---|---|---|---|---|
I | R | G | B | I | R | G | B |
b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
Jeśli są ustawione na 1, poszczególne bity atrybutu koloru posiadają następujące znaczenie:
I - rozjaśnienie
koloru, tzw. bit intensywności R - składowa czerwona (ang. RED) G - składowa zielona (ang. GREEN) B - składowa niebieska (ang. BLUE) |
Bit intensywności rozjaśnia kolory podstawowe, dzięki czemu uzyskujemy jaśniejszy kolor wynikowy. W poniższej tabelce zebrano wszystkie kolory wraz z ich kodami dwójkowymi, szesnastkowymi i dziesiętnymi:
binarnie | szesnastkowo | dziesiętnie | kolor |
---|---|---|---|
0000 | 0 | 0 | |
0001 | 1 | 1 | |
0010 | 2 | 2 | |
0011 | 3 | 3 | |
0100 | 4 | 4 | |
0101 | 5 | 5 | |
0110 | 6 | 6 | |
0111 | 7 | 7 | |
1000 | 8 | 8 | |
1001 | 9 | 9 | |
1010 | A | 10 | |
1011 | B | 11 | |
1100 | C | 12 | |
1101 | D | 13 | |
1110 | E | 14 | |
1111 | F | 15 |
Na przykład chcemy otrzymać wartość atrybutu dla znaku intensywnie żółtego na brązowym tle: łączymy kod koloru tła z kodem koloru znaku: 0x4 i 0xe = 0x4e.
Tryb tekstowy w kolorze dostępny jest w oknie konsoli Windows.
Poniższy program demonstruje sposób uzyskania kolorów. Działa tylko w Windows.
Utwórz w CodeBlocks projekt aplikacji konsoli, do edytora przekopiuj poniższy program, skompiluj go i uruchom:
C++// B O M B O W I E C //-------------------------------------------- // (C)2018 mgr Jerzy Wałaszek I LO w Tarnowie #include <conio.h> #include <windows.h> #include <strings.h> #include <iostream> #include <cstdlib> #include <ctime> using namespace std; //---------------------------------------------------- // Deklaracja klasy gry //---------------------------------------------------- class TMiasto { public: int domy[81]; void Inicjuj(); int Koniec(int x, int y); }; class TBomba { int oby; public: int bx,by; void Inicjuj(); void ZrzutBomb(int x, int y); void LotBomby(int * y); }; class TSamolot { int ox,oy; public: int sx,sy; void Inicjuj(); void LotBombowca(); }; class TGra { TMiasto miasto; TBomba bomba; TSamolot samolot; int a; void StronaTytulowa(); public: void Inicjuj(); void Uruchom(); int Koniec(); }; //---------------------------------------------------- // PROCEDURY I FUNKCJE POMOCNICZE //---------------------------------------------------- const int BLACK = 0; const int BLUE = 1; const int GREEN = 2; const int CYAN = 3; const int RED = 4; const int MAGENTA = 5; const int BROWN = 6; const int LIGHTGRAY = 7; const int DARKGRAY = 8; const int LIGHTBLUE = 9; const int LIGHTGREEN = 10; const int LIGHTCYAN = 11; const int LIGHTRED = 12; const int LIGHTMAGENTA = 13; const int YELLOW = 14; const int WHITE = 15; static int __BACKGROUND = BLACK; static int __FOREGROUND = LIGHTGRAY; // Procedura ustawia pozycję wydruku w oknie konsoli //---------------------------------------------------- void gotoxy(int x, int y) { COORD c; c.X = x - 1; c.Y = y - 1; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c); } // Procedura ustawia kolor tła wydruku //---------------------------------------------------- void textbackground(int color) { __BACKGROUND = color; SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), __FOREGROUND + (color << 4)); } // Procedura ustawia kolor tekstu //---------------------------------------------------- void textcolor(int color) { __FOREGROUND = color; SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color + (__BACKGROUND << 4)); } // Procedura ustawia atrybuty koloru tekstu i tła //---------------------------------------------------- void textattr(int _attr) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), _attr); } // Funkcja zwraca aktualną pozycję x kursora //---------------------------------------------------- int wherex() { CONSOLE_SCREEN_BUFFER_INFO info; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); return info.dwCursorPosition.X + 1; } // Funkcja zwraca aktualną pozycję y kursora //---------------------------------------------------- int wherey() { CONSOLE_SCREEN_BUFFER_INFO info; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); return info.dwCursorPosition.Y + 1; } // Procedura czyści zawartość okna konsoli //---------------------------------------------------- void clrscr() { DWORD written; FillConsoleOutputAttribute(GetStdHandle (STD_OUTPUT_HANDLE), __FOREGROUND + (__BACKGROUND << 4), 2000, (COORD){0, 0}, &written); FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), ' ', 2000, (COORD){0, 0}, &written); gotoxy(1, 1); } // Procedura ukrywa kursor okienka konsoli //------------------------------------------------------ void CursorOff() { CONSOLE_CURSOR_INFO Info; GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info); Info.bVisible = 0; SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info); }; // Procedura przywraca kursor okienka konsoli //------------------------------------------------------ void CursorOn() { CONSOLE_CURSOR_INFO Info; GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info); Info.bVisible = -1; SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info); }; // Funkcja PL konwertuje tekst ze standardu Windows 1250 // na standard konsoli znakowej Latin II //------------------------------------------------------ string PL(string s) { unsigned int i; char c; for(i = 0; i < s.length(); i++) { switch(s[i]) { case 'ą' : c = char(165); break; case 'ć' : c = char(134); break; case 'ę' : c = char(169); break; case 'ł' : c = char(136); break; case 'ń' : c = char(228); break; case 'ó' : c = char(162); break; case 'ś' : c = char(152); break; case 'ż' : c = char(190); break; case 'ź' : c = char(171); break; case 'Ą' : c = char(164); break; case 'Ć' : c = char(143); break; case 'Ę' : c = char(168); break; case 'Ł' : c = char(157); break; case 'Ń' : c = char(227); break; case 'Ó' : c = char(224); break; case 'Ś' : c = char(151); break; case 'Ż' : c = char(189); break; case 'Ź' : c = char(141); break; default: c = s[i]; }; s[i] = c; }; return(s); } // Procedura centruje w bieżącym wierszu tekst podany jako parametr //----------------------------------------------------------------- void Centruj(string t) { gotoxy(1 + (80 - t.length()) / 2, wherey()); cout << t << endl; } // Procedura rysuje pojedynczą ramkę ze znaków // tabelek. Parametry określają współrzędne // lewego górnego i prawego dolnego narożnika //---------------------------------------------------- void Ramka(int xp,int yp,int xk,int yk) { int i; gotoxy(xp,yp); putch(char(218)); gotoxy(xp,yk); putch(char(192)); gotoxy(xk,yp); putch(char(191)); gotoxy(xk,yk); putch(char(217)); for(i = xp + 1; i <= xk - 1; i++) { gotoxy(i,yp); putch(char(196)); gotoxy(i,yk); putch(char(196)); }; for(i = yp + 1; i <= yk - 1; i++) { gotoxy(xp,i); putch(char(179)); gotoxy(xk,i); putch(char(179)); }; } // Procedura wprowadza opóźnienie o zadaną ilość milisekund //--------------------------------------------------------- void Delay(unsigned int d) { long start; start = GetTickCount(); while((GetTickCount() - start) < d); } //---------------------------------------------------- // Definicje metod klas //---------------------------------------------------- void TMiasto::Inicjuj() { int i,j; textbackground(0xb); clrscr(); // tło nieba textattr(0x1e); //granatowe domy for(i = 1; i <= 80; i++) { if((i >= 6) && (i <= 75)) { domy[i] = 1 + rand() % 10; for(j = 1; j <= domy[i]; j++) { gotoxy(i,26-j); cout << "-"; }; } else domy[i] = 0; }; } int TMiasto::Koniec(int x, int y) { int i,t; if(y == domy[x]) { textattr(0xce); gotoxy(x,26-y); cout << "#"; textattr(0xb4); cout << " KRACH!"; textattr(0x1f); gotoxy(1,6); Centruj(PL(" GRA SKOŃCZONA ")); return(true); } else { t = 0; for(i = 6; i <= 75; t = t + domy[i++]); if(t == 0) { textattr(0x1e); gotoxy(1,6); Centruj(" GRATULACJE! "); return(true); }; }; return(false); } //------------------------------------------------------ void TBomba::Inicjuj() { bx = 1; by = oby = 0; } void TBomba::ZrzutBomb(int x, int y) { char c; if(kbhit()) { while(!(c = getch())) ; if((c == ' ') && !by) { bx = x; by = y; oby = by - 1; }; }; } void TBomba::LotBomby(int * y) { if(by) { textattr(0xb0); gotoxy(bx,26-oby); cout << " "; oby = --by; if(*y > by) { *y = by; textattr(0xce); }; if(by) { gotoxy(bx,26-by); cout << "*"; }; }; } //------------------------------------------------------ void TSamolot::Inicjuj() { sx = ox = 1; sy = oy = 25; } void TSamolot::LotBombowca() { if(++sx > 80) { sx = 1; --sy; }; gotoxy(ox,26-oy); textattr(0xb0); cout << " "; gotoxy(sx,26-sy); cout << ">"; ox = sx; oy = sy; } //------------------------------------------------------ void TGra::StronaTytulowa() { textbackground(0); clrscr(); gotoxy(1,4); textattr(0x5e); Centruj(PL(" ")); Centruj(PL(" B O M B O W I E C ")); Centruj(PL(" ===================== ")); Centruj(PL(" ")); textattr(0x1f); Centruj(PL(" ")); Centruj(PL(" (C)2018 mgr Jerzy Wałaszek ")); Centruj(PL(" ")); textattr(0xf0); Centruj(PL(" ")); Centruj(PL(" Przygotuj się na bombardowanie...")); Centruj(PL(" ")); textattr(0xf4); Centruj(PL(" Gdy będziesz gotowy, ")); Centruj(PL(" naciśnij dowolny klawisz ")); Centruj(PL(" ")); while(getch() == 0); // Oczekiwanie na dowolny klawisz textattr(0x07); clrscr(); } void TGra::Inicjuj() { StronaTytulowa(); miasto.Inicjuj(); samolot.Inicjuj(); bomba.Inicjuj(); } void TGra::Uruchom() { do { samolot.LotBombowca(); bomba.ZrzutBomb(samolot.sx,samolot.sy); bomba.LotBomby(&miasto.domy[bomba.bx]); Delay(100); } while(!miasto.Koniec(samolot.sx,samolot.sy)); } int TGra::Koniec() { gotoxy(1,2); textattr(0x4e); Centruj(" "); Centruj(" Jeszcze raz ? [T] = Tak, [Inny] = Nie "); Centruj(" "); return(toupper(getch()) != 'T'); } int main() { TGra gra; srand((unsigned)time(NULL)); CursorOff(); do { gra.Inicjuj(); gra.Uruchom(); } while(!gra.Koniec()); CursorOn(); textbackground(0); textcolor(7); clrscr(); return(0); } |
W trybach tekstowych jest ograniczenie tylko do zdefiniowanych znaków, nie można wyświetlać dowolnych obrazów. Dlatego od połowy lat 80-tych zaczęły pojawiać się komputery wyposażone w karty graficzne, które oprócz tekstu potrafiły również wyświetlać obrazy z pikseli. Obraz zbudowany z pikseli, czyli punktów nazywamy obrazem rastrowym (ang. raster – siatka prostokątnych punktów). Cechuje go tzw. rozdzielczość, czyli liczba wierszy i kolumn rastra oraz liczba kolorów możliwych jednocześnie do wyświetlenia na ekranie, tzw. głębia koloru.
W naszym kraju dużą popularnością cieszyła się kiedyś karta graficzna Hercules. Umożliwiała ona pracę w monochromatycznym trybie tekstowym (25 wierszy po 80 znaków) oraz w trybie graficznym o rozdzielczości 720 punktów w poziomie na 348 punktów w pionie. Na owe czasy był to potężny skok jakościowy i pamiętam, że wielu poważnych ludzi pracowało na komputerach z kartami Hercules. Obraz graficzny wyglądał tak:
Karta Hercules była monochromatyczna,
tzn. w trybie graficznym punkty albo były czarne, albo jasne.
Jeden piksel w pamięci karty reprezentowany był jednym bitem.
Ramka obrazu graficznego zajmowała zatem
Tryb monochromatyczny działa na dosyć prostej zasadzie. Obraz również zbudowany jest z linii. W buforze ekranu przechowywane są bajty zawierające kolejne piksele linii obrazu. Pojedynczy bit zawiera informację o kolorze (a właściwie o jasności) odpowiadającego mu piksela. Np. bit 0 może oznaczać piksel zgaszony, a 1 zaświecony. Układ graficzny pobiera z bufora kolejne bajty linii obrazu, przetwarza w sygnał obrazowy, a następnie przesyła wyjście do monitora monochromatycznego.
Aby stosunkowo niskim kosztem wprowadzić grafikę kolorową, wymyślono tryb paletowy. Działał on w ten sposób, iż w pamięci ekranu piksele reprezentowane były przez grupy bitów. Załóżmy, że piksel będzie definiowany przez dwa sąsiadujące ze sobą bity. W każdym bajcie jest 8 bitów b0 ... b7, zatem jeden bajt pamięci ekranu może pomieścić cztery piksele p0 ...p3:
Bajt obrazu | |||||||
p3 | p2 | p1 | p0 | ||||
b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
Piksel p0 definiują bity b0
i b1.
Piksel p1 definiują bity b2 i b3.
Piksel p2 definiują bity b4 i b5.
Piksel p3 definiują bity b6 i b7.
Jeśli potraktujemy te dwa bity każdego
piksela jako liczbę dwójkową, to otrzymamy cztery możliwe
wartości: 00 = 0, 01 = 1, 10 = 2, 11 = 3. Wartości te są
numerami kolorów palety. Kolory palety można przydzielać z
szerokiego zestawu kolorów. W ten sposób jednocześnie na obrazku
mogą być cztery wybrane kolory, a obrazek nie zajmuje zbyt wiele
miejsca w pamięci. Na przykład obrazek o rozdzielczości
Tryb paletowy działa podobnie do trybu monochromatycznego. Oprócz bufora ekranu układ graficzny posiada dostęp do palety kolorów, w której są zdefiniowane kolory dla poszczególnych kombinacji bitów pikseli. Kolory te mogą być ustalone na stałe lub definiowane przez użytkownika, co daje więcej możliwości. Obraz zbudowany jest z linii. W buforze ekranu przechowywane są bajty kolejnych linii obrazu. W bajtach tych piksele zajmują określoną liczbę bitów (w powyższym przykładzie każdy piksel to dwa bity). Układ graficzny pobiera kolejne bajty linii obrazu z bufora. Następnie z pobranych bajtów wydziela bity poszczególnych pikseli. Na podstawie tych bitów pobiera z palety odpowiedni kolor piksela i przesyła go na wyjście do monitora kolorowego.
00 | 01 | 10 | 11 |
Obrazek:
00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
00 | 00 | 00 | 00 | 00 | 00 | 00 | 11 | 11 | 11 | 11 | 11 | 11 | 00 | 00 | 00 |
00 | 00 | 00 | 00 | 00 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 00 | 00 |
00 | 00 | 00 | 00 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 00 | 00 |
00 | 00 | 00 | 00 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 00 |
00 | 00 | 00 | 00 | 00 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 00 | 00 |
01 | 01 | 01 | 01 | 01 | 01 | 01 | 11 | 11 | 11 | 11 | 11 | 11 | 01 | 01 | 01 |
01 | 01 | 01 | 01 | 01 | 01 | 01 | 01 | 01 | 10 | 10 | 01 | 01 | 01 | 01 | 01 |
01 | 01 | 01 | 01 | 01 | 01 | 01 | 01 | 01 | 10 | 10 | 01 | 01 | 01 | 01 | 01 |
01 | 01 | 01 | 01 | 01 | 01 | 01 | 01 | 01 | 10 | 10 | 01 | 01 | 01 | 01 | 01 |
01 | 01 | 01 | 01 | 01 | 01 | 01 | 01 | 01 | 10 | 10 | 01 | 01 | 01 | 01 | 01 |
01 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 10 | 10 | 11 | 11 | 11 | 11 | 11 |
11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 |
11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 |
11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 |
Jeśli chcemy zwiększyć liczbę kolorów, to zwiększamy ilość bitów w grupie piksela. Dla 4 bitów (grupy 3-bitowe nie mieszczą się ładnie w bajcie: 2-3-3, dlatego takiego przydziału zwykle się nie stosuje) będzie to 16 różnych kolorów, dla 8 bitów (piksel zajmuje cały bajt) możemy mieć 256 różnych kolorów. Typowym przykładem obrazków paletowych jest format GIF, który przechowuje paletę do 256 kolorów, a piksele mogą zawierać do 8 bitów indeksujących kolory palety. 256 kolorów zwykle wystarcza do tworzenia realistycznie wyglądających obrazów:
Zaletą trybu paletowego jest mały rozmiar bufora ekranu, co było korzystne dla wolnych procesorów. Dzisiaj te tryby w komputerach IBM PC mają znaczenie prawie wyłącznie historyczne, chociaż wciąż są obecne na kartach graficznych dla kompatybilności wstecznej.
Pierwszą kartą graficzną stosującą kolor w trybie paletowym była karta CGA (ang. Color Graphic Adapter) zwana popularnie cegłą. Posiadała następujące parametry:
40 kolumn x 25 wierszy, 16 kolorów tekstu i tła
80 kolumn x 25 wierszy, 16 kolorów tekstu i tła
Wg dzisiejszych standardów jakość tych obrazów jest tragiczna, ale pamiętaj, że to były lata 80-te i ludzie się tym zachwycali.
Na potrzeby bardziej wymagających użytkowników opracowano lepszą kartę graficzną o nazwie EGA (ang. Enhanced Graphic Adapter). Obraz wciąż był tworzony w trybie paletowym, jednak EGA rezerwowała na piksel 4 bity, co umożliwiało stosowanie wyświetlania pikseli w 16 kolorach z palety 64 kolorów. Parametry karty EGA były następujące:
40 kolumn x 25 wierszy, znaki w matrycy 8 x
8, 16 kolorów
80 kolumn x 25 wierszy, znaki w matrycy 8 x 8, 16 kolorów
80 kolumn x 25 wierszy, znaki w matrycy 8 x 14
(lepsza czytelność liter), 16
kolorów
80 kolumn x 43 wiersze, znaki w matrycy 8 x 8, 16 kolorów
640 x 350, 16 kolorów z palety 64 kolorów
640 x 350 w trybie monochromatycznym 640 x 200 w 16 kolorach 320 x 200 w 16 kolorach |
Obraz generowany przez kartę EGA jest bez porównania lepszy od obrazu możliwego do uzyskania na karcie CGA. Jednak koszt karty EGA w latach 80-tych był na poziomie zaporowym, tylko nieliczni mogli sobie pozwolić na to cudo. Do tego dochodził jeszcze niebagatelny koszt kolorowego monitora.
Pod koniec lat 80-tych pojawiła się karta VGA (ang. Video Graphic Array). Wciąż pracowała w trybach paletowych, jednak kolory palety mogły być dowolnie definiowane przez określanie intensywności barw podstawowych (czerwonej, zielonej i niebieskiej) z rozdzielczością 6 bitów (wartości od 0 do 63). W efekcie na karcie VGA kolory palety mogły być wybierane z puli 64 x 64 x 64 = 262144 kolorów. Parametry VGA były następujące:
40 kolumn x 25 wierszy, znaki w matrycy 9
x 16, 16 kolorów 80 kolumn x 25 wierszy, znaki w matrycy 9 x 16, 16 kolorów 80 kolumn x 43 wiersze, znaki w matrycy 8 x 8, 16 kolorów, kompatybilność z EGA 80 kolumn x 50 wiersze, znaki w matrycy 8 x 8, 16 kolorów |
640 x 480 w 16 kolorach 640 x 350 w 16 kolorach, kompatybilność z EGA 640 x 200 w 16 kolorach, kompatybilność z EGA 320 x 200 w 16 kolorach, kompatybilność z EGA 320 x 200 w 256 kolorach |
Karty Hercules, CGA, EGA i VGA wytyczają drogę rozwoju grafiki komputerowej. Dla porównania przedstawiamy ten sam obrazek wyświetlany na każdej z tych kart:
Hercules, obraz monochromatyczny |
CGA, obraz w 4 ustalonych kolorach |
EGA, obraz w 16 wybranych kolorach |
VGA, obraz w 256 definiowanych kolorach |
Poczuj teraz zazdrość tych, którzy w latach 80-tych mieli komputery z kartą Hercules, a widzieli obraz generowany przez VGA, która w trybie 256 kolorów potrafiła wyświetlać grafikę prawie w jakości fotograficznej. Zostawmy to historykom. Karta VGA kończy czasy trybów paletowych, lecz pamiętaj, że współczesne karty graficzne są kompatybilne w dół z kartą VGA. Na przykład, Windows, jeśli nie potrafi rozpoznać karty graficznej komputera, na którym pracuje, to włącza tryb paletowy VGA w 16 kolorach (również robi tak w trybie awaryjnym, gdy są problemy z obsługą ekranu). Zakłada się bowiem, że każda karta graficzna ten tryb posiada. Jak widzisz, nie jest to zupełna staroć i czasem się z VGA spotkasz.
Na początku lat 90-tych pojawiły się karty
graficzne, które dodawały do trybów VGA nowe tryby o
większej rozdzielczości i większej liczbie kolorów. Nazywano je
kartami
SVGA (ang. Super Video Graphic Array)
lub UVGA (ang. Ultra Video Graphic
Array). Początkowo były to rozszerzone tryby paletowe,
np. obraz w rozdzielczości 1024 x 768 pikseli w 256 kolorach.
Jednak wkrótce pojawił się nowy tryb graficzny, zwany
Hi-color. W trybie tym każdy piksel w buforze ekranu składał
się z 16 bitów. Bity te podzielone były na 3 grupy: 5-6-5
(w niektórych rozwiązaniach ograniczano się do
15 bitów: 5-5-5). Każda grupa określała jasność barwy
składowej czerwonej, zielonej i niebieskiej. Grupy były
traktowane jako liczby w kodzie NBC, co daje dla 5 bitów
wartości od 0 do 31 (kolor czerwony i
niebieski), a dla 6 bitów dostajemy wartości od 0 do 63
(kolor zielony). W efekcie piksel definiuje swój własny
kolor, nie potrzebuje palety. Wszystkich kolorów jest
W trybie Hi-color można wyświetlać obrazy w jakości bliskiej fotografii. Poniżej mamy obrazek prezentujący możliwe do wyświetlenia kolory:
Konsekwencją trybu hi-color było
powstanie trybu RGB. Tutaj każdy piksel był
reprezentowany w pamięci obrazu przez 3 bajty. Bajty te
zawierały informację o intensywności poszczególnych barw
składowych czerwonej, zielonej i niebieskiej. Bajt to 8
bitów i w kodzie NBC przyjmuje wartości od 0 do 255. Daje to
256 różnych poziomów jasności dla każdej barwy składowej.
Wszystkich kolorów będzie zatem
Wkrótce karty zaczęto wyposażać w dodatkowe układy, w tzw. akceleratory graficzne. Są to w zasadzie specjalizowane, szybkie, wielowątkowe komputery, a ich zadaniem jest bardzo szybka obróbka danych graficznych i odciążenie procesora głównego, który w tym czasie może zająć się czymś innym. Dzięki akceleratorom powstają ruchome obrazy przestrzenne o wysokiej jakości. Bez nich nie istniałyby współczesne gry 3D.
Obraz jest tworzony w postaci siatki pikseli zwanych rastrem.
Rozdzielczość (ang. resolution)
określa liczbę kolumn i wierszy rastra. Zwykle jest to co
najmniej
Głębia koloru (ang. color depth) określa ilość bitów na jeden piksel obrazu. Zwykle będzie to 32 bity (karty stosujące 24 bity na piksel należą dzisiaj już do historii).
Kolor piksela określany jest przez jasność trzech kolorów składowych: czerwonego (ang. R red), zielonego (ang. G Green) i niebieskiego (ang. B Blue). Mieszanka tych kolorów daje wszystkie barwy, które mogą przyjmować piksele. Informacja o jasności barw podstawowych zawarta jest w kodzie piksela. Jeśli piksel ma rozmiar 4 bajty (32 bity), to zwykle pierwsze trzy bajty lub trzy ostatnie definiują składowe koloru R, G i B, a czwarty bajt jest albo nieużywany, albo zawiera informację o stopniu przezroczystości piksela (tzw. kanał Alfa). Omówimy to dokładniej w kolejnych rozdziałach.
Uwaga: kolejność bajtów może być odwrotna. Zależy to od rozwiązań technicznych w konkretnym komputerze. Powyżej jest tylko przykład poglądowy.
32-bitowy rozmiar pikseli jest wygodny dla współczesnych procesorów, które umożliwiają jednoczesny dostęp do danych 32 bitowych w pamięci, jeśli te dane leżą w komórkach, z których pierwsza ma adres podzielny przez 4. Wiąże się to ze sposobem dostępu do pamięci przez taki procesor.
Bufor ekranu (ang. frame buffer), to obszar pamięci, w którym jest zawarta treść obrazu. Współczesne karty graficzne posiadają własną pamięć wewnętrzną, w której przechowują wyświetlany obraz. Zwykle w pamięci głównej RAM tworzy się pomocniczy bufor, do którego ma dostęp procesor. Obraz jest tworzony w tym pomocniczym buforze, a gdy zostanie w całości ukończony, jest przesyłany do bufora karty (niektóre karty graficzne współdzielą pamięć z procesorem komputera – szczególnie to dotyczy akceleratorów graficznych zintegrowanych z procesorami Intela). Dzięki temu wyświetlany obraz nie jest zakłócany.
Zatem aby obraz pojawił się na ekranie, należy go utworzyć w buforze ekranu, a następnie przesłać zawartość bufora do pamięci karty. Często operacje takie wykonuje akcelerator karty graficznej, jeśli bufor znajduje się w pamięci karty (tzw. VRAM, czyli Video RAM), co znakomicie przyspiesza wyświetlanie grafiki. Wersje 64 bitowe procesorów Intela (innych firm też, np. AMD) są wyposażane w układ akceleratora grafiki, który potrafi samodzielnie tworzyć obraz graficzny o wysokiej rozdzielczości. Użyty akcelerator może nie jest najwyższych lotów, ale do prostych zadań graficznych (wyświetlanie filmów HD, animacje 3D) jest zupełnie wystarczający. Przy bardziej wymagających zadaniach, np. do tworzenia zaawansowanej grafiki trójwymiarowej, potrzebna jest zwykle porządna karta graficzna, niestety, kosztuje kilkaset złotych (a nawet kilka tysięcy, taka z górnej półki). Oczywiście, aby mieć jakikolwiek zysk z zakupu takiej karty, musisz również posiadać wydajny procesor (np. i7) i dużo szybkiej pamięci RAM w komputerze (o monitorze odpowiedniej jakości już nie wspomnę). Na szczęście zabawę z grafiką można uprawiać nawet na prostym sprzęcie.
Znając rozdzielczość i głębię koloru można łatwo wyliczyć
rozmiar bufora ekranowego. Na przykład obraz o rozdzielczości
W kolejnych rozdziałach wykonasz odpowiednie ćwiczenia, które przybliżą ci te zagadnienia. Zapraszam
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.