cet - directx 9.0 programiranje u c++ programskom jeziku

34
DirectX 9.0 Programiranje u C++ programskom jeziku Rastko Ilić Da li ste se ikada zapitali kako se prave video igrice? Odgovor je kao i uvek programiranjem. Ipak na polju video igrica pored programiranja postoji mnogo različitih poslova koje treba uraditi kako bi ste dobili konačan rezultat koji ste osmislili. Tu su timovi modelara koji se bave isključivo 3D modelima vaših objekata, pa timovi ljudi koji su zaduženi za nanošenje tekstura i materijala na te objekte, dizajneri koji se bave okruženjem i svetom u kome je smeštena vaša video igra. Ipak na kraju je na programerima da udahnu život karakterima, objektima, prirodi i celom svetu video igre. To se postiže uz pomoć takozvanog "3D engine"-a u kome su sva prikazivanja i sve interakcije definisane. Tu na scenu stupa DirectX kao programski jezik uz koji sve ovo možete napraviti i definisati. Ovaj programski jezik nije jednostavan i veoma je kompleksan, to je zato što je osmišljen tako da kroz njega dobijete najveću moguću moć i da kada jednom ovladate njime jedina prepreka na koju možete naići je vaša maštovitost. U ovom tekstu bavićemo se naj osnovnijim strukturama DirectX-a i donekle vas uvesti u priču grafičkog programiranja, to ćemo učiniti kroz C++ zato što sam DirectX i jeste i nije programski jezik za sebe, već veliki broj poziva i predefinisanih funkcija koje koristite u nekom od već poznatih programskih jezika kao što je VB, C++ ili C#. Pa da počnemo.

Upload: ibiz4

Post on 28-Nov-2015

66 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

DirectX 9.0 Programiranje u C++ programskom jeziku

Rastko Ilić

Da li ste se ikada zapitali kako se prave video igrice? Odgovor je kao i uvek programiranjem. Ipak na polju video igrica pored programiranja postoji mnogo različitih poslova koje treba uraditi kako bi ste dobili konačan rezultat koji ste osmislili. Tu su timovi modelara koji se bave isključivo 3D modelima vaših objekata, pa timovi ljudi koji su zaduženi za nanošenje tekstura i materijala na te objekte, dizajneri koji se bave okruženjem i svetom u kome je smeštena vaša video igra. Ipak na kraju je na programerima da udahnu život karakterima, objektima, prirodi i celom svetu video igre. To se postiže uz pomoć takozvanog "3D engine"-a u kome su sva prikazivanja i sve interakcije definisane. Tu na scenu stupa DirectX kao programski jezik uz koji sve ovo možete napraviti i definisati. Ovaj programski jezik nije jednostavan i veoma je kompleksan, to je zato što je osmišljen tako da kroz njega dobijete najveću moguću moć i da kada jednom ovladate njime jedina prepreka na koju možete naići je vaša maštovitost. U ovom tekstu bavićemo se naj osnovnijim strukturama DirectX-a i donekle vas uvesti u priču grafičkog programiranja, to ćemo učiniti kroz C++ zato što sam DirectX i jeste i nije programski jezik za sebe, već veliki broj poziva i predefinisanih funkcija koje koristite u nekom od već poznatih programskih jezika kao što je VB, C++ ili C#. Pa da počnemo.

Page 2: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Šta vam je sve potrebno?

- Microsoft Visual Studio (ili Dev C++)

Microsoft Visual C++ je put koji smo mi izabrali. DirectX 9 podržava samo MS Visual C++ 7 verziju, i naravno verzije novije od nje, Visual C++ 6 je napušten.

- DirectX SDK

Software Development Kit za DirectX jeste veliki ali nažalost za korisnike sa slabijim internet vezama i neophodan. Možete ga preuzeti na http://msdn.microsoft.com/directx/sdk/ .

Podešavanje

Nakon instalacije i Microsoft Visual Studio (VS) programa i Direct X SDK, podešavanja su sledeća.

U osnovnom prozoru VS kliknite na Options i daljim klikom na direktorijum Projects dobićete sledeću listu:

U VC++ Directories podesite putanju na vaš SDK kao što je na slici prikazana (prva stavka), nemojte još uvek kliknuti OK jer imamo još par stvari da podesimo unutar ovog prozora.

Page 3: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

U padajućoj listi u kojoj trenutno piše Executable files pronađite stavku Include files.

Kao i malopre odredite putanju na vaš include direktorijum na računaru gde vam se nalazi SDK.(stavka jedan na slici) Ni ovde ne pritiskajte još uvek OK jer ostala je još jedna stvar koju treba uraditi.

U padajućoj listi gde ste malopre odabrali Include files sada odaberite Library files.

Page 4: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

I ovde kao i u prethodnim slučajevima odredite putanju vašeg lib direktorijuma unutar SDK na vašem računaru. Mala napomena, ukoliko ste sa interneta preuzeli poslednju verziju DirectX SDK a to je u ovom momentu Decembar 2005, primetićete da se unutar njegovih direktorijuma nalaze često dve opcije koje su X86 i X64. X64 se odnosi na računare nove generacije koji su 64-bitni tako da pazite da odabere u svojim podešavanjima u prethodnim koracima baš X86 direktorijume.

Sada kada smo sve podesili spremni smo da pređemo na sam DirectX i počnemo sa početnim objektima, strukutrama i funkcijama unutar njega.

Prozori (Window klase)

Ne preterano iznenađujuće, osnovni element Windows aplikacija su upravo prozori. U tipičnoj Windows aplikaciji, svaki vidljivi objekat je prozor. Bilo da je u pitanju dugme ili polje za unos, svi objekti su prozori. Tipična Direct3D aplikacija radi ipak malo drugačije. Većina aplikacija preuzme monitor i prozor primarno koristi kao medijum preko kojeg dobija poruke od operativnog sistema. Iako ove aplikacije intereaguju sa njihovim prozorima i sa standardnim WIN32 API pozivima mnogo manje, i dalje je njihova uloga veoma bitna a primena neophodna.

Postoje tri glavna koncepta koje bi trebalo da naučite pri podešavanju i upravljanju sa prozorima unutar Direct3D aplikacije:

• window klase • prozori • upravljačke jedinice nad porukama

Page 5: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Window klase

Window klasa nije tipična C++ klasa, iako postoje sličnosti. Pre svega ova klasa je šablon koji definiše određene atribute. Svaki prozor stvoren iz ove klase nasleđuje te atribute. Evo uprošćene verzije deklaracije strukture window klase:

struct WNDCLASS { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCSTR lpszMenuName; LPCSTR lpszClassName; };

Pošto je cilj ovog teksta da vas nauči i uputi u Direct3D nećemo zalaziti do besvesti u same detalje ove strukture, već ćemo ukratko opisati najbitnije članove, a onda vam ponuditi kodove koji će ilustrovati inicijalizaciju strukture, kreiranje window klase i konačno njeno uništavanje.

style - Kontroliše različita ponašanja prozora. lpfnWndProc - Ovo je pokazivač na upravljačku jedinicu poruka u window klasi. cbClsExtra i cbWndExtra - Ovim obezbeđujete dodatni memorijski prostor kao sastavni deo klase i prozora. Retko se koristi. hInstance - Ovo je upravljač vašom aplikcijom. Do njega se može doći pozivanjem GetModuleHandle() funkcije sa parametrom NULL. Instanca se prosleđuje takođe WinMain klasi pa vam je stoga i tu dostupna. hIcon, hCursor, hbrBackground - Ovo postavlja predefinisane postavke pri renderovanju ikona, kursora i pozadine aplikacije. lpszMenuName - Koristi se pri kreiranju menija.

Page 6: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

lpszClassName - Ovaj parametar daje klasi javno ime po kojoj se prepoznaje. Prozor može biti napravljen iz ovog šablona jednostavnim postavljanjem imena. Nakon što je window klasa popunjena, registrujete je putem RegisterClass funkciju. Iz primera koda (kompletni kodovi su priloženi uz ovaj tekst ), evo isečka koji ilustruje inicijalizaciju window klase i njene strukutre, registraciju i konačno odjavljivanje.

WNDCLASS window_class; HINSTANCE instance=GetModuleHandle(NULL); window_class.style = CS_OWNDC; window_class.cbClsExtra = 0; window_class.cbWndExtra = 0; window_class.hInstance = instance; window_class.hIcon = LoadIcon(NULL,IDI_APPLICATION); window_class.hCursor = LoadCursor(NULL,IDC_ARROW); window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); window_class.lpszMenuName = NULL; window_class.lpszClassName = "DH Class"; window_class.lpfnWndProc = p_wndproc; //Spoljna funkcija koja se bavi porukama prozora //Registracija klase sa prozorom if(!RegisterClass(&window_class)){ //Upravljač greškama ide ovde } // Ostatak aplikacije ide ovde //Konačno kada smo završili sa klasom pozivamo UnregisterClass: UnregisterClass("DH Class",instance);

Napomena: Svi prozori kreirani od strane klasa, moraju se zatvoriti pre nego što pozovete UnregisterClass za tu klasu.

Page 7: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Kreiranje prozora Sada kada smo napravili window klasu možemo kreirati i sam prozor. Evo primera:

HWND CreateWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, y, int nWidth, nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam );

Sada ćemo kao i malopre proći kroz parametre ukratko, pa ćemo pogledati primer koda koji ih ilustruje.

lpClassName - Ovo je ime klase koju ste kreirali u prethodnom koraku.

lpWindowName - Ime priključeno za vaš prozor, ukoliko imate naslov u svom prozoru ovo ime će se tu prikazati. dwStyle - Stilovi prozora određuju da li prozor ima prostor za naslov, kakve su mu ivice i još mnoge druge stvari. U aplikaciji koja se pokreće preko celog ekrana, WS_POPUP|WS_VISIBLE su često korišćene jer mogu da naprave prozore bez ikakvih vidljivih ivica .

x and y - Postavljanje Pozicije gledano iz gornjeg levog ugla. Pozicija (0,0) je stoga skroz u gornjem levom uglu. nWidth and nHeight - Širina i Visina prozora u pikselima. hWndParent - Identifikuje prozor koji želite da postane roditelj novo nastalim prozorima.

hMenu - Pokazivač i upravljač menijem. hInstance - Ovo je upravljač vašom aplikcijom. Do njega se može doći pozivanjem GetModuleHandle() funkcije sa parametrom NULL. Instanca se prosleđuje takođe WinMain klasi pa vam je stoga i tu dostupna.

Page 8: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

lpParam - Čudni Windows-ov vudu, ostavite ga na NULL ukoliko niste sigurni šta radite. Deluje kao puno stvari koje treba naučiti samo da biste napravili prozor, ali činjenica je da ćete stalno korisiti jedan isti kod kad god vam zatreba sa malim izmenama. Treba napomenuti da ukoliko će vaša aplikacija preuzeti čitav ekran, nije bitno koliko će veliki prozori biti jer ćete u svakom slučaju zauzeti čitav ekran. Ukoliko korisite prozorski mod, vaši prozori mogu biti bilo koje veličine koju vi odredite, jedina stvar na koju treba da obratite pažnju jeste da vaši prozori dolaze sa naslovom i ivicama, tako da ukoliko ste zatražili prozor rezolucije 640 x 480 zbog ivica možete dobiti samo 630 piksela radne površine. Evo i primera:

if(is_app_fullscreen){ //Upit sistemo da vrati veličinu desktop-a window_width=GetSystemMetrics(SM_CXSCREEN); window_height=GetSystemMetrics(SM_CYSCREEN); style=WS_POPUP|WS_VISIBLE; }else{ //U prozorskom modu, jednostavno samo pravimo prozor veličine koju mi želimo window_width=desired_width; window_height=desired_height; style=WS_OVERLAPPED|WS_SYSMENU|WS_VISIBLE; } p_window=CreateWindow("DH Class", ime naše klase window_name, //Ime prozora/naslov style, //Stilovi 0, //X pozicija 0, //Y pozicija window_width, //širina prozora window_height,//visina prozora NULL, //Roditelj prozora NULL, //Meni instance, //upravljač aplikacijom NULL); //pokazivač na prozor if(!p_window){ //upravlanje greškama } if(is_app_fullscreen){ ShowCursor(FALSE); }

Page 9: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

if(!p_fullscreen){ GetClientRect(*p_window,&client_rect); MoveWindow(*p_window, 0, //leva ivica 0, //gornja ivica window_width+(window_width-client_rect.right), //Nova širina window_height+(window_height-client_rect.bottom), //Nova visina TRUE); }

Uništavanje vašeg prozora

Ovaj deo je dobio zasebno mesto u tekstu jer postoje dva načina da se reši, a mi ćemo ih pokriti oba.

U standardnom Windows programiranju vi ne uništavate direktno prozor, već mu šaljete poruku da se samouništi. Ovo se često primenjuje unutar upravljačke jedinice nad porukama, koja je sama po sebi samo pozivajuća funkcija. Tako da funkcija koja se indirektno poziva od strane vaše aplikacije šalje poruku prozoru da se uništi. Većina programera koja nije koristila Windows pre smatra da je ovo veoma čudan pristup. Ukoliko ste alocirali resurse trebali biste i da ih dealocirate. Ukoliko pogledate istorijat iza WIN32 API poziva videćete da ovo ima smisla. Aplikacija miruje i čeka da dobije poruku i nakon što je dobije, opet se vraća u stanje mirovanja do sledeće. Dok programiranje bazirano na događajima (eng. event-driven) ima puno smisla u biznis aplikacijama ipak nije prikladna za većinu igara, uzimajući u obzir da igre konstanto ažuriraju i renderuju što brže mogu, i kao takve koriste se minimalno Windows modelom. Često je zgodno da se aplikacija pokrenuta preko celog ekrana ponaša kao da je zauzela čitavu mašinu. Ovo naravno nije istina, ali sa malo truda moguće je održati iluziju.

Jedan od omiljenih načina da se prozor uništi je njegovo eksplicitno uništavanje. Kreira se lepa kontinualnost vaše aplikacije koja ujedno i vizuleno odgovara samom kodu. Kreirajte prozor, koristite prozor i onda ga uništite. Lepo i jednostavno. Iskreno obe metode su esencijalno iste. Jedna je manje direktna nego druga ali na kraju krajeva obe daju isti rezultat. Ovo je više pitanje samog programera i njegovog stila. Nećemo pokazati standardni metod već ćemo se skoncentrisati na ovaj drugi:

Page 10: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Zbog načina na koji Windows radi, vaš prozor ne mora da se uništi odmah, zbog zakasnelih poruka koje se još obrađuju u redu. Kako bismo bili dodatno sigurni, proveravamo da je red prazan. Evo i koda:

MSG msg; DestroyWindow(my_window); //Očisti svaku obrađivanu poruku unutar reda while(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)){ TranslateMessage(&msg); DispatchMessage(&msg); }

Procesiranje poruka prozora

U ovom momentu znate da kada kreirate prozor morate proslediti pokazivač na funkciju obrade poruka. Kada god dođe do nekog događaja poruka je poslata prozoru (korisnik pritiska dugme, sat je odbrojao...). Ova poruka se prosleđuje upravljačkoj funkciji za poruke koja proverava da li je poruka njemu poznata i da li zna šta sa njom dalje treba uraditi. Ukoliko mu poruka nije poznata dalje je prosleđuje predefinisanoj proceduri DefWindowProc kako bi dao Windows-u do znanja da je poruka vratila kao odgovor nulu.

Evo jedne jednostavne upravljačke funkcije nad porukama:

LRESULT CALLBACK default_window_proc(HWND p_hwnd,UINT p_msg,WPARAM p_wparam,LPARAM p_lparam){ switch(p_msg){ case WM_KEYDOWN: // Taster je pritisnut, ukini aplikaciju case WM_CLOSE: //Pritisnuto Close Window dugme, ukini aplikaciju case WM_LBUTTONDOWN: //pritisnuto levo dugme miša,ukini aplikaciju g_app_done=true; return 0; } return (DefWindowProc(p_hwnd,p_msg,p_wparam,p_lparam)); }

Page 11: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

p_hwnd- je upravljač prozorima.Ukoliko vaša aplikacija ima više prozora koji koriste istu window klasu uz pomoć ovoga ćete odrediti koji od prozora je dobio poslatu poruku. p_msg- Tip poruke. Tipovi poruka u prethodnom kodu su WM_KEYDOWN, WM_CLOSE, i WM_LBUTTONDOWN. p_wparam i p_lparam - Specifične poruke. U slučaju WM_KEYDOWN, i WPARAM čuvaju podatke o tasteru koji je pritisnu dok LPARAM čuva podatke o tome koliko je puta pritsnuto i još mnoge druge informacije.

U našem primeru postavili smo da se aplikacija ugasi kad god korisnik pritisne taster, klikne levim dugmeto miša ili klikne baš na dugme koje inače zatvara prozor.

Sada smo prošli kroz čitav proces window klase i načina na koji možemo da napravimo prozor, koristimo ga i na kraju uništimo. Ovo je najosnovniji objekat unutar DirectX-a a može se reći i samog Windows-a. U sledećem broju pozabavićemo se samom inicijalizacijom Direct3D-a.

Page 12: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

DirectX 9.0 Programiranje u C++ programskom jeziku

(2.deo)

Rastko Ilić

UVOD

U ovom delu naučićete da napravite svoju prvi Direct3D objekat i uređaj koji su nam neophodni za rad same aplikacije. Ta aplikacija neće biti grandiozni i kompleksni projekat ali će vas naučiti kako se pravi prozor i kako se inicijalizuje Direct3D. Takođe ćemo prikazati kako se uklanja sve sa prozora i kako se neke stavke prezentuju korisnicima. Samo renderovanja će biti uprošćeno ali ne brinite u nekom od sledećih nastavaka proćićemo i kroz renderovanje detaljnije.

Page 13: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Kreiranje Direct3D-a

Prvi korak je kreiranje IDirect3D9 objekta i to je veoma jednostavno. Pogledajte kod koji kreira objekat i nakon toga ga oslobađa:

IDirect3D9 *g_D3D=NULL; g_D3D = Direct3DCreate9( D3D_SDK_VERSION); if(!g_D3D){ //Upravljač greškama } //Na samom kraju aplikacije if(g_D3D){ g_D3D->Release(); g_D3D=NULL; }

Prvo, deklarisaćemo pokazivač na IDirect3D9 objekat. Ovaj pokazivač pokazaće se nepotrebnim u daljem radu jer ćete na mnogim mestima videti deklaracije kao što je na primer LPDIRECT3D9. LPDIRECT3D9 je tipa typedef, što je samo po sebi pokazivač na IDIRECT3D9 objekat. Svi DirectX objekti imaju svoj typedef koji se prepoznaju po velikim slovima LP na početku svog imena. Mi ćemo korisiti prvi način kako bi se jasno videlo šta radimo i koji objekti se referišu na neke bitnije DirectX objekte. Direct3DCreate9 ima samo jedan parametar. U gotovo svakom primeru videćete da je taj parametar D3D_SDK_VERSION. Ovo kreira Direct3D objekat koji je kompatibilan sa SDK-om koji koristite u datom momentu. Ako zbog nekog razloga morate da radite sa starijim Direct3D9 verzijama, preko već spomenutog parametra možete proslediti da je upravo ta verzija ona sa kojom želite da radite. Nadamo se da ovo nećete morati često da radite u budućnosti, ipak u svakom slučaju sada ostavite 3D_SDK_VERSION.

Nakon što ste završili sa radom nad IDirect3D9 objektom, pozivate njegovu metodu za otpuštanje (Release). Najkraće objašnjenje ove metode i jeste da ona govori vašoj aplikaciji da otpusti objekat. DirectX koristi COM (Component Object Model) i svi njegovi objekti nasleđuju iz IUnknown klase. Kada je IUnknown objekat kreiran inkrementuje se broj interne reference i nakon što se Release metoda pozove, interna referenca kreće da se dekrementuje. Kada referenca dostigne 0 objekat je pušten.

Page 14: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Referenca objekta se može inkrementovati direktno pozivanjem njegove AddRef metode. Napredni korisnici će želeti ovo da iskoriste pri organizaciji svojih objekata kada su oni deljeni na više različitih mesta. Broj referenci se najčešće poziva indirektno. Ukoliko renderujete mesh, Direct3D će inkrementovati svoju referncu i dekrementovati je nakon što je završio. Na ovaj način iako ste uklonili svoj objekat za koji ste mislili da se ne koristi, Direct3D će i dalje renderovati mesh. Detaljno razumevanje COM-a nije neophodno da biste mogli da koristite DirectX, ali i te kako pomaže pri razumevanju osnovnih koncepta DirectX-a. Kada pozovemo Release, prvo proveravamo da li je pokazivač NULL. Direferenciranje NULL pokazivača će napraviti exception koji će ukinuti aplikaciju. Ukoliko pokazivač nije NULL, pozivamo Release i tada postavljamo pokazivač na NULL kako bismo ga sprečili od pokušaja da se oslobodi više puta.

Microsoft definisani MACRO, SAFE_RELEASE, ponaša se identično kao i naš Release. SAFE_RELEASE je definisan u dxutil.h biblioteci koja se nalazi u Common folderu u vašem SDK.

Kreiranje Direct3D Uređaja

Direct3D uređaj (IDirect3DDevice9), mi ćemo kako ne bismo komplikovali tekst ovo nazivati jednostavno uređaj, se koristi za koumnikaciju sa video karticom. U pitanju je 1 na 1 veza između karitce i uređaja i ukoliko želite da renderujete na više karica neophodno je napraviti uređaj za svaku od njih. Za razliku od IDirect3D-a stvaranje novog uređaja je malo komplikovanije. Kako je ovaj tekst u početničkom duhu, kroz naprednije delove o uređaju pričaćemo u nekom od narednih tekstova.

Postoji pomalo užasavajuća količina podataka koja se može podesiti kada se kreira novi uređaj. Kako bismo izbegli postavljanja oko 80 različitih parametara (većina njih je opcionalna) u jednoj funkciji, popunićemo strukturu u kojoj ćemo tačno reći šta mi želimo od našeg uređaja. Ova struktura se zove D3DPRESENT_PARAMETERS, možda ćete se zapitati da li je neko u Microsoft-u polomio Caps Lock taster kada je smišljao DirectX, ipak evo strukture:

Page 15: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

struct D3DPRESENT_PARAMETERS{ UINT BackBufferWidth; UINT BackBufferHeight; D3DFORMAT BackBufferFormat; UINT BackBufferCount; D3DMULTISAMPLE_TYPE MultiSampleType; DWORD MultiSampleQuality; D3DSWAPEFFECT SwapEffect; HWND hDeviceWindow; BOOL Windowed; BOOL EnableAutoDepthStencil; D3DFORMAT AutoDepthStencilFormat; DWORD Flags; UINT FullScreen_RefreshRateInHz; UINT PresentationInterval; };

A evo i kratkog objašnjenja svakog od parametara:

BackBufferWidth i BackBufferHeight

Širina i visina back buffer-a. U aplikaciji koja se pokreće preko celog ekrana ovi parametri moraju odgovarati i samoj rezoluciji ekrana. U ovo tekstu koristićemo već predefinisani model sa 640x480 px.

BackBufferFormat

Služi za opisivanje dubine back buffer-a (tipično 16 i 32bit-a). U DirectX9 verziji 24bit-ni pozadinski baferi nisu podržani. Format takođe opisuje i same formate pojedinačnih pixela. Dva najpoznatija formata u 16 bit-a su D3DFMT_R5G6B5 i D3DFMT_X1R5G5B5. U prozorskom režimu možete koristiti D3DFMT_UNKNOWN koji automatski preuzima model koji koristi i vaš dektop.

BackBufferCount

Vrednosti od 0 do 3, gde se 0 tretira kao 1. Tipično se samo jedan pozadinski bafer koristi, a u koliko to nije slučaj onda se primenjuje duplo baferisanje. U duplom baferisanju iscrtavanje se vrši u pozadinskom baferu a onda se scena prikazuje kao celina korisniku. Više bafera mogu poboljšati iscrtavanje i učiniti da vaša aplikacija dobije na glatkoći, naravno sve to po ceni više potrošnje memorije.

Page 16: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

MultiSampleType and MultiSampleQuality

Kontorliše višestruko semplovanje koje je vrsta pomagača u režimu rada preko celog ekrana i pogotovu anti-aliasing-a. Može značajno poboljšati kvalitet vaše renderovane scene, ali koštaće vas memorije i performansi. Treba spomenuti da višestruko semplovanje nije podržano od većeg broja grafičkih karti. U ovom tekstu se time nećemo baviti pa tip našeg višestrukog semplovanja podešavamo na D3DMULTISAMPLE_NONE a kvalitet na 0.

SwapEffect

Vrednosti ovog parametra su D3DSWAPEFFECT_DISCARD, D3DSWAPEFFECT_FLIP i D3DSWAPEFFECT_COPY. D3DSWAPEFFECT_DISCARD će naterati vaš uređaj da koristi najbržu metode koju može pri prikazivanju pozadniskog bafera. Ostale efekte nažalost ne možemo spominjati u ovom tekstu jer su isuviše komplikovane.

hDeviceWindow

Ovu metodu ostavljamo takvom kakva jeste. Napredniji korisnici koji su zainteresovani za podršku sistema sa više grafičkih karti, u dokumentaciji DirectX-a mogu pronaći više detalja.

Windowed

Ukoliko je false, Direct3D će preuzeti ekran i promeniti model kako bi odgovarao dimezijama zadatim u BackBufferWidth i BackBufferHeight. Ukoliko je true, model prikazivanja ekrana neće biti promenjen.

EnableAutoDepthStencil

Postavlja opciju da li će vaša aplikacija koristiti dubinu posebnog stencil bafera. Za sada postavićemo je na FALSE.

AutoDepthStencilFormat

Slično formatu pozadinskog bafera, određuje dubinu bitova i formata korišćenih od strane Depth/Stencil buffer. Kada je EnableAutoDepthStencil FALSE, ovo stanje se ignoriše.

Page 17: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Flags

Za napredne korisnike. Postavićemo ih za sada na 0.

FullScreen_RefreshRateInHz

Mera u Hz, određuje brzinu osvežavanja ekrana. Ukoliko je brzina koju ste naveli veća nego što to uređaj ili ekran može da podrži, kreiranje uređaja će ili propasti, ili će poslati poruku ekranu da ne može da se izbori sa zadatom brzinom. Kako bismo bili sigurni postavićemo je na D3DPRESENT_RATE_DEFAULT.

PresentationInterval

Kontrola nad kašnjenjem u prikazivanju pozadinskog bafera korisnicima. D3DPRESENT_INTERVAL_DEFAULT će sačekati da se nešto desi po vertikali pa će tada iscrtavati.

Sada kada smo sve objasnili, možemo da kreiramo naš uređaj. Evo jednog prototipa metode:

With that out of the way, we can create our device. Let's look at the prototype for the method.

HRESULT CreateDevice( UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface ); U sledećem delu pozabavićemo se svakom od metoda i atributa unutar ove strukture i nastaviti dalje ka našoj prvoj aplikaciji u DirectX-u.

Page 18: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

DirectX 9.0 Programiranje u C++ programskom jeziku

(3.deo)

Rastko Ilić

UVOD

U ovom broju bavićemo se metodama i atributima neophodnim za kreiranje uređaja, kao mali podesetnik evo i koda kod kojeg smo stali: HRESULT CreateDevice( UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface );

Page 19: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Adapter Ovom metodom određujemo koj adapter ćemo dodeliti našem uređaju. Najčešći slučaj je upravo dodeljivanje jedan-na-jedan sa grafičkom karticom koja se nalazi u računaru. Na karticama koje podržavaju više grafičkih procesora, popularno nazvane kartice sa više glava (kartice koje mogu da koriste više monitora na jednoj grafičkoj kartici) svaka od tih glava može pretstavljati nezavisni adapter. Kako bismo dobili primarno korišćeni adapter koristimo D3DADAPTER_DEFAULT. DeviceType Najčešće se koristi D3DDEVTYPE_HAL. HAL je skraćeno od Hardware Acceleration Layer i koristi se za izvlačenje maksimuma iz grafičke karte. D3DDEVTYPE_REF vrši svo procesiranje softverski. Iako je ovo procesiranje je neverovatno sporo, njegova dobra strana je što u mnogome pomaže pri debagiranju aplikacije. REF je skraćeno od Reference Rasterizer, i predstavlja kompletnu implementaciju Direct3D specifikacija. Podržava veliki broj operacija koje možda čak ni vaša grafička karta ne podržava. Ukoliko dok koristite HAL pronađete nešto što ne radi kako treba, možete to isto pokrenuti na REF-u i ukoliko se i tamo pokaže da ne radi, najverovatnije je bug u samom programu, u suprotnom moguć je bau i u samom drajveru grafičke karte. REF dolazi sa standardnim SDK-om, tako da ne računajte na to da će ga i vaši korisnici imati. hFocusWindow Postavite iste vrednoti kao i kod metode DeviceWindow u vašim presentacionim parametrima. Ukoliko koristite sliku preko celog ekrana, fokus mora biti prozor velikog priroriteta (top level). BehaviorFlags Ovim kontrolišete veliki deo ponašanja iza scene. Najveći broj tih kontrola je isuviše napredan pa ćemo se mi pozabaviti samo nekim od njih. Tri najčešće korišćene zastavice su: D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DCREATE_HARDWARE_VERTEXPROCESSING, i D3DCREATE_MIXED_VERTEXPROCESSING. Samo jedna od ove tri zastavice se može koristiti u jednom procesiranju.

Page 20: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

SOFTWARE podešava sva vertex procesiranja (na primer osvetljenje) da se izvršava softverski. Ova zastavica je podržana od svih grafičkih kartica i ima veoma olabavljena ograničenja na to šta može da uradi. S'obzirom da se izvršava u softveru, sva vertex procesiranja se vrše u CPU (procesoru računara). Sa odabranom HARDWARE zastavicom, svo procesiranje se vrši u grafičkoj karti. Ovaj metod je brži zato što su grafičke karte specijalno dizajnirane za ovaj posao i zato što se time oslobađa CPU koji za to vreme može da se pozabavi drugim poslovima. Većina modernijih grafičkih karti podržava hardversko procesiranje vertexa. Korišćenjem MIXED zastavice kao što i samo ime kaže dozvoljava skakanje između već smopenutih dva načina rada. Ukoliko postoje operacije koje vaš hardver ne podržava, možete se prebaciti na softver dok se te operacije ne završe. pPresentationParameters Ovo je samo pokazivač na vašu PRESENTATION_PARAMETERS strukturu. IDirect3DDevice9 Ukoliko poziv na CreateDevice uspe, vaš novi uređaj će se vratiti ovde. Evo primera koda svega što smo do sada spomenuli: IDirect3D9 *d3d; //Pretpostavlja da je sve već inicijalizovano kako treba HWND wnd; //Prepostvalja da je inicijalizovano D3DFORMAT format=D3DFMT_R5G6B5; //Zbog jednostavnosti za sada ćemo ovo hardkodovati D3DPRESENT_PARAMETERS pp; IDirect3DDevice9 *p_device=NULL; HRESULT hr; //Iako smo podesili sve njegove članove, dobra praksa je da ih //sve postavimo na tačne vrednosti. ZeroMemory(&pp,sizeof(D3DPRESENT_PARAMETERS)); pp.BackBufferCount= 1; //Potreban nam je samo jedan bafer pp.MultiSampleType=D3DMULTISAMPLE_NONE; //Bez višestrukog semplovanja pp.MultiSampleQuality=0;

Page 21: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

pp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Uklanjamo prethodne frejmove, ne trebaju nam pp.hDeviceWindow=wnd; //Ovo je naš main (jedini)prozor pp.Flags=0; //Bez zastavica pp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT; //Predefinisani Refresh Rate pp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT; //Predefinisana Presentation vrednost pp.BackBufferFormat=format; //Format prikazivanja pp.EnableAutoDepthStencil=FALSE; //Bez dubinskog/stencil bufera if(is_app_fullscreen){ pp.Windowed = FALSE; pp.BackBufferWidth = 640; pp.BackBufferHeight = 480; }else{ pp.Windowed = TRUE; } hr=p_d3d->CreateDevice(D3DADAPTER_DEFAULT, //The default adapter, on a multi-monitor system //there can be more than one. D3DDEVTYPE_HAL, //Koristite hardversku akceleraciju, pre nego softversku pri renderovanju. //Naš prozor wnd, //Procesiranje vertexa u softveru. Sporije od hardvera,ali će --//raditi na svim grafičkim kartama. D3DCREATE_SOFTWARE_VERTEXPROCESSING, //Naša D3DPRESENT_PARAMETERS struktura, kako bi znao šta //želimo da napravimo. &pp, //Ovo će biti pokazivač na naš novi uređaj. &p_device); if(FAILED(hr)){ // Obrađivač grešaka } HRESULT i Testiranje Virtuelno svi metodi u DirectX-u vraćaju HRESULT kako bi potvrdili da li je

Page 22: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

nešto uspešno ili neuspešno. Pravilan način testiranja da li je metoda neuspešna je FAILED makro. Postoji takođe i SUCCEEDED makro koji proverava da li je metoda uspešna. U mnogim primerima, uspeh će se testirati poređenjem HRESULT i D3D_OK. Ovo nije pravilan način kojim biste trebalo da proveravate. Jedini garantovani metod testiranja nečega neuspešnog je sa već spomenutim makroima. HRESULT sadrži više od jedne uspešno/neuspešno zastavce. Zapravo može vam pružiti detaljnije informacije koje vam govore šta se desilo. Na primer, ukoliko pozovete CreateDevice a nema dovoljno memorije, vratiće D3DERR_OUTOFVIDEOMEMORY. Kako biste od nečitljivih kodovanih grešaka dobili nešto što je lakše i mnogo razumljivije možete koristiti DirectX Error Lookup alatku koja dolazi uz SDK. Sprovedite joj numeričku vrednost greške i alat će vam objasniti grešku. Drugi način rada sa isipisivanjem grešaka je DXGetErrorString9 koji uzima jedan HRESULT kao parametar a vraća pokazivač na string koji objašnjava grešku. Određivanje korisnog D3DFORMAT formata U prethodnim slučajevima koristili smo hardkodovanu vrednost za D3DFORMAT. Ovo je loša ideja jer time podrazumevamo da i grafička karta kod korisnika podržava isti format, što ako je zaista i slučaj će sprečiti aplikaciju da napravi uređaj. Pravilan pristup ovom problemu je da upitamo uređaj da proveri da li podržava zadati format. Kako bismo ovo uradili koristimo CheckDeviceType metodu našeg IDirect3D9 objekta pre nego što kreiramo uređaj. HRESULT CheckDeviceType( UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL Windowed ); Adapter Ovo je ista vrednost koju ćemo koristiti u pozivanju CreateDevice-a, Ovime se identifikuje koja grafička karta će se koristiti.

Page 23: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

DeviceType S'obzirom da želimo da testiramo podržane formate od strane nape grafičke karte, koristimo D3DDEVTYPE_HAL. DisplayFormat Format korišćen od strane monitora. U prikazu preko celog ekrana biće isti kao i format pozadinskog bafera. Uz pomoć IDirect3D9->GetAdapterDisplayMode možete doći do trenutno korišćenog režima prikaza. BackBufferFormat Ovo je format u kome će se vaš pozadniski bafer prikazivati. Windowed S'obzirom da postoji više pravila korišćenja prikazivanja preko celog ekrana i prikazivanja u prozorskom režimu, morate odrediti koji koristite. Evo primera testiranja da li je D3DFMT_R5G6B5 podržan u prikazu preko celog ekrana. HRESULT hr; hr=d3d->CheckDeviceType(D3DADAPTER_DEFAULT, //Adapter D3DDEVTYPE_HAL, //Tip uređaja D3DFMT_R5G6B5, //Format prikazivanja D3DFMT_R5G6B5, //BackBuffer Format false); //Prozorski režim if(SUCCEEDED(hr)){ //Format je validan }else{ //Pojava greške } U prozorskom režimu rada, najbolje je staviti D3DFMT_UNKNOWN u pozivu CreateDevice-a. Render Petlja

Page 24: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

U ovom broju nećemo još uvek ništa renderovati, ali upustićemo se u samo radno okruženje našeg rendera kako bi nam kasnije stvari koje dolaze bile jednostavnije za shvatanje. Da bacimo pogled na osnovnu main petlju: bool g_app_done=false; HRESULT hr; while(!g_app_done){ dhMessagePump(); //Proverava poruke od strane prozora hr=render(); //Iscrtava našu neverovatnu grafiku } Prolazimo kroz petlju sve dok ne dođemo do zastavice koja signalizira kraj naše aplikacije. Ova zastavica dobija vrednosti od našeg prozorskog rukovodioca sa porukama. Svaki put kada prolazimo kroz našu petlju mi pozivamo našu render funkciju. Ovo je u najkraćim crtama kako se poziva render funkcija koju ćemo u sledećim brojevima daleko opširnije i detaljnije objasniti.

Page 25: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

DirectX 9.0 Programiranje u C++ programskom jeziku (4.deo)

Rastko Ilić

UVOD

U ovom broju nastavićemo tamo gde smo i stali kod pozivanja funkcije

render. Prva stvar na koju morate da obratite pažnju kada pozivate render funkciju je da joj zadate da pre svega isprazne pozadinski bafer. Trenutni pozadinski bafer bi mogao još uvek da prikaže sadržaj iz prethodnog okvira ili neki nasumice zaostali deo koji ne želimo. Jedini izuzetak predstavlja korišćenje runtime debagera sa D3DSWAPEFFECT_DISCARD prezentacionom zastavicom. U ovom slučaju pozadinski bafer se prazni kako bi se smenjivale zelena i crvena boja. Ukoliko ikada vidite da se ove dve boje naizmenično menjaju u vašoj aplikaciji to znači da se pozadinski bafer ne prazni kako treba. Pozadinski bafer se prazni pozivanjem metode Clear vašeg uređaja. Ova metoda se može koristiti nad kompletnim baferom ili pak nad određenim njegovim pravougaonicima.

Page 26: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

HRESULT Clear( DWORD Count, const D3DRECT *pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil ); Count Broj individualnih pravougaonika koji želite da ispraznite. Ukoliko praznite čitav bafer podesite na 0.

pRects Ovo je niz RECT struktura koje želite da ispraznite, ukoliko praznite čitav bafer podesite na NULL. Flags Dozvoljene zastavice (svaka kombinacija je dozvoljena) su D3DCLEAR_STENCIL, D3DCLEAR_TARGET and D3DCLEAR_ZBUFFER. Dodatno možete odreditiD3DCLEAR_STENCIL ukoliko imate stencil bafer, a možda ćete koristiti D3DCLEAR_ZBUFFER ukoliko imate Z (dubiski) baferr. Ukoliko odredite zastavicu bez odgovarajuće površine na koju se primenjuje, poziv će propasti. Takođe, makar jedna od ovih zastavica mora biti određena. Color Ovo je pozadina koju želite da postavite za pozadinu vašeg pozadinskog bafera. Možete ga odrediti kao 32-bitni ARGB broj ili u heksadecimalnom zapisu 0xAARRGGBB. Z Ovo je vrednost korišćena za pražnjenje dubinskog bafera. Pravilne vrednosti koje se određuju su u rasponu od 0.0 do 1.0, gde 0.0 predstavlja najbližu distancu a 1.0 najdalju.

Page 27: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Stencil Stencil bafer će se isprazniti do ove vrednosti. Ovo je integer vrednost u rasponu od 0 do 2n-1, gde je n dubina stencil bafera. Kako biste upozorili uređaj da ste spremni za renderovanje pozivate metodu BeginScene,a kako biste ga obavestili da ste završili, metodu EndScene. Kako obe ne zahtevaju nikakve parametre nećemo se opterećivati sa prikazom samih detalja. Sledeće što sledi je prezentovanje pozadinskog bafera korisniku. Kako biste to uraili pozivate Present metodu. Evo kako ona izgleda. HRESULT Present( const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion ); pSourceRect Ovim se određuje pod-pravougaonik kao izvor. Generalno biće vam potrebno da prikažete čitav bafer tako da postavite NULL. pDestRect Ovo je pod-pravouganoik displeja na koji želite da se prikaže vaš pozadniski bafer. Ponovo, ovde se najčešće postavlja NULL kako biste pokrili čitavu površinu. hDestWindowOverride Ukoliko zadate NULL, pozadinski bafer će se kopirati na prozor koji ste vi odredili kada ste napravili uređaj. Postavljanjem ovoga na različit prozor dozvoljava vam da i prikažete u drugom prozoru. pDirtyRegion Ovim se određuje da se samo jedan deo slike mora ažurirati i taj deo i definiše ovaj region. Ovo je mali trik pri optimizaciji aplikacija, ali za sada ćemo ostaviti NULL kao vrednost.

Page 28: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Sada kada smo sve objasnili, probajmo da sve i spojimo.

hr=g_d3d_device->Clear(0,NULL, D3DCLEAR_TARGET, 0x00000000,1.0f, 0 ); if(FAILED(hr)){ } hr=g_d3d_device->BeginScene(); //početak iscrtavanja if(FAILED(hr)){ } //Ovde ćete staviti vaše sjajne kreacije //Obavestite uređaj da je kraj scene g_d3d_device->EndScene(); //Prikažite rezultat hr=g_d3d_device->Present(NULL,NULL,NULL,NULL, NULL ); if(FAILED(hr)){ }

Da smo zapravo i renderovali nešto, na mestu gde piše da ćete staviti vaše kreacije bi se nalazilo ono što se i renderuje. Izgubljeni uređaji

Ovo je jedna od bitnijih stvari koje bi trebalo naučiti. Ukoliko imate aplikaciju koja se prikazjue preko celog ekrana i korisnik pritisne ALT+TAB kako bi se vratio na dektop, vaša aplikacija izgubi pristup displeju. Postoje i drugi događaji koji mogu prouzrokovati sličnu neprijatnost, ali ipak je to najčešće ALT+TAB kombinacija.

Jednom kada ste izgubili vaš uređaj više niste u mogućnosti da renderujete bilo šta. Pokušaji da se pozove Present će se završiti vraćenom greškom D3DERR_DEVICELOST. Jedan drastičan način da se stvari vrate na svoje mesto je da se sve oslobodi i ponovo kreira. Ali postoji i jednostavniji način. Pozovite TestCooperativeLevel koji upituje urešaj za njegov status. Ukoliko se vrati upešno, vaš uređaj je u redu. Ukoliko se pak javi D3DERR_DEVICELOST vaš uređaj je nestao i ne može još uvek biti resetovan.

Page 29: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

Pre nego što uređaj dozvoli da se ponovo pokrene, vi morate osloboditi određene resurse. U našem primeru napravili smo funkciju FreeVolatileResources koja će nam to uraditi. Takođe smo napravili funkciju koja se zove InitVolatileResources koja se koristi nakon što je uređaj uspešno ponovo pokrenut.

Vrednost koju vraća D3DERR_DEVICENOTRESET predstavlja znak da je bezbedno resetovati uređaj. TestCooperativeLevel ne uzima nikakve parametre, a da biste ponovno pokrenuli uređaj pozivate Reset metodu.

HRESULT Reset( D3DPRESENT_PARAMETERS *pPresentationParameters );

Kao što i sami možete videti, Reset uzima samo jedan parametar, pokazivač na vaš D3DPRESENT_PARAMETERS. Iz ovog razloga dobra je ideja da čuvate kopiju vaših trenutnih parametara negde u svom kodu. Na ovaj način takođe neverovatno lako možete namerno menjati paramtre u svojoj aplikaciju, na primer kada želite da vaša aplikacija može da prelazi iz prozorskog režima u režim preko celog ekrana. Evo koda koji obrađuje izgubljeni uređaj.

HRESULT hr; hr=p_device->TestCooperativeLevel(); if(hr == D3DERR_DEVICELOST) { //uređaj je izgubljen i nije spreman za resetovanje Sleep(500); FreeVolatileResources(); }else if(hr == D3DERR_DEVICENOTRESET){ //izgubljen ali ga sada možemo resetovati hr=p_device->Reset(p_pp); if(SUCCEEDED(hr)){ InitVolatileResources(); } } Ovim smo pokrili sve što se događa u render fazi, u sledećem broju krećemo sa zanimljivijom temom, osnovnim grafičkim objektima kao što su tačke,

Page 30: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

primitive i kordinatni sistem. Od sada ćemo u okviru svakog broja dostavljati i kod u ovome dokumentu kako biste mogli da kopirate i isprobate ili pak poredite sa svojim kada budete i sami radili. Kod korišćen u ovom broju: #include <D3DX9.h> #include "../common/dhWindow.h" #include "../common/dhD3D.h" #include "../common/dhUtility.h" #include "../Common/dhUserPrefsDialog.h" #pragma comment(lib,"d3d9.lib") #pragma comment(lib,"dxerr9.lib") LRESULT CALLBACK default_window_proc(HWND p_hwnd,UINT p_msg,WPARAM p_wparam,LPARAM p_lparam); HRESULT init_scene(void); void kill_scene(void); HRESULT render(void); void InitVolatileResources(void); void FreeVolatileResources(void); const char *g_app_name="Incijalizovanje D3D9 aplikacije"; const int g_width=640; const int g_height=480; const int g_depth=16; bool g_app_done=false; IDirect3D9 *g_D3D=NULL; IDirect3DDevice9 *g_d3d_device=NULL; D3DPRESENT_PARAMETERS g_pp; // Funkcija:WinMain

Page 31: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

int APIENTRY WinMain(HINSTANCE ,HINSTANCE ,LPSTR ,int ){ bool fullscreen; HWND window=NULL; D3DFORMAT format; HRESULT hr; dhUserPrefs user_prefs(g_app_name); if (!user_prefs.QueryUser()) { dhLog("Izlazak\n"); return 0; } fullscreen = user_prefs.GetFullscreen(); hr=dhInitWindow(fullscreen,g_app_name,g_width,g_height,default_window_proc,&window); if(FAILED(hr)){ dhLog("Neuspesno kreiranje prozora",hr); return 0; } hr=dhInitD3D(&g_D3D); if(FAILED(hr)){ dhKillWindow(&window); dhLog("Neuspesno kreiranje D3D-a",hr); return 0; } hr=dhGetFormat(g_D3D,fullscreen,g_depth,&format); if(FAILED(hr)){ dhKillWindow(&window); dhLog("Neuspelo dobavljanje displej formata ",hr); return 0; } DWORD adapter = user_prefs.GetAdapter(); D3DDEVTYPE dev_type = user_prefs.GetDeviceType(); //Inicijalizacija sadasnjih parametara

Page 32: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

dhInitPresentParameters(fullscreen,window,g_width,g_height,format, D3DFMT_UNKNOWN,&g_pp); //Kreiranje uredjaja hr=dhInitDevice(g_D3D,adapter,dev_type,window, &g_pp,&g_d3d_device); if(FAILED(hr)){ dhKillD3D(&g_D3D,&g_d3d_device); dhKillWindow(&window); dhLog("Neuspeno kreiranje uredjaja",hr); return 0; } init_scene(); while(!g_app_done){ dhMessagePump(); //Provera windows poruka hr=g_d3d_device->TestCooperativeLevel(); if(SUCCEEDED(hr)){ hr=render(); } //Uredjaj izgubljen if(hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET){ dhHandleLostDevice(g_d3d_device,&g_pp,hr); }else if(FAILED(hr)){ g_app_done=true; dhLog("Greska pri renderovanju",hr); } } kill_scene(); dhKillD3D(&g_D3D,&g_d3d_device);

Page 33: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

dhKillWindow(&window); return 0; } void InitVolatileResources(void){ } void FreeVolatileResources(void){ } HRESULT init_scene(void){ HRESULT hr=D3D_OK; InitVolatileResources(); return hr; } void kill_scene(void){ FreeVolatileResources(); } HRESULT render(void){ HRESULT hr; hr=g_d3d_device->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0 ); if(FAILED(hr)){ return hr; }

Page 34: CET - DirectX 9.0 Programiranje u C++ Programskom Jeziku

hr=g_d3d_device->BeginScene(); if(FAILED(hr)){ return hr; } g_d3d_device->EndScene(); hr=g_d3d_device->Present(NULL,NULL,NULL, NULL ); return hr; } LRESULT CALLBACK default_window_proc(HWND p_hwnd,UINT p_msg,WPARAM p_wparam,LPARAM p_lparam){ switch(p_msg){ case WM_KEYDOWN: case WM_CLOSE: case WM_LBUTTONDOWN: g_app_done=true; return 0; } return (DefWindowProc(p_hwnd,p_msg,p_wparam,p_lparam)); }