Il modo in cui lo faccio è il seguente.
IDirect3DDevice9 :: GetBackBuffer : ottieni l'accesso a IDirect3DSurface9 che rappresenta il back buffer, lo stesso che hai attualmente. Non dimenticare di rilasciare questa superficie al termine poiché questa chiamata aumenterà il conteggio dei riferimenti!
IDirect3DSurface :: GetDesc : ottieni la descrizione della superficie del buffer posteriore, che ti darà larghezza, altezza e formato.
IDirect3DDevice9 :: CreateOffscreenPlainSurface : crea un nuovo oggetto superficie in D3DPOOL_SCRATCH; di solito vuoi usare la stessa larghezza, altezza e formato (ma in realtà non devi farlo con questo metodo). Ancora una volta, rilascia quando hai finito. Se stai eseguendo questa operazione ogni fotogramma (nel qual caso stai meglio guardando alternative come un approccio basato su shader a ciò che stai cercando di fare) potresti semplicemente creare la superficie normale fuori schermo una volta all'avvio e riutilizzarla invece di crearlo ogni frame.
D3DXLoadSurfaceFromSurface : copia dalla superficie del buffer posteriore alla superficie normale offsceen. Ciò comporterà automaticamente il ridimensionamento e la formattazione della conversione. In alternativa, se non si desidera o non è necessario ridimensionare o modificare il formato, è possibile utilizzare IDirect3DDevice9 :: GetRenderTargetData , ma in tal caso creare invece la superficie normale fuori schermo in D3DPOOL_SYSTEMMEM.
IDirect3DSurface9 :: LockRect : ottieni l'accesso ai dati nella superficie normale dello schermo esterno e segui la tua strada malvagia; UnlockRect al termine.
Sembra molto più codice ma scoprirai che è veloce quanto glReadPixels e può anche essere più veloce se non hai bisogno di fare una conversione del formato (cosa che glReadPixels usando GL_RGB quasi certamente fa).
Modifica per aggiungere: ho anche alcune funzioni di supporto (rought 'n' ready) che possono essere utili per l'utilizzo di questo metodo per gli screenshot:
// assumes pitch is measured in 32-bit texels, not bytes; use locked_rect.Pitch >> 2
void CollapseRowPitch (unsigned *data, int width, int height, int pitch)
{
if (width != pitch)
{
unsigned *out = data;
// as a minor optimization we can skip the first row
// since out and data point to the same this is OK
out += width;
data += pitch;
for (int h = 1; h < height; h++)
{
for (int w = 0; w < width; w++)
out[w] = data[w];
out += width;
data += pitch;
}
}
}
void Compress32To24 (byte *data, int width, int height)
{
byte *out = data;
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++, data += 4, out += 3)
{
out[0] = data[0];
out[1] = data[1];
out[2] = data[2];
}
}
}
// bpp is bits, not bytes
void WriteDataToTGA (char *name, void *data, int width, int height, int bpp)
{
if ((bpp == 24 || bpp == 8) && name && data && width > 0 && height > 0)
{
FILE *f = fopen (name, "wb");
if (f)
{
byte header[18];
memset (header, 0, 18);
header[2] = 2;
header[12] = width & 255;
header[13] = width >> 8;
header[14] = height & 255;
header[15] = height >> 8;
header[16] = bpp;
header[17] = 0x20;
fwrite (header, 18, 1, f);
fwrite (data, (width * height * bpp) >> 3, 1, f);
fclose (f);
}
}
}