Con la lezione precedente, abbiamo finito la lista
delle definizioni da aggiungere. Ma dobbiamo ancora modificare molte
delle nostre funzioni prima di vedere qualcosa...
Aggiunte in InitD3D()
La funzione InitD3D è quella dove inizializziamo tutto ciò che riguarda
il Direct3D. E quindi un posto naturale dove creare il nostro
vertex buffer.
...creare? Non lo avevamo già definito, e non avevamo già fatto
addirittura un array di strutture per i vertici?
Sì, ma quellarray NON era il vertex buffer: era solo un array
fatto per la nostra comodità. Il vertex buffer è una cosa interna
alle DirectX, generalmente nascosta ai nostri occhi.
if ( FAILED( g_pd3dDevice->CreateVertexBuffer(
sizeof(MIOVERTICE) *3, 0, D3DFVF_MIOVERTICE, D3DPOOL_DEFAULT, &g_pVB
)))
return E_FAIL;
La funzione CreateVertexBuffer() del d3dDevice prende
numerosi argomenti: la grandezza del buffer (che calcoliamo come
la grandezza di un vertice moltiplicato 3 vertici), una serie di
flag speciali che noi mettiamo a zero, il tipo di vertice utilizzato
(il D3DFVF_MIOVERTICE), la zona di memoria (il pool) dove
mettere il buffer (noi lasciamo decidere alle DirectX), e infine
un puntatore al nostro puntatore vertex buffer. Questultimo
è quello che useremo per riferirci al vertex buffer appena creato.
Inoltre, sempre in InitD3D facciamo un paio di chiamate a SetRenderState(),
per disattivare gli automatismi su poligoni visibili e luci: noi
siamo interessati solo a vedere il poligono, non ad una simulazione
accurata.
g_pd3dDevice->SetRenderState(
D3DRS_CULLMODE, D3DCULL_NONE );
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
Questi automatismi ci saranno utili in seguito, ma per adesso devono
essere disattivati: il nostro programma è troppo primitivo per loro.
Aggiunte in CleanUp()
Una volta creato il vertex buffer, non dobbiamo dimenticarci di
rilasciarlo, come la maggior parte degli oggetti DirectX,
alla fine del programma:
if ( g_pVB != NULL)
g_pVB->Release();
Aggiunte in Render()
Finalmente, passiamo alla cosa interessante: il disegno.
Dopo la funzione BeginScene(), dobbiamo riempire il nostro
vertex buffer
VOID* pVertices;
if( FAILED( g_pVB->Lock( 0, sizeof(Vertices), (BYTE**)&pVertices,
0 )))
return;
memcpy( pVertices, Vertices, sizeof(Vertices) );
g_pVB->Unlock();
La copia vera e propria è un semplice memcpy dal nostro array
di vertici nel vertex buffer. Quello che qui ci interessa è il locking:
prima di poter scrivere dentro un vertex buffer, dobbiamo ottenere
un lock su di esso. Un lock ci assicura che, in quel momento,
solo noi stiamo accedendo al vertex buffer, e nessun altro (Altro,
qui, significa qualche altra routine DirectX o qualche altra sezione
del nostro programma). Senza un lock, si rischia di scrivere sul
vertex buffer mentre questo viene letto da qualche altra parte,
con effetti disastrosi.
Il lock viene ottenuto chiamando la funzione Lock() del vertex buffer
stesso (non è semplicemente un buffer, è una classe, come avete
appena scoperto :-). Gli argomenti di Lock() sono numerosi, perché
è possibile Lock-are anche solo una parte del buffer. Il primo argomento
è loffset, in bytes, del primo byte da lock-are dentro al
buffer.
Per noi, loffset è zero, ovverosia linizio del buffer.
Il secondo argomento è la lunghezza del tratto da lock-are, che
per noi equivale alla lunghezza del buffer. Occorre poi dare un
puntatore, di tipo BYTE**, che punta ad un puntatore che punta al
segmento di buffer disponibile dopo il lock (come vedete, nelle
DirectX ci sono molti doppi puntatori). Lultimo argomento
è una serie di flags che noi mettiamo a zero.
Dopo la copia, chiamiamo la funzione UnLock(), che rilascia il lock
precedentemente ottenuto e rende disponibile il buffer al resto
del mondo.
(segue nella prossima lezione...)
Torna all'indice Generale del corso di Corso di DirectX di Software Planet