Save scene to a file

Started by
7 comments, last by Evil Steve 14 years, 4 months ago
Hi guys, I'm trying to save my current scene to a file in 24-bit RGB format. This should work in both windowed and fullscreen mode. Therefore, GetFrontBufferData doesn't work, since it gets a screenshot of the whole desktop, and I just want the contents of my app's window. This should be done outside of the render loop if possible (although I think I could set a flag so that it gets saved on the next render cycle). This is what I tried:

BYTE* CDirect3D::GetImageBuffer() const{

	// Lock backbuffer just for reading
	D3DLOCKED_RECT lockRect;
	m_pBackBuffer->LockRect(&lockRect, NULL, D3DLOCK_READONLY );
		BYTE *pBuffer = (BYTE*)lockRect.pBits;
		BYTE *pBufferCopy = new BYTE[600*400*4];	//TODO: Check when this is freed <MEM>
		memcpy(pBufferCopy, pBuffer, 600*400*4);
	m_pBackBuffer->UnlockRect();
	return pBuffer;
}


I use the function above to get the back buffer's bytes and send them to a file. Done this way, I see the same trash if I load the saved image on my app and on ImageJ. I thought the problem was that if I access the back buffer outside the render cycle, it might be not ready for display (that happens only right before the call to Present, I believe). So I tried saving right before Present(), but then I got a black image... and so I got stumped =( PS: I believe the problem is that the back buffer's format is X8R8G8B8 = 32 bits, and I need only 24 bits. Therefore, I need to trim the back buffer's bytes before sending them to the file. I'm gonna try that now. If anyone knows of a D3DX helper function which does this conversion, please tell me =)
Advertisement
1. You can use GetBackBuffer() to get the backbuffer, but the contents are only going to be valid between EndScene() and Present().
2. You can't lock your backbuffer unless you created your device with the D3DCREATE_LOCKABLE_BACKBUFFER (Or whatever the flag is).

Have you tried using GetBackBuffer() and then D3DXSaveSurfaceToFile?
Alright, so I'm gonna try D3DXSaveSurfaceToFile between BeginScene() and EndScene(). If that works, I'll call it from outside using a flag. If I succeed, I'll post the working code snippet.
Thanks!
Quote:Original post by dario_ramos
Alright, so I'm gonna try D3DXSaveSurfaceToFile between BeginScene() and EndScene(). If that works, I'll call it from outside using a flag. If I succeed, I'll post the working code snippet.
Thanks!
You want to do it between EndScene() and Present(), not BeginScene() and EndScene().
Ok, so first I tried this:

if( SUCCEEDED( m_pd3dDevice->BeginScene() ) ) {    //Render stuff    // ...    // Save back buffer    m_pd3dDevice->GetBackBuffer(0,                                0,                                D3DBACKBUFFER_TYPE_MONO,                                &m_pBackBuffer);    D3DXSaveSurfaceToFile( L"C:\\Fralala.bmp", //<IMG>                           D3DXIFF_BMP,                           m_pBackBuffer,                           NULL,                           NULL );


And I saw the same as before. But then I changed "Fralala.bmp" to "Fralala.jpeg" and "D3DXIFF_BMP" to "D3DXIFF_JPG" and it worked.
So my guess is that as JPEG uses 24 bits and the back buffer uses 32, that's why saving to a bmp didn't work.
The problem is that my app can't handle jpg images, only 24-bit RGB. So I'm gonna try to "trim" the back buffer bytes before sending them to a file.
Is there a D3DX way to convert a copy of the back buffer surface from 32 bits to 24 bits? That would be a lifesaver...

Quote:
You want to do it between EndScene() and Present(), not BeginScene() and EndScene().


Woops, missed that. It works now, sorry =).
Thanks a bunch!

Quote:Original post by dario_ramos
Woops, missed that. It works now, sorry =).
Thanks a bunch!
So it works with BMPs as well as JPG? There really shouldn't be a reason for one to work and not another, D3DX can convert between bit depths for you.

It'd definitely be worthwhile enabling the debug runtimes, they'll highlight bugs like accessing the backbuffer at invalid times by trashing the contents (In a recognisable way, green and magenta on alternate frames) after the Present() call.
Yeah, it works alright now. I think the problem was that when I tried to convert to BMP before EndScene(), D3DX could'nt convert the backbuffer 'cos it was still being accessed.
I got the debug runtimes active, but I must have missed a message 'cos D3D's output gets jumbled with Visual Studio's (which shows a lot of dll messages which I want to turn off someday)...
Quote:Original post by dario_ramos
Yeah, it works alright now. I think the problem was that when I tried to convert to BMP before EndScene(), D3DX could'nt convert the backbuffer 'cos it was still being accessed.
I got the debug runtimes active, but I must have missed a message 'cos D3D's output gets jumbled with Visual Studio's (which shows a lot of dll messages which I want to turn off someday)...
Ah cool.

You could always run DebugView, which won't show the DLL load / unload messages, but it's a bit horrible just to read some debug spew [smile]

This topic is closed to new replies.

Advertisement