您的位置:首页 > 运维架构

mfc opengl 多文档

2015-11-20 21:59 543 查看
在多文档中绘制OpenGL图形,相对比较复杂,主要步骤和关键技术是:
(1)由于在多文档中有多个窗口需要绘制,而当前的OpenGL绘制描述表RC只有一个,因此,在窗口的图形绘制完成之后,必须将OpenGL绘制描述表RC释放,以备其他窗口所用。
(2)必须新建一个视图父类,在该视图类中对Windows设备描述表DC和OpenGL的绘制描述表进行管理,而应用程序的其他各视图类均从该类中派生。
(3)在该新建的视图类中定义一个OpenGL绘图虚函数(下面程序中为OnDrawGL),在其派生类中可以对其进行重写。这样可以在派生的视图类中调用OpenGL命令绘图。
(4)必须删除派生的视图类中的WM_DRAW消息处理函数和PreCreateWindow虚函数的声明和实现。
以下是具体的编程步骤:
0 建立工程MDIOpenGL添加一个新类CGLEnabledView,class type为MFC Class,Base Class为CView
1 给CGLEnabledView添加成员变量
CDC* m_pDC; // Windows设备描述表
HGLRC m_hRC; // OpenGL渲染描述表
CRect m_ClientRect; // 客户区的大小
double m_dAspectRatio; // 窗口的比例
HPALETTE m_hPalette; //调色板

2 在CGLEnabledView类中添加Windows Message Handler处理WM_CREATE,WM_DESTROY,WM_SIZE消息。以及virtual void OnDrawGL();// 图形绘制虚函数,在继承类中可以改写
void CGLEnabledView::OnDrawGL()
{
// 绘制三个坐标轴
glBegin(GL_LINES);
// 绘制红色的x轴
glColor3f(1.f,0.f,0.f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glVertex3f(0.9f,0.1f,0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glVertex3f(0.9f,-0.1f,0.0f);
// 绘制蓝色的y轴
glColor3f(0.f,1.f,0.f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,1.0f,0.0f);
glVertex3f(0.0f,1.0f,0.0f);
glVertex3f(0.1f,0.9f,0.0f);
glVertex3f(0.0f,1.0f,0.0f);
glVertex3f(-0.1f,0.9f,0.0f);
// 绘制绿色的z轴
glColor3f(0.f,0.f,1.f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,0.1f,0.9f);
glVertex3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,-0.1f,0.9f);
glEnd();
}
3 OnDraw是个虚函数,MFC已经替我们创建。在void CGLEnabledView::OnDraw(CDC* pDC)的实现代码中加入如下代码
void CGLEnabledView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: add draw code here
static BOOL bBusy = FALSE; // 准备一个标志信号
if(bBusy) return; //如果忙,则返回
bBusy = TRUE; //置标志为忙,下面开始场景绘制
wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC); // 获取设备描述表
// 清除颜色缓冲区和深度缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
OnDrawGL();// 调用场景绘制函数
glFinish();// 完成图形的绘制
SwapBuffers(m_pDC->GetSafeHdc()); // 启用双缓冲
bBusy = FALSE; // 绘制完毕,置标志为空闲
wglMakeCurrent(NULL,NULL); // 释放OpenGL绘制描述表
}
4 在int CGLEnabledView::OnCreate(LPCREATESTRUCT lpCreateStruct)的实现部分加入如下代码
int CGLEnabledView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
m_pDC = new CClientDC(this);
// 初始化OpenGL
InitializeOpenGL(m_pDC);
// 释放OpenGL绘制描述表
wglMakeCurrent(NULL,NULL);
return 0;
}
5 在void CGLEnabledView::OnDestroy()的实现部分加入如下代码
void CGLEnabledView::OnDestroy()
{
// 获得设备描述表的OpenGL绘制描述表
wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);
// 释放绘制描述表
if (m_hRC!=NULL) ::wglDeleteContext(m_hRC);
if (m_hPalette)
DeleteObject(m_hPalette);//释放调色板
// 释放Windows设备描述表
if(m_pDC) delete m_pDC;
CView::OnDestroy();
// TODO: Add your message handler code here
}
6 在void CGLEnabledView::OnSize(UINT nType, int cx, int cy)的实现中添加如下代码
void CGLEnabledView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);

// TODO: Add your message handler code here
if ( 0 < cx && 0 < cy )
{
// 更新客户区,计算窗口的比例
m_ClientRect.right = cx;
m_ClientRect.bottom = cy;
m_dAspectRatio=double(cx)/double(cy);

// 获取OpenGL绘制描述表
wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);
// 设置视口变换
glViewport(0,0,cx,cy);

// 设置透视变换
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0,m_dAspectRatio,0.1f, 10.0f);
glTranslatef(0.0f,0.0f,-4.f);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

// 释放OpenGL绘制描述表
wglMakeCurrent(NULL,NULL);

// 更新窗口内容
Invalidate(TRUE);
};
}
7 在CGLEnabledView类上右击Add VirtualFunction添加PreCreateWindow虚函数,然后在BOOL CGLEnabledView::PreCreateWindow(CREATESTRUCT& cs)的实现中加入如下代码
BOOL CGLEnabledView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
////////////////////////////////////////////////////////////////////////////
//设置窗口风格
//OpenGL要求
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
//多文档应用程序要求
cs.lpszClass = AfxRegisterWndClass(CS_OWNDC | CS_HREDRAW | CS_VREDRAW);
/////////////////////////////////////////////////////////////////////////////
return CView::PreCreateWindow(cs);
}
8 在CGLEnabledView上右击Add Member Function分别添加三个public类型的成员函数
BOOL SetupPixelFormat();
BOOL InitializeOpenGL(CDC* pDC);
void SetLogicalPalette(void);
9 添加以上三个函数BOOL SetupPixelFormat();和BOOL InitializeOpenGL(CDC* pDC); 以及void SetLogicalPalette(void);的实现。在CGLEnabledView的cpp文件中添加
/////////////////////////////////////////////////////////////////////
// 设置逻辑调色板
//////////////////////////////////////////////////////////////////////
void CGLEnabledView::SetLogicalPalette(void)
{
struct
{
WORD Version;
WORD NumberOfEntries;
PALETTEENTRY aEntries[256];
} logicalPalette = { 0x300, 256 };

BYTE reds[] = {0, 36, 72, 109, 145, 182, 218, 255};
BYTE greens[] = {0, 36, 72, 109, 145, 182, 218, 255};
BYTE blues[] = {0, 85, 170, 255};

for (int colorNum=0; colorNum<256; ++colorNum)
{
logicalPalette.aEntries[colorNum].peRed =
reds[colorNum & 0x07];
logicalPalette.aEntries[colorNum].peGreen =
greens[(colorNum >> 0x03) & 0x07];
logicalPalette.aEntries[colorNum].peBlue =
blues[(colorNum >> 0x06) & 0x03];
logicalPalette.aEntries[colorNum].peFlags = 0;
}

m_hPalette = CreatePalette ((LOGPALETTE*)&logicalPalette);
}

//////////////////////////////////////////////////////////
// 初始化openGL场景
//////////////////////////////////////////////////////////
BOOL CGLEnabledView::InitializeOpenGL(CDC* pDC)
{
m_pDC = pDC;
SetupPixelFormat();
//生成绘制描述表
m_hRC = ::wglCreateContext(m_pDC->GetSafeHdc());
//置当前绘制描述表
::wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);

return TRUE;
}

//////////////////////////////////////////////////////////
// 设置像素格式
BOOL CGLEnabledView::SetupPixelFormat()
{
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 // 忽略层,可见性和损毁掩模
};
int pixelformat;
pixelformat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);//选择像素格式
::SetPixelFormat(m_pDC->GetSafeHdc(), pixelformat, &pfd); //设置像素格式
if(pfd.dwFlags & PFD_NEED_PALETTE)
SetLogicalPalette(); //设置逻辑调色板
return TRUE;
}
//////////////////////////////////////////////////////////

10 利用MFC Class Wizard 为CMDIOpenGLView类删除标准消息WM_DRAW以及Window虚函数PreCreateWindows的响应函数,并且删除cpp文件中的相应的实现部分。
11 修改CMDIOpenGLView类的继承关系,使之继承于CGLEnabledView类:首先应该在CMDIOpenGLView类的头文件中修改继承关系
class CMDIOpenGLView: public CGLEnabledView
其次,在CMDIOpenGLView类的实现文件中将以下两句的CView改为CGLEnabledView
IMPLEMENT_DYNCREATE(CMDIOpenGLView, CView)
BEGIN_MESSAGE_MAP(CMDIOpenGLView, CView) 要改变为
IMPLEMENT_DYNCREATE(CMDIOpenGLView, CGLEnabledView)
BEGIN_MESSAGE_MAP(CMDIOpenGLView, CGLEnabledView)
12 在CMDIOpenGLView类的声明文件MDIOpenGLView.h中首先添加私有成员变量
///////////////////////////////////////////////////////////////////////////////
//添加私有成员变量
private:
CPoint MouseDownPoint;
double X_Angle;
double Y_Angle;

其次在Class语句上面添加包含CGLEnabledView的头文件的语句
////////////////////////////////////////////////////////////////////////////////
//包含类CGLEnabledView的说明文件
#include "GLEnabledView.h"

最后,在CMDIOpenGLView类中添加改写CGLEnabledView类的场景绘制虚函数OnDrawGL()的声明
public:
//////////////////////////////////////////////////////////////////////////////////////
//改写CGLEnabledView类的场景绘制虚函数的声明
void OnDrawGL();
//////////////////////////////////////////////////////////////////////////////////////
13 利用MFC Class Wizard 为CMDIOpenGLView类添加消息WM_LBUTTONDOWN以及WM_LBUTTONUP和WM_MOUSEMOVE的响应函数。它们的实现分别如下:
void CMDIOpenGLView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
// 记录鼠标的位置
MouseDownPoint=point;
// 捕捉鼠标的运动
SetCapture();
//CView::OnLButtonDown(nFlags, point);
}

void CMDIOpenGLView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
// 鼠标抬起位置置于原点
MouseDownPoint=CPoint(0,0);
// 解除捕捉鼠标
ReleaseCapture();
//CView::OnLButtonUp(nFlags, point);
}

void CMDIOpenGLView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
// 检测是否捕捉鼠标
if (GetCapture()==this)
{
// 旋转对象一个步长
X_Angle+=double(point.y-MouseDownPoint.y)/3.6;
Y_Angle+=double(point.x-MouseDownPoint.x)/3.6;
// 更新场景
Invalidate(TRUE);
// 记下鼠标位置
MouseDownPoint=point;
};
//CView::OnMouseMove(nFlags, point);
}

14 在CMDIOpenGLView的构造函数中对X_Angle,Y_Angle进行初始化
CMDIOpenGLView::CMDIOpenGLView()
{
// TODO: add construction code here
/////////////////////////////////////////////////////////////////////////////
//初始化成员变量
X_Angle=0.0;
Y_Angle=0.0;
//////////////////////////////////////////////////////////////////////////////
}
15 在CMDIOpenGLView的cpp文件中添加虚函数OnDrawGL()的实现。
void CMDIOpenGLView::OnDrawGL()
{
glPushMatrix();
// 旋转对象一个给定的角度
glRotated(X_Angle,1.0,0.0,0.0);
glRotated(Y_Angle,0.0,1.0,0.0);
glBegin(GL_LINES);
// yellow x axis arrow
glColor3f(1.f,1.f,0.f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glVertex3f(0.9f,0.1f,0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glVertex3f(0.9f,-0.1f,0.0f);
// cyan y axis arrow
glColor3f(0.f,1.f,1.f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,1.0f,0.0f);
glVertex3f(0.0f,1.0f,0.0f);
glVertex3f(0.1f,0.9f,0.0f);
glVertex3f(0.0f,1.0f,0.0f);
glVertex3f(-0.1f,0.9f,0.0f);
// magenta z axis arrow
glColor3f(1.f,0.f,1.f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,0.1f,0.9f);
glVertex3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,-0.1f,0.9f);
glEnd();

glPopMatrix();
}
16 在stdafx.h中包含有关OpenGL函数的头文件

////////////////////////////////////////////////////////////////////////////
// 包含有关OpenGL函数的头文件
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>
#include <gl/glut.h>
////////////////////////////////////////////////////////////////////////////
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: