Informácie ku cvičeniam 1, 2, 3 a 4
Na prvých štyroch cvičeniach sa budeme zaoberať základnými grafickými operáciami, od zapnutia grafického režimu, vykreslenia jedného pixelu až po základné 3D zobrazenie kocky. Aby sme sa vyhli rôznym prekážkam, ktoré kladú moderné OS pri prístupe k hardvéru, budeme programovať v DOSe (pomocou DOSBoxu) a konkrétne v Turbo C++ 3.0, ktorý je voľne stiahnuteľný. Táto kombinácia prináša žiaľ jeden dosť otravný problém. O ňom, ako aj o samotnom používaní prostredia, si môžete prečítať na tejto stránke v sekcii Používanie DOSBoxu s Turbo C++.
Pre prvotné nakopnutie určite navštívte stránku http://www.brackeen.com/vga/. Obsahuje množstvo užitočných informácií a ukážkových zdrojových kódov.
Assembler a prerušenie 0x10 (Video Services, VGA)
Kompilátor Borland Turbo C++ 3.0 si rozumie s Intel syntaxou zápisu assembleru. Čiže napríklad funkcia na zapnutie grafického režimu môže vyzerať nasledovne:
/**
*Procedura ugr_asm_setmode(uint8_t mode)
*
*Aktivovanie vybraneho grafickeho modu
*AH = 0x00
*AL ... cislo modu
* 0x01 ... text 40x25
* 0x03 ... text 80x25
* 0x11 ... 640x480x2
* 0x12 ... 640x480x16
* 0x13 ... 320x200x256
*/
void ugr_asm_setmode(uint8_t mode)
{
asm{
mov ah,0x00
mov al,mode
int 0x10
}
}
Všimnite si, že assemblerovský kód je vložený medzi asm { }. Používame Intel syntax, teda pri operácii MOV je uvádzaný najprv cieľ a potom zdroj. Lokálne premenné môžeme volať priamo ich názvom, dôležité je ale dôsledne dodržiavať typ premennej a samozrejme jej veľkosť, inak kompilácia zlyhá.
Registre AX, BX, CX a DX sú veľkosti 16-bit, teda do nich môžeme kopírovať len premenné typu uint16_t, int16_t, int, short int a unsigned int. Ich "podregistre" AL, AH, BL, BH, atď. sú veľkosti 8-bit, teda do nich môžeme kopírovať premenné typu uint8_t, int8_t, char a unsigned char.
Tabuľka dôležitých funkcií
register AH | funkcia | parametre (registre) |
0x00 | nastaví video mód 0x01 ... text 40x25 (0xB8000000L) 0x03 ... text 80x25 (0xB8000000L) 0x11 ... 640x480x2 (0xA0000000L) 0x12 ... 640x480x16 (0xA0000000L) 0x13 ... 320x200x256 (0xA0000000L) |
AL ... číslo módu |
0x02 | nastavenie pozície kurzora | BH ... číslo stránky DH ... riadok DL ... stĺpec |
0x05 | nastaví aktívnu stránku | AL ... číslo stránky |
0x06 | scrollovanie textu (obdĺžnika) nahor | AL ... počet riadkov BH ... atribút prázdnych znakov CH ... riadok ľavého horného rohu CL ... stĺpec ľavého horného rohu DH ... riadok pravého dolného rohu DL ... stĺpec pravého dolného rohu |
0x09 | zapísanie znaku na aktuálnu pozíciu | AL ... znak (ASCII kód) BH ... číslo stránky BL ... atribút (text. režim), index farby (graf.) CX ... počet opakovaní |
0x0C | vykreslenie jedného pixelu | AL ... index farby (0x80 znamená xor režim) BH ... číslo stránky CX ... stĺpec DX ... riadok |
0x0D | prečítanie jedného pixelu | BH ... číslo stránky CX ... stĺpec DX ... riadok Výsledok: AL ... index farby |
0x0F | zistí aktuálny mód obrazovky | Výsledok: AH ... počet znakov v riadku AL ... číslo módu BH ... číslo aktívnej stránky |
0x10 | nastaví paletu, RGB hodnoty v intervale 0..63 | AL ... 0x10 (nastavenie jednej farby) BL ... index farby DH ... red CH ... green CL ... blue |
Dátové typy
Ak ste niekedy programovali aplikácie pre rôzne operačné systémy a rôzne architektúry, možno ste niekedy narazili na problém, že rovnako nazývané dátové typy majú v rôznych kompilátoroch rôzne veľkosti. Dobrým príkladom je dátový typ int, ktorý má v Turbo C++ 3.0 veľkosť 2 bajty (16 bitov), v 32-bitových kompilátoroch veľkosť 4 bajty (32 bitov) a v 64-bitových kompilátoroch veľkosť 8 bajtov (64 bitov).
Aby sme sa vyhli takýmto problémom, väčšina implementácií jazyka C definuje špeciálne celočíselné dátové typy, ktoré by mali mať rovnakú veľkosť na ľubovoľnom systéme. Nás budú zaujímať hlavne tieto:
Názov | Veľkosť | Rozsah | Ekvivalent v TC 3.0 |
uint8_t | 8 bitov | 0 až 255 | unsigned char |
int8_t | 8 bitov | -128 až 127 | char |
uint16_t | 16 bitov | 0 až 65 535 | unsigned int |
int16_t | 16 bitov | -32 768 až 32 767 | int |
uint32_t | 32 bitov | 0 až 4 294 967 295 | unsigned long |
int32_t | 32 bitov | -2 147 483 648 až 2 147 483 647 | long |
Keďže Turbo C++ 3.0 ich priamo nedefinuje, používať ich môžete až po includovaní hlavičkového súboru ugh.h.
V Turbo C++ 3.0 sú dostupné aj dátové typy s plávajúcou desatinnou čiarkou.
Názov | Veľkosť | Rozsah |
float | 32 bitov | 3.4 * 10-38 až 3.4 * 1038 |
double | 64 bitov | 1.7 * 10-308 až 1.7 * 10308 |
long double | 80 bitov | 3.4 * 10-4 932 až 1.1 * 104 932 |
Ak Vás zaujíma veľkosť akéhokoľvek dátového typu, môžete ju zistiť nasledujúcim programčekom:
int main(void)
{
printf("Velkost je %d bajtov.",sizeof(uint32_t));
return 0;
}
Paleta
Paletou sa nazýva tabuľka, pomocou ktorej vie grafická karta každému indexu farby priradiť správne hodnoty RGB. Celková problematika paliet je veľmi rozsiahla, preto sa zameriam len na popis palety, ktorá sa používa v grafickom režime 0x13.
V tomto režime vie grafický karta zobraziť súčasne maximálne 256 rôznych farieb (teda s rôznymi hodnotami RGB). Po zapnutí grafického režimu sa aktivuje nasledujúca paleta:
Výber farieb je teda veľmi obmedzený a nie je vhodný na zobrazenie napríklad fotografií. Preto je možne zvoliť pre každú farbu inú hodnotu RGB zložiek, pre každú zložku z rozsahu 0 až 63. Všetkých možných farieb je teda 262 144 (2^18, teda 6 bitov pre červenú, 6 bitov pre zelenú a 6 bitov pre modrú). Po nastavení nových RGB hodnôt pre akúkoľvek farbu sa tie začínajú používať okamžite, teda všetky pixely danej farby vykreslené už skôr, budú "svietiť" už s novými hodnotami RGB.
Ďalšie režimy, s ktorými sa bežne stretneme na PC sú 15 a 16-bitové režimy (65 536 farieb), nazývané aj hi-color režimy. Tieto už z praktických príčin využívajú len pevnú paletu, ktorú nie je možné meniť. RGB zložky sú na farby mapované podľa kľúča 5-5-5, resp. 5-6-5 bitov. Pri 16-bitovom režime je na zelenú zložku využitých až 6 bitov oproti 5 pre červenú a modrú. Dôvôdom je to, že ľudské oko je najviac citlivé na zmeny práve tejto základnej farby.
Ako zaujímavosť iste stojí za zmienku to, že v hi-color režimoch je na jednu zložku (okrem už spomínanej zelenej pri 16-bit) menej bitov ako pri 256 farebnom režime. Preto sa ľahko môže stať, že po konverzii 8-bitového obrázka na 16-bitový môžete prísť o časť obrazovej informácie.
Dnes sa najčastejšie využívajú 24 a 32-bitové režimy. Tieto používajú taktiež statickú paletu a mapovanie je podľa kľúča 8-8-8, teda 8 bitov na každú zložku. Pri 32-bitovom režime je ešte takzvaná Alpha zložka, ktorá určuje priehľadnosť daného pixelu. Tá sa samozrejme nevykresľuje (málokto ma doma priehľadný monitor), ale využíva sa napríklad, ak sa kreslí viac obrazkov na seba. Tento fakt budeme využívať pri práci s OpenGL.
Pomôcky k 3D transformáciám
Najjednoduchší spôsob na aplikáciu rôznych 3D transformácií je pomocou matíc. V trojrozmernom priestore konkrétne matíc o veľkosti 4x4. Aby nebolo nutné vytvárať viacero funkcií a vystačili sme si len s jednou funkciou na násobenie matíc, samotné súradnice bodov je vhodné ukladať do matice o veľkosti 4x1, kde v poslednom riadku bude vždy jednotka. Viac si môžete prečítať na stránke http://www.devmaster.net/wiki/Transformation_matrices, odkiaľ sú prebrané aj nasledujúce obrázky pre rýchlejší prehľad samotných matíc:
Translácia
Rotácia
Bod
Ako už z rozmerov jednotlivých transformačných matíc vyplíva, môžu sa násobiť v akomkoľvek poradí, bod však musí byť vždy posledný, lebo výsledkom násobenie matice 4x4 a 4x1 je opäť matica 4x1. Čiže napríklad môžete zapísať T*Rx*p alebo aj Rx*T*p (pozor, výsledok nebude rovnaký), ale v žiadnom prípade Rx*p*T.
Čo sa týka poradia, transformácie sa aplikujú "odzadu" (od poslednej), to znamená, že ak vynásobíte T*Rx*p, tak najprv sa na bod aplikuje rotácia okolo X a až následne translácia. Pri Rx*T*p je to najprv translácia a až potom rotácia.
Keď ste získaly transformovaný bod v priestore a potrebujete ho vykresliť na obrazovku, musíte vykonať projekciu z 3D na 2D. Typov projekcií je viacero, my však budeme využívať iba jednu a to perspektívu, kde pozícia pozorovateľa je v bode [0,0,0], stred obrazovky v bode [0,0,1] a pozeráme sa rovnobežne s osou Z. Na základe týchto informácií a diagramu na wikipedii určite nebudete mať problém napísať potrebný vzorec. Pre istotu len doplním, že Bz=1, Ax, Ay, Az sú 3D súradnice bodu a Bx, By sú súradnice bodu na obrazovke.
Používanie DOSBoxu s Turbo C++
DOSBox je x86 emulátor s DOSovským prostredím, ktorý dokáže bežať vo viacerých operačných systémoch. Používa sa na hranie viacerých starších hier, no nám umožní pristupovať ku grafickému hardvéru v reálnom režime bez obmedzení, na ktoré by sme inak narazili.
K dispozícii dostanete už pripravený inštalačný balík (pre Windows) alebo komprimovanú dosbox partíciu (pre iné OS), ktorý obsahuje všetko potrebné. Po spustení DOSBoxu sa automaticky spustí súborový manažér Volcov Commander:
Prostredie Turbo C++ 3.0 môžete spustiť príkazom tc
Základné klávesové skratky prostredia:
- F10 - horné menu
- F2 - uloženie súboru
- F3 - otvorenie súboru alebo aj vytvorenie nového súboru
- F9 - kompilácia
- Ctrl+F9 - kompilácia a následné spustenie
- Ctrl+F1 - vyvolanie zoznamu príkazov jazyka C
- Shift+šípky - označenie textu
- Ctrl+Insert - skopírovanie do schránky (Copy)
- Shift+Insert - vloženie zo schránky (Paste)
- Shift+Delete - vystrihnutie do schránky (Cut)
- Alt+F3 - zatvorenie aktívneho okna
- F6 - prepínanie medzi oknami
- Alt+X - vypnutie prostredia
DOSBox má žiaľ jednu nepríjemnú vlastnosť a to neochotu meniť časy prístupu na fyzickom disku, ak si to aplikácie v ňom spustené vyžiadajú. Preto sa Vám môže stať, že pri pokuse uložiť práve editovaný súbor uvidíte nasledujúcu hlášku:
Znamená to, že prostredie niekedy predtým zadalo príkaz na nastavenie času prístupu k súboru, no DOSBox to odmietol vykonať. Pri kontrole teda prostedie uvidí súbor s pôvodným časom prístupu, čo sa nezhoduje so záznamom, ktorý ma v pamäti a preto si myslí, že súbor bol počas editovania zmenený niekym iným. Nezostáva Vám nič iné, len potvrdiť uloženie (stačí stlačiť Enter).
Horšia varianta je pri spustení programu (napríklad cez Ctrl+F9) a následnom vrátení do prostredia, kde Vás občas môže privítať nasledujúca hláška:
Ak by ste túto hlášku potvrdili, tak sa Vám aktuálne editovaný súbor nahradí verziou, ktorá je uložená na disku a teda ak ste spravili nejaké zmeny a pred kompiláciou ste si ich neuložili, prídete o nich. Preto odporúčam ukladať súbor tak často, ako to je možné (F2 a prípadný enter) a hlášku po skončení programu radšej automaticky zrušiť Escapom.
Spočiatku to môže byť dosť otravné, ale dá sa na to dosť rýchlo zvyknúť. Chce to len trochu zvyku, ktorý bezpochyby získate, kým sa budete dlhé hodiny trápiť s domácimi úlohami :)
Vtipné príkladíky
- Celkom zaujímavý efekt vytvorený pomocou zmeny palety.
(zdrojový kód,exe)
- Jednoduchý oheň. Môžete si na vlastnej koži vyskúšať rozdiel v rýchlosti zápisu priamo do pamäte a cez volanie prerušenia 0x10.
(zdrojový kód,exe)
- Sierpinskeho trojuholník.
(zdrojový kód,exe)