DirectX tutorial za Delphi i Lazarus

1

DirectX tutorial za Delphi i Lazarus

offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2478
  • Gde živiš: Ljubljana

Microsoft DirectX je vrlo mocan API ugradjen u Microsoft Windows operativni sistem koji nam omogucava lako (bolje receno relativno lako) pravljenje aplikacija koje koriste 3D grafiku, ulazne uredjaje kao sto su tastatura, mis, dzojstik, volan..., zvuk, mrezno igranje...

Vise o DirectX-u mozete procitati na Microsoft-ovom sajtu

Jedina mana DirectX-u je sto moze da radi samo na Windows operativnim sistemima, ali ako ste opredeljeni samo za Windows onda to nije nikakav problem.

Da biste koristili DirectX u Delphi-u potrebni su vam prevedeni header fajlovi i pomocni dll fajlovi.
Instalacija ovih fajlova je vrlo laka. Sve sto treba je da kopirate dll fajlove u Windows\System32 folder, a prevedene fajlove raspakujete u bilo koji folder i taj folder dodate u Library path u Delphi-u. To je sve Smile

U ovim tutorialima necemo koristiti VCL (forme, dugmice, labele i slicno) nego cist Win32 API i DirectX API. Da kasnije ne bi bilo problema sa Win32 API kodom prvo cemo nauciti kako se on koristi za kreiranje prozora.

Prvo sto treba da uradimo je da kreiramo prazan projekat (samo *.dpr fajl... sve *.pas fajlove izbacite iz projekta ako ih Delphi sam ubaci, a iz *.dpr fajla obrisite sav kod). Posto cemo koristiti Windows funkcije i poruke dodacemo sledeci kod
uses   Windows, Messages;
Windows unit sadrzi procedure, funkcije, tipove, konstante... vezane za Windows, a u Messages sve sto je potrebno za rad sa Win porukama.

Da bi kreirali prozor moramo prvo da registrujemo klasu naseg prozora. Ova registracija omogucava Windows-u da zna kakav prozor zelimo da kreiramo (kakve ivice da ima, da li ima minimize, maximize i close dugme i slicno). Funkcija koja nam omogucuje registrovanje klase prozora je RegisterClassEx. Ova funkcija uzima samo jedan parametar tipa TWNDClassEx. Ovaj tip sadrzi sve potrebne podatke da Windows zna kako da radi sa prozorom koji zelimo da registrujemo.
TWNDClassEx = packed record   cbSize: UINT;   style: UINT;   lpfnWndProc: TFNWndProc;   cbClsExtra: Integer;   cbWndExtra: Integer;   hInstance: HINST;   hIcon: HICON;   hCursor: HCURSOR;   hbrBackground: HBRUSH;   lpszMenuName: PAnsiChar;   lpszClassName: PAnsiChar;   hIconSm: HICON; end;

cbSize treba da popunimo velicinom ovog tipa pre nego sto prosledimo podatak funkciji. Ovo se vrlo lako radi i najbolje je da se uradi pre unosa ostalih podataka (da se ne zaboravi posle)
WndClass.cbSize := SizeOf(WndClass);

style definise neke od opcija koje odredjuju kako je klasa registrovana, kada prozor iscrtava svoj deo ekrana i slicno. Za sve flagove koji mogu biti u ovom podatku pogledajet Win32 API Help. Podatke koje cemo mi postaviti ce uticati na prozor tako da se iscrtava svaki put kada mu se promeni velicina... ako deo prozora bude zaklonjen nekim drugim prozorom, a zatim ponovo otkriven i tada ce, naravno, doci do crtanja (ovo ne treba da se definise nekim specijalnim flagom)
WndClass.style := CS_HREDRAW or CS_VREDRAW;

lpfnWndProc je procedura koja ce se pozivati svaki put kada Windows prosledi neku poruku nasem prozoru. Postavicemo je na WndProc (kasnije cemo napisati WndProc proceduru).
WndClass.lpfnWndProc := @WndProc;

cbClsExtra dozvoljava aplikaciji da kreira klasu sa dodatnim prostorom za cuvanje podataka. Ova mogucnost nam nece biti potrebna pa je necu posebno objasnjavati.

cbWndExtra dozvoljava aplikaciji da za svaki kreiran prozor ove klase ima dodatni prostor u kojem moze da upise podatke. I ova mogucnost na nece biti potrebna pa je necemo dalje objasnjavati. Kome su ova dva podatka bitna moze pogledati Win32 API Help.
Postavimo ova dva podatka na 0
WndClass.cbClsExtra := 0; WndClass.cbWndExtra := 0;

hInstance podatak treba da sadrzi vrednost HInstance promenljive koja je definisana u System unit-u.
WndClass.hInstance := HInstance;

hIcon sadrzi ikonicu koja se vidi u gornjem levom uglu prozora. Ikona se ucitava funkcijom LoadIcon. Windows u sebi ima i neke specijalne ikone pa cemo iskoristiti jednu od njih (standardnu).
WndClass.hIcon := LoadIcon(0, IDI_APPLICATION);

hCursor sadrzi kursor koji ce se videti kad je mis preko prozora. Ucitava se funkcijom LoadCursor. Windows takodje ima i par standardnih kursora.
WndClass.hCursor := LoadCursor(0, IDC_ARROW);

hbrBackground je boja kojom ce prozor biti ispunjen... koristicemo istu kao i Delphi.
WndClass.hbrBackground := COLOR_BTNFACE + 1;

lpszMenuName je ime menija u *.res fajlu koji zelimo da nas prozor ima kada se kreira. Posto nam meni sada nije potreban stavicemo nil.
WndClass.lpszMenuName := nil;

lpszClassName sadrzi ime klase koju kreiramo... neka bude MojProzor.
WndClass.lpszClassName := 'MojProzor';

hIconSm je ikona koja se koristi za prikaz kada je potrebno iscrtati malu ikonicu. Ako ovaj parametar nije definisan onda se ikona iz hIcon koristi i za prikaz male ikonice sto je nama sasvim uredu.
WndClass.hIconSm := 0;

Sada nam jos samo preostaje da registrujemo klasu.
RegisterClassEx(WndClass);

Kada imamo registrovanu klasu mozemo da kreiramo prozor. Za to cemo koristiti funkciju CreateWindowEx.
function CreateWindowEx(   dwExStyle: DWORD;   lpClassName: PChar;   lpWindowName: PChar;   dwStyle: DWORD;   X, Y, nWidth, nHeight: Integer;   hWndParent: HWND;   hMenu: HMENU;   hInstance: HINST;   lpParam: Pointer): HWND;

dwExStyle kontrolise kakav cemo prozor napraviti (da li ce imati kontrole u sebi, da li prihvata fajlove kada se puste iznad njega, da li je transparentan...). Za sve flagove pogledajte Win32 API Help.
Mi cemo koristiti:
WS_EX_OVERLAPPEDWINDOW

lpClassName ime klase koju zelimo da koristimo za nas prozor.
Koristimo nasu klasu:
'MojProzor'

lpWindowName text koji ce se videti u title bar-u.
Stavicemo:
'Prozor bez VCL'

dwStyle je slicno kao i dwExStyle. Mozemo definisati da li ce prozor bidi minimiziran po defaultu, disable-ovan, da li ce imati scroll bar (vertikalni, horizontalni),... Za sve flagove pogledati Win32 API Help.
Mi cemo postaviti ove flagove na:
WS_OVERLAPPEDWINDOW

X, Y, nWidth, nHeight predstavljaju poziciju i velicinu prozora.
Postavicemo prozor na 100, 100 sa sirinom 400 i visinom 300:
100, 100, 400, 300

hWndParent predstavlja prozor u koji cemo postaviti nas nov prozor. Posto ce nas prozor biti glavni ovaj parametar je 0.
0

hMenu predstavlja meni koji zelimo da prozor ima ako ne zelimo da koristimo onaj koji smo definisali u klasi prozora. Nama ne treba meni pa cemo i ovaj parametar postaviti na 0.
0

hInstance parametar je isti kao i kod registaracije klase. Pokazuje na HInstance promenljivu.
HInstance

lpParam parametar se prosledjuje prozoru kada se kreira. Moze sluziti za prenosenje bilo kojeg podatka, ali nama to nije bitno pa cemo ovaj parametar postaviti na nil.
nil
Na kraju dobijamo ovakav poziv:
Wnd := CreateWindowEx(   WS_EX_OVERLAPPEDWINDOW,   'MojProzor',   'Prozor bez VCL',   WS_OVERLAPPEDWINDOW,   100, 100, 400, 300,   0,   0,   HInstance,   nil );

Kada smo kreirali prozor, mozemo i da ga prikazemo
ShowWindow(Wnd, SW_SHOWDEFAULT); UpdateWindow(Wnd);
ShowWindow uzima dva parametra. Prvi je prozor koji zelimo da prikazemo/sakrijemo, a drugi kaze sta zelimo da radimo.
UpdateWindow tera prozor da se iscrta.

Lepo nam ide za sad. Sada cemo napisati kod koji ce citati poruke koje Windows salje nasem prozoru i zatim objasniti taj deo koda.
while GetMessage(Msg, 0, 0, 0) do   DispatchMessage(Msg);
Msg je promenljiva tipa TMsg koja ce sadrzati poruku koju nam Windows salje.
GetMessage uzima 4 parametra. Prvi je TMsg promenljiva u kojoj ce poruka biti smestena, drugi parametar je prozor za koji zelimo da uzmemo poruku (ako je ovaj parametar 0 tada primamo poruke svih prozora koje smo kreirali), a treci i cetvrti oznacavaju koje poruke zelimo da primimo. Ta dva parametra mozemo koristiti da uzmemo recimo samo poruke sa tastature ili misa, samo poruke za crtanje, itd... Kada su i jedan i drugi parametar 0 tada primamo sve poruke. Ova funkcija vraca True sve dok prozor ne kaze da je vreme za gasenje (pokazacemo kako se to radi).
DispatchMessage poziva proceduru koju smo definisali za klasu prozora i prosledjuje joj poruku.

Skoro da smo zavrsili. Kada se prozor zatvori ostaje nam da izbrisemo klasu iz memorije. To se radi funkcijom UnregisterClass.
UnregisterClass('MojProzor',HInstance);
Dva parametra koje uzima su ime klase koju zelimo da izbrisemo iz memorije (ne mozemo izbrisati klasu koju nismo registrovali) i HInstance promenljiva.

Sve sto nam ostaje je jos da napisemo WndProc funkciju. Ona mora biti posebnog oblika:
function WndProc(   Wnd: HWnd;   Msg: UINT;   wParam: WPARAM;   lParam: LPARAM ): LRESULT; stdcall;
Prvi parametar koji ce primiti je prozor za koji je funkcija pozvana, drugi je poruka koja se prosledjuje, a treci i cetvrti su podaci vezani za poruku i za svaku poruku imaju neko drugo znacenje.
Rezultat javlja Windows-u da li smo obradili poruku ili ne.
U ovom primeru cemo obraditi samo jednu poruku. Ona koju prozor dobija kada treba da se ugasi.
function WndProc(Wnd: HWnd; Msg: UINT;   wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin   case Msg of     WM_DESTROY:     begin       PostQuitMessage(0);       Result:= 0;     end   else     Result:= DefWindowProc(Wnd, Msg, wParam, lParam);   end; end;
Poruka koja se dobija kada prozor treba da se zatvori je WM_DESTROY i tada nas prozor poziva PostQuitMessage funkciju. Ona oznacave da GetMessage treba da vrati False i time prekine petlju citanja poruka. Vrednost koju dajemo u PostQuitMessage funkciji se pojavljuje kao wParam u WM_QUIT poruci. Kada obradimo poruku rezultat postavljamo na 0 sto znaci da smo obradili poruku.
Pravilo je da se sve poruke koje ne obradimo proslede funkciji DefWindowProc koja ih obradjuje kako je to u windows-u po default-u definisano.

Iiiii... to je to... ovako se kreira prozor u cistom Win32 API Smile

Kreiranje prozora radimo ovako jer ce nam izvrsni fajl biti manji, a takodje i brzi sto je, uglavnom, bitno za aplikacije koje koriste DirectX (to su... igre Smile ).

[url=http://www.mycity.rs/must-login.png (Delphi)[/url] | [url=http://www.mycity.rs/must-login.png (Lazarus)[/url] | [url=http://www.mycity.rs/must-login.png



Registruj se da bi učestvovao u diskusiji. Registrovanim korisnicima se NE prikazuju reklame unutar poruka.
offline
  • Passwd 
  • Novi MyCity građanin
  • Pridružio: 15 Jan 2006
  • Poruke: 1

Hehe, odlican tutorial..bas mi se svidio! (cak sam se registrirao rad njega)
Dal se moze ocekivat nastavak tutoriala kako dodat objekte (button,edit...) na takav prozor i kako im napravit evente itd..

-sam prozor u delphiu (VCL) iznosi oko 400kb
-ovako napravljen prozor-15kb
c00l Wink

Samo tako, p0z Smile



offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2478
  • Gde živiš: Ljubljana

offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2478
  • Gde živiš: Ljubljana

offline
  • Pridružio: 10 Nov 2004
  • Poruke: 966
  • Gde živiš: Novi Sad

Evo ti jedna veeeelika pohvala od mene!!!
Stvarno si se potrudio!

POZDRAV!!!

offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2478
  • Gde živiš: Ljubljana

offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2478
  • Gde živiš: Ljubljana

offline
  • Pridružio: 15 Feb 2006
  • Poruke: 17
  • Gde živiš: 1:442:5

Srki tebi treba podici spomenik odma posle Nikole Tesle, puno hvala :bow:

offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2478
  • Gde živiš: Ljubljana

offline
  • Pridružio: 11 Apr 2005
  • Poruke: 22

I ako mi nikada verovatno nece trebati nista od ovoga, ja stvarno moram da ti odam priznje za ulozeni trud.SVAKA TI CAST!

Ko je trenutno na forumu
 

Ukupno su 768 korisnika na forumu :: 70 registrovanih, 10 sakrivenih i 688 gosta   ::   [ Administrator ] [ Supermoderator ] [ Moderator ] :: Detaljnije

Najviše korisnika na forumu ikad bilo je 1567 - dana 15 Jul 2016 19:18

Korisnici koji su trenutno na forumu:
Korisnici trenutno na forumu: aBobban, Aleksandar Tomić, aleksmajstor, aljosa7, aposoulyptic, Arhiv, axa, baki60, bbrasnjo, Bloody, Boris902, CheefCoach, cika_cajko, coa93, darkangel, Davor Kondic, Dimitrise93, djboj, dskrlec33, Dzoni Stek, dzoni25, FOX, Fric Rebernik, Gama, Georgius2, goxin, GrobarRomanticar, Gvozdena reč, igorovic, Irbis, ivlo, krstovic2, KUZMAR, ladro, Lulubi, MB120mm, mikrimaus, Milenko Vujinovic, Mixelotti, nebkv, Niko Bitan, nindza52, NiZdr, pavle_pzs, pein, pevtschik, proka89, RADOVAN.S, radoznao2, raketaš, renoje2, samsung, Skywhaler, SlobaBgd, srbi, Srky Boy, StefanNBG90, stringer bell, T-72, t84dar, teodorica, trajkoni018, VaRvArI 85, vasa.93, vathra, VJ, Vlad000, WS2, zola92, zukara