正文

OpenGL与Memory DC2009-01-13 16:15:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/yuqiexing/40490.html

分享到:

   用GDI绘图时,双缓冲是经常采用的技术。其中关键的一步,就是要先把图形绘制到内存设备环境中,然后拷贝到屏幕上。        OpenGL本身已经有双缓冲的功能了。但是因为开发需要,在采用OpenGL的绘图程序中,我还是需要首先在内存设备环境上绘制一个物体,然后保存为bmp图像。但是采用类似于GDI相似的方法,却发现图像是一片空白。     代码如下:   HBITMAP  GetObjBitmap(LPRECT lpRect, BOOL bSave, CString filename)     { // 屏幕和内存设备描述表     HDC  hScrDC, hMemDC;          // 为屏幕创建设备描述表     hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);         // 为屏幕设备描述表创建兼容的内存设备描述表     hMemDC = CreateCompatibleDC(hScrDC);   // 图像宽度和高度     int nBMPWidth,nBMPHeight;     nBMPWidth = nBMPHeight = 128;       // 图像格式参数 int iPixel = 32;     LPBITMAPINFO lpbmih = new BITMAPINFO;     lpbmih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);     lpbmih->bmiHeader.biWidth = nBMPWidth;     lpbmih->bmiHeader.biHeight = nBMPHeight;     lpbmih->bmiHeader.biPlanes = 1;     lpbmih->bmiHeader.biBitCount = iPixel;     lpbmih->bmiHeader.biCompression = BI_RGB;     lpbmih->bmiHeader.biSizeImage = 0;     lpbmih->bmiHeader.biXPelsPerMeter = 0;     lpbmih->bmiHeader.biYPelsPerMeter = 0;     lpbmih->bmiHeader.biClrUsed = 0;     lpbmih->bmiHeader.biClrImportant = 0;       BYTE *pBits;     // 创建一个与屏幕设备描述表兼容的位图     hBitmap = CreateDIBSection(hMemDC,lpbmih,DIB_PAL_COLORS,(void **)&pBits,NULL,0);       // 把新位图选到内存设备描述表中     hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);       CRect rc(0,0,nBMPWidth,nBMPHeight);        // 利用OpenGL在内存dc绘制图形     Display(hMemDC,rc,3);          hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);         //清除     DeleteDC(hScrDC);     DeleteDC(hMemDC); }      检查了好多遍,都没有发现问题,但生成的图像就是一片空白。        Google了一下,有人跟我遇到一模一样的问题,也在论坛上提问。一开始越看越开心,也越激动,到后来越来越郁闷了,因为没有给出解决方案,不过还是给了一些线索的。我也发现了一些问题,顺藤摸瓜,顺利解决了。   (1)第一个问题就是Display函数。以前的OpenGL程序都是直接绘制到屏幕的dc,因此从程序启动开始我都是只设置了一次OpenGL环境。设置OpenGL环境的代码如下: void CModel3Ds::InitOpenGL(CDC *pDC) {     PIXELFORMATDESCRIPTOR pfd=     {       sizeof(PIXELFORMATDESCRIPTOR),       1,       PFD_DRAW_TO_WINDOW |       PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER       PFD_TYPE_RGBA,       24,       0,0,0,0,0,0,       0,0,0,0,0,0,0,       32,       0,0,       PFD_MAIN_PLANE,       0,       0,0,0     };       int pixelFormat=ChoosePixelFormat(pDC->m_hDC,&pfd);     SetPixelFormat(pDC->m_hDC,pixelFormat,&pfd);     m_hRC=wglCreateContext(pDC->m_hDC);    }      既然现在要绘制到新的内存dc,因此要重新设置一次,代码修改如下:                 //利用OpenGL绘制图形        InitOpenGL(CDC::FromHandle(hMemDC));        Display(hMemDC,rc,3);           我想这次应该搞定了,但图像还是一片空白。   (2) 第二个问题在于InitOpenGL函数。以前对PIXELFORMATDESCRIPTOR这个结构了解不多,打开MSDN查阅了就发现有点猫腻在里面。       这个结构体的第三个成员是标志位,有一个PFD_DRAW_TO_WINDOW支持绘图到窗口 ,原来还有一个PFD_DRAW_TO_BITMAP支持绘图到内存环境,PFD_SUPPORT_GDI支持GDI绘制。MSDN解释如下:   PFD_DRAW_TO_WINDOW The buffer can draw to a window or device surface. PFD_DRAW_TO_BITMAP The buffer can draw to a memory bitmap. PFD_SUPPORT_GDI The buffer supports GDI drawing. This flag and PFD_DOUBLEBUFFER are mutually exclusive in the current generic implementation.     于是修改代码如下,成功解决问题。   void CModel3Ds::InitOpenGL(CDC *pDC) {     PIXELFORMATDESCRIPTOR pfd=     {       sizeof(PIXELFORMATDESCRIPTOR),       1,       PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP       PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER| PFD_SUPPORT_GDI       PFD_TYPE_RGBA,       24,       0,0,0,0,0,0,       0,0,0,0,0,0,0,       32,       0,0,       PFD_MAIN_PLANE,       0,       0,0,0     };       int pixelFormat=ChoosePixelFormat(pDC->m_hDC,&pfd);     SetPixelFormat(pDC->m_hDC,pixelFormat,&pfd);     m_hRC=wglCreateContext(pDC->m_hDC);    }   (3)但是还有一个问题。PFD_SUPPORT_GDI和PFD_DOUBLEBUFFER是不能共存的,后者是双缓冲的重要标志。因此最好的解决方案就是2套初始化方案,如下:   // 屏幕dc相关的OpenGL环境设置 void CModel3Ds::InitOpenGLWithScreenDC(CDC *pDC) {     PIXELFORMATDESCRIPTOR pfd=     {       sizeof(PIXELFORMATDESCRIPTOR),       1,       PFD_DRAW_TO_WINDOW |       PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER       PFD_TYPE_RGBA,       24,       0,0,0,0,0,0,       0,0,0,0,0,0,0,       32,       0,0,       PFD_MAIN_PLANE,       0,       0,0,0     };       int pixelFormat=ChoosePixelFormat(pDC->m_hDC,&pfd);     SetPixelFormat(pDC->m_hDC,pixelFormat,&pfd);     m_hRC=wglCreateContext(pDC->m_hDC);    }   // 内存dc相关的OpenGL环境设置 void CModel3Ds::InitOpenGLWithMemoryDC(CDC *pDC) {     PIXELFORMATDESCRIPTOR pfd=     {       sizeof(PIXELFORMATDESCRIPTOR),       1,       PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP       PFD_SUPPORT_OPENGL| PFD_SUPPORT_GDI       PFD_TYPE_RGBA,       24,       0,0,0,0,0,0,       0,0,0,0,0,0,0,       32,       0,0,       PFD_MAIN_PLANE,       0,       0,0,0     };       int pixelFormat=ChoosePixelFormat(pDC->m_hDC,&pfd);     SetPixelFormat(pDC->m_hDC,pixelFormat,&pfd);     m_hRC=wglCreateContext(pDC->m_hDC);    }

阅读(10237) | 评论(5)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册