Guida alla Programmazione di Giochi con le DirectX di David Joffe
Capitolo 5: Nuovi argomenti vari
non scelti
conv3ds -X: Salva i templates. Niente di cui preoccuparsi, fa parte della natura
dei files .x. Utile, a patto che vediate cosa significano i vari parametri (come
materials).
conv3ds -m: Unisce tutti gli oggetti in un singolo reticolato (mesh). Utile
se non vi servono reticolati separati, e può velocizzare il caricamento.
conv3ds -x: Salva come un file di testo: Certamente non una cattiva idea, specialmente
durante il debugging. Aiuta ad avere un controllo rapido sui files, etc.
conv3ds -T: Crea un frame top-level con tutti gli oggetti come frames discendenti.
Questo è utile poiché pFrame->Load carica solo il primo frame
che trova nel file.
conv3ds -v Bug possibili (possibili non in v5, solo in v3) .. sembra avere bisogno che
XForms venga resettato in 3dstudio oppure accadono cose strane. Forse lo controllerò..
Quando si usa un oggetto pFrame per caricare un reticolato da un file mesh,
e avete bisogno di contenere (ne parlerò di più)
A breve:
Progetto per imparare OpenGL: Confronti etc, per quanto possa fare appello
alla mia imparzialità.
Enumerating device drivers
Callbacks
RM contro IM
Un esempio decente di codice D/L-abile.
Commenti agli esempi MS
Come compilare con NMAKE
faq: main: linker error
Matematica per il 3D
Fog + qualche altra tecnica di ottimizzazione del frame rate
Caricare e mostrare un .bmp (o .png :)
Execute buffers contro DrawPrimitive
5.1 Disegno di un pixel con DirectDraw Microsoft non ha fornito una funzione del tipo "PutPixel"
con DirectDraw per disegnare un pixel su una superficie DirectDraw. Certo, nessun
gioco disegnerebbe la sua grafica ricorrendo ad una routine PutPixel, dato che
sarebbe troppo lento - ma sarebbe stato carino averla come "funzione di
utilità", e sarebbe stata anche comoda in materia di testing. Alcune
applicazioni che non hanno necessariamente bisogno di velocità, potrebbero
trarre vantaggio da una routine come PutPixel. Però, le DirectX non sono
state progettate con la comodità in mente.
Ad ogni modo, esistono parecchi modi per scrivere una routine
PutPixel. Un modo potrebbe essere di usare funzioni GDI sulla superficie, utilizzando
GetDC(). Un altro modo è di usare la funzione IDirectDrawSurface::Blt(),
specificando una gestione di un colore solido con un rettangolo 1x1. Un terzo
modo è di ottenere un puntatore alla memoria che rappresenta la superficie
chiamando IDirectDrawSurface::Lock(), e disegnando il pixel in memoria da soli.
Ognuno di questi metodi mostra tecniche generali la cui utilità supera
una semplice funzione PutPixel.
5.1.1 PutPixel tramite surface locking La base di questa tecnica è di ottenere un puntatore alla
memoria che rappresenta la superficie. Potete quindi calcolare l'offset in questa
memoria per le coordinate del pixel che volete disegnare, e quindi scrivere
i bytes che rappresentano il colore del pixel che volete in quella posizione
della memoria. Non c'è niente di difficile o complesso, è solo
un sacco di sporco lavoro e di salti di buche.
Per default, potreste non avere la possibilità di scrivere
direttamente nella memoria di una superficie. Dovrete prima ottenere l'accesso
esclusivo a questa superficie, effettuandovi un "locking". Questo viene fatto
con una chiamata a Il puntatore alla memoria della superficie è uno dei membri
della struttura DDSURFACEDESC, e viene riempito dalla chiamata a Ora, per disegnare un pixel, avete bisogno di capire come i pixel
sono rappresentati in memoria, cosa che dipenderà dalla profondità
di colore dello schermo in cui si trova la vostra superficie (vedere il Capitolo
2). Ovviamente, se create una routine PutPixel "generica", questa
lavorerà senza badare alla modalità dello schermo, dovrete probabilmente
specificare il colore in un qualche formato leggibile dall'uomo, come un RGB
triplo. La routine PutPixel deve quindi convertirlo, memorizzarlo da qualche
parte, e scaricarlo nella memoria della superficie. Io uso un Qui c'è la routine PutPixel attuale, che prende come input
una superficie DirectDraw, una locazione (x,y) e un RGB triplo con r,g e b nel
raggio di 0 a 255. La funzione restituisce 0 in caso di successo. Notate che
la funzione, come CreateRGB, assume l'esistenza di g_iBpp, che spiegherò
tra un po'.
Esistono alcune cose che vale la pena di menzionare su questa
funzione. Primo, può essere ottimizzata molto, lo so. Ma nella produzione
di un gioco, questa non è la funzione che utilizzerete per tutte le vostre
routines di disegno, in ogni modo (Una delle regole dell'ottimizzazione - mai
ottimizzare quello che non vi serve). Secondo, crea alcune grossolane premesse
sulla vostra architettura - potrebbe non funzionare se il vostro sistema è
big endian. Comunque, l'Intel x86 è little endian, e per quello che ne
so, le DirectX sono disponibili solo per Intel x86. Terzo, funziona solo su
un numero limitato di modalità dello schermo, e un giorno o l'altro,
quando la gente comincerà ad utilizzare modalità video con profondità
bit più elevate (come 48), il codice non funzionerà più
(comunque, per quello che posso dire, le stesse DirectDraw non sono in grado
di utilizzare profondità di colore di 48-bit). Comunque, il punto è
che, per rendere "corretta" la routine PutPixel qui sopra, c'è
bisogno di un po' di lavoro ulteriore.
Il Un'altra cosa che vale la pena menzionare è che, se questa
superficie DirectDraw è la superficie primaria - cioè, rappresenta
l'intero schermo, e siete in modalità windowed e non in modalità
full-screen - allora gli offsets del pixel qui sono relativi alla parte in alto
a sinistra dello schermo, e non alla finestra della vostra applicazione. Lo
troverete da soli disegnando su tutto lo schermo, fino ad utilizzare l'offset
della vostra finestra nei vostri calcoli (es. utilizzando la chiamata Win32
ClientToScreen o qualcos'altro).
5.1.2 PutPixel tramite l'utilizzo di IDirectDrawSurface::Blt Questa routine è provata nell'esempio DDSamp fornito.
Questo metodo utilizza anche la funzione Questo metodo è molto semplice, e probabilmente un po'
più "sicuro" del metodo descritto in 5.1.1.
Quello che ho fatto qui è:
Questo è quanto.
5.2 Alcune parole sul surface locking Prima che corriate a fare il locking di ogni superficie che incontrate,
è bene menzionare alcune limitazioni che esistono nel surface locking
(che cosa vi aspettavate?). Queste vengono riepilogate dai files di help delle
DirectX.
Notate che potete avere rettangoli multipli in contemporanea
su una superficie locked, a condizione che i rettangoli non si sovrappongano
(overlap).
La documentazione DirectX fa anche i seguenti avvertimenti che
non ho ben capito:
Copy aligned to display memory. Windows 95 uses a page fault
handler, Vflatd.386, to implement a virtual flat-frame buffer for display
cards with bank-switched memory. The handler allows these display devices
to present a linear frame buffer to DirectDraw. Copying unaligned to display
memory can cause the system to suspend operations if the copy spans memory
banks.
dj5.html; creato il: 19 Giugno 1998. Aggiornato
il 21 Aprile 1999.
Lock()
.
HRESULT IDirectDrawSurface::Lock( LPRECT
pRect, LPDDSURFACEDESC pDDSD, DWORD dwFlags, HANDLE hEvent );
Lock()
con un puntatore valido. Potete quindi scrivere in questa memoria, e quando
avrete finito, dovrete solo chiamare Unlock
su quella superficie.
unsigned
int
per memorizzare tremporaneamente il valore del pixel. Per convenienza,
ho creato una funzione CreateRGB
che può generare
questo unsigned int
dai valori RGB forniti con estensione
da 0 a 255:
/*--------------------------------------------------------------------------*/
// Create color from RGB triple
unsigned int CreateRGB( int r, int g, int b )
{
unsigned int pixel;
switch (g_iBpp)
{
case 8:
// Here you should do a palette lookup to find the closest match.
// I'm not going to bother with that. Many modern games no
// longer support 256-color modes.
break;
case 16:
// Break down r,g,b into 5-6-5 format.
pixel = ((r/8)<<11) | ((g/4)<<5) | (b/8);
break;
case 24:
case 32:
pixel = (r<<16) | (g<<8) | (b);
break;
default:
pixel =0;
}
return pixel;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
int PutPixel( LPDIRECTDRAWSURFACE pDDS, int x, int y, int r, int g, int b )
{
DDSURFACEDESC ddsd; // Surface description
unsigned int pixel; // Store pixel to be dumped to screen
int offset; // Store offset of destination memory location
unsigned char * szSurface; // Store pointer to surface
HRESULT hr;
int pixelwidth; // The width of a single pixel, in bytes
// Initialize struct information
ddsd.dwSize = sizeof(ddsd);
// Calculate how the pixel is represented in memory
pixel = CreateRGB( r, g, b );
// Lock entire surface, wait if it is busy, return surface memory pointer
hr = pDDS->Lock( NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL );
if (FAILED(hr))
return -1;
// Get surface memory pointer
szSurface = (unsigned char*)ddsd.lpSurface;
// Calculate the width of a pixel in bytes - this is how many bytes
// we must write to the surface
switch (g_iBpp)
{
case 16: pixelwidth = 2; break;
case 24: pixelwidth = 3; break;
case 32: pixelwidth = 4; break;
default: pixelwidth = 1;
}
// Calculate memory offset
// (Notice I use dwPitch instead of dwWidth - see Chapter 2)
offset = (y*ddsd.lPitch + x*pixelwidth);
// Copy pixel onto the surface, need string.h for this
memcpy( szSurface + offset, &pixel, pixelwidth );
// Unlock the surface. The parameter may be NULL if you locked the entire
// surface, otherwise it must be a pointer to the DirectDraw surface memory.
hr = pDDS->Unlock( NULL );
if (FAILED(hr))
return -2;
return 0;
}
/*--------------------------------------------------------------------------*/
g_iBpp
nel codice qui in alto è un integer
che rappresenta i bits per pixel della modalità dello schermo della superficie.
Potete ottenerlo da DDSURFACEDESC.
CreateRGB
descritta in 5.1.1, quindi andatevela a leggere se non lo avete ancora fatto.
/*--------------------------------------------------------------------------*/
// PutPixel routine for a DirectDraw surface
void DDPutPixel( LPDIRECTDRAWSURFACE pDDS, int x, int y, int r, int g, int b )
{
HRESULT hr;
DDBLTFX ddbfx;
RECT rcDest;
POINT p;
// Safety net
if (g_pDDS == NULL)
return;
// Initialize the DDBLTFX structure with the pixel color
ddbfx.dwSize = sizeof( ddbfx );
ddbfx.dwFillColor = (DWORD)CreateRGB( r, g, b );
// Prepare the destination rectangle as a 1x1 (1 pixel) rectangle
p.x = x;
p.y = y;
ClientToScreen( g_hWnd, &p );
OffsetRect( &rcDest, p.x, p.y );
SetRect( &rcDest, p.x, p.y, p.x+1, p.y+1 );
// Blit 1x1 rectangle using solid color op
hr = g_pDDS->Blt( &rcDest, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbfx );
if (FAILED(hr))
OutputDebugString( (LPCTSTR)"Royal fuckup\n" );
}
/*--------------------------------------------------------------------------*/
Blt
sulla superficie, specificando DDBLT_COLORFILL
come operazione blit
IDirectDrawSurface::GetDC
e IDirectDrawSurface::ReleaseDC
implicano anche una chiamata
a Lock e Unlock, quindi utilizzatele con cautela.
Copyright (C) David Joffe 1998,1999.
http://www.geocities.com/SoHo/Lofts/2018/
---
Traduzione: Papero - IPG 1999
Eng?Ita! Team
http://www.ItaProGaming.com