Can I copy IDirect3DSurface8 surface data to a BMP object?
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!
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:
D3DSURFACE_DESC desc;
TEXTURE->GetLevelDesc(iLevel, &desc);
Then you will need to lock the surface:
D3DLOCKED_RECT rect;
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++)
{
pPixel++;
}
pBits += rect.Pitch;
}
And then of course you need to unlock the rectangle:
pSurface->UnlockRect();
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
else
{
// 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
SAFE_RELEASE(pFrontBuffer)
}
}
Good luck!
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:
D3DSURFACE_DESC desc;
TEXTURE->GetLevelDesc(iLevel, &desc);
Then you will need to lock the surface:
D3DLOCKED_RECT rect;
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++)
{
pPixel++;
}
pBits += rect.Pitch;
}
And then of course you need to unlock the rectangle:
pSurface->UnlockRect();
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
else
{
// 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
SAFE_RELEASE(pFrontBuffer)
}
}
Good luck!
Ok, I tried the code above, but I ran into a problem. Here is the code that I used:
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!
D3DSURFACE_DESC desc; D3DLOCKED_RECT SurfRect; HRESULT RetVal; 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!
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.
Thanks!
Thanks!
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.
my apologies. I read BMP as .bmp. So many people don''t read the documentation, I just assumed...
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement