QuestionCopyright.org

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 AHfunkciaparametre (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ázovVeľkosťRozsahEkvivalent v TC 3.0
uint8_t8 bitov0 až 255unsigned char
int8_t8 bitov-128 až 127char
uint16_t16 bitov0 až 65 535unsigned int
int16_t16 bitov-32 768 až 32 767int
uint32_t32 bitov0 až 4 294 967 295unsigned long
int32_t32 bitov-2 147 483 648 až 2 147 483 647long

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ázovVeľkosťRozsah
float32 bitov3.4 * 10-38 až 3.4 * 1038
double64 bitov1.7 * 10-308 až 1.7 * 10308
long double80 bitov3.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:

VGA 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

Translácia

Rotácia

Rotácia okolo X Rotácia okolo Y Rotácia okolo Z

Bod

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:

Volcov Commander

Prostredie Turbo C++ 3.0 môžete spustiť príkazom tc

Turbo C++ 3.0

Základné klávesové skratky 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:

Turbo C++ 3.0 - ukladanie

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:

Turbo C++ 3.0 - navrat z programu

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