Corso di DirectX

Disegno di oggetti in DirectX: il primo triangolo (II)

 

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 quell’array 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. Quest’ultimo è 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 è l’offset, in bytes, del primo byte da lock-are dentro al buffer.

Per noi, l’offset è zero, ovverosia l’inizio 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). L’ultimo 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