Taking screenshots with DirectX 9.0 and C++

by Dimi 29. January 2008 03:16

In this article we will learn how to take screenshots using DirectX 9.0 I adapted this article from my tutorial on www.g-productions.net

It is quite easy to take screenshots from DirectX applications, you don't have to take care of too much things. So let's take a closer look.
What we need is a surface to save the image and we also need a function that saves the surface to file. Thanks to Microsoft the DirectX SDK ships with a function which does all the work for us.
Here are the necessary steps:

  1. Specify a filename to save the screenshot to.
  2. Create a surface which is capable of holding the screen data.
  3. Get the screen data and write it to our surface
  4. Save our surface to a file
1. Specify a filename to save the screenshot

Here we do only the necessary. Check if a filename exists or step over to the next filename. Here is the code:

   1: FILE* f;
   2: for(int i=0;i<999;i++)
   3: {    
   4:     // build the filename    
   5:     sprintf(filename, "screen%.3d.bmp", i);    
   6:     f = fopen(filename, "r");    
   7:     if( f == NULL)        
   8:         break;    
   9:     else        
  10:         fclose( f );
  11: }
Looks easy? It won't get any harder, so let's head over to the next step.
2. Create a surface which is capable of holding the screen data

The only thing we need here is the method CreateOffscreenPlainSurface which awaits the following parameters:

  • the screen size (x, y)
  • the format of the surface to be created
  • the memory in which the surface will be put and finaly
  • the surface interface

The desired format could be something like D3DFMT_A8R8G8B8 and so I suggest you to use this format since it creates a 32 bit surface with an alpha channel and 8 bits per each channel.
We should define D3DPOOL_SCRATCH as the memory class which holds our surface, since our resource won't be bound to any device or format restrictions.
Last we pass our surface of type LPDIRECT3DSURFACE9 in.

The code should look something like this:

   1: g_pd3dDevice->CreateOffscreenPlainSurface(x, y, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &frontbuf, NULL);
3. Get the screen data and write it to our surface

That's kind of easy, simply call GetFrontBufferData and the whole front buffer (your rendered scene with effects...) will be copied to your surface

   1: g_pd3dDevice->GetFrontBufferData(NULL, frontbuf);
4) Save our surface to a file

The last step we have to do is to save the surface to a file. The D3DX library contains the following function which we will use: D3DXSaveSurfaceToFile
The parameters are the following: First pass the filename we created earlier. Second pass the desired file format you want to save your image, in our case we decided to save to bmp so we choose D3DXIFF_BMP. The third parameter is the surface which contains the captured screen. We are finished. Fill the last two parameters with NULL since we don't want to use a palette and we want to save the entire screen to the file not only a part.
Here is the complete code. It's copy/paste ready so you can try it out.
In order to use this code you will need to include the apropriate header file and link to the library, so put the next lines somewhere in your code:

   1: #pragma comment(lib, "d3dx9.lib")
   2: #include <d3dx9.h>

assuming that the variables g_bWindowed is of type boolean and determines whether this is a windowed (true) or fullscreen (false) application and g_hWnd is of type HWND and is a valid window handle to our created window, check out the complete code:

   1: HRESULT blTakeScreenShot()
   2: {    
   3:     HRESULT hr = S_OK;    
   4:     LPDIRECT3DSURFACE9 frontbuf;    
   5:     char filename[64];    
   6:     FILE* f;    
   7:     int x, y;    
   8:     RECT rcWindow;     
   9:     
  10:     // look for the next free file    
  11:     for(int i=0;i<999;i++)    
  12:     {        
  13:         // build the filename        
  14:         sprintf(filename, "screen%.3d.bmp", i);        
  15:         f = fopen(filename, "r");        
  16:         if( f == NULL)            
  17:             break;        
  18:         else            
  19:             fclose( f );    
  20:     }     
  21:     // get the screen resolution. If it's a windowed application get the whole    
  22:     // screen size. If it's a fullscreen application you might have somewhere     
  23:     // your defines as: #define SCREEN_WIDTH 800    
  24:     if( !g_bWindowed )    
  25:     {        
  26:         x = SCREEN_WIDTH;        
  27:         y = SCREEN_HEIGHT;    
  28:     }    
  29:     else    
  30:     {        
  31:         x = GetSystemMetrics( SM_CXSCREEN );        
  32:         y = GetSystemMetrics( SM_CYSCREEN );                
  33:         // to get the window sizes        
  34:         GetWindowRect( g_hWnd, &rcWindow );    
  35:     }     
  36:     // here we create an empty Surface. The parameter D3DFMT_A8R8G8B8 creates an 32 bit image with    
  37:     // an alpha channel and 8 bits per channel.    
  38:     if( FAILED( hr = g_pd3dDevice->CreateOffscreenPlainSurface(x, y, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &frontbuf, NULL)))        
  39:         return hr;     
  40:     // now we copy the entire frontbuffer into our new surface. The first parameter is NULL since    
  41:     // we assume we have only one swap chain    
  42:     if( FAILED( hr = g_pd3dDevice->GetFrontBufferData(NULL, frontbuf)))    
  43:     {        
  44:         // if this fails release our surface so we have no memory leak        
  45:         frontbuf->Release();        
  46:         return hr;    
  47:     }     
  48:     // This is the most important functions. The DirectX-SDK provides this handy little function to    
  49:     // save our surface to a file. The first parameter is our specified filename, the second parameter    
  50:     // tells DirectX what kind of file we want to save (in this example we decide to save to BMP)    
  51:     // Note the difference between a fullscreen screenshot and a windowed one. If we have a windowed application    
  52:     // we only want the specified RECT saved from our screen capture    
  53:     if( !g_bWindowed )        
  54:         D3DXSaveSurfaceToFile(filename, D3DXIFF_BMP, frontbuf, NULL, NULL);    
  55:     else        
  56:         D3DXSaveSurfaceToFile(filename, D3DXIFF_BMP, frontbuf, NULL, &rcWindow);     
  57:     
  58:     frontbuf->Release();     
  59:     return hr;
  60: }

Tags: ,

game development

Comments

2/15/2008 10:41:58 AM #

Malcom

Nice work buddy,
was looking for similar in c# but helped me out with this getfrontbufferdata

Malcom

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.6.0.0
Theme adopted by Dimi with portions of Mads Kristensen and portions of Rtur.net

RecentPosts