在MFC的对话框程序中需要使用OpenGL在某个对话框中作图,综合了网上的两篇文章的内容(文章一,文章二),也有自己的心得体会。
首先需要配置好opengl的环境,程序中会使用到glaux中的库和函数,这里将它的lib,h,dll文件的下载链接附上。其他的库windows中好像带有。
先将对OpenGL的操作封装成一个类,这是第一篇文章的主要思想:
头文件OpenGL.h
#pragma once
#include <gl/GL.h>
#include <gl/GLU.h>
#include <GLAUX.H>
class COpenGL
{
public:
COpenGL(void);
~COpenGL(void);
HDC hDC;
HGLRC hRC;
public:
/************************************************************************/
/* 对OpenGL的一些初始化工作,width和height表示窗口的宽和高 */
/************************************************************************/
void Init(int width,int height);
/************************************************************************/
/* 设置像素格式 */
/************************************************************************/
bool SetupPixelFormat(HDC hDC0);
/************************************************************************/
/* 窗口大小改变时的回调函数 */
/************************************************************************/
void Reshap(int width,int height);
/************************************************************************/
/* 具体的渲染操作,窗口中显示的内容是在这个函数中完成的 */
/************************************************************************/
void Render();
};
源文件OpenGL.cpp
#include "StdAfx.h"
#include "OpenGL.h"
COpenGL::COpenGL(void)
{
}
COpenGL::~COpenGL(void)
{
wglMakeCurrent(hDC,NULL);
wglDeleteContext(hRC);
}
void COpenGL::Init(int width,int height){
// openGL的初始化设置
glClearColor(0.0, 1.0, 1.0, 0.0);
glShadeModel(GL_SMOOTH);
//glViewport(0, 0, 200, 200);
glMatrixMode(GL_PROJECTION);
gluPerspective(60, (GLfloat)width/(GLfloat)height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
bool COpenGL::SetupPixelFormat(HDC hDC0){
int nPixelFormat; // 象素点格式
hDC=hDC0;
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // pfd结构的大小
1, // 版本号
PFD_DRAW_TO_WINDOW | // 支持在窗口中绘图
PFD_SUPPORT_OPENGL | // 支持OpenGL
PFD_DOUBLEBUFFER, // 双缓存模式
PFD_TYPE_RGBA, // RGBA 颜色模式
24, // 24 位颜色深度
0, 0, 0, 0, 0, 0, // 忽略颜色位
0, // 没有非透明度缓存
0, // 忽略移位位
0, // 无累加缓存
0, 0, 0, 0, // 忽略累加位
32, // 32 位深度缓存
0, // 无模板缓存
0, // 无辅助缓存
PFD_MAIN_PLANE, // 主层
0, // 保留
0, 0, 0 // 忽略层,可见性和损毁掩模
};
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);
wglMakeCurrent(hDC, hRC);
return TRUE;
}
void COpenGL::Reshap(int width,int height){
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective
( 60.0f,
(GLfloat)width/(GLfloat)height,
0.1f,
100.0f
);
//gluLookAt(10,5,10,0,0,0,0,1,0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void COpenGL::Render(){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0);
glLoadIdentity();
glTranslatef(0.0, 0.0, -5.0);
glBegin(GL_TRIANGLES);
glVertex3f(0.0, 1.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glEnd();
SwapBuffers(hDC);
}
上面将对OpenGL的操作封装成了一个工具类,但是照第一篇文章的思路实现时由于我的工程是基于MFC的对话框程序,照他上面说的方法显示出的对话框中没有东西。于是使用这个工具类时参照了第二篇文章的方法,也明白了如何在其他的工程中使用这个工具类。
具体的方法是:
1.在需要绘图的窗口类中添加OpenGL.h头文件,并声明一个COpenGL类型的成员变量。如我想在CDialog4这个类中使用OpenGL绘图,那么在它 的头文件中包含OpenGL.h,并声明一个COpenGL类型的成员变量。
2.添加两个消息响应函数,即WM_SIZE和WM_TIMER消息的处理,重写一个函数OnInitDialog。
这两步操作完成后,CDialog4的头文件如下:
#pragma once
#include "OpenGL.h"
// CDialog4 对话框
class CDialog4 : public CDialog
{
DECLARE_DYNAMIC(CDialog4)
public:
COpenGL openGL;
public:
CDialog4(CWnd* pParent = NULL); // 标准构造函数
virtual ~CDialog4();
// 对话框数据
enum { IDD = IDD_DIALOG4 };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnSize(UINT nType, int cx, int cy);
virtual BOOL OnInitDialog();
afx_msg void OnTimer(UINT_PTR nIDEvent);
};
CDialog4的源文件如下:
// Dialog4.cpp : 实现文件
//
#include "stdafx.h"
#include "ComputerGraphic.h"
#include "Dialog4.h"
// CDialog4 对话框
IMPLEMENT_DYNAMIC(CDialog4, CDialog)
CDialog4::CDialog4(CWnd* pParent /*=NULL*/)
: CDialog(CDialog4::IDD, pParent)
{
}
CDialog4::~CDialog4()
{
}
void CDialog4::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CDialog4, CDialog)
ON_WM_SIZE()
ON_WM_TIMER()
END_MESSAGE_MAP()
void CDialog4::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
openGL.Reshap(cx,cy);
}
BOOL CDialog4::OnInitDialog()
{
CDialog::OnInitDialog();
/************************************************************************/
/* 传递给SetupPixelFormat的参数是要绘图的对象的DC,可以是窗口中的某一个控件
这里使用的是窗口的DC,即在窗口中绘图,而不是在窗口的某个控件中绘图*/
/************************************************************************/
openGL.SetupPixelFormat(::GetDC(m_hWnd));
//得到绘图区域对应的长方形
CRect rect;
GetClientRect(&rect);
//设置绘图区域的宽和高
openGL.Init(rect.right,rect.bottom);
SetTimer(1,10,0);
return TRUE; // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}
void CDialog4::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
openGL.Render();
CDialog::OnTimer(nIDEvent);
}
重点是在OnInitDialog中的函数调用,获取不同控件的DC就可以在不同的控件中绘图了。这时使用该方法就很灵活方便了。OnSize函数是在窗口改变时重新设置透视投影的宽和高,如果没有这个消息处理当窗口大小改变时图形的位置不会变化,看起来就会很奇怪。
程序运行后的效果如下图: