我正在制作一个包含一堆小窗口和控件的应用程序(2D渲染),我想将每个窗口和控件渲染到自己的位图。到目前为止这是:
uses dglOpenGL;
...
var BMP: TBitmap;
DC, RC: HDC;
...
function TMainForm.Init: Boolean;
begin
Result := InitOpenGL;
if Result = True then
begin
BMP := TBitmap.Create;
BMP.PixelFormat := pf24bit;
BMP.Width := 1280;
BMP.Height := 1024;
DC := (BMP.Canvas.Handle);
RC := CreateRenderingContext(DC,
[opGDI, opDoubleBuffered], // tried changing, didn't help
24,
24,
0,
0,
0,
0);
ActivateRenderingContext(DC, RC);
glClearColor(0.27, 0.4, 0.7, 0.0); // light blue
glViewport(0, 0, 1280, 1024);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
glOrtho(0, 1280, 0, 1024, -1, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
end;
end;
渲染程序:
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
// red quad
glColor3f(1, 0, 0);
glBegin(GL_QUADS);
glVertex2f(100, 100);
glVertex2f(1280-100, 100);
glVertex2f(1280-100, 1024-100);
glVertex2f(100, 1024-100);
glend;
// swap
SwapBuffers(DC);
但是没有输出。
如果我使用MainForm.Canvas.Draw(0, 0, BMP);
,则会出现一个白色矩形。
我想在位图上渲染东西,因为我可以使用位图做很多事情(绘制其他图像,绘制文本,模糊),但如果有其他方法可以做屏幕渲染,那么它没关系......
那么如何设置我的应用程序进行屏幕外渲染?
必须创建与目标设备上下文匹配的OpenGL上下文。对于Windows,它们的创建方式与位图不同。请参阅http://msdn.microsoft.com/en-us/library/windows/desktop/dd368826(v=vs.85).aspx,尤其是dwFlags
,其中包括
PFD_DRAW_TO_WINDOW缓冲区可以绘制到窗口或设备表面。
PFD_DRAW_TO_BITMAP缓冲区可以绘制到内存位图。
但是,您不应该抢先为DIB DC创建渲染上下文。为什么?因为它会很慢,因为在DIB部分上的OpenGL渲染上下文将使用仅支持在CPU上运行的OpenGL-1.1的软件光栅化器。
相反,您应该创建一个Framebuffer对象,附加一个颜色渲染缓冲附件,并在完成glReadPixels
后进入您的DIBSection。更容易,更快。
(我不知道为什么StackOverflow没有正确的语法着色,即找出评论的位置和不在哪里)
// flushes the OpenGL error queue and
// counts the total number of errors
int flushGLErrors(void)
{
int i = 0;
while( glGetError() != GL_NO_ERROR ) {
i++;
}
return i;
}
// returns a HBITMAP or NULL.
// The HBITMAP must be freed using DeleteObject
HBITMAP ReadPixelsToHBITMAP(
int x,
int y,
int width,
int height )
{
void *pdata = NULL;
/* Note that this values only makes sense if we know a target
* output size like if we put the image to paper. */
const int physical_resolution = 2835; /* 72 DPI */
BITMAPINFOHEADER bmih = {
/* .biSize = */ sizeof(bmih),
/* .biWidth = */ width,
/* .bi.Height = */ height,
/* .biPlanes = */ 1, /* mandatory */
/* .biBitCount = */ 24, /* 8 bits per pixel */
/* .biCompression = */ BI_RGB, /* uncompressed */
/* .biSizeImage = */ 0, /* implicit */
/* .biXPelsPerMeter = */ physical_resolution, /* ignored */
/* .biYPelsPerMeter = */ physical_resolution, /* ignored */
/* .biClrUsed = */ 0, /* no palette */
/* .biClrImportant = */ 0
};
HBITMAP hbm = CreateDIBSection(
hdc, /* may be different than the DC used for OpenGL */
(PBITMAPINFO)&bmih, /* can do this cast, because no palette is used */
DIB_RGB_COLORS,
&pdata,
NULL,
0
);
if( !hbm ) {
return NULL;
}
flushGLErrors();
glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
glPixelStorei(GL_PACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
if( glGetError() != GL_NO_ERROR ) {
DeleteObject(hbm);
return NULL;
}
glReadPixels(x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, pdata);
if( glGetError() != GL_NO_ERROR ) {
DeleteObject(hbm);
return NULL;
}
return hbm;
}