How to render to bitmap - Part 3

Hi

I received the sample you sent me, but it doesn't help me at all. Let me refine the subject... I have a 3D View with 3D objects inside it. I can watch this 3D View in a window. In order to do that, I must attach a window to the view, so everything is rendered to this window. But I want to render to a MEMORY bitmap, that is a portion of memory that represents what I see in the view. I don't want to import, or export the view in a .bmp file. I know that OpenGL supports rendering to a MEMORY bitmap, via the flag PFD_DRAW_TO_BITMAP in the PIXELFORMATDESCRIPTOR structure. Is there any way to do the same with OpenCascade?????

Regards: Vladimir

Andreas Hussong's picture

Hi,

I have the same problem as mentioned by Vladimir. I need to render the information of the 3dView to a memory Bitmap (espacially in DIB-Format) to work with this data. Unfortunately there aren't any replies to Vladimirs message and I can't reach him by eMail because his domain doesn't seem to work.

I would be pleased if somebody has some information about that topic or if you Vladimir found a solution in the meantime...

Regards,

Andreas

n-southall's picture

Hi All,

I found this thread in the forum whilst looking for help on creating a bitmap of an OpenCascade view so that I could send it to the Windows clipboard. I contacted Andreas directly to see if he had come up with a solution since posting his query. He very kindly sent a solution to me which worked perfectly and he also suggested that we post a solution to the forum for future reference.

Here is the solution by Andreas for rendering to a bitmap (with thanks to Zafir Anjum for the conversion to DIB from "Converting DDB to DIB" at http://www.codeguru.com/bitmap/ddb_to_dib.shtml)

Many thanks to Andreas for coming up with this solution.

Best regards,

Neil

How to render to a bitmap:

//get HWND of the View-Window
Handle(Aspect_Window) anAspectWindow = myView->Window();
Handle(WNT_Window) aWNTWindow = Handle(WNT_Window)::DownCast(anAspectWindow);
HWND hWindow = (HWND)aWNTWindow->HWindow();

//get size of client area
RECT WindowClientRect;
::GetClientRect(hWindow,&WindowClientRect);
int BitmapWidth=WindowClientRect.right;
int BitmapHeight=WindowClientRect.bottom;

//get or create DeviceContexts
HDC hDCWindow=::GetDC(hWindow);
HDC hDCMem=CreateCompatibleDC(hDCWindow); //MemoryDC

//create MemoryBitmap for MemoryDC
HBITMAP hMemBmp=CreateCompatibleBitmap(hDCWindow,BitmapWidth,BitmapHeight);

SelectObject(hDCMem,hMemBmp);

SelectObject(hDCWindow,(HBITMAP)aWNTWindow->HPixmap());

//copy Bits from HPixmap() to hMemBmp
BitBlt(hDCMem,0,0,BitmapWidth,BitmapHeight,hDCWindow,0,0,SRCCOPY);

//from now on converting to DIB !!!

//create logical palette if neccesary
CPalette Palette;
if (GetDeviceCaps(hDCWindow,RASTERCAPS) & RC_PALETTE)
{
UINT nSize=sizeof(LOGPALETTE)+(sizeof(PALETTEENTRY)*256);
LOGPALETTE *pLP=(LOGPALETTE*)new BYTE[nSize];
pLP->palVersion=0x300;

pLP->palNumEntries=GetSystemPaletteEntries(hDCWindow,0,255,pLP->palPalEntry);

//create palette
Palette.CreatePalette(pLP);

delete[]pLP;
}

//otherwise use DEFAULT_PALETTE
HPALETTE hPalette;
CPalette* pPalette=&Palette;
hPalette=(HPALETTE)pPalette->GetSafeHandle();
if (hPalette==NULL)
hPalette=(HPALETTE)GetStockObject(DEFAULT_PALETTE);

BITMAP Bmp;
BITMAPINFOHEADER BmInfoHeader;
LPBITMAPINFOHEADER lpBmInfoHeader;
DWORD dwLen;
HANDLE hDIB; // Handle the new DIB
HANDLE handle;
HDC hDC;

//make from HBITMAP hMemBmp a BITMAP Bmp
GetObject(hMemBmp,sizeof(Bmp),(LPSTR)&Bmp);

//define Bitmapinfoheader
BmInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
BmInfoHeader.biWidth = Bmp.bmWidth;
BmInfoHeader.biHeight = Bmp.bmHeight;
BmInfoHeader.biPlanes = 1;
BmInfoHeader.biBitCount = Bmp.bmPlanes* Bmp.bmBitsPixel;
BmInfoHeader.biCompression = BI_RGB;
BmInfoHeader.biSizeImage = Bmp.bmHeight*((Bmp.bmWidth+3) & ~3); //0;
BmInfoHeader.biXPelsPerMeter= 0;
BmInfoHeader.biYPelsPerMeter= 0;
BmInfoHeader.biClrUsed = 0;
BmInfoHeader.biClrImportant = 0;

//calculate size of Infoheader and Colortable
int nColors = (1 << BmInfoHeader.biBitCount);
if(nColors>256)
nColors=0;
dwLen=BmInfoHeader.biSize+nColors*sizeof(RGBQUAD);

hDC =::GetDC(NULL);
hPalette=SelectPalette(hDC,hPalette,FALSE);
RealizePalette(hDC);

//allocate memory for BitmapinfoHeader and Colortable
hDIB=GlobalAlloc(GMEM_FIXED,dwLen);

lpBmInfoHeader=(LPBITMAPINFOHEADER)hDIB;

*lpBmInfoHeader=BmInfoHeader;

//Getting size of biSizeImage
GetDIBits(hDC,hMemBmp,0L,(DWORD)BmInfoHeader.biHeight,(LPBYTE)NULL,(LPBITMAPINFO)lpBmInfoHeader,(DWORD)DIB_RGB_COLORS);

BmInfoHeader=*lpBmInfoHeader;

if(BmInfoHeader.biSizeImage==0){
BmInfoHeader.biSizeImage=((((BmInfoHeader.biWidth*BmInfoHeader.biBitCount)+31)&~31)/8)*BmInfoHeader.biHeight;
}

//enlarge buffer
dwLen += BmInfoHeader.biSizeImage;
if(handle=GlobalReAlloc(hDIB,dwLen,GMEM_MOVEABLE))
hDIB=handle;
else{
GlobalFree(hDIB);

SelectPalette(hDC,hPalette,FALSE);
::ReleaseDC(NULL,hDC);
}

lpBmInfoHeader=(LPBITMAPINFOHEADER)hDIB;

//CREATION of the DIB
GetDIBits(hDC,hMemBmp,0L,(DWORD)BmInfoHeader.biHeight,(LPBYTE)lpBmInfoHeader+(BmInfoHeader.biSize+nColors
*sizeof(RGBQUAD)),(LPBITMAPINFO)lpBmInfoHeader,(DWORD)DIB_RGB_COLORS);

SelectPalette(hDC,hPalette,FALSE);
::ReleaseDC(NULL,hDC);

BITMAPINFOHEADER* dib;
dib=(BITMAPINFOHEADER*)hDIB;

Having rendered to a DIB it is very easy to send this to the clipboards with:

// Send the DIB to the clipboard
if (OpenClipboard())
{
BeginWaitCursor();
EmptyClipboard();
SetClipboardData (CF_DIB, hDIB );
CloseClipboard();
EndWaitCursor();
}

Pavele's picture

Nice. But it has a nasty "feature". Try to capture the view in the way shown there when having a window that overlaps the view (e.g. Task manager window). Ha! Surprise !!! :)

The original question was how to render directly to a bitmap, not to capture what's rendered. Capturing the alredy rendered scene can be dificult and have driver-dependant "features". This is true especially when having ovelaping windows in the screen. In full screen mode usually is ok though.

The solution for the original problem is as folows:
- create a memory DC
- create a bitmap (32bp)
- select the bitmap in the DC
- set the pixel format (32 bpp)
- create a OpenGL context based on the memory DC
- render
- do with the bitmap whatever you want
- (do not forget to clean-up objects in the proper order)
- enjoy

this approach WORKS as I have used it many times
Regards,
Pavele

Philippe CARRET's picture

Pavele,

Could you give us that piece of code ?

Philippe