1、基于MFC的OpenGL程序

首先,使用的库是GLUT以及GLAUX,先下载两者,添加查找路径以及链接

一、单文本文件  

工程openGLMFC

1、创建单文本文件

2、添加路径、链接

方法如之前篇章所示,

链接库为opengl32.lib ;glu32.lib ;glut32.lib ;glaux.lib

3、头文件

在stdafx.h中加入下列语句:

//openGL 所需要的头文件
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <gl/glaux.h>

4、设置窗口风格

将窗口风格设为WS_CLIPCHILDREN和 WS_CLIPSIBLINGS,从而避免OpenGL绘制到其他窗口中去。这些应该放在PreCreateWindow()中。

BOOL CopenGLMFCView::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs
    cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
    return CView::PreCreateWindow(cs);
}

5、变量、函数声明

初始化GL,考虑到使用设备上下文、绘图上下文,

先在openGLMFCView.h中声明需要的变量以及函数

HGLRC m_hRC;    //RC 绘图上下文
CDC* m_pDC;        //DC 设备上下文
BOOL InitializeOpenGL();    //初始化 OpenGL
BOOL SetupPixelFormat();    //为 DC 建立像素格式

6、创建消息响应函数

初始化需要在WM_CREATE触发

资源释放在WM_DESTROY触发

窗口大小变化时 WM_SIZE触发,需要调整绘图

由于使用opengl绘制背景,故不需要窗口自己在绘制背景了,需要改写 WM_ERASEBACKGROUND消息触发的事件

故,打开classWizard,在openGLMFCView类中添加上面四个消息响应函数

OnCreate   OnDestroy  OnSize  OnEraseBkground

7、初始化

将通过建立像素格式和绘制上下文来初始化OpenGL. 在InitializeOpenGL()中会创建一个设备上下文(DC),为这个DC选择一个像素格式,创建和这个DC相关的绘制上下文(RC),然后选择这个RC.这个函数会调用SetupPixelFormat()来建立像素格式。

int CopenGLMFCView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;

    // TODO:  Add your specialized creation code here
    InitializeOpenGL();
    return 0;
}

BOOL CopenGLMFCView::InitializeOpenGL()
{
    //客户区获得DC
    m_pDC = new CClientDC(this);
    //Failure to Get DC
    if (m_pDC == NULL)
    {
        MessageBox(L"Error Obtaining DC");
        return FALSE;
    }
    //为DC建立像素格式
    if (!SetupPixelFormat())
    {
        return FALSE;
    }
    //创建 RC
    m_hRC = ::wglCreateContext(m_pDC->GetSafeHdc());
    //Failure to Create Rendering Context
    if (m_hRC == 0)
    {
        MessageBox(L"Error Creating RC");
        return FALSE;
    }
    //设定OpenGL当前线程的渲染环境。
    //以后这个线程所有的OpenGL调用都是在这个hdc标识的设备上绘制。
    if (::wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC) == FALSE)
    {
        MessageBox(L"Error making RC Current");
        return FALSE;
    }
    //背景颜色
    ::glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    //深度缓存 1最大,让任何都能显示出来
    ::glClearDepth(1.0f);
    //如果通过比较后深度值发生变化了,会进行更新深度缓冲区的操作
    ::glEnable(GL_DEPTH_TEST);
    return TRUE;
}
//建立像素格式
/////////////////////////////////////////////////////////////////////////////
BOOL CopenGLMFCView::SetupPixelFormat()
{
    static PIXELFORMATDESCRIPTOR pfd =
    {
        sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
        1,                              // version number
        PFD_DRAW_TO_WINDOW |            // support window
        PFD_SUPPORT_OPENGL |            // support OpenGL
        PFD_DOUBLEBUFFER,                // double buffered
        PFD_TYPE_RGBA,                  // RGBA type
        24,                             // 24-bit color depth
        0, 0, 0, 0, 0, 0,               // color bits ignored
        0,                              // no alpha buffer
        0,                              // shift bit ignored
        0,                              // no accumulation buffer
        0, 0, 0, 0,                     // accum bits ignored
        16,                             // 16-bit z-buffer
        0,                              // no stencil buffer
        0,                              // no auxiliary buffer
        PFD_MAIN_PLANE,                 // main layer
        0,                              // reserved
        0, 0, 0                         // layer masks ignored
    };
    int m_nPixelFormat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
    if (m_nPixelFormat == 0)
    {
        return FALSE;
    }
    if (::SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd) == FALSE)
    {
        return FALSE;
    }
    return TRUE;
}

8、绘制场景

在绘制场景时,一般包括如下步骤:1)清空缓存。2)绘制场景。3)Flush掉渲染流水线。4)若设置了双缓冲,则交换前后台缓冲区。

void CopenGLMFCView::OnDraw(CDC* /*pDC*/)
{
    CopenGLMFCDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    // TODO: add draw code for native data here

    // 清除颜色、深度缓存
    ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //可以添加渲染函数

    // Flush掉渲染流水线
    ::glFinish();
    // 交换前后缓存区
    ::SwapBuffers(m_pDC->GetSafeHdc());

}

9、背景绘制修改

试试改变窗口的大小,你会看到很严重的闪烁,并且关闭程序后会报告内存泄露,因此我们这就来解决这两个问题吧。

发生闪烁的原因是Windows先绘制背景,然后再是OpenGL绘制,因为我们已经让OpenGL负责清空背景色,因此我们不需要Windows去清空背景了

BOOL CopenGLMFCView::OnEraseBkgnd(CDC* pDC)
{
    // TODO: Add your message handler code here and/or call default

    return TRUE;//CView::OnEraseBkgnd(pDC);
}

内存泄露的原因是我们在InitializeOpenGL()中使用了new运算符来为CClientDC对象分配内存,因此需要显示delete掉。

void CopenGLMFCView::OnDestroy()
{
    CView::OnDestroy();

    // TODO: Add your message handler code here
    if (::wglMakeCurrent(0, 0) == FALSE)
    {
        MessageBox(L"Could not make RC non-current");
    }

    //Delete the rendering context
    if (::wglDeleteContext(m_hRC) == FALSE)
    {
        MessageBox(L"Could not delete RC");
    }
    //Delete the DC
    if (m_pDC)
    {
        delete m_pDC;
    }
    //Set it to NULL
    m_pDC = NULL;
}

10、大小调整

在OnSize()中一般用来设置视口和视锥,因为这些是和窗口大小相关的。基本操作包括设置视口,选择投影矩阵,设置模型视图矩阵。

void CopenGLMFCView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);

    // TODO: Add your message handler code here
    GLdouble aspect_ratio; // width/height ratio

    if (0 >= cx || 0 >= cy)
    {
        return;
    }
    // select the full client area
    ::glViewport(0, 0, cx, cy);
    // compute the aspect ratio
    // this will keep all dimension scales equal
    aspect_ratio = (GLdouble)cx / (GLdouble)cy;
    // select the projection matrix and clear it
    ::glMatrixMode(GL_PROJECTION);
    ::glLoadIdentity();
    // select the viewing volume
    ::gluPerspective(45.0f, aspect_ratio, .01f, 200.0f);

    // switch back to the modelview matrix and clear it
    ::glMatrixMode(GL_MODELVIEW);
    ::glLoadIdentity();
}

通过上面得到运行结果:

二、基于对话框

工程:openGLMFCDialog

1-3步骤同上

4、变量函数声明

在openGLMFCDialogDlg.h文件中,声明如上。

其余步骤同上,不同点在于,需要将OnDraw里面的写到

OnPaint函数里面,其中IsIconic()是判断是否为最小化,可以放到else里面即可。

得到结果

时间: 2024-10-03 14:00:38

1、基于MFC的OpenGL程序的相关文章

基于MFC的DirectUI程序的消息响应设计

所以消息的获取仍然是来自主窗口,也就是MFC自己的一套消息映射,比如鼠标点击的消息,在主窗口截获,然后通过相关的处理,调用虚子窗口(DirectUI程序中的控件一般不是真正的窗口,没有m_hwnd,暂且称它为虚子窗口吧)的响应函数.所以DirectUI主要的问题是如何将主窗口的消息分派给虚子窗口,要解决这个问题,第一步如何定位虚子窗口. 首先主窗口有很多控件,主窗口有个控件容器,在窗口初始化时加入要显示的控件.加入的控件一般有一些属性,比如控件的大小,相对主窗口的位置,标题等.一般,主窗口有一个

OpenCV:基于MFC的视频播放器和图片读取器

实例工程包下载[OpenCV:基于MFC的视频播放器和图片读取器] 一.实现的功能 1.打开本地视频进行读取.播放.暂停.停止控制 2.图片打开功能分为两种:可使用"打开图片"按钮打开本地图片,或者点击comobox里面设定的图片列表选择并显示图片 二.编译环境 OS:Win8.1 x64 IDE:  Visual Studio 2013 OpenCV: 2.4.8 三.主要思路 1.视频的滑动条控制: ①主窗体的OnHScroll()响应函数负责响应slider滑动条的变化,这样就轻

基于MFC的含四则混合运算的计算器

今天无意间发现win7系统的标准型计算器连最基本的四则混合运算都没做,刚刚好公司给了我一个工作任务,就是用MFC实现一个含四则混合运算的计算器. 我在网上查询资料,发现大部分只是实现了基本的加减乘除运算,而含四则混合运算的也没有能够说得清楚明白.于是我搜索四则混合运算算法,发现要实现四则混合运算,就要用到逆波兰算法,而使用逆波兰算法,就要先把算术式从中缀表达式转换为后缀表达式. 所谓中缀表达式,就是我们平常的算术式,例如:1+2-3*4/5. 而后缀表达式,就是将运算符写在操作数之后,上面算术式

游戏开发视频教程_基于MFC设计的MINI快跑游戏

基于MFC设计的MINI快跑游戏(游戏开发.MFC精讲.线程与进程通信) 课程分类:游戏开发 适合人群:初级 课时数量:36课时 用到技术:MFC涉及项目:MINI快跑游戏 咨询QQ:1840215592 一.模块介绍 1.MFC基础篇:主要讲解c++的一些技术难点以及重点 容器与算法精讲 类与数据抽象精讲 模板与泛型编程精讲 标准IO库知识点深入浅出 2.MFC进阶篇:主要讲解MFC的深入浅出 CObject类详解 消息映射的实现 MFC的DLL精讲 MFC的进程和线程精讲 3.MFC设计篇:

MFC建立应用程序启示录(创世纪新篇)

MFC是vc+的核心部分,需要一定的编程功底. Windows编程基础 编制一个功能强大和易操作的Windows应用程序所需要的代码肯定会比一般的C++程序要多得多,但并不是所有的代码都需要自己从头开始编写,因为Visual C++不仅提供了常用的Windows应用程序的基本框架,而且可以在框架程序中直接调用Win32 API(Application Programming Interface, 应用程序接口)函数.这样,用户仅需要在相应的框架位置中添加自己的代码或修改部分代码就可实现Windo

基于MFC的Media Player播放器的制作(3---功能实现)

|   版权声明:本文为博主原创文章,未经博主允许不得转载. 下面我们试试一下,按下退出Button退出播放器的功能: 首先,我们双击退出Button按钮,就会弹出下图的框: 上面的弄好之后我们就实现退出函数的功能: 这个代码写好之后,我们可以运行一下,在单击退出按钮,可以发现,按下之后我 们的播放器自动退出 下面我们在实现打开文件的功能,这个功能比较复杂,第一步我们首先双击打开文件按钮,在CPandaPlayerDlg.cpp中创建函 数OnOpenfile():创建过程同上. 可以看到函数:

基于MFC的Media Player播放器的制作介绍

|   版权声明:本文为博主原创文章,未经博主允许不得转载. 因为这次多媒体课程设计做一个基于MFC的播放器,因为本人实力太菜,需要播放音乐或视频文件时候,自己写不出解码 函数,所以准备使用第三方多媒体库或是第三方控件辅助播放,找来找去还是觉得用Windows Media Player控件来编写比较 方便,因此这次播放器的制作主要是根据Media Player控件来实现,因为在微软平台已经封装好了一系列的解码方法(如声音解 码和视频解码)和一些常用的操作方法(如声音音量的增加,快进等等),因此使

基于MFC的socket编程(异步非阻塞通信)

对于许多初学者来说,网络通信程序的开发,普遍的一个现象就是觉得难以入手.许多概念,诸如:同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)等,初学者往往迷惑不清,只知其所以而不知起所以然. 异步方式指的是发送方不等接收方响应,便接着发下个数据包的通信方式:而同步指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式. 阻塞套接字是指执行此套接字的网络调用时,直到成功才返回,否则一直阻塞在此网络调用上,比如调用recv()函数读取网络缓冲区中的数据,

基于MFC的网络版连连看系统

系统介绍:基于MFC的网络版连连看系统 集成开发环境:VS2010 开发语言:C++ 上图看程序: 老大自己手写的,好看的界面有木有? 可以联网啊! 实至名归的网络连连看系统! 喜欢的可以hi我哦! 也可以去到这个地址下载: http://item.taobao.com/item.htm?spm=a1z10.3.w4002-1535108827.25.EjmM5Y&id=41291941854