OpenGL在MFC中的配置与前面文章所述基本一样,不再赘述。本篇主要记录如何用OpenGL在MFC的Picture Control控件中绘图。假定已经配置好了环境,而且已经在MFC中创建了ID为“IDC_STATIC_SHOW”的Picture Control控件。
需要做的不是很多,就下面几步:
- 设定像素格式,为OpenGL与HDC连接做准备
- 创建OpenGL渲染上下文,使得OpenGL可在上面绘制
- 在OnTimer(UINT_PTR nIDEvent)函数中调用绘图函数进行绘制
具体的,在MFC的类头文件中添加函数和相关变量:
BOOL SetWindowPixelFormat(HDC hDC);//设定像素格式,为OpenGL与HDC连接做准备
BOOL CreateViewGLContext(HDC hDC);//创建OpenGL渲染上下文,使得OpenGL可在上面绘制
void RenderScene();//绘制场景
void Reshape(int width, int height);//改变窗口大小时对视窗进行的操作
HDC hrenderDC;//设备上下文
HGLRC hrenderRC;//OpenGL渲染上下文
int PixelFormat;//像素格式
Mat imgbgr;
Mat imgbgra;
具体函数定义:
BOOL xxx::SetWindowPixelFormat(HDC hDC)//设置像素格式
{
PIXELFORMATDESCRIPTOR pixelDesc;
pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pixelDesc.nVersion = 1;
pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER |
PFD_TYPE_RGBA;
pixelDesc.iPixelType = PFD_TYPE_RGBA;
pixelDesc.cColorBits = 32;
pixelDesc.cRedBits = 0;
pixelDesc.cRedShift = 0;
pixelDesc.cGreenBits = 0;
pixelDesc.cGreenShift = 0;
pixelDesc.cBlueBits = 0;
pixelDesc.cBlueShift = 0;
pixelDesc.cAlphaBits = 0;
pixelDesc.cAlphaShift = 0;
pixelDesc.cAccumBits = 0;
pixelDesc.cAccumRedBits = 0;
pixelDesc.cAccumGreenBits = 0;
pixelDesc.cAccumBlueBits = 0;
pixelDesc.cAccumAlphaBits = 0;
pixelDesc.cDepthBits = 0;
pixelDesc.cStencilBits = 1;
pixelDesc.cAuxBuffers = 0;
pixelDesc.iLayerType = PFD_MAIN_PLANE;
pixelDesc.bReserved = 0;
pixelDesc.dwLayerMask = 0;
pixelDesc.dwVisibleMask = 0;
pixelDesc.dwDamageMask = 0;
PixelFormat = ChoosePixelFormat(hDC, &pixelDesc);
if (PixelFormat == 0) // Choose default
{
PixelFormat = 1;
if (DescribePixelFormat(hDC, PixelFormat,
sizeof(PIXELFORMATDESCRIPTOR), &pixelDesc) == 0)
{
return FALSE;
}
}
if (SetPixelFormat(hDC, PixelFormat, &pixelDesc) == FALSE)
{
return FALSE;
}
return TRUE;
}
BOOL xxx::CreateViewGLContext(HDC hDC)//创建OpenGL渲染描述表,使得OpenGL可在上面绘制
{
hrenderRC = wglCreateContext(hDC);
if (hrenderRC == NULL)
return FALSE;
if (wglMakeCurrent(hDC, hrenderRC) == FALSE)
return FALSE;
return TRUE;
}
void xxx::RenderScene()
{
//将纹理映射到四边形上
glBegin(GL_QUADS);
//纹理的坐标和四边形顶点的对应,可以通过设置四边形的位置调整图像在窗体的位置
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(1.0, 1.0, 0.0);
glEnd();
glFlush();
SwapBuffers(hrenderDC);
}
void xxx::Reshape(int width, int height)//改变窗口大小时对视窗进行的操作
{
glViewport(0, 0, width, height);
}
设置MFC程序响应计时器消息
在初始化函数OnInitDialog()中加入初始化代码:
imgbgr = imread("demo.jpg");
cvtColor(imgbgr, imgbgra, COLOR_BGR2RGBA);
CWnd* wnd = GetDlgItem(IDC_STATIC_SHOW);
hrenderDC = ::GetDC(wnd->m_hWnd);
if (SetWindowPixelFormat(hrenderDC) == FALSE)
return 0;
if (CreateViewGLContext(hrenderDC) == FALSE)
return 0;
//根据图像数据生成一个2D纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imgbgra.cols, imgbgra.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgbgra.data);
//设置纹理参数,放大和缩小采取的插值方式为线性插值
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//启用一个2D纹理
glEnable(GL_TEXTURE_2D);
//定时显示
SetTimer(1, 30, 0);
编译运行就可以了。
如果要调整显示窗口的大小,需要重新调整视窗。代码如下:
CRect rect;
CWnd* wnd = NULL;
wnd = GetDlgItem(IDC_STATIC_SHOW);//下边窗口
rect.left = 0;
rect.right = 800;
rect.bottom = 500;
rect.top = 0;
wnd->MoveWindow(&rect);
Reshape(800,500);
如果要切换显示的图像。代码如下:
glDisable(GL_TEXTURE_2D);
imgbgr = imread("1.bmp");
cvtColor(imgbgr, imgbgra, COLOR_BGR2RGBA);
//根据图像数据生成一个2D纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imgbgra.cols, imgbgra.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgbgra.data);
//设置纹理参数,放大和缩小采取的插值方式为线性插值
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//启用一个2D纹理
glEnable(GL_TEXTURE_2D);
imgbgr.release();
imgbgra.release();
遇到问题:
不知道为什么只能在OnTimer函数中调用OpenGL显示,直接在多线程中调用只能看到一片黑色
参考文章:https://blog.csdn.net/qq_29477855/article/details/52260314