Professional Documents
Culture Documents
OpenGL Játékfejlesztéssimplified
OpenGL Játékfejlesztéssimplified
Ksztette:
Kurta Istvn
Cskszereda, 2007
1
Tartalomjegyzk
Bevezets.................................................................................................................... 5 ltalnos lersok s jellemzk ................................................................................. 6
A jtkok ltalnos felptse ...................................................................................................... 6 Felhasznlt fejlesztsi eszkzk .................................................................................................. 7 A jtk konfigurcis prbeszdablaka ....................................................................................... 9 A jtk irnytsa s jellemzi ................................................................................................... 10
Knyvszet ............................................................................................................... 35
Bevezets
Az interaktv szrakoztats jelentsen megntt az elmlt vtizedben. Szmtgpes jtkok, amely egy kis piacnak indult, egy tbb milli dollros ipargg ntte ki magt. Az elmlt pr v egy gyorsan fejld irnyzatot mutat, amelynek a vge mg nincs lthatron. Az interaktv szrakoztat ipar egy robbankony piac, amely a legjabb szmtgpes technolgikat maximlisan kihasznlja s segt a mestersges intelligencia s grafika tern j fejlesztseket ltrehozni. Attl, hogy jtkiparban dolgozunk s sok olyan emberrel beszlnnk akik ugyanebben a szakmban dolgoznak, egy dolog hajtja az embereket, hogy tanuljanak s sikereket rjenek el a jtkfejleszts tern: a szrakozs. A jtkok az egyik legismertebb formi a szoftver fejlesztsnek, s a lenygz jtkok, amelyeket kiadtak az elmlt vekben, ennek a bizonyti. Jtkok, mint Halo a Bungie Softwaretl, a jtkksztst olyan szintre emeltk, amely utn az ipar soha nem lesz mr ugyanaz., mint rgen. A jtkfejlesztket az a gondolat hajtja ebben az iparban, hogy olyan egyni virtulis vilgokat alkossanak, amelyet majd ezrek, ha nem millik fognak egy nap tapasztalni. A jtkfejleszt arra trekszik, hogy j kihvsokkal nzzen szembe, j technolgikat s vilgokat fedezzen fel. Br sok vllalat hozzjrult a 3D jtkok fejldshez, egy specilis emltst kell tenni az idSoftware-rl, amely nagy gyorstja volt a 3D jtkok emelkedsben. Tbb, mint 10 ve, John Carmack, s vllalata egy kis jtkot mutatott be a vilgnak Wolfenstein 3D nven. Wolf3D a jtk vilgot trdre knyszertette a valsidej 3D sugrkvet grafikjval s egy olyan vilggal, amely hatsra a jtkosok tbb rn keresztl a szmtgp eltt jtszottak. A jtk egy j kezdet volt az ipar szmra, s soha nem nzett vissza. 1993-ban, a Doom vilga uralkodott, s a 3D technolgit egy lpssel tovbbfejlesztette a 2.5D-s jtkmotorral. A jtkvilg nnepelt az idSoftware ltal behozott technikai jtsoktl, amelyek a Doom-ban voltak fellelhetek, de a fejlds nem llt meg itt. Egy pr vvel ksbb, Quake megvltoztatta vglegesen a 3D jtkokat. A lehetsgeket most mr csak az korltozta, hogy hny poligont kpes a CPU (s alkalomszeren a GPU) a kpernyn megjelenteni. A Quake kiadsa ta, az ipar szinte minden hnapban jabb technolgiai fejlesztsekkel gyarapodik. A 3D jtkok fejldse rvn ltrejttek a 3D gyorst krtyk, amelyek a 3D matematikai szmtsokat a sajt processzorkban vgzik el. Most minden hatodik hnapban j hardvert adnak ki, amely ktszer akkora teljestmnnyel (nyers er, gyorsasg s rugalmassg) br, mint az eldje. Ez a dolgozat a kezd jtkfejlesztknek szeretne segtsget nyjtani, hogy knnyedn megtanulhassk az alapvet technikkat s lpseket jtkprogramok ksztshez egy egyszer jtkprogram fejlesztsnek lpsenknti bemutatsa sorn, amely egy egyser replgp szimultor. Minden egyes lps fejezetenknt van trgyalva, esetenknt forrskd rszletekkel s hivatkozsokkal, hogy az adott rsz, amelyrl ppen sz van, mely forrskdban van implementlva. A dolgozat legelejn bemutatsra kerlnek a felhasznlt programok s fejlesztsi krnyezetek s rvid lers arrl, hogy mikbl is ll egy jtkprogram s kiknek a munkjra van szksg. A dolgozat leginkbb az OpenGL grafikus rendszerrl fog szlni, s annak hasznlatrl, majd sz lesz arrl is hogyan lehet hangokat hozzilleszteni a jtkunkhoz az OpenAL hangrendszer segtsgvel, majd a legvgn rviden bemutatjuk azt is, hogy hogyan kszthetnk hlzatos jtkot az addig elkszlt programunkbl. A dolgozat elksztshez nagyrszt angol forrsanyagok kerltek felhasznlsra, mivel ezekben tallhatak a legrszletesebb lersok az OpenGL-rl s a felhasznlt szoftver fejlesztsi krnyezetekrl. Remlem itten elegend informcit tudok szolgltatni azok szmra akik szeretnk megtanulni az OpenGL grafikus rendszer hasznlatt s a vele kapcsolatos jtkfejlesztsi lpseket. 3
dntsek hozdnak meg a bemenet s kimenet vezrlsre. A fenti brn lthat architektra elgg egyszer, br a kvetkez brn lthat hogyan nz ki egy komplexebb jtk architektrja.
Sokkal komplexebb komponensek fejlesztdnek s hasznldnak fel, ahhoz hogy bizonyos tulajdonsgokat s mkdskszsgeket implementljanak, amelyek szksgesek a jtk szoftver j mkdshez. Mikor jtkot fejlesztnk, akkor egy mtrgyat alkotunk, amelyet oly mdon is kell kezelni. Fel kell legynk kszlve j dolgok kiprblsra s jratervezznk ltez technolgikat, hogy az elvrsainknak megfeleljenek. Nincs egy meghatrozott md a jtkfejlesztsre, ugyangy mint ahogy egy kpnek a festsre sincs egy megadott eljrs. Trekedjnk arra, hogy legynk innovatvak s lltsunk fel j standardokat.
meghatrozza azokat az objektumokat s mveleteket, amelyek szksgesek a magas minsg hang kimenethez, fleg tbbcsatorns kimenetre a 3D trben elhelyezett hangforrsok esetn egy hallgat krl. Az OpenAL platform fggetlen s knnyen hasznlhat. Az OpenGL-hez hasonl programozsi stlust, szintaxist s konvencikat alkalmaz. A programoz szempontjbl, OpenAL utastsok gyjtemnye, amelyek lehetv teszik a hang forrsok megadst s a hallgatt a hrom dimenzis trben, kombinlva olyan utastsokkal, amelyek irnytjk a hangforrsok megjelentst a kimeneti pufferbe. Az OpenAL parancsok hatsa nem garantlt, hogy azonnali, mivel vrakozsi idk lphetnek fel az implementcitl fggen, de idelis esetben ez a kss nem rzkelhet a felhasznl ltal. Egy tipikus program, amely OpenAL-t hasznl olyan fggvnyhvsokkal kezddik, amelyek megnyitnak egy hang eszkzt, amelyet, a kimenet feldolgozsra s annak a hozzcsatolt hardvern visszajtsszon (hangszrk vagy fejhallgat). Majd, hivatkozsok trtnnek, hogy egy AL kontextust foglaljunk s hozzrendeljk az audio eszkzhz. Amint egy AL kontextus lefoglaldott, a programoz szabadon hasznlhatja az AL utastsokat. Egyes utastsok a forrsok megjelentsre (pont s irnytott forrsok, ciklikus vagy sem) , mg msok a forrsok megjelentst befolysoljk, hogyan halkul el tvolsg vltozsnl s relatv irny esetn. A jtkban tallhat 3D modellek Milkshape 3D modellez program segtsgvel kszltek. Ez egy ingyenesen letlthet program, amelyben nagyon hatkonyan s gyorsan lehet modelleket kszteni. A replgp modell Half-Life modell, amely egy modell fjl s tbb animcis llomny, valamint a textrk kompillsval hozhat ltre mdl kiterjesztssel . A plyamodellek pedig Milkshape 3D modellek, amelyek ms3d kiterjesztssel mentdnek s nem ignyelnek kompillst, azonban a textrkat kell mellkelni.
szlelhetek, mg textra srts nlkl hibtlanul fognak megjelenni a textrk. A textra srtst viszont 16 bites szn md hasznlata esetn be kell kapcsolni, mert torzulsok lesznek
szlelhetek anlkl, teht az ellenkezje trtnik, mint 32 bites sznmd hasznlata esetn. Az anisotropic szrs az lek elsimtsra hasznlatos OpenGL kibvt eljrs, amelyrl bvebben ksbb lesz sz. Majd lehetsgnk van, arra hogy hlzatos jtk mdot indtsunk, aktivlva a Multiplayer jell ngyzetet, ezutn pedig lehetsgnk van arra, hogy kivlasszuk, hogy szerver vagy kliens szerepet fog betlteni az indul program. Ezutn az Okra kattintva elmentdik az aktulis konfigurci a config.fdt elnevezs llomnyba s elindul a jtk, vagy az Exit gombra kattintva ments nlkl bezrul a program. 7
Felbonts, sznmlysg s frissts Textra minsg Vilgts ki/be kapcsolsa Vilgts komponenseinek ki/be kapcsolsa A plya kd effektusnak ki/be kapcsolsa Plya felbonts a (hromszgekben) Textra srts s anisotropic szrs ki/be kapcsolsa Hlzatos jtk md ki/be kapcsolsa Kliens vagy szerver mdban induljon a jtk Szerver IP cme vagy neve
A konfigurcis ablak a Visual C++ Resource editorval kszlt drag&drop technikval, majd minden windows kontrollnak kln-kln azonost lett adva, mert a forrskdban trtnik a tulajdonsgaiknak a mdostsa s ezeken az azonostkon keresztl lehet hivatkozni rjuk. A jell ngyzetek stt llapotukban ki vannak kapcsolva, a Server-Client nyomgombok kzl pedig mindig csak az egyiket lehet kivlasztani. A vilgts s hlzatos gombok ha kikapcsolt llapotban vannak, akkor az csoportjba tartoz windows kontrollok inaktv llapotba kerlnek, gy ezek llapott nem lehet mdostani.
Jtk implementcija
OpenGL megjelents Win32 alkalmazs ltrehozsa
Ebben a fejezetben arrl lesz, hogy miknt kell egy OpenGL megjelents ablakot ltrehozni a Visual Studio hasznlatval. Legelszr a Visual C++ segtsgvel ltrehozunk egy j projektet, a File->New menpontot kivlasztva, majd a felbukkan ablakban a Projects flre kattintunk s itt a Win32 Application elemet vlasztjuk ki, ezutn a Project name alatt megadjuk a projektnk nevt, a Location alatt pedig a mentsi helyt a projektnknek. rdemes egy j knyvtrat ltrehozni s ennek az elrsi tvonalt megadni, mert a Visual C++ klnbz fjlokat generl a kompills sorn. lltsuk a Create new workspace-re a rdigombot, ha nem azon tallhat, hogy egy tiszta munkafelleten tudjunk, dolgozni, mert hanem hozz fogja fzni egy mr ltez munkafellethez ami mr ltezik. A Platforms alatt pedig a Win32 mdot jelljk be. Az Okra kattintva a kvetkez ablakban vlasszuk az res projektet gy nem fog a Visual C++ flsleges llomnyokat generlni. Ezutn ltrehozzuk a projektnk f forrsllomnyt, amely irnytja az alkalmazs futst. Vlasszuk ki a File->New menpontot, ezutn a Files flre kattintva vlasszuk a C++ Source File pontot s a File name alatt adjunk neki nevet (Main.cpp), majd kattintsunk az Okra. Ezutn jhet a forrskd szerkesztse. Legelszr a library (fggvny gyjtemnyt tartalmaz llomny) llomnyokat csatoljuk a forrsllomnyunkhoz, gy kompills sorn a Visual Studio az alaprtelmezett knyvtraiban utna keres s hozzcsatolja a projekthez.
#pragma #pragma #pragma comment (lib, "opengl32.lib") comment (lib, "glu32.lib") comment (lib, "glaux.lib")
Az els hrom llomny az OpenGL fggvnyeihez szksgesek. A kvetkez konstans hatsra a projektbe nem fogja belekompillni a ritkn hasznlt dolgokat a header llomnyokbl: #define WIN32_LEAN_AND_MEAN. A kvetkez lps a header llomnyok megadsa, amelyek hasznljk a fenti librarykben tallhat fggvnyeket, illetve azokat melyek szksgesek a windows ablak ltrehozshoz s windows kontrollok irnytshoz.
#include <windows.h> #include <winbase.h> #include <gl/gl.h> #include <gl/glu.h> #include <gl/glaux.h> // Header llomny a windowshoz // Windows base // Header llomny az OpenGL32 libraryhez // Header llomny az GLu32 libraryhez // Header llomny az Glaux libraryhez
Most jhetnek a globlis vltozok deklarlsai, amelyeket felhasznlunk az ablak ltrehozsra s billentyzet lekezelsre, hogy ellenrizni tudjuk, hogy a program aktv llapotban van-e, a kperny belltsok elvgzshez szksges vltozk, a kd, vilgts s anyag tulajdonsgokat tartalmaz vltozk is itten vannak deklarlva.
HDC HGLRC HWND HINSTANCE DEVMODE bool bool hDC=NULL; hRC=NULL; hWnd=NULL; hInstance; // Privt GDI eszkz kapcsolat // lland megjelentsi kapcsolat // Ablak eszkzkapcsolat-ler // Alkalmazs folyamata // Kperny belltsok
GLuint fogMode[] = {GL_EXP, GL_EXP2, GL_LINEAR}; // Kd tpusok GLuint fogFilter = 2; // Melyik kd mdot hasznljuk GLfloat fogColor[4] = {0.75f, 0.75f, 0.75f, 1.0f}; // Kd szne GLfloat fogStart = 0.0f; // Kd kezdpontja GLfloat fogEnd = 5.0f; // Kd vgpontja
bool lighting, diffuse, specular; // Vilgts s komponenseinek ki/be kapcsolsa GLfloat LightAmbient[] = {0.5f, 0.5f, 0.5f, 1.0f}; // Ambient vilgts rtke GLfloat LightDiffuse[] = {0.7f, 0.7f, 0.7f, 1.0f}; // Diffuse vilgts rtke GLfloat LightSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f}; // Specular vilgts rtke GLfloat LightPosition[] = {-999.0f, 999.9f, 999.0f, 1.0f}; // Fny pozcija float MatAmb[] = {0.5f, 0.5f, 0.5f, 1.0f}; float MatDif[] = {0.7f, 0.7f, 0.7f, 1.0f}; float MatSpc[] = {1.0f, 1.0f, 1.0f, 1.0f}; float MatShn[] = {0.7f}; // Anyag ambient rtke // Anyag diffuse rtke // Anyag specular rtke // Anyag fnyessge
Ezutn kvetkeznek azok a fggvnyek, amelyeknek csak a deklarcija van meg, mg az implementcijukra ksbb kerl sor a program szerkezet felptse s a fggvnyhivatkozsok szempontjbl.
LRESULT LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); CALLBACK ConfigDlgProc (HWND, UINT, WPARAM, LPARAM);
A kvetkez lps a fggvnyek definciinak lersai. A legels a rajzolsi terlet tmretezsvel kapcsolatos (ReSizeGLScene), vagyis mekkora terleten rajzolunk az ablakban, ami most a teljes ablak mrete lesz, s mg a vettsi mdot adjuk meg. Ebben az esetben perspektv vetts specifiklunk 75 fokos ltszggel, az ablak szlessgnek s magassgnak hnyadosa adja az aspektust, a kzeli vgsk a 0.1-ben, a tvoli vgsk meg 3000-ben lesz.
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) { if (height==0) // Kiszrjk a 0-val val osztst { height=1; // Magassgot egyenlv tesszk eggyel } glViewport (0,0,width,height); // Ltrejv kp mretnek megadsa glMatrixMode (GL_PROJECTION); // Kivlasztjuk a vettsi mtrixot glLoadIdentity(); // Betltjk az identikus mtrixot a vetts visszalltsra // Az ablak aspektusnak belltsa gluPerspective (75.0f, (GLfloat)width/(GLfloat)height, 0.1f, 3000.0f); glMatrixMode (GL_MODELVIEW); // A modell-nzet mtrix kivlasztsa glLoadIdentity(); // A modell-nzet mtrix visszalltsa }
A fggvny meghvsrl ksbb lesz sz. A kvetkez fggvny implementci az a fggvny, amely inicializlja az OpenGL megjelentsi mdjt (InitGL): rnykolsi modell, lsimts mdja, trl sznt, a mlysgi tesztelssel kapcsolatos belltsokat, a perspektivikus megjelents minsgt, majd ezeket kveten a kd, vilgts, s anyagtulajdonsgokat.
int InitGL(GLvoid) { glEnable (GL_TEXTURE_2D); // Textrzs engedlyezse glShadeModel (GL_SMOOTH); // Elsimtott rnykolsi modell alkalmazsa glClearColor (0.0f, 0.0f, 0.0f, 1.0f); // Trlszn glClearDepth (1.0f); // Mlysgi puffer trlse (belltsa) glEnable (GL_DEPTH_TEST); // Mlysgellenrzs bekapcsolsa glDepthFunc (GL_LEQUAL); // Milyen mlysgellenrzst vgezznk glEnable (GL_COLOR_MATERIAL); // Anyag sznezs bekapcsolsa // J minsg perspektv megjelents glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Kd belltsa glFogi (GL_FOG_MODE, fogMode[fogFilter]); // Kd tpus belltsa glFogfv (GL_FOG_COLOR, fogColor); // Kd sznnek belltsa glFogf (GL_FOG_DENSITY, 0.1f); // Kd srsgnek megadsa glHint (GL_FOG_HINT, GL_NICEST);// Kd minsgnek megadsa glFogf (GL_FOG_START, fogStart); // Kd kezdpontja glFogf (GL_FOG_END, fogEnd); // Kd vgpontja
10
glEnable (GL_FOG);
// Kd bekapcsolsa
if (lighting) // Ha a lighting rtke true akkor bekapcsoljuk a vilgtst { // A poligonok mindkt oldalnak megvilgtsnak bekapcsolsa glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); // A GL_LIGHT1 fnyforrs ambient komponensnek belltsa glLightfv (GL_LIGHT1, GL_AMBIENT, LightAmbient); if (diffuse) // Ha diffuse rtke true akkor belltjuk a vilgtsi mdot // Fnyforrs diffuse komponensnek belltsa glLightfv (GL_LIGHT1, GL_DIFFUSE, LightDiffuse); if (specular) // Ha specular rtke true akkor belltjuk a specular mdot // Fnyforrs specular komponensnek belltsa glLightfv (GL_LIGHT1, GL_SPECULAR, LightSpecular); // A fnyforrs pozcijnak belltsa glLightfv (GL_LIGHT1, GL_POSITION, LightPosition); glEnable (GL_LIGHT1); // Fnyforrs bekapcsolsa glEnable (GL_LIGHTING); // Vilgts bekapcsolsa } // Anyag ambient, diffuse, specular tulajdonsgnak belltsa glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, MatAmb); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MatDif); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, MatSpc); // Anyag csillogsnak belltsa glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, MatShn); return true; // Az inicializls sikeres volt }
A megjelents a kvetkezkben definilt fggvny segtsgvel trtnik (DrawGLScene). Ide fognak kerlni a plya, replgp s egyb a megjelentshez szksges fggvnyhivatkozsok. Egyelre csak a kperny s mlysgi puffer trlse, majd az identikus mtrix betltse a vetts visszalltshoz fontos fggvnyek hvdnak meg.
bool DrawGLScene() { // Szn s mlysgi puffer trlse glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); // A modell-nzet mtrix visszalltsa return true; } // A kirajzolssal minden rendben
A kvetkez fggvny a fprogram vgn hvdik meg, vagy abban az esetben ha az OpenGL megjelent ablak ltrehozsa sorn hiba trtnt (KillGLWindow). A legels dolog, hogy visszavltunk a windows asztal felbontsra, majd megjelentjk a kurzort. Leellenrizzk, hogy van-e megjelentsi kapcsolatunk, leellenrizzk, hogy fel tudjuk-e szabadtani a megjelentsi s eszkz kapcsolatot. Majd felszabadtjuk a megjelentsi kapcsolatot, ha meg tudjuk tenni. Ezutn az eszkz kapcsolatot szabadtjuk fel, vgl az ablakot is felszabadtjuk s az ablak osztlyt trljk. Minden hiba esetn egy prbeszdablakban meg fog jelenni a megfelel hibazenet
GLvoid KillGLWindow(GLvoid) { ChangeDisplaySettings (NULL, 0); ShowCursor (true); // Kpernyfelbonts visszalltsa // Egr mutat megjelentse
if (hRC) // Van-e megjelentsi kapcsolatunk (context)? { // Fel tudjuk-e szabadtani a megjelentsi s eszkz kapcsolatot if (! wglMakeCurrent(NULL, NULL)) { MessageBox(NULL,"Megjelentsi s eszkz kapcsolat hiba!", "Bezsri hiba", MB_OK | MB_ICONINFORMATION); }
11
// Felszabadtjuk a megjelentsi kapcsolatot if (! wglDeleteContext (hRC)) { MessageBox(NULL,"Megjelentsi kapcsolat felszabadtsa sikertelen!", "Bezrsi hiba", MB_OK | MB_ICONINFORMATION); } hRC=NULL; // Megjelentsi kapcsolat NULL rtkre lltsa } if (hDC && !ReleaseDC (hWnd, hDC)) // Eszkz kapcsolat felszabadtsa { MessageBox(NULL, "Eszkz kapcsolat felszabadtsi hiba", "Bezrsi hiba!", MB_OK | MB_ICONINFORMATION); hDC=NULL; // Megjelentsi kapcsolat NULL rtkre lltsa } if (hWnd && !DestroyWindow (hWnd)) // Ablak felszabadtsa { MessageBox(NULL, "Ablak felszabadtsa sikertelen!", "Bezrsi hiba", MB_OK | MB_ICONINFORMATION); hWnd=NULL; // Ablak NULL rtkre lltsa } // Ablak osztlynak felszabadtsa if (!UnregisterClass("OpenGL", hInstance)) { MessageBox (NULL, "Ablak osztlynak felszabadtsa sikertelen!, "Bezrsi hiba", MB_OK | MB_ICONINFORMATION); hInstance=NULL; // Alkalmazs folyamatnak NULL rtkre lltsa } }
Miutn az OpenGL felszabadt eljrst implementltuk, kvetkezik az a fggvny, amely segtsgvel felptjk az OpenGL megjelents ablakunkat (CreateGLWindow). A fggvny trzsben els lpsknt ltrehozzuk a szksges vltozkat az ablak inicializlshoz, majd ezt kveten kivlasztjuk az ablakunk folyamatt s felptjk az ablakunk osztlyt. Majd megprbljuk regisztrlni az ablak osztlyt. Ha ez sikertelen akkor kiratunk egy hibazenetet s kilpnk a programbl. Ha a regisztrci sikeres volt, kvetkezik a konfigurcis prbeszdablak megjelentse s a prbeszdablak fggvnyre val hivatkozs, ahol trtnnek a konfigurcis belltsok. Mieltt folytatnnk az ablak ltrehoz fggvny defincijt, ltre kell hozzuk a konfigurcis prbeszdablakunkat. Ezt megtehetjk, ha Visual C++-ban az Insert->Resource menpontot vlasztjuk, a felbukkan ablakban a Dialog komponenst vlasztjuk, majd az Okra kattintunk. Ennek hatsra automatikusan megjelenik a ltrehozott prbeszdablak a Visual C++ Resource editorban. A prbeszdablakra ktszer kattintva eljn annak a tulajdonsgait tartalmaz ablak, s a General flet kivlasztva bellthatjuk a nevt, amit most IDD_CONFIGra lltunk, s a Caption alatt megadhatjuk, hogy mi jelenjen meg a prbeszdablak fejlcben, ugyanitt bellthat a betstlus s mret. Miutn ez is megtrtnt vlasszuk a Styles flet s itten lltsuk a Style alatti legrdl listbl a Popup stlust, amely hatsra egy felugr ablak szerept fogja betlteni. Ugyanitt bellthatjuk, hogy milyen komponensei jelenjenek meg a prbeszdablaknak. Ebben az esetben a minimalizl s maximalizl gombok ki vannak vve, mert azt szeretnnk hogy ne lehessen a mrett vltoztatni az ablaknak. A More styles fln adjuk meg, hogy igaztsa az ablakot a kperny kzepre, amikor megjelenik, ezt a Center jellngyzet bejellsvel tehetjk meg. Ha ezzel ksz vagyunk, jhetnek a szksges windows kontrollok, amelyekkel majd ki tudjuk vlasztani a kvnt belltsokat. Elszr ltre fogjuk hozni a Felbontst bellt legrdl listt. A Controls ablakbl kivlasztjuk a Combo Box elemet, s a prbeszdablakunkon kattintva megjelenik a legrdl lista. Erre ktszer kattintva megadjuk az azonostjt, s a Styles fln kattintva, itten megadjuk a tpust ami most, Drop list lesz, ez azrt fontos mert gy a felhasznl nem tud egyni mdot berni, hanem kell vlasszon a 12
lehetsges mdok kzl. A Sort jell ngyzetbl vegyk ki a pipt, mert ha rendezni fogja az elemeket, nem tudjuk majd irnytani megfelelen a kivlasztsokat. A tbbi legrdl lista is ebben a stlusban kszl. Ahhoz hogy tudjuk az a bizonyos legrdl lista mit is vgez helyezznk el mell egy statikus szvegmezt, amelybe berjuk a nevet. A jellngyzetek is hasonlan helyezdnek el a prbeszdablakban, annyi klnbsggel, hogy a Caption alatt kell megadjuk a nevt, majd a Styles fln a Horizontal s Vertical alignmentnl Center-t vlasztunk, hogy a jellngyzetben lev szveg kzpre legyen igaztva, de ez szabadon vlaszthat. Ugyanitt be lett jellve a Push-like s Flat jellngyzetek, gy egy laptott gombhoz hasonl hatst rnk el. Ha ki van jellve vilgos rnyalat lesz a jellngyzet, ellenkez esetben pedig stt. Az Extended Style fln abban az esetben jelljk be a Transparent (tltsz mdot), hogyha a jellngyzet egy msik windows kontrol fltt van, mint pldul ebben az esetben egy Group Box fltt, ms esetekben nem jelljk be. A rdi gombok (Client s Server) a jellngyzettel hasonl stlusban kszl, csak a Styles oldalon nem jelljk be a Flat stlust. Miutn ez megtrtnt, a f forrsllomnyuk legelejre betesszk a resource.h header llomnyra val hivatkozst, mert ebben vannak eltrolva a prbeszdablak tulajdonsgai. Az ablak ltrehoz fggvnynkben, ezt kveten leellenrizzk, hogy milyen rtkkel lptnk ki a prbeszdablakbl. Ha az Okra kattintottunk az aktulis belltsok elmentdnek, ellenkez esetben kilp a programbl ments nlkl. Ezutn belltjuk az ablak mreteit, tvltunk teljes kpernys mdba. Belltjuk az ablak stlust, amely kiterjesztet felbukkan ablak s elrejtjk az egrmutatt. Az ablakot a kvnt stlusra llts utn, ltrehozzuk az ablakot. A pfd vltoz belltsval tudjuk megadni, hogy tmogassa az OpenGL-t az ablakunk, milyen sznmlysgben fusson, tmogassa-e a dupla puffer technikt s a z-buffer mlysgtesztelst. Miutn ez is megtrtnt megnzzk, hogy ltezik-e eszkzkapcsolatunk. Ha van akkor belltjuk a pixel formtumot, majd ltrehozzuk az OpenGL kapcsolatot, s bekapcsoljuk ezt. Miutn mindezek sikeresen megtrtntek megjelentjk az ablakot, egy keveset megnveljk a prioritst s a fkusz rlltjuk az ablakunkra s meghvjuk az elbbiekben definilt ReSizeGLScene fggvnyt, hogy segtsgvel belltsuk a ltmez mrett, vagyis ahov fogunk rajzolni az ablakban, ami most a teljes ablak mrete lesz teljes kpernys mdban. Ha egy if utasts trzsben false rtket trt vissza a fggvny akkor, a program le fog llni.
bool CreateGLWindow() { GLuint PixelFormat; WNDCLASS wc; DWORD dwExStyle; DWORD dwStyle; RECT WindowRect; // Pixel formtum // Ablak osztly // Kibvtett ablak stlus // Ablak stlus // Ablak bal-fels s jobb-als koordintihoz
// Kivlasztjuk az ablakunk folyamatt hInstance = GetModuleHandle(NULL); // tmretezs esetn jrarajzols, s sajt eszkz kapcsolat ltrehozsa wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // WndProc fggvny lesz a rendszer zenet feldolgoz wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; // Semmilyen extra ablakadat wc.cbWndExtra = 0; // wc.hInstance = hInstance; // Folyamat belltsa // Alaprtelmezett ikon betltse wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Az egr mutat betltse wc.hCursor = LoadCursor(NULL, IDC_ARROW); // OpenGL-hez nem szksges az ablak httr wc.hbrBackground = NULL; wc.lpszMenuName = NULL; // Nem hasznlunk ment wc.lpszClassName = "OpenGL"; // Osztly neve if (!RegisterClass(&wc)) // Megprbljuk regisztrlni az ablak osztlyt {
13
MessageBox (NULL, "Ablak osztly regisztrcis MB_OK|MB_ICONEXCLAMATION); return false; // false rtkkel kilpnk a fggvnybl }
hiba!",
"Hiba",
if (!DialogBox (hInstance, MAKEINTRESOURCE(IDD_CONFIG), NULL, (DLGPROC)ConfigDlgProc)) // Prbeszdablak megjelentse { MessageBox (NULL, "Semmi vltozs nem trtnt a belltsokban!", "Informci", MB_OK | MB_ICONINFORMATION); KillGLWindow(); // Ablak felszabadtsa exit(1); // kilpnk a fggvnybl } // Belltjuk azt, hogy milyen tulajdonsgokat fogunk mdostani a // kpernyvel kapcsolatosan dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; WindowRect.left = (long)0; // Ablak keret bal szlnek pozcija WindowRect.top= (long)0; // Ablak keret fels szlnek pozcija WindowRect.right = dmScreenSettings.dmPelsWidth; // Jobb szle WindowRect.bottom = dmScreenSettings.dmPelsHeight; // Als szle // Megprbljuk belltani a kpernyt if (ChangeDisplaySettings (&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { MessageBox (NULL, "A kvnt teljes kpernys belltsokat nem tmogatja a videokrtya!", "Hiba", MB_OK|MB_ICONSTOP); return false; // false rtkkel kilpnk a fggvnybl } dwExStyle = WS_EX_APPWINDOW; dwStyle = WS_POPUP; ShowCursor (false); // Ablak bvtett stlusa // Ablak stlusa // Egrmutat elrejtse
// Ablak mretnek belltsa a kvnt rtkre AdjustWindowRectEx (&WindowRect, dwStyle, false, dwExStyle); // Ltrehozzuk az ablakot if (!(hWnd=CreateWindowEx (dwExStyle, // Kibvtett stlus "OpenGL", // Osztly neve NULL, // Ablak fejlc neve dwStyle | // Definilt ablak stlus WS_CLIPSIBLINGS | // Kvnt stlus WS_CLIPCHILDREN, // Kvnt stlus 0, 0, // Ablak pozcija // Az ablak szlessgnek kiszmolsa WindowRect.right-WindowRect.left, // Az ablak magassgnak kiszmolsa WindowRect.bottom-WindowRect.top, NULL, // Szl ablak nem lesz NULL, // Men nem lesz hInstance, // Folyamat // WM_CREATE-nek nem adunk t semmit NULL))) { KillGLWindow(); // Ablak felszabadtsa MessageBox (NULL, "Ablak ltrehozsi hiba!", MB_OK|MB_ICONEXCLAMATION); return false; // false rtkkel kilpnk a fggvnybl }
"Hiba",
14
// pfd megmondja windowsnak hogyan legyenek a dolgok static PIXELFORMATDESCRIPTOR pfd= { // Pixel formtum ler mrete sizeof (PIXELFORMATDESCRIPTOR), 1, // Verzi szm // Formtum kell tmogassa az ablakba val rajzolst PFD_DRAW_TO_WINDOW | // A formtum kell tmogassa az OpenGL-t PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Kell tmogassa a dupla puffer technikt PFD_TYPE_RGBA, // RGBA formtum specifiklsa // Sznmlysg belltsa (unsigned char)dmScreenSettings.dmBitsPerPel, 0, 0, 0, 0, 0, 0, // Szn bitek mellzse 0, // Nem hasznlunk alfa puffert 0, // Eltolsi bit mellzse 0, // Nem hasznlunk gyjt puffert 0, 0, 0, 0, // Gyjt bitek mellzse 16, // 16 bites Z-buffer alkalmazsa 0, // Nem hasznlunk stencil puffert 0, // Nem hasznlunk kiegszt puffert PFD_MAIN_PLANE, // F rajzolsi rteg 0, // Foglalt (fenntartott) 0, 0, 0 // Rteg maszkok mellzse }; if (! (hDC = GetDC (hWnd))) // Eszkz kapcsolatot elrhet-e? { KillGLWindow(); // Ablak felszabadtsa MessageBox(NULL, "OpenGL eszkz kapcsolat ltrehozsi hiba!", "Hiba", MB_OK|MB_ICONEXCLAMATION); return false; // false rtkkel kilpnk a fggvnybl } // Kapott a windows egy megfelel pixel formtumot? if (! (PixelFormat = ChoosePixelFormat (hDC,&pfd))) { KillGLWindow(); // Ablak felszabadtsa MessageBox (NULL, "Nincs megfelel pixel formtum!", "Hiba", MB_OK | MB_ICONEXCLAMATION); return false; // false rtkkel kilpnk a fggvnybl } // Be tudjuk lltani a pixel formtumot? if(! SetPixelFormat (hDC, PixelFormat, &pfd)) { KillGLWindow(); // Ablak felszabadtsa MessageBox (NULL, "Pixel formtum belltsi hiba!", "Hiba", MB_OK | MB_ICONEXCLAMATION); return false; // false rtkkel kilpnk a fggvnybl } // Megjelentsi kapcsolat ltrehozhat-e? if (! (hRC = wglCreateContext (hDC))) { KillGLWindow(); // Ablak felszabadtsa MessageBox (NULL, "OpenGL megjelentsi kapcsolat ltrehozsa sikertelen!", "Hiba", MB_OK|MB_ICONEXCLAMATION); return false; // false rtkkel kilpnk a fggvnybl } // Megprbljuk aktivlni a megjelentsi kapcsolatot if(!wglMakeCurrent (hDC, hRC)) {
15
KillGLWindow(); // Ablak felszabadtsa MessageBox (NULL, "OpenGL megjelentsi kapcsolat aktivlsi hiba!", "Hiba", MB_OK|MB_ICONEXCLAMATION); return false; // false rtkkel kilpnk a fggvnybl } ShowWindow (hWnd, SW_SHOW); // Megjelentjk az ablakot // Priorits nvelse az ablak eltrbe helyezsvel SetForegroundWindow (hWnd); SetFocus (hWnd); // A fkuszt az ablakra lltjuk // Perspektv OpenGL szntr belltsa ReSizeGLScene (dmScreenSettings.dmPelsWidth, dmScreenSettings.dmPelsHeight); return true; // Minden sikerrel vgzdtt }
A kvetkez fggvny (DispatchEvents) segtsgvel fogjuk ellenrizni a billentyzeten trtnt gombok lenyomst, amelyek a keys tmbben vannak eltrolva. Ha egy gomb le van nyomva akkor a keys[billentykd] tmbelem rtke true lesz, ellenkez esetben false rtk tallhat benne.
// Ellenrizzk a lenyomott gombokat s mveleteket vgznk azok fggvnyben void DispatchEvents() { }
Ezutn implementljuk a prbeszdablakunk fggvnyt (ConfigDlgProc). Az els lps a fggvny implementlsban, hogy deklarlunk egy objektumot a CConfigFile osztlybl, amelyet arra hasznlunk, hogy elmentsk segtsgvel az aktulis belltsokat, hogyha az Okra kattintunk, illetve a rgi belltsok betltsre. Ezen osztly a ConfigFile.h header llomnyban lett definilva s egy struktrban trolja el az adatokat. Kt tagfggvnye van: ReadCfgFromFile(paramterek) A paramterknt tadott belltsi paramterekbe berja a konfigurcis (config.fdt) llomnyban tallhat belltsokat, WriteCfgToFile(paramterek) A paramterknt tadott belltsi paramtereket elmenti a konfigurcis fjlba. A f forrsllomnyunkra visszatrve kvetkezik egy switch dntsi hl, amelyben ellenrizzk a prbeszdablakban trtn windows zeneteket (esemnyeket). A WM_INITDIALOG zenet akkor kvetkezik be amikor megjelentjk a prbeszdablakot, ebben a programkd rszletben fogjuk beolvasni a konfigurcis llomnyban eltrolt belltsokat s belltjuk a prbeszdablak eszkzeit azoknak megfelelen. A WM_COMMAND zenet a prbeszdablakban trtn billentyzet s egr mveleteket figyeli. Ha pldul kattintunk az Ok gombra akkor az annak megfelel if utasts trzsben lev programrsz hajtdik vgre, ami az Ok esetben a prbeszdablakban lev belltsokat elmenti a konfigurcis fjlba. Teht minden windows kontrollnak a prbeszdablakbl, amelynek valamilyen tulajdonsgt szeretnnk mdostani, azt itten kell megadni, pldul if (wParam == IDEXIT) EndDialog (hWnd, 0); esetn ha a wParam rtke megegyezik a kilps gomb azonostjval, vagyis kattintottunk a kilps gombon, akkor bezrja a prbeszdablakot 0-s rtket trtve vissza (program bezrsa). A WM_CLOSE zenet pedig akkor kvetkezik be amikor a prbeszdablak jobb fels sarkban lev X kilps gombra kattintunk. A windows kontrollok tulajdonsgainak mdostsra a SendDlgItemMessage fggvnyt alkalmazzuk els paramtere a prbeszdablak azonostja, amely a windows kontrollt tartalmazza(hDlg), a msodik paramter a windows kontroll azonostja(nIDDlgItem), amely az zenetet megkapja, a harmadik a kldend zenet (Msg), negyedik s tdik paramter kiegszt zenet specifikus paramterek (wParam, lParam). Ahhoz, hogy pldul egy szvegdoboznak megkapjuk a tartalmt a GetDlgItemText fggvnyt kell meghvjuk, amelynek a paramterei a kv: prbeszdablak azonostja, kontroll azonost, puffer ahov mentjk a szveget, a szveg maximlis mrete. A szvegdoboz szvegnek a belltsra pedig a SetDlgItemText fggvnyt hasznljuk. Paramterei: prbeszdablak azonostja, kontroll azonost, tadott karakterlnc. 16
Egy kontroll aktv llapotnak vltoztatsra az EnableWindow fggvnyt alkalmazzuk. Az els paramterknt a kvetkezt adjuk t, hogy megkapjuk a kontroll hivatkozst: GetDlgItem (hWnd, IDC_MULTIPLAYER_HOST), a msodik paramter pedig az aktv llapotot jelz logikai rtk, amely ktfle lehet: TRUE vagy FALSE. Ha TRUE az tadott rtk akkor, a kontroll aktv llapotba kerl, ellenkez esetben inaktv llapotba, ami azt jelenti, hogy pldul nem tudunk kattintani r. A windows esemnykezel fggvny implementcija kvetkezik ezutn (WndProc). Ebben a fggvnyben trtnik meg a keys tmb elemeinek mdostsa a gombok lenyomsnak fggvnyben. A windows esemnyeket szintn egy switch utastssal kezeljk le, amelynek paramtere a windows zenetek tartalmazja (uMsg). A WM_SYSCOMMAND a rendszerzenetek befogsra szolgl. Ezen bell van megakadlyozva, hogy elinduljon a kperny kml, vagy hogy a kperny ramtakarkos zemmdba lpjen. A WM_CLOSE zenet hatsra kilpnk a programunkbl a case trzsben meghvva a PostQuitMessage(0); fggvnyt, amelynek a paramtere a kilpsi kd. A WM_KEYDOWN zenet hatsra a keys tmbben eltroljuk a lenyomott billentynek megfelel indexen a billenty llapott, amit true-ra lltunk (keys[wParam]=true). A WM_ACTIVE case trzsn bell az ablak aktv llapotval kapcsolatos ellenrzseket s mveleteket vgznk, mint pldul ha az ablak le van kicsinytve akkor a program ne fusson s vltsunk t a jtk felbontsbl az asztal felbontsra. A fggvny vgn pedig visszatrtjk a windows esemny kezeljbe a le nem kezelt esemnyeket. Az utols fggvny, amelyet implementlni kell ebben a forrsllomnyban a WinMain fggvny, amely a program f kezelje. Ebben a fggvnyben elszr deklarlunk egy windows zenet struktrt(msg) s egy logikai vltozt(done), amely segtsgvel ellenrizzk, hogy ki kell-e lpjnk a programbl, ennek kezdeti rtke false. Ezutn meghvjuk a CreateGLWindow fggvnyt egy if utasts paramtereknt, mert ha ez a fggvny false rtkkel tr vissza azt jelenti, hogy az OpenGL ablak ltrehozsa sikertelen volt s a program tovbb nem folytatdhat, s kilpnk a WinMain fggvnybl 0-t trtve vissza. Ezutn ugyangy meghvjuk az InitGL fggvnyt is. Ha ez is sikeresen lefutott, akkor jhet a fprogram ciklusa (while), amely mindaddig hajtdik vgre mg a logikai vltoz (done) rtke true nem lesz. A ciklusban az if gon megnzzk, hogy van-e zenet, amely feldolgozsra vr. Ha igen, akkor megnzzk, hogy a kilps zenetrl van-e sz. Ha kilps zenet rkezett, akkor kilpnk a programbl s a done logikai vltoz rtkt true-ra lltjuk, hanem feldolgozzuk a berkez zenetet. Ha nem rkezett zenet, akkor az else gon megnzzk, hogy a programunk aktv-e. Ha aktv akkor, megnzzk, hogy nem tttk-e le az Esc billentyt. Ha igen akkor a done rtkt true-ra lltjuk, hanem az else gon meghvjuk a DrawGLScene fggvnyt, amellyel elvgezzk a rajzolsokat, meghvjuk a SwapBuffers fggvnyt, hogy cserljk fel a dupla puffer aktv puffert, ezutn a DispatchEvents fggvnyt hvjuk meg billentyzet aktivits ellenrzsre. A WinMain fggvny vgn pedig meghvva a KillGLWindow fggvnyt felszabadtjuk a ltrehozott OpenGL ablakot s a vgn visszatrtjk az zenet struktra aktulis aktivcis azonostjt.
2. Forgats: void glRotate{fd} (TIPUS szg, TIPUS x, TIPUS y, TIPUS z); Megszorozza az aktulis mtrixot egy mtrixxal, amely elforgat egy objektumot (vagy a loklis koordinta rendszert) az rajrsval ellenttes irnyban, a sugr krl, amely az origbl indul s thalad az (x,y,z) ponton. A szg paramter adja a forgats szgt. A mellkelt brn lthat a glRotatef(45.0, 0.0, 0.0, 0.0); fggvnyhvs hatsa, amely egy 45 fokos forgatst vgez a z tengely krl. Ha egy objektum tvolabb van a forgats tengelytl, annl nagyobb lesz a forgats mrtke (nagyobb a sugara), mint egy objektumnak, bra 8 Forgats hatsa amely kzelebb van a tengelyhez.
3. Sklzs: void glScale{fd} (TIPUS x, TIPUS y, TIPUS z); Megszorozza az aktulis mtrixot azzal a mtrixxal, amely nagyt, kicsinyt, vagy tkrz egy objektumot a tengelyek mentn. Minden x, y, z koordintja minden pontnak az objektumbl megszorzdik a megfelel argumentummal x, y, vagy z. A loklis koordinta rendszer esetn, a loklis koordinta tengelyek nagytdnak, kicsinytdnek, vagy tkrzdnek az x, y, z faktorokkal, s a hozzrendelt objektum ezekkel sklzdik. A mellkelt brn lthat a glScalef (2.0, -0.5, 1.0); fggvny bra 9 Sklzs hatsa hatsa. A fent bemutatott transzformcis fggvnyeket felhasznlva kszlt el a Camera osztly, amely a camera.h llomnyban lett deklarlva s a camera.cpp forrsllomnyban lettek definilva a tagfggvnyei. Az osztly segtsgvel vgezhetnk loklis (rotateLoc) s globlis (rotateGlob) forgatst, valamint loklis (moveLoc) s globlis (moveGlob) eltolst. A nzet belltsra a setView tagfggvnyt hasznljuk, amely a forgatsok s eltolsok utn kell 18
kvetkezzen a meghvsi sorrendben. A Camera osztlyt a Main.cpp forrsllomnyban hasznljuk fel arra, hogy a replgp mozgst s forgst szimulljuk, gy hogy a vilgot forgatjuk s mozgatjuk el a replgphez kpest. A replgp mindig egy helyben fog llni, csak az animcii vltoznak, a lenyomott billentyknek megfelelen. A forrsllomny legelejn ahol a globlis vltozkat deklarltuk ltrehozunk egy camera objektumot a Camera osztlybl. A DrawGLScene fggvnyben a mlysgi s szn puffer trlse, valamint az identikus mtrix betltse utn if utastsokban leellenrizzk, hogy volt-e billenty lenyomva, amely hatsra belltdik a megfelel animci a replgp szmra a SetAction fggvny segtsgvel, amely a ksbbiekben trgyalt CAirplane osztly tagja (replgp), s elvgznk a forgatsi szgnek megfelel loklis forgatst a kvnt tengely krl (pl. camera.rotateLoc (szg, 1, 0, 0); - Az X tengely krli loklis forgatst vgez a megadott szggel). Az elmozdulshoz a camera objektum loklis elmozdulst vgz tagfggvnyt hvjuk meg (pl. camera.moveLoc(0, 0, elmozduls); - A loklis Z tengely menti elmozdulst eredmnyez e megadott mrtkben, vagyis brmerre nz a replgp mindig elre halad). Vgl a nzet belltsra meghvjuk a setView tagfggvnyt s ennek hatsra minden amit ezutn kirajzolunk a replgphez viszonytva el lesz forgatva, tolva.
vltoz fogja trolni az utols kirajzols idpontjt (Previous). Az Animaton vltoz a replgp animciinak visszajtszsa eltti tesztben hasznldik fel arra, hogy leellenrizzk, hogy mr belltottuk-e a megfelel vgrehajtand animcit, mert ha minden kirajzolsi ciklusban meghvjuk a replgp modell animcijnak bellt fggvnyt, akkor mindig csak egy tredkt fogjuk ltni a teljes animcinak, mert mindig az elejre fogja lltani a visszajtszst. Az Action vltoz trolja a lejtszand animcit. Az xrot, yrot, zrot vltozk a replgp elforgatshoz szksges vltozk. A publikus vltozk a replgp sebessge (speed), pozcija (position), elfordulsi szge (angle), nyugalmi llapotot jelz logikai vltoz (idle), egy logikai vltoz, amellyel vizsglni tudjuk, hogy a replgp a talajon tallhat vagy a levegben (airborne). Egy msik logikai vltoz segtsgvel azt ellenrizzk, hogy a futmve kiengedett vagy behzott llapotban van-e(gearsin). A gearmovetime vltoz a futmvek mozgsnak ellenrzsre szolgl, vagyis az animci ne lljon meg id eltt. Az ActFrame vltoz az aktulis animcis lpst tartalmazza (az animciban hnyadik lpsben tart), ez is a futm animci esetn hasznldik fel. Az osztly tagfggvnyeinek lersai kvetkeznek. A LoadModel fggvny inicializlja az osztly vltozit nullval, belltja a replgp elforgatst gy, hogy az a kpernybe befele nzzen, inicializlja az idmrt (ctimer.Init();) s betlti a replgp modelljt (PlaneModel.Init(MDLFILE00);) s belltja a lejtszand animcit a nyugalmi llapotot tartalmazra (PlaneModel.SetSequence(IDLE1);). Render fggvny jelenti meg a replgp modellnket. Legels lpsknt belltjuk, hogy a replgpmodellnek azt az oldalt rajzolja ki csak, amely kifele nz (hromszgek oldalai az ramutat jrsval ellenttes irnyban lettek ltrehozva). Az Action vltozban eltrolt animcit belltjuk a replgp szmra egy switch utastson keresztl megkeresve a megfelelt s meghvva a PlaneModel.SetSequence fggvnyt. Az animci megadsa utn lekrdezzk az idmrtl az aktulis idt a Current vltozban eltrolva annak az 1000-vel val oszts utni hnyadost s a replgpmodellnek az animcijt elrbb lltjuk a PlaneModel.AdvanceFrame fggvnnyel, amelynek paramterknt a Current Previous rtket adjuk t (vagyis az utols kirajzols ta eltelt idt). Ezutn betltjk az identikus mtrixot, majd eltoljuk s elforgatjuk a modell-nzetet annyira, hogy a replt amikor megjelentjk htulrl lssuk azt teljes egszben. Ezutn meghvjuk a PlaneModel.DrawModel fggvnyt, amely hatsra megjelentdik a repl. A fggvny vgn elmentjk az aktulis idt a Previous vltozba, s visszakapcsoljuk azt, hogy a hromszgek mindkt oldalt kirajzolja. A GetSequence fggvny segtsgvel le tudjuk krdezni az aktulis lejtszsban lev animcit egyenesen a modellbl a PlaneModel.GetSequence fggvnyhvs eredmnyt tadva a GetSequence fggvny visszatrtsi rtknek. Az UpdateState fggvnynek az a szerepe, hogy az elfordulsi szget elmentse radinban is, s hogy a fokban trtn elforduls 0-360 fokok kztti rtkeket vehessen fel. Az osztly hasznlathoz a Main.cpp forrsllomnyban a hivatkozsokhoz betesszk az airplane.h llomnyra val hivatkozst. A globlis vltozknl ltrehozunk egy replgp objektumot (airplane) a CAirplane osztlybl. Az InitGL fggvny legelejre betesszk az airplane.LoadModel fggvnyhvst, hogy betltsk a replgpmodellt s belltsuk az animcit az airplane.SetAction fggvny segtsgvel, paramterknt most egy nyugalmi llapot llandjt adjuk t. A DrawGLScene fggvnyben ellenrizzk le if utastsok segtsgvel, hogy milyen llapotban (pl. if (airplane.gearsin){}) van a replgpnk, s hogy milyen billenty letsek trtnnek ennek megfelelen fog a replgp animcija belltdni (airplane.SetAction). Miutn az animci belltdott s a forgatsi, eltolsi transzformcik megtrtntek megjelentjk a replnket az airplane.Render fggvny meghvsval, de mieltt a kamernk setView fggvnyt meghvnnk. A DispatchEvents fggvnybe kerltek a replgp sebessgt s forgst irnyt billentyk lekezelse s ezek hatsra a vltozk belltsa. A replgp UpdateState tagfggvnyt a fprogram ciklusban hvjuk meg minden egyes lpsben, a kirajzols s esemnykezels utn. 20
rendeljk hozz a geometriai alakzathoz, gy a felleti mintn is rvnyesl a centrlis vettsbl ered, n. perspektv torzts, pl. egy tglafal tvolabb lev tgli kisebbek lesznek a kpen, s a tglk szemkzti lei nem lesznek prhuzamosak. A textrkat tbbnyire ktdimenzisnak (skbelinek) gondoljuk, azonban a textrk lehetnek egy- vagy hromdimenzisak is. A textrkat lekpezhetjk gy, hogy azok lefedjk a poligonokat (poligonhlkat), de gy is, hogy a textra az objektum szintvonalait, vagy ms jellemzit szemlltesse. Az ersen ragyog fellet objektumok gy is textrzhatk, hogy azt a hatst keltsk, mintha a krnyezet tkrzdne az objektumon. A textra geometriailag egy tglalap alak terlet, mely sorokba s oszlopokba rendezett textraelemekbl, rviden texelekbl (texture element) pl fel. A textra teht adatok 1, 2 vagy 3 dimenzis tmbjnek tekinthet. Az egyes texelekhez trolt adat kpviselhet sznt, fnyerssget vagy szn s alfa rtket, azaz 1, 2, 3 vagy 4 adat tartozhat minden egyes texelhez. A tglalap alak textrkat azonban tetszleges alak poligonokra, poligonhlkra kell rhelyezni. A rhelyezs mikntjt a modelltrben kell megadni, gy a textrkra is hatnak a modell- s vettsi transzformcik. Ennek rdekben az objektumok ltrehozsakor a cscspontok geometriai koordinti mellett a textrakoordintkat is meg kell adni. Egy ktdimenzis textra koordinti a [0.,1.]x[0.,1.] egysgngyzeten bell vltoznak. Amikor a cscsponthoz hozzrendeljk a textra pontjait ezen a terleten kvl es koordintaprt is megadhatunk, de el kell rnunk, hogy az egysgngyzeten kvli koordintkat hogyan rtelmezze a rendszer, pl. ismtelje a textrt (tegye egyms mell). A textra hatsnak rvnyestse a kpmezkoordinta-rendszerben az brzoland objektum fragmentlsa utn trtnik. Elfordulhat, hogy a transzformcikon tesett textra tbb eleme ltszik egy fragmentumon, vagy ellenkezleg, tbb fragmentumon ltszik egyetlen texel. Ennek a problmnak tbbfle megoldst knlja a rendszer, a felhasznlk ltal kivlaszthat n. szrsi mveleteken keresztl. Ezek a mveletek rendkvl szmtsignyesek, ezrt a fejlettebb grafikus munkahelyek hardverbl tmogatjk a textralekpezst. Ha tbb textrt felvltva hasznlunk, akkor clszer textraobjektumokat ltrehozni, melyek egy-egy textrt (esetleg tbb felbontsban) tartalmaznak. Nhny OpenGL implementciban textraobjektumok munkacsoportjt lehet ltrehozni. A csoporthoz tartoz textrk hasznlata hatkonyabb, mint a csoporton kvliek. Ezeket a nagy hatkonysg textraobjektumokat rezidensnek nevezik, s ezek hasznlatt ltalban hardveres vagy szoftveres gyorstk segtik. A felhasznl ltal elrhat, hogy a textra hogyan hasson a megjelentend objektum sznre. Megadhatjuk, hogy a megfelel texel(ek) szne legyen a fragmentum szne (egyszeren fellrja a fragmentum sznt, mintha egy matrict ragasztannk r), elrhatjuk, hogy a textrval mdostsa (pontosabban sklzza) a fragmentum sznt, ami a megvilgts s textrzs hatst kombinlja, vgl a fragmentum sznnek s egy konstans sznnek a textraelemen alapul keverst is elrhatjuk. A textrk trolsra, betltsre s felptsre egy kln forrsllomny lett ltrehozva, az ftexture.h. A forrsllomny legelejn konstansok segtsgvel megadjuk, hogy hny bitmap kpet fogunk betlteni s hny textrnk lesz:
#define MAX_TEXTURE_NAMES #define MAX_TEXTURE_FILES 8 8
Ltrehozunk egy struktra tpust Texture_File nvvel, amely egy llomnynevet trol karakterlnc formjban, s kt vltozt, amelyek az adott textrnak meg fogjk adni a minimalizlsi s maximalizlsi szrinek az rtkt. Ezen struktratpus segtsgvel ltrehozzuk a texture_file tmb vltozt, amelyet egyben inicializlunk a betltend fjlnevekkel s kvnt textra szrsi mdokkal. Ezutn ltrehozunk egy egsz szmokat tartalmaz tmbt, mely trolni fogja a beolvasott textrkra val hivatkozsokat, s majd ezen keresztl fogunk hivatkozni az egyes textrkra. Az osztly, amely segtsgvel a textra beolvasst megoldjuk a CFTexture, amelynek kt privt s egy publikus tagfggvnye van. A LoadBMP privt tagfggvny szerepe, hogy a paramterknt tadott llomnynv alapjn beolvassa a bmp llomnyt, amelyet textraknt szeretnnk felhasznlni, visszatrtsi rtke a beolvasott textra cmre hivatkoz mutat. A fggvny trzsben ltrehozunk egy file 22
nev vltozt a fjl mveletek elvgzse szempontjbl. Egy if utastsban leellenrizzk, hogy a paramterknt tadott karakterlnc tartalmaz-e valamit. Ha NULL az rtke akkor kilpnk a fggvnybl s a textra cmeknt NULL rtket trtnk vissza, ami jelzi, hogy hiba trtnt a beolvass sorn. Ezutn megnyitjuk az llomnyt olvassra. A kvetkez if utastsban megnzzk, hogy sikerltek megnyitnunk. Ha a file tartalma nem egyenl NULL-al akkor sikeresen megtrtnt az llomny megnyitsa, ami utn az if utasts trzsben bezrjuk az llomnyt, majd meghvjuk az auxDIBImageLoad fggvnyt a bitmap kp betltsre, amelynek visszatrtsi rtkt visszatrtjk a bitmap betlt fggvnynknek. A fggvny legvgn pedig NULL rtket trtnk vissza jelezve, hogy hiba trtnt. A LoadGLTexture fggvnynl a paramterknt tadott egsz rtk fog felhasznldni arra, hogy tudjuk hnyadik textrt tltjk be. A fggvny elejn tallhat Status logikai vltoz (kezdeti rtke false) fogja jelezni a fggvny vgn visszatrtdve, hogy volt-e hiba, vagy sem. A TextureImage vltoz fogja trolni a textrt. If utasts paramtereknt tadjuk a TextureImage[0] = LoadBMP (texture_file[tex_id].filename) parancsot, amely ha sikeresen lefut akkor a beolvasott bitmap a Texture_Image vltozba fog tmentdni, ellenkez esetben visszatrnk a fggvnybl a Status vltoz rtkvel, ami ez esetben false. Siker esetn az if utasts trzsben a Status vltoz rtkt true-ra lltjuk, majd egy 2D textraobjektumot hozunk ltre a TextureName[tex_id] nvhez hozzkapcsolva (glBindTexture). A textra generlshoz a glTexImage2D fggvnyt alkalmazzuk, amelyben sorban megadjuk paramterekknt, hogy 2D textrt hozunk ltre, a msodik paramter rtke 0, mivel csak egy felbontsban fogjuk trolni a textrt, a harmadik paramter a texelek sznkomponenseinek lersra szolgl, a negyedik s tdik paramterek a textra szlessgt, illetve magassgt adjk meg, a hatodik paramter a textra formtumt, a hetedik a textra tpust rja le. Az utols paramter pedig a ltrehozand textra adatainak trolsra szolgl tmb cme. A textrk sorai s oszlopai szmnak 2 hatvnyainak kell lenni. A 0-s szintet ltrehoztuk (a legnagyobb textra felbontst), s a gluBuild2DMipmaps fggvny segtsgvel ltrehozzuk a textra sszes szksges alacsonyabb felbonts vltozatt, paramterei hasonlak az elbbi fggvnyhez, azzal a kivtellel, hogy a msodik paramtert elhagyjuk . A texelek nagytsra, illetve kicsinytsre hasznlt szrket a glTexParameteri fggvny segtsgvel lltjuk be. Els paramterknt a textra dimenzijt adjuk meg (GL_TEXTURE_2D), msodik paramternek a GL_TEXTURE_MAG_FILTER a nagytshoz hasznland szr belltshoz s a GL_TEXTURE_MIN_FILTER rtket a kicsinytshez, az utols paramter pedig a szrs tpusnak megadsra szolgl: Szr GL_TEXTURE_MAG_FILTER GL_TEXTURE_MIN_FILTER Szrs tpusa GL_NEAREST, GL_LINEAR GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIMPAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIMAP_LINEAR
A szrs tpusnak alaprtelmezettknt GL_LINEAR lett megadva mind a nagytshoz, mind pedig a kicsinytshez, hogy a legjobb minsgben jelentdjenek meg, de ez megvltoztathat a program elindulsa eltti konfigurcis ablakban trtn belltssal a Texture quality alatti legrdl listbl kivlasztva egy lehetsges mdot a hrom kzl, melyek alacsony, kzepes s magas textra minsget jelkpeznek. A glTexEnvi fggvny segtsgvel azt mondjuk meg, hogy a textrt hogyan hasznlja a rendszer. Ebben az esetben csak simn rrajzolja a felletekre, nem hasznl klnfle funkcionalitsokat, mint a textra kombinlsa a feldolgozand fragmentum sznvel. A fggvny els paramtere GL_TEXTURE_ENV kell legyen, a msodik paramter GL_TEXTURE_ENV_MODE, az utols paramter pedig GL_MODULATE gy az elbbiekben lert textra rajzolsi mdot rjk el. A fggvny vge 23
eltt egy if utastsban leellenrizzk, hogy textrt tartalmaz-e a TextureImage vltoz. Ha igen akkor felszabadtjuk azt. A fggvny legvgn pedig visszatrtjk a Status vltoz rtkt. LoadAllTextures tagfggvny segtsgvel elssorban MAX_TEXTURE_NAMES darab, jelenleg hasznlaton kvli textraobjektum nevet generlunk a TextureName tmbbe. Ezutn egy for ciklus hasznlatval, amelynek indexe (tex_id) 0-tl megy MAX_TEXTURE_FILES-ig, szerre betltjk a tex_id-nek megfelel textrt meghvva a LoadGLTexture fggvnyt a tex_id paramterrel, ha ez sikertelen lenne akkor a fggvnybl kilpnk az aktulis sikertelen betlts esetn a tex_id rtkkel. Ha a fggvny sikeres volt -1-et trtnk vissza. Az osztlyon kvl a forrsllomny vgn tallhat a GetTextureID fggvny mely, a paramterknt tadott fjlnv felhasznlsval egy for ciklusban vgigmegy minden textrn s ha tall megfelel fjlnevet a texture_file tmbben, akkor visszatrti az azonostjt, a tex_id-t. Ha nem tallt hasonlt akkor 0 rtkkel kilp a fggvnybl. Az osztly hasznlathoz a Main.cpp forrsllomnyban betesszk az llomny elejre az ftexture.h llomnyra val hivatkozst. Ezutn a globlis vltozk rszen ltrehozunk egy textures elnevezs objektumot a CFTexture osztlybl. Az InitGL fggvnyben pedig a vgre betesszk a textures.LoadAllTextures fggvnyhivatkozst egy if utastsba, mely hatsra ha sikertelenl vgzdtt a fggvny akkor -1-nl klnbz rtket fog visszatrteni s akkor kiratjuk a textrnak az azonostjt, melyet nem sikerlt betlteni s kilpnk a fggvnybl false visszatrtsi rtkkel, jelezve a programnak, hogy az inicializls nem jrt sikerrel s a program be kell zrdjon. A GetTextureID fggvny a Milkshape 3D modell betltse esetn a textra megadsnl lett felhasznlva a Model.h llomny Model::reloadTextures fggvnyben.
OpenGL bvtmnyek
Ahhoz, hogy az OpenGL j fejlesztseit vagy bvtmnyeit hasznlni tudjuk, szmos j OpenGL forrsllomnyt kell hozzadjunk a projektnkhz. A glext.h s wglext.h llomnyokban tallhatak a frisstett konstansok, fggvnyek s sok ms a legjabb OpenGL verzihoz. Br OpenGL szmos platformon hasznlhat a wglext.h llomny windows specifikus implementcikat tartalmaz. Ezek a bvtmnyek alkalmazhatak arra, hogy szebb s/vagy gyorsabb tegyk az OpenGL programunkat. A bvtmnyek hasznlathoz elszr ltrehozzuk a vltozkat, amelyek szksgesek a szmunkra. Ezek az ftexture.h llomny legelejn tallhatak. A gl_extension karakterlncban fogjuk trolni a lehetsges bvtmnyeket. A glFogCoordfExt vltoz fogja tartalmazni a kd belltshoz szksges fggvny cmt, ugyangy a wglSwapIntervalExt s wglGetSwapIntervalExt a kpernyfrissts belltshoz szksges fggvnyek cmeit. A bvtmnyek betltse az llomny vgn tallhat LoadGLExtensions fggvny segtsgvel trtnik. Elszr eltroljuk a rendszernk ltal tmogatott bvtmnyeket a gl_extension vltozban: gl_extension = (char *)glGetString(GL_EXTENSIONS);. Ezutn a kimentett bvtmnyekben megkeressk az strstr fggvny segtsgvel, hogy ltezik-e neknk megfelel bvtmny. Mindez egy if utasts paramtereknt addik t s emellett a konfigurcis ablakban megadott belltst is figyelembe kell vegyk. Pldul lehet, hogy a rendszernk tmogatja a textra srtst, de mi nem szeretnnk alkalmazni, akkor ne kapcsoldjon be az az rtk mely azt szablyozza. Az els if utastsban a textra srtst, a msodikban az anisotropic szrst ellenrizzk le, hogy tmogatja a rendszernk s ha igen, akkor megnzzk, hogy szeretnnk-e alkalmazni, ha igen akkor a megfelel vltoz rtke true lesz, hanem false. A bvtett kd bekapcsolsnl a fggvny cmt fogjuk eltrolni a glFogCoordfExt vltozban. Az utols dolog amit elvgznk a fggleges frissts kikapcsolsa. A forrsllomnyban lthat hogyan lett megvalstva.
24
25
Hasznlathoz a Main.cpp llomny elejre betesszk a Map.h llomnyra val hivatkozst. Ltrehozunk egy globlis dinamikus plya objektumot map nvvel a CMap osztlybl. Az InitGL fggvny trzsben a textrabetlts utn betesszk a map vltoz ltrehozst, mivel dinamikus objektumrl van sz: map = new CMap;, s inicializljuk a plyt meghvva a map->Init fggvnyt. A DrawGLScene fggvny trzsben a camera objektum setView tagfggvnynek meghvsa utn tesszk be a plya kirajzol fggvnynek meghvst, a map->Render-t. A KillGLWindow fggvny vgre betesszk a map objektumot felszabadt parancsot, amely a delete map; utastsbl ll.
Szvegmegjelents
OpenGL rendszerben, hogy szveget tudjunk megjelenteni ltre kell hozzuk a megfelel bettpust vagy betltsk a betket tartalmaz bitmap kpet s abbl, minden bet szmra kln textrt hozzunk ltre. Ezeket aztn display-listba tesszk s annak az azonostjt vltoztatva tudjuk megjelenteni a megfelel bett. A szveg megjelentsre egy kln forrsllomny lett ltrehozva fgltext.h nvvel amelyben a CFGLText nev osztlyban hrom szvegmegjelentsi md tallhat. Az osztly privt vltozi elssorban hrom display-lista azonostt a megjelentsi mdok szmra (b_base, o_base, t_base), egy textra azonost a textrzott szvegmegjelents szmra (_2DTextureFontID), valamint a 3D szveg megjelentshez felhasznlt karakter puffer (gmf). Hrom megjelentsi mdunk lesz a szveg szmra. Bittrkpes, 3D, valamint textrzott szveg megjelentsi mdjt fogjuk implementlni. Elsknt a bittrkpes szveg megjelentsrl lesz sz. A bittrkpes szvegmegjelentsnek a felptsre a BuildBitmapFont fggvny szolgl, amely paramterknt megkapja az ablakunk eszkz kapcsolatt, hogy tudja hov fogja megjelenteni a szveget. A fggvny elejn ltrehozunk egy bettpus vltozt a ltrehozand bettpus szmra (font), s egy vltoz, amely segtsgvel eltroljuk a rgi bettpus belltsokat. A b_base vltozba legenerlunk 96 karakternek trhelyet szolgltat display-listt a glGenLists fggvny segtsgvel. Ezutn a font vltozba felptjk a bettpusunkat, belltva a tulajdonsgait a CreateFont fggvny segtsgvel. Ezutn kivlasztjuk az eszkzkapcsolatunk szmra a font vltoz ltal trolt bettpust s a SelectObject fggvny eredmnyt, amellyel kivlasztjuk a bettpust, eltroljuk az oldfont vltozban. A wglUseFontBitmaps fggvny segtsgvel felptjk a b_base display listba a bittrkpes karaktereket a 32-stl kezdve 96 karaktert, hozzrendelve az eszkz kapcsolathoz. Ezutn kivlasztjuk az oldfont betkszletet, mivel ezzel a bettpussal szeretnnk megjelenteni a szvegnket. Vgl letrljk a font vltozban trolt betstlust. A bittrkpes szveg megjelentsre a glPrintBitmap fggvny szolgl melynek paramterknt a kiratand szveget fogjuk majd tadni. A fggvny vltoz argumentum lehet ezrt ki kell szedjk a kiratand szveget a paramterlistbl. Els lpsknt kikapcsoljuk a 2D textrzst. Ltrehozunk egy a kiratand szveg eltrolsra megfelel 255 karakter mret karakterlncot (text) s egy mutatt a paramterlistra (ap). Leellenrizzk, hogy kapott-e paramterknt a fggvny karakterlncot, mert ha nem akkor kilpnk a fggvnybl. Ezutn az argumentum listbl kihmozzuk a szmunkra fontos kiratand karakterlncot (vsprintf). Ezutn elmentjk az aktulis display lista bitjeit (glPushAttrib), majd belltjuk a display-lista megjelentsnek kezdeti karaktert a 32-sre (glListBase). Ezutn meghvjuk a glCallLists fggvnyt, mely hatsra ki fog ratdni a szvegnk. Ezutn visszalltjuk a rgi display-listt a glPopAttrib fggvnnyel s visszakapcsoljuk a 2D textrzst. A bittrkpes megjelents felszabadtsra a KillBitmapFont fggvny szolgl, amely a ltrehozott b_base display-listt felszabadtja a glDeleteLists fggvny segtsgvel. A kvetkez szvegmegjelentsi md a 3D szveg megjelentse. A felptse a BuildOutlineFont fggvny segtsgvel trtnik, paramtere az ablakunk eszkz kapcsolata, 26
amelyben megfogjuk jelenteni a szveget. A fggvny elejn ltrehozunk egy font elnevezs vltozt, amelyben elfogjuk trolni a kvnt a betstlust a megjelents szmra. Az o_base vltozba legenerlunk 256 karakter szmra szksges trhelyet szolgltat display-listt, majd a font vltozba elmentjk a kvnt betstlusunkat, amelyet a CreateFont fggvny segtsgvel hozunk ltre. Ezutn kivlasztjuk az eszkzkapcsolatunk szmra a font vltozban trolt bettpust a SelectObject segtsgvel. Majd a wglUseFontOutlines fggvnnyel belltjuk 3D szveg tulajdonsgait, egyben hozzkapcsolva a display listhoz, amelybe eltroldik minden egyes karakter. A 3D szveg megjelentsre a glPrintOutline fggvny szolgl, hasonl paramterrel s paramter feldolgozssal, mint a bittrkpes megjelents esetben. Ebben a megjelentsi mdban is ki kell kapcsoljuk a 2D textrzst a megjelents eltt. A megjelents szempontjbl egy for ciklusban kiszmoljuk a megjelentett szveg, hosszt, majd egy eltolst vgznk, hogy kzpre legyen majd igaztva a szvegnk a f forrsllomnyban megadott pozcihoz kpest. A megjelentse ugyangy trtnik, mint a bittrkpes szveg esetn. A fggvny vgn pedig bekapcsoljuk a 2D textrzst. A 3D szveghez ltrehozott display-lista felszabadtsa a KillOutlineFont fggvnyen bell trtnik, hasonlan a bittrkpes szveg felszabadtshoz, azzal a klnbsggel, hogy itten 256 karakter kell felszabadtsunk. A harmadik szveg megjelentsi md, mely implementlva lett a textrzott szveg megjelentse. Felptse a Build2DTextureFont fggvny segtsgvel trtnik, mely egy display-listba (t_base) elmenti a Font.bmp llomnyban tallhat betket feldarabolva egy for ciklust hasznlva a feldarabolsra. Minden bet egy ngyzetbl fog llni. A textrzott szveg megjelentsre a glPrint2DTexture fggvny szolgl, melynek paramterei segtsgvel megadjuk, hogy melyik pozciba szeretnnk kirajzolni a szveget, s magt a karakterlncot. A textrzott szveget kikapcsolt mlysg ellenrzs mellett rajzolja ki a fggvny s 2D vettsi mdot specifikl, majd a fggvny vgn visszakapcsolja a mlysg vizsglatot s a vettsi mdot visszalltja az eredetire. A felszabadt fggvny a Kill2DTextureFont, mely az elbbi szvegmdok felszabadt fggvnyeihez felszabadtja a karaktereket tartalmaz display-listt. Hasznlathoz a Main.cpp llomny elejre betesszk az fgltext.h llomnyra val hivatkozst, majd ltrehozunk egy objektumot (textit) a CFGLText osztlybl. Ahhoz pldul hogy a bittrkpes szveget jelentsnk meg, a textit objektum glBuildBitmapFont tagfggvnyre val hivatkozst betesszk az InitGL fggvny vgre, ezzel elksztve a szveg megjelentst. A szveget a DrawGLScene fggvnyben jelentjk meg. Belltjuk a megjelentsi sznt a glColor3f fggvnnyel, majd a megjelents pozcijt a glRasterPos2f fggvny segtsgvel s vgl a textit objektum glPrintBitmap tagfggvnynek segtsgvel megjelentjk a szveget. A msik kt szvegmd megjelentse is hasonlkppen mkdik. A fggvny trzsben megjegyzs jelek kztt megtallhat a msik kt md hasznlata is. A felszabadts a KillGLWindow fggvny vgre kerl meghvva a textit objektum KillBitmapFont tagfggvnyt.
27
A felszabadts a Release tagfggvny segtsgvel trtnik, melyben felszabadtjuk a lefoglalt eszkzt s eszkz kapcsolatot. A felszabadts els lpsben leellenrizzk, hogy van-e amit felszabadtanunk, egy if utastson keresztl. Ha nincs akkor kilpnk a fggvnybl. Meghvjuk a ReleaseSources fggvnyt a hangpufferek s forrsok felszabadtsra, majd felszabadtjuk az eszkzkapcsolatot az alcDestroyContext fggvnnyel s utna bezrjuk a hangeszkznket az alcCloseDevice paranccsal. A GetBufferID fggvny arra szolgl, hogy az llomnynv alapjn visszatrtsk az azonostjt egy bizonyos hang puffernek, melyet egy for cikluson bell vgezzk el tallat esetn visszatrti a lps szmt, amelyben tallat van. Ha nincs tallat akkor -1-t fog a fggvny visszatrteni. A CreateSources fggvny segtsgvel fogjuk ltrehozni a hangforrsok szmra a szksges trhelyet az alGenSources fggvnyt alkalmazva. A kvetkez fggvny a SetSource, mellyel belltjuk egy hangforrs pozcijt, oktvjt, hangerejt s visszajtszsi mdjt a paramterben megadott rtkek alapjn. Els kt paramtere a fggvnynek a forrs sorszma s a fjlnv mely a forrs ltal lejtszand wav hangot jelzi. Az x, y, z pozcijt a hangforrsnak elmentjk egy 3 elem vals tmbbe, mert a pozci megadsnl egy tmbt kell majd megadjuk. A buffer vltozba pedig elfogjuk trolni a GetBufferID fggvny eredmnyt, hogy tudjuk melyik elemre hivatkozzunk a SoundSource tmbbl, ezt fogjuk visszajtszani. Az alSource{if}[v] fggvny segtsgvel lltjuk be a forrs tulajdonsgait. Els paramtere a SoundSource[source], amely jelzi, hogy melyik hangforrs tulajdonsgait mdostjuk, msodik s harmadik paramtere a kvetkezk a tulajdonsgok belltsa esetn: Msodik paramter AL_BUFFER AL_PITCH AL_GAIN AL_POSITION AL_LOOPING Harmadik paramter SoundBuffer[buffer] - visszajtszand puffer pitch oktvszm (1.0 az eredeti sebessg) gain hanger position pozci megadsa loop ciklikusan jtssza-e vissza a hangot
Ha minden sikeresen befejezdtt akkor true rtkkel kilpnk a fggvnybl. A PlaySource, PauseSource, StopSource fggvnyek a paramter ltal meghatrozott hangforrsnak elindtjk a lejtszst, szneteltetik azt, vagy lelltjk. Mindhrom fggvny felptse hasonl, a funkcionalitst vgz fggvny kivtelvel: alSourcePlay elindtja a paramterknt megadott hangforrs hangadatnak lejtszst. alSourcePause sznetelteti a lejtszst alSourceStop meglltja a lejtszst. Az utols fggvny mely ebben a CAudio osztlyban tallhat a hallgat belltsa. A SetListener fggvny paramtereknt megadjuk a hallgat pozcijt, valamint az elre s flfele mutat normlist. Ezeket a paramtereket tadjuk a loklisan ltrehozott vltozknak (position, orientation), mert a tulajdonsg belltsa tmbk tadsval trtnik. A pozcit s az irnyt az alSetListenerfv fggvny segtsgvel lltjuk be. A pozci belltsnl els paramterknt az AL_POSITION konstanst adjuk meg, msodik paramterknt pedig a position tmbt. Az irny belltsnl els paramtere a fggvnynek az AL_ORIENTATION lesz, msodik paramtere pedig az orientation tmb, mely tartalmazza az elre s flfele mutat vektor normlist. Mind a kt mvelet utn hibaellenrzst vgznk, s ha hiba trtnt akkor kilpnk a fggvnybl. Az osztly hasznlathoz pedig a Main.cpp llomny elejre betesszk az audio.h llomnyra val hivatkozst, hogy tudjuk hasznlni a benne lev osztlyt. Ltrehozunk egy 29
globlis objektumot audio nvvel a CAudio osztlybl. A WinMain fggvnyben a legelejn meghvjuk az audio.Init fggvnyt egy if utasts paramtereknt egyben leellenrizve, hogy a hangrendszer sikeresen inicializldott-e. Hiba esetn kilpnk a programunkbl. Az InitGL fggvnynk vgn lltjuk be a hangforrsokat egy for ciklusban s egyben el is indtjuk a lejtszsukat. A DrawGLScene fggvny vgn mdostjuk a replgp motor hangjnak forrst s a hallgat pozcijt. A hangrendszer felszabadtsa a WinMain fggvny vgn trtnik meg az audio.Release fggvny meghvsra.
Hlzat hasznlata
A hlzattal kapcsolatos funkcionalitsok a multiplayer.h llomnyban lettek implementlva. A hlzat hasznlathoz els sorban be kell linkeljk a ws2_32.lib fggvny knyvtrat. Ltrehozzuk a hlzat inicializlshoz s hasznlathoz szksges konstansokat, mint a hlzati protokoll, hlzati port, csomag mret, s a csomag rkezst jelz. Felsorols konstanssal adjuk meg azon konstansok rtket, mellyel ellenrizni fogjuk, hogy szerverknt vagy kliensknt fut-e a programunk, illetve milyen tpus csomagot kldnk, hogy a fogad program tudja azt megfelelen feldolgozni. Mg van kt globlis vltoz, melyek arra fognak szolglni, hogy eltroljuk bennk a konfigurcis ablakban megadott hlzattal kapcsolatos belltsokat (multiplayer_mode, host). Az osztly neve mellyel a hlzatot kezeljk CMultiplayer. Privt adattagjai egy struktra, melyben a socket adatait elmentjk (sock_addr), valamint hogy milyen tpus a kapcsolat (connection_type), szerver vagy kliens. Publikus adattagok pedig maga a kommunikcis socket game_socket elnevezssel s a hlzat aktv llapott jelz active logikai vltoz. A kimen (outgoing_packet) s bejv (incoming_packet) csomagok tartalma pedig karakterlnc formjban lesznek elmentve. Az osztly els tagfggvnye melyrl sz lesz a szerver inicializl InitServer fggvny. Ezen bell legelre ltrehozunk egy vltozt, mely a socket adatait fogja tartalmaz (wsaData). Ezutn megprbljuk elindtani a kommunikcis socketet (Winsock 2.0) a WSAStartup fggvny segtsgvel, miutn a Winsock informci a wsaData vltozba kerl. Ha hiba trtnt a fggvny visszatrtsi rtke egyenl lesz a SOCKET_ERROR konstanssal, aminek kvetkeztben kilpnk a fggvnybl egy hibazenettel, elszr felszabadtva a ltrehozott Winsock socketeket. Ha a fggvny sikeresen lefutott, akkor a sock_addr vltozba eltroljuk a cmtartomny csaldjt (AF_INET - amely az internet cmek csaldjbl val), a bejv IP cmet (INADDR_ANY brmilyen IP cmrl fogad kommunikcit), a hlzati portot talaktva a megfelel tpusra (MULTIPLAYER_PORT). A game_socket vltozban eltroljuk a socket ltrehozs eredmnyt, melyet a socket fggvny segtsgvel vgznk el. Ezutn egy if utastsban leellenrizzk, hogy sikerlt-e ltrehozni a socketet. Ha nem akkor kilpnk a fggvnybl, felszabadtva a ltrehozott Winsock socketeket. Ezutn a bind fggvny segtsgvel a game_socket vltozhoz hozzcsatoljuk a sock_addr vltozban eltrolt adatokat, hogy adatokat kaphassunk a hlzaton keresztl. Ezt a fggvnyt is egy if utastson bell hvjuk meg, gy egybl le tudjuk ellenrizni, hogy trtnt-e hiba, s ha igen akkor kilpnk a fggvnybl. A socketet ezutn hallgatz mdba tesszk a listen fggvny segtsgvel, hogy tudjuk fogadni a csomagokat. A fggvny vgn az active llapotot jelz logikai vltoz rtkt true-ra lltjuk jelezve, hogy sikerlt elindtani a szervert. A connection_type vltoznak rtkl a MULTIPLAYER_SERVER rtket adjuk. Minden rendben van s kilpnk a fggvnybl true visszatrtsi rtkkel. A kvetkez fggvny a kliens inicializl fggvny, melynek neve InitClient. Egyetlen paramtere egy karakterlnc, mely a szerver nevt fogja tartalmazni mikor meghvjuk. A socket elindtsa ugyangy a WSAStartup fggvny segtsgvel trtnik, mint a szerver esetben. Ennek a fggvnynek van mg egy plusz hp elnevezs hostent tpus loklis vltozja melyben a szerver informciit troljuk el meghvva a gethostbyname fggvnyt a hostname 30
paramterrel. Ha a hp rtke ha NULL akkor kilpnk a fggvnybl egy hibazenettel s felszabadtva a ltrehozott socketeket. Ha sikeres volt a mvelet akkor feltltjk a sock_addr struktrt. Elsknt a szerver cmt (hp->h_addr, hp->h_length) msoljuk t a hp vltozbl a memcpy fggvny hasznlatval. Ezutn a cmtartomny csaldjt mentjk ugyancsak a hp vltozbl (hp->h_addrtype), vgl a hlzati portot, amit talaktva a megfelel tpusra mentnk el (MULTIPLAYER_PORT). Ezutn ltrehozzuk a socketet a socket fggvny hasznlatval s ennek eredmnyt troljuk a game_socket vltozban. A hibaellenrzs kvetkezik, hogy ltrejtte a socket. Ha nem akkor kilpnk a fggvnybl. Ha sikeres volt a mvelet csatlakozunk a szerverhez a connect fggvny segtsgvel, ha lehetsges, ellenkez esetben kilpnk a fggvnybl egy hibazenettel s felszabadtva a ltrehozott socketeket. Sikeres kapcsolat esetn elindtjuk a hallgatzst a listen fggvnnyel, hogy tudjunk csomagokat fogadni. Az active vltoz rtkt true-ra lltjuk jelezve, hogy a kliens aktv s a connection_type vltoz rtkt MULTIPLAYER_CLIENT-re lltjuk. Vgl true rtkkel kilpnk a fggvnybl, jelezve, hogy minden rendben van. A Release fggvny segtsgvel szabadtjuk fel a lefoglalt socketeket. Elszr leellenrizzk, hogy aktv-e az adott kapcsolat, mert ha nem akkor nincs amit felszabadtani is kilphetnk a fggvnybl. A closesocket fggvny meghvsval bezrjuk a kommunikcis socketnket, majd a WSACleanup fggvny meghvsra felszabadtdnak a ltrehozott socketek. A fggvny vgn az active vltoz rtkt false-ra lltjuk. A Send fggvny valstja meg az zenetkldst. A fggvny elejn leellenrizzk, hogy a hlzati kapcsolatunk aktv-e az active vltoz rtknek vizsglatval. Ha nem aktv akkor kilpnk a fggvnybl false rtkkel. Ezutn leellenrizzk, hogy a kapcsolat tpusa szerver-e, ha igen akkor a sendto fggvnyt hasznljuk az zenet elkldsre, hanem a send parancsot. A retval vltozban troljuk az zenetklds fggvnynek visszatrtsi rtkt, melyet hibaellenrzsre hasznlunk fel a fggvny vgn egy if utastsban. Ha hiba trtnt az zenet elkldsekor false rtkkel kilpnk a fggvnybl. Ha minden rendben volt a fggvny vgn true rtkkel lpnk ki a fggvnybl. A Receive fggvny az zenetfogadst valstja meg. Folyamata hasonl az zenet kldshez azzal a klnbsggel, hogy a sendto s send fggvnyek helyett szerver kapcsolat esetn az zenet fogadsra a recvfrom fggvnyt, kliens kapcsolat esetn pedig a recv fggvnyt hasznljuk. A hlzat kezels hasznlathoz a Main.cpp llomnyban a legelejre betesszk a multiplayer.h llomnyra val hivatkozst. A CMultiplayer osztlybl ltrehozunk egy globlis objektumot s a megfelel vltozkat, hogy tudjuk milyen tpus kapcsolatunk van (connection_type), vagy ha kliens kapcsolatunk van akkor egy karakterlncban el kell troljuk a szerver nevt (hostname). Ezeken kvl kell mg egy vltoz arra, hogy letroljuk mikor kldtk el a legutols csomagot (time_of_last_packet_sent), gy szablyozni tudjuk majd, hogy msodpercenknt hny csomagot kldjnk. Valamint hibajelz logikai vltozk is ltre lettek hozva tesztels szempontjbl, s hogy hibazenetet tudjunk kiratni ha baj van a csomagok kldsnl (error_sending_packet), vagy fogadsnl (error_receiving_packet). A hlzatos md inicializl fggvnynek meghvsa a WinMain fggvnyen bell trtnik annak fggvnyben, hogy milyen belltsokat vgeztnk a konfigurcis prbeszdablakban. Mindez egy if utastson bell trtnik meg. Itten lltjuk be a csomagfogads konstanst, hogy a windows esemnykezelje figyelni tudja mikor kvetkezik be egy zenet rkezse (WSAAsyncSelect). Az zenet klds a SendMultiplayerPacket fggvnyen bell trtnik meg, minden tizedmsodpercben elmentve a kldend informcit a multiplayer.outgoing_packet vltozba az sprintf fggvnyt alkalmazva. Ezutn vgznk egy hibaellenrzst a multiplayer.Send fggvny meghvsra egy if utastsban. Ezutn a time_of_last_packet_sent vltozba elmentjk az aktulis idt, hogy majd ismt vrjunk egy tizedmsodperc elteltre. Ez a fggvny a WinMain fggvny fciklusban hvdik meg mindig annak fggvnyben, hogy aktv-e a hlzati kapcsolat. Az zenet fogadsa a WndProc fggvny switch utastsn bell valsul meg, akkor hogyha a switch paramtereknt tadott uMsg rtke egyenl az MM_PACKET_RECEIVED konstans rtkvel. Ha ez teljesl akkor meghvjuk a multiplayer.Receive fggvnyt, mely 31
hatsra a multiplayer.incoming_packet karakterlncba elmentdik a berkez zenet s majd ebbl szedjk ki a szmunkra fontos vltozkat az sscanf fggvny segtsgvel. Vgl a WSAAsyncSelect fggvnnyel ismt elindtjuk az zenetfogadst. A hlzatos md felszabadtsra a WinMain fggvny vgn meghvjuk a multiplayer.Release fggvnyt.
32
Knyvszet
Varga Sndor OpenGL Benk Tiborn Az OpenGL grafika, C++ Jeff Molofee OpenGL Game Programming Tutorial NeHes OpenGL Tutorials Chris Seddon OpenGL Game Development, Wordware Publishing, 2005 OpenGL Programming Guide, Addison-Wesley Publishing Company Dave Astle, Kewin Hawkins Beginning OpenGL Game Programming OpenAL Programmers Guide
33