Jump to content
  • Advertisement


This topic is now archived and is closed to further replies.


Can I copy IDirect3DSurface8 surface data to a BMP object?

This topic is 5394 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''ve created my own BMP class which contains an array of BYTEs to represent the bitmap''s RGB data. I know how to get a pointer to surface data on a IDirect3DSurface8 object, but I don''t know how data is stored on it. Can I simply copy data over to the bitmap object? Or is the surface data stored in a different format that I will need to convert? Thanks in advance!

Share this post

Link to post
Share on other sites
You can''t just copy the data because there are a couple of things that you will have to understand about the Surface before you copy.

First of all you will need to know if your surface has LOD attached to it (Mip Maps). If so you will need to locate the correct LOD that you want to copy from (Usually the highest LOD). You can do this by called GetLevelCount on the texture to see how many levels there are.

Next you will have to get the format of the texure at that level. You can do this by the following:

TEXTURE->GetLevelDesc(iLevel, &desc);

Then you will need to lock the surface:

pSurface->LockRect(&rect, NULL, 0);

This will return the Rectangle of you addressable data.

Next you need to figure out what format (Height, Width, Pitch) the surface is in like this:

BYTE* pBits = (BYTE*)rect.pBits;
DWORD dwWidth = desc.Width;
DWORD dwHeight = desc.Height;

switch (desc.Format)

Possible formats are:
D3DFMT_R8G8B8 = 20,
D3DFMT_A8R8G8B8 = 21,
D3DFMT_X8R8G8B8 = 22,
D3DFMT_R5G6B5 = 23,
D3DFMT_X1R5G5B5 = 24,
D3DFMT_A1R5G5B5 = 25,
D3DFMT_A4R4G4B4 = 26,
D3DFMT_R3G3B2 = 27,
D3DFMT_A8 = 28,
D3DFMT_A8R3G3B2 = 29,
D3DFMT_X4R4G4B4 = 30,
D3DFMT_A2B10G10R10 = 31,
D3DFMT_A8B8G8R8 = 32,
D3DFMT_X8B8G8R8 = 33,
D3DFMT_G16R16 = 34,
D3DFMT_A2R10G10B10 = 35,
D3DFMT_A16B16G16R16 = 36,

And then as an example, if the format is D3DFMT_X8R8G8B8, then you can do the following to get the information:

for (UINT y = 0; y < dwHeight; y++)
DWORD *pPixel = (DWORD *) pBits;

for (UINT x = 0; x < dwWidth; x++)

pBits += rect.Pitch;

And then of course you need to unlock the rectangle:

The entire process is a little complicated.

If you want to copy a texture to a saved BMP, then the following is something that I use to take a screen shot:

void Edward::ScreenShot(char* pFilename, D3DXIMAGE_FILEFORMAT imageFormat)
char name[80];
strcpy(name, SCREEN_SHOT_PATH);
strcat(name, pFilename);

if (imageFormat == D3DXIFF_BMP) strcat(name, ".bmp");
else if (imageFormat == D3DXIFF_TGA) strcat(name, ".tga");
else if (imageFormat == D3DXIFF_PNG) strcat(name, ".png");
else if (imageFormat == D3DXIFF_DDS) strcat(name, ".dds");
else if (imageFormat == D3DXIFF_PPM) strcat(name, ".ppm");
else if (imageFormat == D3DXIFF_DIB) strcat(name, ".dib");

// Get a pointer to the front buffer
IDirect3DSurface9* pFrontBuffer;

// NOTE: Surface format of the front buffer is D3DFMT_A8R8G8B8 when it is returned
HRESULT hr = m_lpD3DDevice->CreateOffscreenPlainSurface(1280, 1024, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pFrontBuffer, NULL);

// Now we copy the front buffer into our surface
hr = m_lpD3DDevice->GetFrontBufferData(0, pFrontBuffer);

// Error checking
if (hr != D3D_OK)
SAFE_RELEASE(pFrontBuffer) // Release the surface so there is no memory leak

// Now write our screen shot to the file
// the last 2 params are NULL because we want the entire front buffer and no palette
hr = D3DXSaveSurfaceToFile(name, imageFormat, pFrontBuffer, NULL, NULL);

//release the surface so there is no memory leak

Good luck!

Share this post

Link to post
Share on other sites
Ok, I tried the code above, but I ran into a problem. Here is the code that I used:

int Width;
int Height;

//Get surface description information

if(D3DSurf->GetDesc(&desc) != D3D_OK)
return false;
Width = desc.Width;
Height = desc.Height;

//Lock the entire surface

RetVal = D3DSurf->LockRect(&SurfRect, NULL, D3DLOCK_READONLY);
if(RetVal != D3D_OK)
//Failed to lock the surface

return false;

When I execute the above code, the D3DSurf->LockRect() function always returns D3DERR_INVALIDCALL. I checked to make sure that my surface is valid--it is, because the D3DSurf->GetDesc call works fine and the desc.Width and desc.Height values are correct. Any idea why this may be happening?

Thanks again!

Share this post

Link to post
Share on other sites
I figured out the problem. The surface I was trying to lock is a backbuffer surface, and I had neglected to specify D3DPRESENTFLAG_LOCKABLE_BACKBUFFER in the Flags member of my D3DPRESENT_PARAMETERS when I initialized Direct3D. I put that in, and it worked just fine.


Share this post

Link to post
Share on other sites
Guest Anonymous Poster

D3DXSaveSurfaceToFile Function

does this help???

Share this post

Link to post
Share on other sites
Um... no, AP--I don''t want to save my surface to a file. I want to take a screenshot, save the screenshot in memory (not in a file), then print it to a printer. Thus, the D3DXSaveSurfaceToFile does me no good here. Thanks for trying, though.

Share this post

Link to post
Share on other sites
Guest Anonymous Poster
my apologies. I read BMP as .bmp. So many people don''t read the documentation, I just assumed...

Share this post

Link to post
Share on other sites

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!