在MFC框架中使用OpenGL的简单实例
引言
我们知道,在MFC框架中,用于绘图的接口是GDI。但GDI只能绘制简单的2D图形,要想制作精美的3D图形,一个可行的办法是使用OpenGL或者Direct3D等第三方库。
由于最近在给导师的一个小项目帮忙,而且要求使用OpenGL,所以我特地在网上搜索“如何在MFC框架中使用OpenGL”,看了很多博文,甚至论文(居然还有人把这个写成论文)后,自己又到VS2012上尝试了一番,最终摸索出了最最简单基本的使用方法,故总结在这里。一方面开启自己在博客园的学习和自省之路,另一方面也为需要的朋友提供点小小的帮助。相信这个实例会是最简单最容易理解的。
摘要
GDI绘图使用的是HDC,而OpenGL使用的则是HGLRC。与D2D通过把RenderTarget绑定到HDC以实现和GDI的混用的方法类似,OpenGL要想与HDC混用,或者说兼容HDC吧,需要使用wglCreateContext()函数来通过HDC创建一个HGLRC并把它选为当前所使用的环境。不过在此之前,我们还需要把像素格式设置成支持OpenGL的格式。另外,窗口也必须被改为特定的样式才能被OpenGL使用。做好了这三点,就能在MFC框架中使用OpenGL进行绘制了。
具体实现步骤
1. 封装OpenGL类
首先,基于OOP的思想,我们把跟OpenGL相关的数据与操作封装起来:
#pragma once
class COpenGL
{
private:
HDC hDC; //GDI绘图中使用的的设备环境句柄
HGLRC hRC; //OpenGL渲染时使用的渲染环境句柄 public:
COpenGL(void);
virtual ~COpenGL(void); bool SetupPixelFormat(HDC hdc); //设置像素格式为适合OpenGL的格式
void Init(void); //初始化渲染过程中属性的设置
void Render(void); //绘制代码 void Reshape(int width,int height); //改变窗口大小时对视窗进行的操作
};
#include "stdafx.h"
#include "OpenGL.h" COpenGL::COpenGL(void)
{
} COpenGL::~COpenGL(void)
{
wglMakeCurrent(hDC, NULL);
wglDeleteContext(hRC);
} void COpenGL::Init(void)
{
//可添加例如“开启深度探测”等绘图属性设置代码
} bool COpenGL::SetupPixelFormat(HDC hdc)
{
hDC=hdc; PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // pfd结构的大小
, // 版本号
PFD_DRAW_TO_WINDOW | // 支持在窗口中绘图
PFD_SUPPORT_OPENGL | // 支持OpenGL
PFD_DOUBLEBUFFER, // 双缓存模式
PFD_TYPE_RGBA, // RGBA 颜色模式
, // 24 位颜色深度
, , , , , , // 忽略颜色位
, // 没有非透明度缓存
, // 忽略移位位
, // 无累加缓存
, , , , // 忽略累加位
, // 32 位深度缓存
, // 无模板缓存
, // 无辅助缓存
PFD_MAIN_PLANE, // 主层
, // 保留
, , // 忽略层,可见性和损毁掩模
}; int nPixelFormat; // 像素点格式
if (!(nPixelFormat = ChoosePixelFormat(hDC, &pfd)))
{
MessageBox(NULL,L"can not find proper mode",L"Error",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
} SetPixelFormat(hDC,nPixelFormat,&pfd);
hRC = wglCreateContext(hDC); //利用GDI绘图所使用的HDC创建对应的HGLRC
wglMakeCurrent(hDC, hRC); //使OpenGL绘图所使用的HGLRC为当前绘图工具 return TRUE;
} void COpenGL::Render()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //绘制操作:
glColor3ub(,,);
glBegin(GL_POLYGON);//填充凸多边形
glVertex3f(0.5f,0.5f ,0.0f);
glVertex3f(0.5f,-0.5f, 0.0f);
glVertex3f(-0.5f,-0.5f,0.0f);
glVertex3f(-0.5f,0.5f,0.0f);
glEnd(); glFlush();
SwapBuffers(hDC);
} void COpenGL::Reshape(int width,int height)
{
glViewport(,,width,height);
}
2. 使用OpenGL类
接下来,我们在MFC框架中的CProjNameView类中创建刚刚编写的OpenGL类成员并进行相应的调用和操作来进行绘制:
先在头文件中添加成员变量:
COpenGL opengl;
然后,改写CProjNameView::PreCreateWindow()函数以改变窗口样式来适应OpenGL的要求:
BOOL CProjNameView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
cs.style|=WS_CLIPSIBLINGS|WS_CLIPCHILDREN; return CView::PreCreateWindow(cs);
}
再在CProjNameView::OnInitialUpdate()函数中添加设置像素格式、转换当前绘图所使用的环境和初始化OpenGL绘制属性的操作。(这里我们省去了初始化操作,即省去了OpenGL.cpp中的Init()函数的代码。设置像素格式、转换当前绘图所使用的环境都包含在COpenGL类的成员函数SetupPixelFormat()中)
void CProjNameView::OnInitialUpdate()
{
CView::OnInitialUpdate(); // TODO: 写入最终选择模式代码之后移除此代码
m_pSelection = NULL; // 初始化所选内容
opengl.SetupPixelFormat(::GetDC(GetSafeHwnd()));
opengl.Init();
}
接下来,在CProjNameView::OnDraw()函数中添加绘制操作。
void CProjNameView::OnDraw(CDC* /*pDC*/)
{
CFaceModelingDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return; // TODO: 在此处为本机数据添加绘制代码
opengl.Render();
}
最后,再改写CProjNameView::OnSize()函数,就大功告成了!(当然,这个并不是本例子中必要的,没有这项控制也能成功绘制。)
void CProjNameView::OnSize(UINT nType, int cx, int cy)
{
if(cx==)
{
cx=;
}
opengl.Reshape(cx,cy);
}
效果图如下:

补充
当然,事先需要包含gl.h和glut.h两个头文件,他们一般都在GL文件夹目录下,而且gl.h是自带的,glut.h是需要自己扩展的。另外,还需要把glut.lib添加到工程可见的范围内。方便起见,我在这里提供一下glut的下载链接:glut扩展包
另外,在MFC中使用OpenGL的绘制列表和纹理时要注意,MFC貌似不支持OpenGL的绘制列表,而且MFC似乎要求在每次绘制前都要设置一次纹理。这之中的道理只有深入了解MFC和OpenGL后才能明白了,如果有朋友知道的话,希望能在评论里给一些指导哦~!
如果还有什么问题或是建议的话,希望大家提出来!新人第一次写随笔,还请多多指教~!
在MFC框架中使用OpenGL的简单实例的更多相关文章
- 《MFC dialog中加入OpenGL窗体》
<MFC dialog中加入OpenGL窗体> 最近学习了如何在MFC对话框程序中加入OpenGL窗体的方法,在这里将自己的实现过程归纳一下. 步骤零: 加入PictureControl控 ...
- [转]用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口
原文链接: 1.用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口 2.Windows MFC 两个OpenGL窗口显示与线程RC问题
- 介绍MFC框架中涉及到的设计模式(二)
接着上一篇<介绍MFC框架中涉及到的设计模式(一)>介绍 单例模式(Singleton Pattern) 单例模式是一种经常使用的软件设计模式.在它的核心结构中仅仅包括一个被称为单例类的特 ...
- spark2.4.5计算框架中各模块的常用实例
本项目是使用scala语言给出了spark2.4.5计算框架中各模块的常用实例. 温馨提醒:spark的版本与scala的版本号有严格的对应关系,安装请注意. Spark Core RDD以及Pair ...
- MFC框架中消失的WinMain()
学过一段时间的MFC之后,很多人大概都有一个疑问:在MFC中,WinMain()哪去了?因为任何一个使用过Win32 SDK编程的人都知道,WinMain()函数是Win32程序开始的入口点,可是在M ...
- Java集合框架中List接口的简单使用
Java集合框架可以简单的理解为一种放置对象的容器,和数学中的集合概念类似,Java中的集合可以存放一系列对象的引用,也可以看做是数组的提升,Java集合类是一种工具类,只有相同类型的对象引用才可以放 ...
- 知乎上有一个问题“在mfc框架中,有上面方法能直接将opencv2.0库中的Mat格式图片传递到Picture Control”中显示?
一直以来,我使用的方法都是shiqiyu在opencvchina上面提供的引入directshow,并且采用cvvimage和cameraDs的方法.这个方法虽然在xp/win7/win8下面都能够成 ...
- django框架中form组件的简单使用示例:注册验证
Django中form组件的三大特点: 1. 生成页面可使用的HTML标签 2. 对用户提交的数据进行初步校验 3. 保留上次输入内容 废话不多说,直接进入正题. 这是注册界面截图: 与上一篇a ...
- Python中Scrapy框架元素选择器XPath的简单实例
原文标题:<Python网络爬虫-Scrapy的选择器Xpath> 对原文有所修改和演绎 优势 XPath相较于CSS选择器,可以更方便的选取 没有id class name属性的标签 属 ...
随机推荐
- WDC2106 iOS10新特性及开发者要注意什么
昨晚苹果在旧金山召开了WWDC,看了WWDC2016直播,我们发现变得谨慎而开放的苹果在新一版四大平台系统中展示了很多变化,当然重中之重还是伟大的iOS.通过试用iOS10beta版,除了长大了的更强 ...
- 【链表】BZOJ 2288: 【POJ Challenge】生日礼物
2288: [POJ Challenge]生日礼物 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 382 Solved: 111[Submit][S ...
- 【leetcode】Trapping Rain Water(hard)
Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...
- NPOI.dll学习
NPOI 是 POI 项目的 .NET 版本.POI是一个开源的Java读写Excel.WORD等微软OLE2组件文档的项目. 简介 编辑 使用 NPOI 你就可以在没有安装 Office 或者相应环 ...
- UIcollectionView的使用(首页的搭建1)
今天做一个首页的效果: 首页是用UICollectionView做的.下面我来结合首页的效果介绍一下: 一.创建基类继承自UIViewController 01 创建基类继承自UIViewContr ...
- 核心思想:早胜过一切,张小龙的Foxmail居然可以卖1200万
现在谁都可以做一个类似的软件,但是市场已经成熟了,满大街都是,也就没有人会来收购你的软件了.
- 【今日推荐】10大流行的 Metro UI 风格的 Bootstrap 主题和模板
1. BootMetro 基于 Twitter Bootstrap 的简单灵活的 HTML.CSS 和 Javascript 框架,Win8 风格,大爱啊! 立即下载 效果演示 2. Boot ...
- socket.io 使用
socket.io是一个以实现跨浏览器.跨平台的实时应用为目的的项目.针对不同的浏览器版本或者不同客户端会做自动降级处理,选择合适的实现方式(websocket, long pull..),隐藏实现只 ...
- android系统平台显示驱动开发简要:Samsung LCD接口篇『三』
平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...
- uboot源码整体框架
源码解压以后,我们可以看到以下的文件和文件夹: cpu 与处理器相关的文件.每个子目录中都包括cpu.c和interrupt.c.start.S.u-boot.lds. cpu.c:初始化CPU.设 ...