DirectX coding - TRIANGLE
Evo nas nazad... Nema čekanja, svi koji ste gladni znanja, 'ajmo u red! Danas ćemo prvo imati malo teorije... Već vidim kako ste se svi snuždili. Znam da ste svi željni odmah skočiti na 3D grafiku, no brzo biste se vratili na mjesto gdje se nalazite, zato se fino opustite, nađite Coca-Colu da ostanete budni i to je sve što vam treba zasad.
KOORDINATNI SUSTAVI
Svi smo svjesni da je matematika osnova računala, a tako i 3D grafike i programiranja iste. Kao što sam na početku ove serije istaknuo, nije ništa komplicirano, ako možete koristiti zdravi razum, shvatit ćete ove koncepte. Ono što moramo ponoviti sada su koordinatni sustavi, vjerujem da smo svi upoznati sa Kartezijevim koordinatnim tj. možda bolje rečeno 2D koordinatnim sustavom ( x i y). Njegova upotreba je vrlo jednostavna i služi za lociranje neke točke na velikoj 2D ploči. Dvije dimenzije su godinama vladale gaming industrijom, no danas bez jednog elementa ne možemo zamisliti igranje igara. Vjerojatno pogađate, radi se o osjećaju dubine, prostora ekvivaletnom ovom našem u kojem živimo. Z os, divan nadodatak na 2D koord. sustav koji nam je omogućio da vidimo Larine... erm... oči iz milijun kuteva u 3D svemiru.
S
(Slika sa Wikipedije)
Oke, imamo taj 3D koordinatni sustav ali što s njim? Pa, pogledajmo kako se on koristi u 3D grafici. Ako neka točka(vertex, REMEMBER THIS) na 3D koordinatnom sustavu predstavlja neku poziciju u prostoru, mogla bi se napraviti mreža takvih pozicija koje bi eventualno stvorile 3D model. Da ne spajamo bezveze točke kao u zabavnoj rubrici u nekim novinama, puno efikasniji način je "izumljen"... A korijen uzima u trigonometriji, dakle, koristit ćemo osnovu geometrije za formiranje kompleksnih 3D modela. Radi se o trokutima. I mi ćemo upravo napraviti jedan, u čast matematičkog elementa koji je stvorio modernu gaming industriju =).
Da biste više saznali o 3D modeliranju, što je 3D model... Napisao sam nedavno tekst za Vidipediju. KLIK OVDJE!
TROKUT ( tris, triangle, trougao, kako god želite )
Sada kada smo se upoznali sa osnovom koordinatnih sustava, vrijeme je napokon da se bacimo na posao. Ali... Da, ali... Moramo nešto veoma bitno raspraviti prije toga. Radi se FVFima ili Flexible Vertex Formatima. Kako smo već spominjali točke (vertex jednina, vertices množina) u 3D prostoru obilježavaju se kroz 3 brojčane vrijednosti spremljene u x, y i z. Svojstva samih točaka također se mogu odrediti uz pomoć brojčanih vrijednosti. DirectX (Direct3D točnije) koristi tehnologiju koja se naziva Flexible Vertex Format (FVF) i taj vertex format je zapravo kolekcija podataka koje sadržavaju informacije o lokaciji i svojstvima nekog vertexa (točke). Fleksibilan je jer nije statičan, kakav zaključak hehe... Može se modificirati i prilagoditi vašim potrebama. Valja pojasniti kako ovo funkcionira...
Vertex je napravljen od strukture (struct, C++) koja sadrži podatke potrebne za stvaranje neke 3D slike. Da bi prikazali sliku, moramo kopirati cijelu vojsku podataka u video RAM i narediti Direct3Du da kopira podatke u back buffer. Što bi se dogodilo kada bi nas sustav tjerao da šaljemo sve podatke koji bi mogli biti povezani sa vertex structom? Svi smo upoznati da je računalo, tupo ali moćno oružje te uz malu pomoć ljudskog uma, inženjeri su uspjeli "izolirati" samo one podatke potrebne, a upravo tome služi Flexible Vertex Format!
U Direct3Du, svaki vertex je definiran od već napravljenog vertex formata. Naslov slovi da se radi o fleksibilnom sustavu pa je veoma moguće da mi kao programeri možemo modificirati vertex format da se prilagodi našim potrebama. Uskoro ćemo morati uključiti lokaciju i difuznu boju naših točaka (vertices-a). Taj kôd bi glasio ovako:
Code:
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
S ovim, više nećemo morati stalno pisati FVF kôd svaki put kad nam zatreba u radu sa vertices-ima. Ima mnogo zastavica na koje se FVF može postaviti, a zasad vam baš i nisu potrebne... Oni koji su znatiželjni mogu se konzultirati sa MSDNom.
KREIRANJE VERTICES-a
Došlo je vrijeme da iskoristimo napokon ovaj FVF format te da napravimo par verticesa. Pa napravimo onda CUSTOMVERTEX strukturu.
Code:
struct CUSTOMVERTEX
{
FLOAT x, y, z, rhw; // Sjećate se prvog flaga?
DWORD color; // a drugog?
}
Kao što možete vidjeti ovdje, prve četiri vrijednosti FLOAT (radi preciznosti) reprezentirane su zapravo uz pomoć D3DFVF_XYZRHW zastavice, dok je DWORD reprezentiran koristeći drugu zastavicu (D3DFVF_DIFFUSE). Da malo zagrijemo atmosferu, idemo napraviti vertex koristeći našu malu strukturu koja je ispisana gore.
Code:
CUSTOMVERTEX nVertex = { 320.0f, 50.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255)};
Koristeći novostečeno znanje, napravimo sada mrežu od 3 vertexa koji će formirati naš trokut:
Code:
CUSTOMVERTEX nVertices[]S=
{
{320.0f, 50.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255),},
{520.0f, 400.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0),},
{120.0f, 400.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0),},
};
VERTEX SPREMNIK (Vertex Buffer eng.)
Došli smo do jako bitnog segmenta koji će omogućiti vizualizaciju našega trokuta. Što želim reći jest da ga moramo pripremiti za izlazak pred publiku tj. da ga Direct3D može eventualno prikazati na zaslonu naše kante. Vertex buffer je sučelje koje priprema dio u memoriji da se u njega ubace potrebni podaci o vertices-ima. DirectX arsenal nudi nam veoma jednostavnu funkciju da brzo i efikasno sagradimo naš vertex buffer, CreateVertexBuffer(). Evo prototipa kako ga golog majka MSDN pokazuje:
Code:
HRESULT CreateVertexBuffer(
UINT Length,
DWORD Usage,
DWORD FVF,
D3DPOOL Pool,
LPDIRECT3DVERTEXBUFFER9 ppVertexBuffer,
HANDLE* pSharedHandle);
Kao što nam je to trademark postao, 'ajmo razbiti na manje dijelove.
UINT Length
Ovaj parametar sadržava veličinu buffera (spremnika) kojeg želimo stvoriti. Ovaj broj možemo dobiti množenjem veličine jednog vertexa sa brojem verticesa koji će biti pohranjeni u buffer. Najjednostavnije: 3 * sizeof(CUSTOMVERTEX).
DWORD Usage
Nekad je potrebno koristiti vertices-e na specijalan način pa ovo mijenja način na koji DirectX rukuje s njima. Uglavnom, ovdje ubacite zastavicu koja indicira da se treba specijalno rukovati navedenim. Samo puknite 0 ovdje.
DWORD FVF
Ovdje dolazi FVF kôd kojeg smo definirali par trenutaka prije. pošto smo definirali ga kao CUSTOMFVF, znate što vam je činiti ovdje. Ovo kaže DirectXu u kojem su formatu verticesi koje prima u vertex buffer
D3DPOOL Pool
Ovaj parametar kaže Direct3Du gdje stvoriti vertex buffer i kako. Trenutno, nama najviše odgovara zastavica D3DPOOL_MANAGED. Tako da ju jednostavno umjestite na ovo ljepuškasto parking mjesto. Za više zastavica, MSDN vam stoji na usluzi.
LPDIRECT3DVERTEXBUFFER9 ppVertexBuffer
Je l' tko prebrojao slova na ovom gadu? Doduše, objašnjenje je puno kraće i jednostavnije... Ovo je pokazivač/pointer na vertex buffer sučelje koje sada stvaramo. Samo ćemo ubaciti prazni pokazivač i funkcija će ga popuniti.
HANDLE *pSharedHandle
Ovaj ni meni nije jasan, dokumentacija ga deklarira ovako: "Reserved. Set this parameter to NULL". Ok, DirectX timu, vi ste gazde... Čuli ste što su velike face rekle, tu ide NULL.
Zaslužili smo vidjeti kako izgleda u samom programu kada se pretvori sve ovo trabunjanje u praksu:
Code:
LPDIRECT3DVERTEXBUFFER9 t_buffer;
d3ddev->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
Imamo vertex buffer... Što sad? Trebamo utjerati one podatke iz CUSTOMVERTEX strukture u vertex buffer. Ali vertex buffer ne da unutra lako. Da bi dobili pristup bufferu, moramo ga zaključati. Kinky... Dva su veoma jednostavna razloga zašto je ovo potrebno. Prvi jest da trebamo reći Direct3Du da nam treba potpuna kontrola nad memorijom. Ne želimo da niti jedan drugi aktivni proces prčka po njoj dok se mi bavimo ovim delikatnim stvarima. Još bitnije, moramo reći hardveru da se ne miče naokolo... Metaforički jelte... Želim reći da memorija ne lunja naokolo sa jedne adrese na drugu dok mi pokušavamo ugurati sve ove podatke unutra.
Da bismo zaključali ga, koristimo logično nazvanu funkciju, Lock() koja ima četiri zanimljiva parametra. Pljuc-prototip:
Code:
HRESULT Lock(UINT OffsetToLock,
UINT SizeToLock,
VOID** ppbData,
DWORD Flags);
UINT OffsetToLock, UINT SizeToLock
Kada bismo željeli zaključati samo dio našeg vertex buffera, ovdje bismo to indicirali. Prvi pita koliko duboko u buffer, u bajtovima, zaključavanje treba započeti. Drugi služi tome da se pokaže koliko toga treba biti zaključano, također u bajtovima. Želimo potpuni lockdown, tako da puknete 0.
VOID** ppbData
Evo jedan jako zanimljiv parametar. Ovo što vidite ovdje, void* jest pokazivač koji pokazuje prema "praznini" tj. nedefiniranom tipu podataka. Uzmite primjer double*, ovaj pointer pokazuje prema double data typeu, dok int* pokazuje prema intu. Svaki ima svoj data type, te prijelaz iz jednog u drugog bi uzrokovao gubitak vitalne preciznosti... Zato se koristi pointer prema voidu, jer tu se ništa ne gubi, a lako se prijelazi u int, double, bilo što po tom pitanju. Ovdje trenutno imamo pokazivač prema void*-u. Ovakav se pokazivač popuni sa lokacijom memorije koja će sadržavati naše vertices-e. Sučelje vertex buffera će se pobrinuti za sve sitne detalje, ali mi moramo "ponuditi" pokazivač. Nije strašno, zar ne?
DWORD Flags
Uf, ovo je kompliciranije od prethodnog parametra, a iskreno ni ja ga najbolje ne razumijem. Uglavnom, ovo bi trebalo ponuditi specijalne načine da se manipulira zaključanom memorijom. DirectX dokumentacija možda vam da više informacija. Zasad, samo ubacite ovdje 0.
Evo kako izgleda sve ovo gore u praksi:
Code:
VOID* pVoid; // praznina o kojoj smo pričali =)
t_buffer->Lock(0, 0, (void**)&pVoid, 0); // zaključava t_buffer koji smo maloprije napravili
Sada moramo utjerati sve ove podatke iz structa u taj zaključani vertex buffer. Koristimo jednostavnu funkciju memcpy():
Code:
memcpy(pVoid, nVertices, sizeof(nVertices)); // kopiramo podatke u vertex buffer
Na kraju, kada je sve unutra, otključamo buffer:
Code:
t_buffer->Unlock(); // otključaj =)
Baš je simpatična mala funkcija...
Zbog ogromne količine stvari koje smo upravo napravili, koristeći zdravu programsku logiku, strpajmo ovo u funkciju init_graphics():
Code:
void init_graphics(void)
{
// napravi tri vertexa koji će tvoriti vrhove trokuta
CUSTOMVERTEX nVertices[]S=
{
{ 320.0f, 50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 520.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 120.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
};
// napravi vertex buffer i stavi pokazivač u t_buffer, koji je napravljen na "globalnoj razini"
d3ddev->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
VOID* pVoid; // pokazivač u prazno
t_buffer->Lock(0, 0, (void**)&pVoid, 0); // zaključaj
memcpy(pVoid, nVertices, sizeof(nVertices)); // kopiraj vertices iz strukture CUSTOMVERTEX u vertex buffer
t_buffer->Unlock(); // otključaj
return;
}
ISCRTAVANJE TROKUTA, NAPOKON!
Vjerujem da ste se umorili, ali držite se još malo, idemo napokon to sve istjerati na monitor. Imamo tri jednostavne funkcije koje koristimo za to... Ovo bi trebalo biti brzo gotovo.
SetFVF()
SetFVF() je funkcija koja kaže Direct3Du koji FVF kôd trenutno koristimo. Možemo imati više različitih zastavica aktivnih na različitim segmentima scene. Prije nego li išta iscrtamo, moramo Direct3Du reći što je naš izbor.
Code:
d3ddev->SetFVF(CUSTOMFVF);
SetStreamSource()
Ova funkcija govori Direct3Du koji vertex buffer treba koristiti za iscrtavanje. Ima nekoliko parametara koji su poprillično jednostavni:
Code:
HRESULT SetStreamSource(UINT StreamNumber,
LPDIRECT3DVERTEXBUFFER9 pStreamData,
UINT OffsetInBytes,
UINT Stride);
Prvi parametar je broj izvora. Ako budem nastavio ovu seriju, reći ću više o tome, zasad ostavimo to na 0.
Drugi parametar je pointer prema vertex bufferu kojeg smo napravili nedavno.
Treći parametar je veličina svakog vertexa. Ovo se popuni sa: sizeof(CUSTOMVERTEX).
Sve ovo gore postavimo u praksu:
Code:
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
DrawPrimitive()
Sada kada smo Direct3Du rekli kakve vertices-e koristimo i lokaciju odakle ih treba potegnuti, moramo mu reći da iscrta trokut baziranu na podacima iz vertex buffera. Evo prototipa pa ćemo polako naprijed.
Code:
HRESULT DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,
UINT StartVertex,
UINT PrimitiveCount);
Prvi parametar je način na koji ćemo povezati vertices-e iz vertex buffera... Koristit ćemo TRIANGLELIST kao parametar ovdje, a za ostale konzultirajte se sa DirectX dokumentacijom kao i uvijek.
Drugi parametar je broj prvog vertexa kojeg želimo istjerati na scenu. Mogli bismo početi u sredini vertex buffera, ali želim cijeli buffer iscrtan, dakle? 0... Nula, null...
Zadnji parametar je broj trokuta koje želimo iscrtati. Logično, tu stavljamo 1.
Pogledajmo sada što smo to zapravo napravili od render_frame() funkcije:
Code:
// ovu funkciju koristimo da renderiramo jedan frame
void render_frame(void)
{
// pozadinu oboji u crno.
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene(); // započinje 3D scenu
// kažemo koji vertex format koristimo
d3ddev->SetFVF(CUSTOMFVF);
// koji vertex buffer treba prikazati
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
// kopiramo vertex buffer u back buffer
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->EndScene(); // završava 3D scenu
d3ddev->Present(NULL, NULL, NULL, NULL); // prikazuje renderiranu "scenu"
return;
}
Također je potrebno nakon zatvaranja programa releasati vertex buffer... Što se radi veoma jednostavnom funkcijom... Release():
Code:
t_buffer->Release(); // oslobodi vertex buffer
Dodaje se u cleanD3D() funkciju...
EVO GA CJELOKUPNI KOD SA KOMENTARIMA:
Code:
// osnovni header fileove koji su nam potrebni
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
// MALI BONUS ZA SVE KOJI SE TRUDE =)
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
// uključi Direct3D biblioteku u projekt
#pragma comment (lib, "d3d9.lib")
// globalne deklaracije
LPDIRECT3D9 d3d; // pointer prema našem D3D sučelju
LPDIRECT3DDEVICE9 d3ddev; // pointer prema klasi uređaja
LPDIRECT3DVERTEXBUFFER9 t_buffer = NULL; // pointer prema vertex bufferu
//prototip funkcija vezanih uz Direct3D
void initD3D(HWND hWnd); // sets up and initializes Direct3D
void render_frame(void); //renderira jedan frejm/sliku/render
void cleanD3D(void); // Čisti nered koji smo napravili
void init_graphics(void); // inicijalizacija grafike
//prototip WindowProc funkcije (sjećate se, ona koja rukuje sa porukama)
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
struct CUSTOMVERTEX {FLOAT X, Y, Z, RHW; DWORD COLOR;};
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
// ulazna točka u svaku windows aplikaciju
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// "ručica za prozor", ispuni se funkcijom
HWND hWnd;
// struktura prozora
WNDCLASSEX wc;
// očisti strukturu prozora
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// ajmo popuniti članove ove strukture
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
//wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass1";
// registriraj klasu koristeći informacije date wc-u
RegisterClassEx(&wc);
// napravi prozor i koristi rezultat kao ručicu (hWnd)
hWnd = CreateWindowEx(NULL,
L"WindowClass1", // Ime windows klase
L"PCPlay Ucionica", // Naziv prozora
WS_EX_TOPMOST | WS_POPUP, // elementi za full screen prozor
0, 0, // x i y moraju biti na 0
SCREEN_WIDTH, SCREEN_HEIGHT, // postavi prozor na 1024x768
NULL, // nema roditeljskog prozora
NULL, // ne koristimo izbornik
hInstance, // ručica aplikacije (remember)
NULL); // ne koristi se sa više prozora
// napokon ju prikaži:
ShowWindow(hWnd, nCmdShow);
// inicijalizacija D3Da
initD3D(hWnd);
// ulaz u glavni loop
// ova struktura sadrži predivne poruke koje nam Windows šalje
MSG msg;
// primijetite kako ovo zapravo stvara infinite loop
while(TRUE)
{
// Provjeri za porukice u event queueu... Kako glupa riječ ^^
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Ako je poruka jednaka WM_QUIT, break out!
if (msg.message == WM_QUIT)
break;
// Standarno procesiranje kroz WindowProc funkciju
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//pozivamo funkciju da renderira unutar loopa
render_frame();
}
//kada izađe iz loopa, zatvori Direct3D uređaj i direct3D
cleanD3D();
// vrati ovaj dio WM_QUITa Windowsu
return msg.wParam;
}
// ova funkcija rukuje sa svim porukama koje naša aplikacija prima
// dakle, poštar :)
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// traži određenu akciju koja treba biti provedena pri dobivanju poruke
switch(message)
{
// ovo se pročita kada korisnik pritisne crveni X
case WM_DESTROY:
{
// zatvori aplikaciju
PostQuitMessage(0);
return 0;
} break;
}
// rukuj sa svakom porukom koju WindowProc nije procesirao osobno
return DefWindowProc (hWnd, message, wParam, lParam);
}
// ova funkcija priprema Direct3D za korištenje
void initD3D(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION); // create the Direct3D interface
D3DPRESENT_PARAMETERS d3dpp; // stvaramo strukturu koja će sadržavate neke parametre, kul, zar ne?
ZeroMemory(&d3dpp, sizeof(d3dpp)); // počisti istu za korištenje
d3dpp.Windowed = TRUE; // program je zasad prozor
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // odbaci stare slike
d3dpp.hDeviceWindow = hWnd; // odredi koji će prozor D3D koristiti
// sada stvori uređaj na bazi svih podataka gore.
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
init_graphics(); // inicijalizacija trokuta
return;
}
// ovu funkciju koristimo da renderiramo jedan frame
void render_frame(void)
{
// pozadinu oboji u crno.
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene(); // započinje 3D scenu
// kažemo koji vertex format koristimo
d3ddev->SetFVF(CUSTOMFVF);
// koji vertex buffer treba prikazati
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
// kopiramo vertex buffer u back buffer
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->EndScene(); // završava 3D scenu
d3ddev->Present(NULL, NULL, NULL, NULL); // prikazuje renderiranu "scenu"
return;
}
void init_graphics(void)
{
// napravi tri vertexa koji će tvoriti vrhove trokuta
CUSTOMVERTEX nVertices[]S=
{
{ 320.0f, 50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 520.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 120.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
};
// napravi vertex buffer i stavi pokazivač u t_buffer, koji je napravljen na "globalnoj razini"
d3ddev->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
VOID* pVoid; // pokazivač u prazno
t_buffer->Lock(0, 0, (void**)&pVoid, 0); // zaključaj
memcpy(pVoid, nVertices, sizeof(nVertices)); // kopiraj vertices iz strukture CUSTOMVERTEX u vertex buffer
t_buffer->Unlock(); // otključaj
return;
}
// ova funkcija čisti nered za nama
void cleanD3D(void)
{
t_buffer->Release(); // oslobodi vertex buffer
d3ddev->Release(); // oslobodi D3D grafički uređaj
d3d->Release(); // oslobodi Direct3D
return;
}
Rezultat uočite sami
ŽIVJELI VI MENI