为此,在我的WM_PAINT处理函数中我有:
hdc = BeginPaint(hWnd, &ps);
displayFunc(hdc);
if (!skipsaveframes) saveframetobmpfile(hWnd, hdc);
EndPaint(hWnd, &ps);
其中函数displayFunc()执行一些基本的OpenGL渲染(实际上是一些GL_LINES,有许多GL_POLYGON,没有纹理,没有着色),函数saveframetobmpfile()将窗口框架保存为磁盘上的.bmp图像文件。现在,在我使用GDI渲染窗口框架的其他应用程序中,这个saveframetobmpfile()函数完美地运行。
但是在这种由OpenGL完成帧渲染的实际情况下,saveframetobmpfile()函数总是将最初渲染的帧保存到磁盘。所以我在磁盘上得到了一系列相同的.bmp图像,所有这些都显示了相同的第一个渲染帧。
我将在这里粘贴这两个函数,必须有一些我不知道的明显的东西。我不是OpenGL的专家,所以这可能就是为什么我要问你们这些专家!
bool currentlysavingframe = false; //2018april05
bool skipsaveframes = true;
string global_outputfoldername = "frames";
int global_frameid = 0;
void saveframetobmpfile(HWND hwnd, HDC hdc)
{
currentlysavingframe = true;
//HDC hdcScreen;
HDC hdcWindow;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
BITMAP bmpScreen;
// Retrieve the handle to a display device context for the client
// area of the window.
//hdcScreen = GetDC(NULL);
hdcWindow = hdc; //hdcWindow = GetDC(g_hWnd);
// Create a compatible DC which is used in a BitBlt from the window DC
hdcMemDC = CreateCompatibleDC(hdcWindow);
if (!hdcMemDC)
{
currentlysavingframe = false;
return;
}
RECT rcClient;
GetClientRect(hwnd, &rcClient); //GetClientRect(g_hWnd, &rcClient);
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left,
rcClient.bottom - rcClient.top);
if (!hbmScreen)
{
DeleteObject(hdcMemDC);
currentlysavingframe = false;
return;
}
HBITMAP oldhbitmap = (HBITMAP)SelectObject(hdcMemDC, hbmScreen);
if (!BitBlt(hdcMemDC,
0, 0,
rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
hdcWindow,
0, 0,
SRCCOPY))
{
SelectObject(hdcMemDC, oldhbitmap);
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
currentlysavingframe = false;
return;
}
GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 *
bmpScreen.bmHeight;
// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
char *lpbitmap = (char *)GlobalLock(hDIB);
// Gets the "bits" from the bitmap and copies them into a buffer
// which is pointed to by lpbitmap.
GetDIBits(hdcWindow, hbmScreen, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO *)&bi, DIB_RGB_COLORS);
// A file is created, this is where we will save the screen capture.
string filename = global_outputfoldername;
filename += "\\frame_";
global_frameid++;
char buf[256];
sprintf(buf, "%06d", global_frameid);
filename += buf;
filename += ".bmp";
HANDLE hFile = CreateFileA(filename.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER)+
sizeof(BITMAPINFOHEADER);
//Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)+
(DWORD)sizeof(BITMAPINFOHEADER);
//Size of the file
bmfHeader.bfSize = dwSizeofDIB;
//bfType must always be BM for Bitmaps
bmfHeader.bfType = 0x4D42; //BM
DWORD dwBytesWritten = 0;
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
//Unlock and Free the DIB from the heap
GlobalUnlock(hDIB);
GlobalFree(hDIB);
//Close the handle for the file that was created
CloseHandle(hFile);
//Clean up
/*
done:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
//ReleaseDC(NULL,hdcScreen);
//ReleaseDC(g_hWnd,hdcWindow);
*/
SelectObject(hdcMemDC, oldhbitmap);
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
currentlysavingframe = false;
return;
}
为简单起见,我不会粘贴我的OpenGL渲染功能,但如果你们问,我很乐意在这里做。