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.
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.
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