OpenGL.Hu - VIII. Rész

Textúrázás - 3. felvonás!

            Mint ahogy ígértem, továbbra is a textúrázás marad a témánk, hiszen most egy olyan részébe próbálom bevezetni az érdeklődőket, amely manapság a legtöbb grafikus motor igen fontos részét képezi. Ez a multitextúrázás. Mi is a lényege? Egyetlen polyra kettő vagy több textúrát húzunk rá és (a blendelést is segítségül hívva) ezzel olyan effekteket idézünk elő, amelyeket eddig csak nehézkesen tudtunk volna megoldani. Vegyük példának a jó öreg Half-Life-féle graffitit. J Sajnos ez a technika egy kicsit bonyolultabbá teszi a dolgokat, mert eredetileg nem volt része az OpenGL-nek és utólag került bele. Ráadásul a régebbi videokártyák nem is támogatják. (Azért nem kell megijedni, egy manapság átlagos GeForce2-n már rég természetes dolog a multitexturing.) Az, hogy hogyan lett megvalósítva az OpenGL-ben a multitextúrázás, ott látszik, hogy egy kis búvárkodásra lesz szükség a Windows mélységeiben, hogy ezt előcsaljuk a kártyából, pontosabban annak driveréből. (Megj.: Ismét csak a Linuxosok lelkébe fogok gázolni, ugyanis még ismerősöm sincs, aki ilyen mélységben művelné az OpenGL-t a fent említett operációs rendszer alatt.)

OpenGL Extension... Hogy mi?!

            Az utólag OpenGL-be implementált és opcionálisan támogatott funkciókat hívjuk röviden Extension-nek. Ez a definíció szép és jó, de erre gondolom nem volt nehéz rájönni. A nagy kérdés továbbra is az, hogy hogyan működnek ezek... Ja és persze, hogy milyenek vannak és melyik kell nekünk a multitextúrázáshoz. Az Extension-ök úgy lettek megoldva, hogy a driverhez kapott OpenGL32.DLL fájl tartalmazza őket, dinamikus függvényként és közvetlenül a DLL-ből kell őket meghívni... Hűha! Most fognak megkövezni, mert az elején azt mondtam, hogy elég egy minimális C/C++ ismeret. Hát akkor most ebből is tartanom kell egy gyorsított tanfolyamot. (Akinek nem lesz teljesen világos, nyugodtan küldjön e-mailt!)

            Tehát, a Windows DLL fájljai egyetlen nemes cél érdekében készültek: azért, hogy ugyanazt az erőforrást használó programok mindegyikének ne kelljen az adott erőforrást tartalmaznia, ezzel is növelve a program méretét. Erőforrás alatt bármit érthetünk: kódrészt, menüt, képet, ikont, stb. Emellett a DLL olyan szinten alkot külön egységet a programtól, hogy egy program komponenseit, ha azok DLL-ben vannak, le tudjuk cserélni, anélkül, hogy a programot magát (.Exe) módosíteni kellene. Sőt, mindezt futásidőben is meg tudjuk tenni!

Bennünket az erőforrások közül most csak a függvények érdekelnek, illetve ezek betöltése. A Windows alapesetben is többszáz .DLL fájlt tartalmaz, ezek jó része pedig rendszerszintű függvényeket, mint pl. gépleállítás, stb. Ezek összessége alkotja a Windows API-t. Ha tudjuk, hogy mit hol keressünk, ennek felhasználásával szinte bármit megtehetünk.

            Mi most speciel a már említett OpenGL32.DLL-ben keresünk függvényeket. Már csak a kérdés, hogy mit? Nos, az OpenGL-hez sok helyről (pl. a videokártya gyártójának developer oldaláról, ha van ilyen) le lehet tölteni a Glext.h nevű fájlt, amely az egyes Extension-ök betöltéséhez szükséges definíciókat tartalmazza. A DLL-ben a függvényekhez úgy tudunk hozzáférni, hogy speciális, egyedi nevük (pl. SAJAT_FUGV) vagy szamuk (egyszeru integer) adjuk meg.

A betöltést a wglGetProcAddress() függvény segítésével végezzük. Az említett függvényünk működésére egy példa a következő utasítás:

            glActiveTextureARB    =   

      (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");

      Most pedig elemezzük ki egy kicsit a fenti utasítást, hiszen így elsőre elég rémísztően hat.

A glActiveTextureARB egy változó, melynek definíciója a következő sor:

      PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;

Célja, hogy eltároljuk benne azt a memóriacímet, ahová a függvény töltődött a memóriában.

A definícióban látható típus egyike azoknak, amelyek a GLext.h-ban vannak definiálva. Ugyanezt a típust kényszerítjük rá (typecasting - típuskényszerítés, bízok benne, hogy mindenki összefutott már vele) a wglGetProcAddress által visszaadott értékre. A wglGetProcAddress paramétere a függvény neve, amelyet be akarunk tölteni. Ez a függvény nem más, mint a kívánt Extension-ünk. Habár ez a név formás és könnyen megjegyezhető, az Interneten sokszor fogunk nehezkesebb alakú Extension nevekkel találkozni.

            Összegezzük tehát, mit is tudunk eddig az egészből! Eddig a következőket kell tennünk egy OpenGL Extension beüzemeléséhez:

#include "glext.h" (No comment, ez kell és kész! J)

Kíválasztjuk a nekünk kellő Extension-t a Glext.h-ból és a megadott típussal definiálunk egy változót, amely majd a függvény címét kapja meg.

Meghívjuk a wglGetProcAddress()-t az Extension nevével és rákényszerítve a típust, megkapjuk a függvény használatához szükséges pointert.

Gondolom közben felmerült egy kérdés néhány lelkes programózóban (bízom benne, hogy minél többekben). Ez a kérdés: honnan tudom, hogy a videokártyám támogatja az adott Extension-t? Nos, ha nem támogatja, akkor valószínűleg a driverében sincs benne. Ha viszont nincs benne, akkor onnan (miután az OpenGL32.DLL a driver része) nem is tudjuk betölteni. Így elég ellenőrizni azt, hogy a betöltés sikeres volt-e, úgy hogy teszteljük, hogy a visszaadott cím NULL-e. Ha nem, akkor sikeres volt a betöltés.

            Léteznek ennél kifinomultabb megoldások is ennek tesztelésére (pl. a GLUT is tartalmaz erre egy függvényt), de mivel az esetek nagy részében ez bőven elegendő így, nem szándékoztam kitérni rájuk. Az OpenGL extension-ökről az Interneten számos helyen áll rendelkezésre információ, melyek nagy részét rendszeresen frissítik. Ezek közül a http://oss.sgi.com/projects/ogl-sample/registry cím a legjelentősebb és legkedveltebb.

            Úgy gondoltam, ez egy kicsit elméletibb rész lesz és magát a példaprogramot a következő részre hagyom, teljes magyarázattal, elemzéssel, stb. Hirtelen sok mindent kellett most elmagyarázni, de remélem, hogy sikerült valamennyire. Várom kérdéseiteket, kommentárjaitokat e-mailben illetve a fórumokon is. Jó munkát/szórakozást kívánok az OpenGL-lel!

 Merczel László - laszlo.merczel@mailbox.hu