Lekce 29

Lekce 29 - Blitter, nahrßvßnφ .RAW textur

V tΘto lekci se nauΦφte, jak se nahrßvajφ .RAW obrßzky a konvertujφ se do textur. Dozvφte se takΘ o blitteru, grafickΘ metod∞ p°enßÜenφ dat, kterß umo₧≥uje modifikovat textury potΘ, co u₧ byly nahrßny do programu. M∙₧ete jφm zkopφrovat Φßst jednΘ textury do druhΘ, blendingem je smφchat dohromady a takΘ roztahovat. MaliΦko upravφme program tak, aby v dob∞, kdy nenφ aktivnφ, v∙bec nezat∞₧oval procesor.

Blitting... v poΦφtaΦovΘ grafice je toto slovo hodn∞ pou₧φvanΘ. OznaΦuje se jφm zkopφrovßnφ Φßsti jednΘ textury a vlo₧enφ do druhΘ. Pokud programujete ve Win API nebo MFC, jist∞ jste slyÜeli o funkcφch BitBlt() nebo StretchBlt(). P°esn∞ toto se pokusφme vytvo°it.

Chcete-li napsat funkci, kterß implementuje blitting, m∞li byste n∞co v∞d∞t o lineßrnφ grafickΘ pam∞ti. Kdy₧ se podφvßte na monitor, vidφte spousty bod∙ reprezentujφcφch n∞jak² obrßzek, ovlßdacφ prvky nebo t°eba kurzor myÜi. VÜe je prost∞ slo₧eno z matice pixel∙. Ale jak vφ grafickß karta nebo BIOS, jak nakreslit bod nap°φklad na sou°adnicφch [64; 64]? JednoduÜe! VÜechno, co je na obrazovce nenφ v matici, ale v lineßrnφ pam∞ti (v jednorozm∞rnΘm poli). Pozici bodu v pam∞ti m∙₧eme zφskat nßsledujφcφ rovnicφ:

adresa_v_pam∞ti = (pozice_y * rozliÜenφ_obrazovky_x) + pozice_x

Pokud mßme rozliÜenφ obrazovky 640x480, bude bod [64; 64] umφst∞n na pam∞¥ovΘ adrese (64*640) + 64 = 41024. Proto₧e pam∞¥, do kterΘ budeme uklßdat bitmapy je takΘ lineßrnφ, m∙₧eme tΘto vlastnosti vyu₧φt p°i p°enßÜenφ blok∙ grafick²ch dat. V²slednou adresu jeÜt∞ budeme nßsobit barevnou hloubkou obrßzku, proto₧e nepou₧φvßte jedno-bytovΘ pixely (256 barev), ale RGBA obrßzky. Pokud jste tento v²klad nepochopili, nemß cenu jφt dßl...

Vytvo°φme strukturu TEXTURE_IMAGE, kterß bude obsahovat informace o nahrßvanΘm obrßzku - Üφ°ku, v²Üku, barevnou hloubku. Pointer data bude ukazovat do dynamickΘ pam∞ti, kam nahrajeme ze souboru data obrßzku.

typedef struct Texture_Image// Struktura obrßzku

{

int width;// èφ°ka v pixelech

int height;// V²Üka v pixelech

int format;// Barevnß hloubka v bytech na pixel

unsigned char *data;// Data obrßzku

} TEXTURE_IMAGE;

DalÜφ datov² typ je ukazatelem na prßv∞ vytvo°enou strukturu. Po n∞m nßsledujφ dv∞ prom∞nnΘ t1 a t2. Do nich budeme nahrßvat obrßzky, kterΘ potom blittingem slouΦφme do jednoho a vytvo°φme z n∞j texturu.

typedef TEXTURE_IMAGE *P_TEXTURE_IMAGE;// Datov² typ ukazatele na obrßzek

P_TEXTURE_IMAGE t1;// Dva obrßzky

P_TEXTURE_IMAGE t2;

GLuint texture[1];// Jedna textura

Rot prom∞nnΘ urΦujφ ·hel rotace v²slednΘho objektu. Nic novΘho.

GLfloat xrot;// X rotace

GLfloat yrot;// Y rotace

GLfloat zrot;// Z rotace

Funkcφ AllocateTextureBuffer(), alokujeme dynamickou pam∞¥ pro obrßzek a vrßtφme ukazatel. P°i ne·sp∞chu se vracφ NULL. Funkci p°edßvß program celkem t°i parametry: Üφ°ku, v²Üku a barevnou hloubku v bytech na pixel.

P_TEXTURE_IMAGE AllocateTextureBuffer(GLint w, GLint h, GLint f)// Alokuje pam∞¥ pro obrßzek

{

Ukazatel na obrßzek ti vrßtφme na konci funkce volajφcφmu k≤du. Na zaΦßtku ho inicializujeme na NULL. Prom∞nnΘ c, p°i°adφme takΘ NULL. P°edstavuje ·lo₧iÜt∞ nahrßvan²ch dat.

P_TEXTURE_IMAGE ti = NULL;// Ukazatel na strukturu obrßzku

unsigned char *c = NULL;// Ukazatel na data obrßzku

Pomocφ standardnφ funkce malloc() se pokusφme alokovat dynamickou pam∞¥ pro strukturu obrßzku. Pokud se operace poda°φ, program pokraΦuje dßle. P°i jakΘkoli chyb∞ vrßtφ malloc() NULL. VypφÜeme chybovou zprßvu a oznßmφme volajφcφmu k≤du ne·sp∞ch.

ti = (P_TEXTURE_IMAGE)malloc(sizeof(TEXTURE_IMAGE));// Alokace pam∞ti pro strukturu

if(ti != NULL)// Poda°ila se alokace pam∞ti?

{

Po ·sp∞ÜnΘ alokaci pam∞ti vyplnφme strukturu atributy obrßzku. Barevnß hloubka nenφ v obvyklΘm formßtu bit na pixel, ale kv∙li jednoduÜÜφ manipulaci s pam∞tφ v bytech na pixel.

ti->width = w;// Nastavφ atribut Üφ°ky

ti->height = h;// Nastavφ atribut v²Üky

ti->format = f;// Nastavφ atribut barevnΘ hloubky

Stejn²m zp∙sobem jako pro strukturu alokujeme pam∞¥ i pro data obrßzku. Jejφ velikost zφskßme nßsobenφm Üφ°ky, v²Üky a barevnΘ hloubky. P°i ·sp∞chu nastavφme atribut data struktury na prßv∞ zφskanou dynamickou pam∞¥, ne·sp∞ch oÜet°φme stejn∞ jako minule.

c = (unsigned char *)malloc(w * h * f);// Alokace pam∞ti pro strukturu

if (c != NULL)// Poda°ila se alokace pam∞ti?

{

ti->data = c;// Nastavφ ukazatel na data

}

else// Alokace pam∞ti pro data se nepoda°ila

{

MessageBox(NULL, "Could Not Allocate Memory For A Texture Buffer", "BUFFER ERROR", MB_OK | MB_ICONINFORMATION);

P°ekl.: Tady by sprßvn∞ m∞la funkce vrßtit namφsto NULL prom∞nnou ti nebo jeÜt∞ lΘpe p°ed opuÜt∞nφm funkce dealokovat dynamickou pam∞¥ struktury ti. Bez vrßcenφ ukazatele nem∙₧eme z venku pam∞¥ uvolnit. Pokud operaΦnφ systΘm nepracuje tak, jak mß (Toto nenφ narß₧ka na MS Windows :-), Φili po skonΦenφ neuvolnφ poskytne zdroje programu, vznikajφ pam∞¥ovΘ ·niky.

// Uvoln∞nφ pam∞ti struktury (P°ekl.)

// free(ti);

// ti = NULL;

return NULL;

}

}

else// Alokace pam∞ti pro strukturu se nepoda°ila

{

MessageBox(NULL,"Could Not Allocate An Image Structure","IMAGE STRUCTURE ERROR",MB_OK | MB_ICONINFORMATION);

return NULL;

}

Pokud dosud nebyly ₧ßdnΘ problΘmy, vrßtφme ukazatel na strukturu ti.

return ti;// Vrßtφ ukazatel na dynamickou pam∞¥

}

Ve funkci DeallocateTexture() d∞lßme prav² opak - uvol≥ujeme pam∞¥ obrßzku, na kterou ukazuje p°edan² parametr t.

void DeallocateTexture(P_TEXTURE_IMAGE t)// Uvolnφ dynamicky alokovanou pam∞¥ obrßzku

{

if(t)// Pokud struktura obrßzku existuje

{

if(t->data)// Pokud existujφ data obrßzku

{

free(t->data);// Uvolnφ data obrßzku

}

free(t);// Uvolnφ strukturu obrßzku

}

}

VÜechno u₧ mßme p°ipravenΘ, zb²vß jenom nahrßt .RAW obrßzek. RAW formßt je nejjednoduÜÜφ a nejrychlejÜφ zp∙sob, jak nahrßt do programu texturu (samoz°ejm∞ krom∞ funkce auxDIBImageLoad()). ProΦ je to tak jednoduchΘ? Proto₧e .RAW formßt obsahuje pouze samotnß data bitmapy bez hlaviΦek nebo n∞Φeho dalÜφho. JedinΘ, co musφme ud∞lat, je otev°φt soubor a naΦφst data tak, jak jsou. TΘm∞°... bohu₧el tento formßt mß dv∞ nev²hody. Prvnφ je to, ₧e ho neotev°ete v n∞kter²ch grafick²ch editorech, o druhΘ pozd∞ji. Pochopφte sami :-(

Funkci p°edßvßme nßzev souboru a ukazatel na strukturu.

int ReadTextureData(char *filename, P_TEXTURE_IMAGE buffer)// NaΦte data obrßzku

{

Deklarujeme handle souboru, °φdφcφ prom∞nnΘ cykl∙ a prom∞nnou done, kterß indikuje ·sp∞ch/ne·sp∞ch operace volajφcφmu k≤du. Na zaΦßtku jφ p°i°adφme nulu, proto₧e obrßzek jeÜt∞ nenφ nahran². Prom∞nnou stride, kterß urΦuje velikost °ßdku, hned na zaΦßtku inicializujeme na hodnotu zφskanou vynßsobenφm Üφ°ky °ßdku v pixelech s barevnou hloubkou. Pokud bude obrßzek Üirok² 256 pixel∙ a barevnß hloubka 4 byty (32 bit∙, RGBA), velikost °ßdku bude celkem 1024 byt∙. Pointer p ukazuje do pam∞ti dat obrßzku.

FILE *f;// Handle souboru

int i, j, k;// ╪φdφcφ prom∞nnΘ cykl∙

int done = 0;// PoΦet naΦten²ch byt∙ ze souboru (nßvratovß hodnota)

int stride = buffer->width * buffer->format;// Velikost °ßdku

unsigned char *p = NULL;// Ukazatel na aktußlnφ byte pam∞ti

Otev°eme soubor pro Φtenφ v binßrnφm m≤du.

f = fopen(filename, "rb");// Otev°e soubor

if(f != NULL)// Poda°ilo se ho otev°φt?

{

Pokud soubor existuje a Üel otev°φt, zaΦneme se postupn∞ vno°ovat do cykl∙. VÜe by bylo velice jednoduchΘ, kdyby .RAW formßt byl trochu jinak uspo°ßdßn. ╪ßdky vedou, jak je obvyklΘ, zleva doprava, ale jejich po°adφ je invertovanΘ. To znamenß, ₧e prvnφ °ßdek je poslednφ, druh² p°edposlednφ atd. Vn∞jÜφ cyklus tedy nastavφme tak, aby °φdφcφ prom∞nnß ukazovala dol∙ na zaΦßtek obrßzku. Soubor naΦφtßme od zaΦßtku, ale hodnoty uklßdßme od konce pam∞ti vzh∙ru. V²sledkem je p°evrßcenφ obrßzku.

for(i = buffer->height-1; i >= 0 ; i--)// Od zdola nahoru po °ßdcφch

{

Nastavφme ukazatel, kam se prßv∞ uklßdß, na sprßvn² °ßdek pam∞ti. Jejφm zaΦßtkem je samoz°ejm∞ buffer->data. SeΦteme ho s umφst∞nφm od zaΦßtku i * velikost °ßdku. P°edstavte si, ₧e buffer->data je strßnka v pam∞ti a i * stride p°edstavuje offset. Je to ·pln∞ stejnΘ. Offsetem se pohybujeme po p°id∞lenΘ strßnce. Na zaΦßtku je maximßlnφ a postupn∞ klesß. V²sledkem je, ₧e v pam∞ti postupujeme vzh∙ru. Myslφm, ₧e je to pochopitelnΘ.

p = buffer->data + (i * stride);// P ukazuje na po₧adovan² °ßdek

Druh²m cyklem se pohybujeme zleva doprava po pixelech obrßzku (ne bytech!).

for (j = 0; j < buffer->width; j++)// Zleva doprava po pixelech

{

T°etφ cyklus prochßzφ jednotlivΘ byty v pixelu. Pokud barevnß hloubka (= byty na pixel) bude 4, cyklus projde celkem 3x (od 0 do 2; format-1). D∙vodem odeΦtenφ jedniΦky je, ₧e v∞tÜina .RAW obrßzk∙ neobsahuje alfa hodnotu, ale pouze RGB slo₧ky. Alfu nastavφme ruΦn∞.

VÜimn∞te si takΘ, ₧e ka₧d²m pr∙chodem inkrementujeme t°i prom∞nnΘ: k, p a done. ╪φdφcφ prom∞nnß k je jasnß. P ukazovalo p°ed vstupem do vÜech cykl∙ na zaΦßtek poslednφho °ßdku v pam∞ti. Postupn∞ ho inkrementujeme a₧ dosßhne ·plnΘho konce. Potom ho nastavφme na p°edposlednφ °ßdek atd. Done na konci funkce vrßtφme, oznaΦuje celkov² poΦet naΦten²ch byt∙.

for (k = 0; k < buffer->format-1; k++, p++, done++)// JednotlivΘ byty v pixelu

{

Funkce fgetc() naΦte ze souboru f jeden znak a vrßtφ ho. Tento znak mß velikost 1 byte (U₧ vφte proΦ zrovna unsigned char?). Pova₧ujeme ho za slo₧ku barvy. Proto₧e se cyklus po t°etφm pr∙chodu zastavφ, naΦteme a ulo₧φme slo₧ky R, G a B.

*p = fgetc(f);// NaΦte R, G a B slo₧ku barvy

}

Po opuÜt∞nφ cyklu p°i°adφme alfu a op∞t inkrementujeme ukazatel, aby se posunul na dalÜφ byte.

P°ekl.: Tady se hodφ poznamenat, ₧e alfa nemusφ b²t zrovna 255 (nepr∙hlednß), ale m∙₧eme ji nastavit na polovinu (122) a tak vytvo°it polopr∙hlednou texturu. Nebo si °φct, ₧e pixel o urΦit²ch slo₧kßch RGB bude pr∙hledn². V∞tÜinou se vezme Φernß nebo bφlß barva, ale nic nebrßnφ nap°. naΦtenφ levΘho hornφho pixelu obrßzku a zpr∙hledn∞nφ vÜech ostatnφch pixel∙ se stejn²m RGB. Nebo postupn∞, jak naΦφtßme jednotlivΘ pixely v °ßdku, sni₧ovat alfu od 255 do 0. Textura bude vlevo nepr∙hlednß a vpravo pr∙hlednß - plynul² p°echod. S pr∙hlednostφ se d∞lajφ hodn∞ kvalitnφ efekty. MaliΦkΘ upozorn∞nφ na konec: Efekty s alfa hodnotou jsou mo₧nΘ nejen u .RAW textur. Nezapome≥te, ₧e u₧ v 6. lekci !!! jsme m∞li p°φstup k dat∙m textury. Funkci glTexImage2D() jsme na konci LoadGLTextures() p°edßvali parametr data!

*p = 255;// Alfa nepr∙hlednß (ruΦnφ nastavenφ)

p++;// Ukazatel na dalÜφ byte

}

}

PotΘ, co projdeme vÜechny byty v pixelu, pixely v °ßdku a °ßdky v souboru se vÜechny cykly ukonΦφ. Uf, KoneΦn∞! :-) Po ukonΦenφ cykl∙ zav°eme soubor.

fclose(f);// Zav°e soubor

}

Pokud byly problΘmy s otev°enφm souboru (neexistuje ap.) zobrazφme chybovou zprßvu.

else// Soubor se nepoda°ilo otev°φt

{

MessageBox(NULL,"Unable To Open Image File","IMAGE ERROR",MB_OK | MB_ICONINFORMATION);

}

Nakonec vrßtφme done. Pokud se soubor nepoda°ilo otev°φt a my nic nenaΦetli, obsahuje nulu. Pokud bylo vÜe v po°ßdku done se rovnß poΦtu naΦten²ch byt∙.

return done;// Vrßtφ poΦet naΦten²ch byt∙

}

Mßme loadovanß data obrßzku, tak₧e vytvo°φme texturu. Funkci p°edßvßme ukazatel na obrßzek. Vygenerujeme texturu, nastavφme ji jako aktußlnφ, zvolφme lineßrnφ filtrovßnφ pro zv∞tÜenφ i zmenÜenφ a nakonec vytvo°φme mipmapovanou texturu. VÜe je ·pln∞ stejnΘ jako s knihovnou glaux, ale s tφm rozdφlem, ₧e jsme si obrßzek tentokrßt nahrßli sami.

void BuildTexture(P_TEXTURE_IMAGE tex)// Vytvo°φ texturu

{

glGenTextures(1, &texture[0]);// Generuje texturu

glBindTexture(GL_TEXTURE_2D, texture[0]);// Vybere texturu za aktußlnφ

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// Lineßrnφ filtrovßnφ

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// Mipmapovanß textura

gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, tex->width, tex->height, GL_RGBA, GL_UNSIGNED_BYTE, tex->data);

}

Funkci Blit(), kterß implementuje blitting, je p°edßvßna spousta parametr∙. Co vyjad°ujφ? Vezmeme to hezky popo°ad∞. Src je zdrojov²m obrßzkem, jeho₧ data vklßdßme do cφlovΘho obrßzku dst. Ostatnφ parametry vyznaΦujφ, kterß data se zkopφrujφ (obdΘlnφk urΦen² Φty°mi src_* Φφsly), kam se majφ do cφlovΘho obrßzku umφstit (dst_*) a jak²m zp∙sobem (blending, pop°. alfa hodnota).

// Blitting obrßzk∙

void Blit(P_TEXTURE_IMAGE src,// Zdrojov² obrßzek

P_TEXTURE_IMAGE dst,// Cφlov² obrßzek

int src_xstart,// Lev² hornφ bod kopφrovanΘ oblasti

int src_ystart,// Lev² hornφ bod kopφrovanΘ oblasti

int src_width,// èφ°ka kopφrovanΘ oblasti

int src_height,// V²Üka kopφrovanΘ oblasti

int dst_xstart,// Kam kopφrovat (lev² hornφ bod)

int dst_ystart,// Kam kopφrovat (lev² hornφ bod)

int blend,// Pou₧φt blending?

int alpha)// Hodnota alfy p°i blendingu

{

Po °φdφcφch prom∞nn²ch cykl∙ deklarujeme pomocnΘ prom∞nnΘ s a d, kterΘ ukazujφ do pam∞ti obrßzk∙. Dßle oÜet°φme p°edßvanΘ parametry tak, aby alfa hodnota byla v rozmezφ 0 a₧ 255 a blend 0 nebo 1.

int i, j, k;// ╪φdφcφ prom∞nnΘ cykl∙

unsigned char *s, *d;// PomocnΘ ukazatele na data zdroje a cφle

if(alpha > 255)// Je alfa mimo rozsah?

alpha = 255;

if(alpha < 0)

alpha = 0;

if(blend < 0)// Je blending mimo rozsah?

blend = 0;

if(blend > 1)

blend = 1;

P°ekl.: CelΘ kopφrovßnφ rad∞ji vysv∞tlφm na p°φkladu, bude snßze pochopitelnΘ. Mßme obrßzek 256 pixel∙ Üirok² a chceme zkopφrovat nap°. oblast od 50. do 200. pixelu o urΦitΘ v²Üce. P°ed vstupem do cyklu se p°esuneme na prvnφ kopφrovan² °ßdek. Potom skoΦφme na 50. pixel zleva, zkopφrujeme 150 pixel∙ a skoΦφme na konec °ßdku p°es zb²vajφcφch 56 pixel∙. VÜe opakujeme pro dalÜφ °ßdek, dokud nezkopφrujeme cel² po₧adovan² obdΘlnφk dat zdrojovΘho obrßzku do cφlovΘho.

P°φklad

Nynφ nastavφme ukazatele d a s. Cφlov² ukazatel zφskßme seΦtenφm adresy, kde zaΦφnajφ data cφlovΘho obrßzku s offsetem, kter² je v²sledkem nßsobenφ y pozice, kam zaΦneme kopφrovat, Üφ°kou obrßzku v pixelech a barevnou hloubkou obrßzku. Tφmto zφskßme °ßdek, na kterΘm zaΦφnßme kopφrovat. Zdrojov² ukazatel urΦφme analogicky.

// Ukazatele na prvnφ kopφrovan² °ßdek

d = dst->data + (dst_ystart * dst->width * dst->format);

s = src->data + (src_ystart * src->width * src->format);

Vn∞jÜφ cyklus prochßzφ kopφrovanΘ °ßdky od shora dol∙.

for (i = 0; i < src_height; i++)// ╪ßdky, ve kter²ch se kopφrujφ data

{

U₧ mßme ukazatel nastaven na sprßvn² °ßdek, ale jeÜt∞ musφme p°iΦφst x-ovou pozici, kterß se op∞t nßsobφ barevnou hloubkou. Akci provedeme pro zdrojov² i cφlov² ukazatel.

// Posun na prvnφ kopφrovan² pixel v °ßdku

s = s + (src_xstart * src->format);

d = d + (dst_xstart * dst->format);

Pointery nynφ ukazujφ na prvnφ kopφrovan² pixel. ZaΦneme cyklus, kter² v °ßdku prochßzφ jednotlivΘ pixely.

for (j = 0; j < src_width; j++)// Pixely v °ßdku, kterΘ se majφ kopφrovat

{

Nejvnit°n∞jÜφ cyklus prochßzφ jednotlivΘ byty v pixelu. VÜimn∞te si, ₧e se takΘ inkrementujφ pozice ve zdrojovΘm i cφlovΘm obrßzku.

for(k = 0; k < src->format; k++, d++, s++)// Byty v kopφrovanΘm pixelu

{

P°ichßzφ nejzajφmav∞jÜφ Φßst - vytvo°enφ alfablendingu. P°edstavte si, ₧e mßte dva pixely: Φerven² (zdroj) a zelen² (cφl). Oba le₧φ na stejn²ch sou°adnicφch. Pokud je nezpr∙hlednφte, p∙jde vid∞t pouze jeden z nich, proto₧e p∙vodnφ pixel bude nahrazen nov²m. Jak jist∞ vφte, ka₧d² pixel se sklßdß ze t°φ barevn²ch kanßl∙ RGB. Chceme-li vytvo°it alfa blending, musφme nejd°φve spoΦφtat opaΦnou hodnotu alfa kanßlu a to tak, ₧e odeΦteme tuto hodnotu od maxima (255 - alpha). Nßsobφme jφ cφlov² (zelen²) pixel a seΦteme ho se zdrojov²m (Φerven²m), kter² jsme nßsobili neupravenou alfou. Jsme skoro hotovi. KoneΦnou barvu vypoΦφtßme d∞lenφm v²sledku maximßlnφ hodnotou pr∙hlednosti (255). tuto operaci z d∙vodu v∞tÜφ rychlosti vykonßvß bitov² posun doprava o osm bit∙. A je to! Mßme pixel slo₧en² z obou p°edchßzejφcφch pixel∙. VÜimn∞te si, ₧e se v²poΦty postupn∞ provßd∞jφ se vÜemi kanßly RGBA. Vφte, co jsme prßv∞ implementovali? OpenGL techniku glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).

if (blend)// Je po₧adovßn blending?

{

*d = ((*s * alpha) + (*d * (255-alpha))) >> 8;// SlouΦenφ dvou pixel∙ do jednoho

}

Pokud nebudeme chtφt blending, jednoduÜe zkopφrujeme data ze zdrojovΘ bitmapy do cφlovΘ. Äßdnß matematika, alfa se ignoruje.

else// Bez blendingu

{

*d = *s;// ObyΦejnΘ kopφrovßnφ

}

}

}

Dojdeme-li a₧ na konec kopφrovanΘ oblasti, zv∞tÜφme ukazatel tak, aby se dostal na konec °ßdku. Pokud dob°e rozumφme ukazatel∙m a pam∞¥ov²m operacφm, je blitting hraΦkou.

// SkoΦφ ukazatelem na konec °ßdku

d = d + (dst->width - (src_width + dst_xstart)) * dst->format;

s = s + (src->width - (src_width + src_xstart)) * src->format;

}

}

Inicializace je tentokrßt zm∞n∞na od zßklad∙. Alokujeme pam∞¥ pro dva obrßzky velikΘ 256 pixel∙, kterΘ majφ barevnou hloubku 4 byty (RGBA). PotΘ se je pokusφme nahrßt. Pokud n∞co nevyjde vypφÜeme chybovou zprßvu a ukonΦφme program.

int InitGL(GLvoid)// Inicializace

{

t1 = AllocateTextureBuffer(256, 256, 4);// Alokace pam∞ti pro prvnφ obrßzek

if (ReadTextureData("Data/Monitor.raw", t1) == 0)// Nahraje data obrßzku

{

// Nic se nenahrßlo

MessageBox(NULL, "Could Not Read 'Monitor.raw' Image Data", "TEXTURE ERROR", MB_OK | MB_ICONINFORMATION);

return FALSE;

}

t2 = AllocateTextureBuffer(256, 256, 4);// Alokace pam∞ti pro druh² obrßzek

if (ReadTextureData("Data/GL.raw", t2) == 0)// Nahraje data obrßzku

{

// Nic se nenahrßlo

MessageBox(NULL, "Could Not Read 'GL.raw' Image Data", "TEXTURE ERROR", MB_OK | MB_ICONINFORMATION);

return FALSE;

}

Pokud jsme se dostali a₧ tak daleko, je bezpeΦnΘ p°edpoklßdat, ₧e m∙₧eme pracovat s daty obrßzk∙, kterΘ se pokusφme blittingem slouΦit do jednoho. P°edßme je funkci - obrßzek t2 jako zdrojov², t1 jako cφlov². V²sledn² obrßzek zφskan² slouΦenφm se ulo₧φ do t1. Vytvo°φme z n∞j texturu.

// Blitting obrßzk∙

Blit(t2,// Zdrojov² obrßzek

t1,// Cφlov² obrßzek

127,// Lev² hornφ bod kopφrovanΘ oblasti

127,// Lev² hornφ bod kopφrovanΘ oblasti

128,// èφ°ka kopφrovanΘ oblasti

128,// V²Üka kopφrovanΘ oblasti

64,// Kam kopφrovat (lev² hornφ bod)

64,// Kam kopφrovat (lev² hornφ bod)

1,// Pou₧φt blending?

128)// Hodnota alfy p°i blendingu

BuildTexture(t1);// Vytvo°φ texturu

P°ekl.: P∙vodn∞ jsem cht∞l vlo₧it obrßzky, abyste v∞d∞li, jak vypadajφ, ale bohu₧el ani jeden grafick² editor, kter² mßm zrovna doma .RAW formßt nepodporuje. V anglickΘm tutorißlu je zmφn∞no, ₧e Adobe Photoshop to svede. Ale poradil jsem si... vφte jak? OpenGL.

Obrßzek t2 Obrßzek t1 Obrßzek t1 po blittingu

Potom, co je vytvo°ena textura, m∙₧eme uvolnit pam∞¥ obou obrßzk∙.

DeallocateTexture(t1);// Uvolnφ pam∞¥ obrßzk∙

DeallocateTexture(t2);

Nßsledujφ b∞₧nß nastavenφ OpenGL.

glEnable(GL_TEXTURE_2D);// Zapne texturovßnφ

glShadeModel(GL_SMOOTH);// JemnΘ stφnovßnφ

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);// ╚ernΘ pozadφ

glClearDepth(1.0);// Povolφ mazßnφ depth bufferu

glEnable(GL_DEPTH_TEST);// Zapne testovßnφ hloubky

glDepthFunc(GL_LESS);// Typ testovßnφ hloubky

return TRUE;

}

DrawGLScene() renderuje obyΦejnou krychli - to u₧ urΦit∞ znßte.

GLvoid DrawGLScene(GLvoid)// Vykreslovßnφ

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Sma₧e buffery

glLoadIdentity();// Reset matice

glTranslatef(0.0f,0.0f,-10.0f);// P°esun do hloubky

glRotatef(xrot, 1.0f,0.0f,0.0f);// Rotace

glRotatef(yrot, 0.0f,1.0f,0.0f);

glRotatef(zrot, 0.0f,0.0f,1.0f);

glBindTexture(GL_TEXTURE_2D, texture[0]);// Zvolφ texturu

glBegin(GL_QUADS);// ZaΦßtek kreslenφ obdΘlnφk∙

// ╚elnφ st∞na

glNormal3f(0.0f, 0.0f, 1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 1.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 1.0f);

// Zadnφ st∞na

glNormal3f(0.0f, 0.0f,-1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f,-1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f,-1.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f,-1.0f,-1.0f);

// Hornφ st∞na

glNormal3f(0.0f, 1.0f, 0.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f,-1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f,-1.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);

// Dolnφ st∞na

glNormal3f(0.0f,-1.0f, 0.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 1.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,-1.0f,-1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,-1.0f,-1.0f);

// Pravß st∞na

glNormal3f(1.0f, 0.0f, 0.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f,-1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 1.0f);

// Levß st∞na

glNormal3f(-1.0f, 0.0f, 0.0f);

glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f,-1.0f);

glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 1.0f);

glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f,-1.0f);

glEnd();// Konec kreslenφ

xrot += 0.3f;// Zv∞tÜφ ·hly rotace

yrot += 0.2f;

zrot += 0.4f;

}

MaliΦko upravφme k≤d WinMain(). Pokud nenφ program aktivnφ (nap°. minimalizovan²), zavolßme WaitMessage(). VÜechno se zastavφ, dokud program neobdr₧φ n∞jakou zprßvu (obyΦejn∞ o maximalizaci okna). Ve v²sledku dosßhneme toho, ₧e pokud program nenφ aktivnφ nebude v∙bec zat∞₧ovat procesor.

// Funkce WinMain() - v hlavnφ smyΦce programu

if (!active)// Je program neaktivnφ?

{

WaitMessage();// ╚ekej na zprßvu a zatφm nic ned∞lej

}

Tak₧e to bychom m∞li. Nynφ mßte ve sv²ch hrßch, enginech, demech nebo jak²chkoli programech vÜechny dve°e otev°enΘ pro vytvß°enφ velmi efektnφch blending efekt∙. S texturov²mi buffery m∙₧ete vytvß°et v∞ci jako nap°φklad real-time plazmu nebo vodu. Vzßjemnou kombinacφ vφce obrßzk∙ (i n∞kolikrßt za sebou) je mo₧nΘ dosßhnout tΘm∞° fotorealistickΘho terΘnu. Hodn∞ Üt∞stφ.

napsal: Andreas L÷ffler & Rob Fletcher
p°elo₧il: Michal Turek - Woq & Vßclav SlovßΦek - Wessan

ZdrojovΘ k≤dy

Lekce 29

<<< Lekce 28 | Lekce 30 >>>