Jump to content
  • Advertisement
Sign in to follow this  
CHTHONIC

Creating a HBITMAP from a DirectX BackBuffer (One more quick question!)

This topic is 4849 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

Creating a HBITMAP from a LPD3DXBUFFER. First of all is this possible? Below is my current code with the annotated space where this transformation is required. (If this post is in the wrong section please move it, i was not sure where to ask!)
HBITMAP MyClass::ScreenGrab()
{
//RenderTargetSurface.
IDirect3DSurface9* pRenderTargetSurface = NULL;

//DestinationTargetSurface
IDirect3DSurface9* pDestinationTargetSurface = NULL;

//DisplayMode
D3DDISPLAYMODE d3dDipMode;

//HBITMAP that will be the return of the method
HBITMAP hbm;

if (m_pd3dDevice == NULL)
return NULL;

//Get the client rectangle
RECT rc;
GetClientRect(myhWnd, &rc);
ClientToScreen(myhWnd, LPPOINT(&rc.left));
ClientToScreen(myhWnd, LPPOINT(&rc.right));


//GetRenderTargetSurface.
if(FAILED(m_pd3dDevice->GetRenderTarget(0, &pRenderTargetSurface)))
return NULL;

//Display Mode (d3dDipMode)
if(FAILED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3dDipMode)))
return NULL;

//GetDestinationTargetSurface
if(FAILED(m_pd3dDevice->CreateOffscreenPlainSurface((rc.right - rc.left),
(rc.bottom - rc.top),
d3dDipMode.Format,
D3DPOOL_SYSTEMMEM,
&pDestinationTargetSurface,
NULL)))
return NULL;

//copy RenderTargetSurface -> DestTarget
if(FAILED(m_pd3dDevice->GetRenderTargetData(pRenderTargetSurface, pDestinationTargetSurface)))
return NULL;

LPD3DXBUFFER bufferedImage = NULL;

//Save the DestinationTargetSurface into memory (as a bitmap)
if(FAILED(D3DXSaveSurfaceToFileInMemory(&bufferedImage,
D3DXIFF_BMP,
pDestinationTargetSurface,
NULL,
NULL)))
{
return NULL;
}


//TRANSFORMATION REQUIRED HERE!!!!
//I WANT TO TRANSFORM bufferedImage INTO A HBITMAP SO THAT THE METHOD RETURNS
//THAT HBITMAP TO FULFIL MY CONTRACT.


//Release Resources
pRenderTargetSurface->Release();
pDestinationTargetSurface->Release();

//Return HBITMAT
return hbm;
}



Thanks for your help in advance,Alex. [Edited by - CHTHONIC on December 8, 2005 5:07:59 AM]

Share this post


Link to post
Share on other sites
Advertisement
I got a reply on another forum as follows:

"Yes, just use CreateDIBitmap(). You'll need read the Windows Platform SDK documentition on bitmaps to learn how to calculate the various pointer values you need. After you've created the bitmap, you can release the ID3DXBuffer pointer."

Does this sound reasonable? I do not want to put the time and effort in to learn how to do this only to find it is not possible.

Thanks,

Alex.

Share this post


Link to post
Share on other sites
Yes and no.

D3DXSaveSurfaceToFileInMemory creates a .bmp-File in memory in your case. This is not quite the same as the raw bitmap data which you'd need for CreateDIBitmap or CreateDIBSection.

You can however create a raw memory block the size of your texture. Then lock the texture and memcpy the image line per line (Pitch!) to this memory block. Make sure the memory block and the texture pixel data is the same byte format.

After that you can call CreateDIBitmap/CreateDIBSection with the pointer to your memory block.

Share this post


Link to post
Share on other sites
Thanks Endurion.

Why line by line? Would something like the following suffice?
(where rc is the client rectangle)

int windowSize = (rc.bottom - rc.top) * (rc.right - rc.left) * 4;
LPBYTE lpSource = reinterpret_cast<LPBYTE>(lockedRC.pBits);
LPBYTE lpDestination = new BYTE[windowSize];
memcpy(lpDestination, lpSource, windowSize);

Thanks again for your help,

Alex.

Share this post


Link to post
Share on other sites
Ok i attempted to do vaguely what you suggested but i am getting errors on myt memcpy method so obviously i am not doing that correctly. If you could point me in the right direction I would be much obliged. Here is the code as it stands:


HBITMAP MyClass::ScreenGrab()
{
//RenderTargetSurface.
IDirect3DSurface9* pRenderTargetSurface = NULL;

//DestinationTargetSurface
IDirect3DSurface9* pDestinationTargetSurface = NULL;

//DisplayMode
D3DDISPLAYMODE d3dDipMode;

if (m_pd3dDevice == NULL)
return NULL;

RECT rc;
GetClientRect(myhWnd, &rc);
ClientToScreen(myhWnd, LPPOINT(&rc.left));
ClientToScreen(myhWnd, LPPOINT(&rc.right));

//GetRenderTargetSurface.
if(FAILED(m_pd3dDevice->GetRenderTarget(0, &pRenderTargetSurface)))
return NULL;

//Display Mode (d3dDipMode)
if(FAILED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3dDipMode)))
return NULL;

//GetDestinationTargetSurface
if(FAILED(m_pd3dDevice->CreateOffscreenPlainSurface((rc.right - rc.left),
(rc.bottom - rc.top),
d3dDipMode.Format,
D3DPOOL_SYSTEMMEM,
&pDestinationTargetSurface,
NULL)))
return NULL;

//copy RenderTargetSurface -> DestTarget
if(FAILED(m_pd3dDevice->GetRenderTargetData(pRenderTargetSurface, pDestinationTargetSurface)))
return NULL;

//Create a lock on the DestinationTargetSurface
D3DLOCKED_RECT lockedRC;
pDestinationTargetSurface->LockRect(&lockedRC,
&rc,
D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY);


int windowSize = (rc.bottom - rc.top) * (rc.right - rc.left) * 4;
LPBYTE lpSource = reinterpret_cast<LPBYTE>(lockedRC.pBits);
LPBYTE lpDestination = new BYTE[windowSize];
memcpy(lpDestination, lpSource, windowSize);
// ERRORS ON MEMCPY.. NO MEANINGFUL ERROR (then againt his is C++.. oh how
// i HATE C++... bloody job... I'm a C# developer for gods sake!)


//Create a handle to a bitmap (return from CreateDIBitmap())
HBITMAP hbm;

//Create a Device Context (parameter 1 for CreateDIBitmap())
HDC hdcBitmap = NULL;
pDestinationTargetSurface->GetDC(&hdcBitmap);

//Create a BITMAPINFO/BITMAPINFOHEADER structure and fill it(parameter 2 & 5 for CreateDIBitmap())
BITMAPINFO bmpInfo;
ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biBitCount=32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biWidth=GetSystemMetrics(SM_CXSCREEN);
bmpInfo.bmiHeader.biHeight=GetSystemMetrics(SM_CYSCREEN);
bmpInfo.bmiHeader.biSizeImage=abs(bmpInfo.bmiHeader.biHeight)*bmpInfo.bmiHeader.biWidth*bmpInfo.bmiHeader.biBitCount/8;

hbm = CreateDIBitmap(hdcBitmap,
&bmpInfo.bmiHeader,
CBM_INIT,
lpDestination,
&bmpInfo,
DIB_RGB_COLORS);


//Release Resources
pDestinationTargetSurface->ReleaseDC(hdcBitmap);
pRenderTargetSurface->Release();
pDestinationTargetSurface->Release();

return hbm;
}





Thanks again,

Alex

[Edited by - Muhammad Haggag on December 1, 2005 7:44:47 AM]

Share this post


Link to post
Share on other sites
Line by line because the driver might add some data between the lines of your texture data (for performance reason). Never ever assume that the pixel data is in one continious block:


int windowSize = (rc.bottom - rc.top) * (rc.right - rc.left) * 4;
LPBYTE lpSource = reinterpret_cast<LPBYTE>(lockedRC.pBits);
LPBYTE lpDestination = new BYTE[windowSize];

for ( int iY = 0; iY < rc.right - rc.left; ++iY )
{
memcpy( lpDestination, lpSource, 4 * ( rc.bottom - rc.top ) );

lpSource += lockedRC.Pitch;
}


Also, this will only work if you really create a 32 bit DIB, 24 bit will not be enough.

Share this post


Link to post
Share on other sites
Thanks again Endurion,

I tried what you suggested but it is still churning out the same non-descript error on the memcpy (suggesting there is a Null Pointer in the memcpy assembler code).

Alex.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

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

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!