基于MFC的OpenGL 绘图例程

来源:互联网 发布:加湿器知乎 编辑:程序博客网 时间:2024/05/07 05:46
所 附 的 程 序 用 M F C 完 成 了 一 个 简 单 的OpenGL 作 图, 用OpenGL 的 辅 助 库 画 了 一 个 有 光 照 的 实 心 圆 球。OpenGL 本 身 的 函 数 这 里 就 不 解 释 了, 仅 对 用MFC 编OpenGL 时 需 要 注 意 的 内 容 做 一 个 简 要 的 说 明:

---- 1. 一 旦 设 定 了 一 个DC 的 位 图 格 式, 该DC 所 联 系 的 窗 口 的 位 图 格 式 随 之 设 定。 该 窗 口 若 含 有 子 窗 口 或 者 有 兄 弟 窗 口, 这 些 兄 弟/ 子 窗 口 的 位 图 格 式 没 有 设 成 与 对 应RC 一 致 的 格 式,OpenGL 在 它 们 上 面 作 图 就 容 易 出 错。 故 而OpenGL 作 图 的 窗 口 必 须 具 有WS_CLIPCHILDREN 和 WS_CLIPSIBLINGS 风 格, 程 序 中 在 主 框 窗 的 构 造 函 数 中 用LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,NULL,NULL ); 指 定 了 主 窗 口 的 风 格。

---- 2. 在ANSI C 的OpenGL 编 程 中, 由auxReshapeFunc 定 义 设 置OpenGL 视 口 大 小 和 作 图 尺 寸 的 回 调 函 数。 在MFC 中 应 该 由WM_SIZ 消 息 的 处 理 函 数 来 完 成。 在ANSI C 的OpenGL 编 程 中, 由EauxMainLoop 定 义 作 图 的 回 调 函 数。 在MFC 中 应 该 由WM_PAINT 消 息 的 处 理 函 数 来 处 理。 相 应 的, 由OpenGL 定 义 的 键 盘、 鼠 标 处 理 函 数 都 应 该 由 相 应 的Windows 处 理 函 数 来 响 应。

---- 3. OpenGL 自 己 有 刷 新 背 景 的 函 数glClear, 故 而 应 禁 止Windows 刷 新 窗 口 背 景。 否 则, 当 窗 口 需 要 重 画 时,Windows 会 自 动 先 发 送WM_ERASEBKGND, 而 缺 省 的 处 理 函 数 使 用 白 色 的 背 景 刷。 当OpenGL 使 用 的 背 景 颜 色 不 是 白 色 时, 作 图 时 有 一 帧 白 色 的 闪 烁。 这 种 现 象 在 做 动 画 时 特 别 明 显。 程 序 中 只 需 要 在WM_ERASEBKGND 的 消 息 处 理 函 数 中 禁 止 父 窗 口 类 的 消 息 处 理, 简 单 的 返 回 一 个TRUE 即 可。

---- 4. 由 于OpenGL 的 跨 平 台 性, 它 必 须 用 操 作 系 统 的 调 色 板。 所 以 如 果GL_INDEX_MODE 作 图 时, 必 须 用VC 自 己 定 义 调 色 板。 不 过 一 般 情 况 下, 用GL_RGBA_MODE 模 式 比 较 方 便, 很 少 用 到GL_INDEX_MODE 模 式。

---- 5. 在OpenGL 作 图 期 间,RC 对 应 的DC 不 能 删 除 或 者 释 放。

---- 6. 由 于OpenGL 作 图 时 需 要 长 时 间 占 用DC, 所 以 最 好 把 作 图 窗 口 类 设 成CS_OWNDC。MFC 缺 省 的 窗 口 类 风 格 中 没 有 设 这 一 属 性, 程 序 中 在 主 窗 口C++ 类 的PreCreateWindow 方 法 中 自 己 注 册 了 一 个 窗 口 类, 除 了 设 定 了CS_OWNDC 属 性 以 外, 还 设 定 了CS_HREDRAW、CS_VREDRAW 和CS_SAVEBITS。 设 定CS_HREDRAW、CS_VREDRAW 是 为 了 让 窗 口 缩 放 时 产 生WM_PAINT 消 息, 修 正OpenGL 视 口 和 作 图 尺 寸; 由 于OpenGL 作 图 需 要 很 多 计 算, 设 定CS_SAVEBITS 是 为 了 在OpenGL 窗 口 被 遮 盖 后 显 现 出 来 时, 不 产 生WM_PAINT 消 息, 用 内 存 存 储 的 图 象 来 填 充, 从 而 用 空 间 消 耗 换 取 计 算 时 间。

---- 7. 本 程 序 中 没 有 对OpenGL 函 数 的 出 错 情 况 作 出 处 理。OpenGL 出 错 后 返 回 错 误 码, 不 会 抛 出 异 常; 而 且 在 某 一 个 函 数 出 错 以 后, 后 继 函 数 也 一 般 不 会 出 现 异 常, 只 是 返 回 错 误 码, 一 不 小 心 就 可 能 忽 略 某 些 错 误。 而 对 每 一 个OpenGL 函 数 都 做 出 错 与 否 的 判 断 比 较 麻 烦, 所 以 编 程 序 时 对OpenGL 的 函 数 应 当 非 常 小 心。

---- 参 考 书 籍:

---- 《OpenGL Programmer's Guide》 SGI inc.

---- 《OpenGL 三 维 图 形 程 序 设 计》 廖 朵 朵、 张 华 军 著, 星 球 地 图 出 版 社

---- 《Visual C++ 5.0 联 机 帮 助》

---- 附 程 序:

---- 程 序 运 行 时 必 须 确 定OpenGL32.dll、glu.dll、glaux.dll 在Windows 的System 目 录 下。 如 果 找 不 到 这 些 文 件, 可 以 从Windows 95 OSR2 的 机 器 上 面 将 这 些 文 件 拷 贝 过 来 即 可。 OpenGL 运 行 不 需 要 注 册 库 信 息。 在VC 的STUDIO 中 运 行 程 序 时, 工 程 文 件 中 必 须 加 入OpenGL.H 、glu.h、glaux.h 以 及OpenGL.lib、glu.lib、glaux.lib, 这 些 文 件 由VC 自 带。

---- 主 窗 口 类 定 义(OpenGLWnd.h):

s#if !defined(AFX_OPENGLWND_H__3FB1AB28_0E70_11D2_9ACA_48543300E17D__INCLUDED_)#define AFX_OPENGLWND_H__3FB1AB28_0E70_11D2_9ACA_48543300E17D__INCLUDED_#if _MSC_VER >= 1000#pragma once#endif // _MSC_VER >= 1000#include < afxwin.h >#include "SimpleGLApp.h"#include "resource.h"// OpenGLWnd.h : header file///////////////////////////////////////////////////////////////////////////////// COpenGLWnd frameclass COpenGLWnd : public CFrameWnd{DECLARE_DYNCREATE(COpenGLWnd)public:COpenGLWnd();  // protected constructor used by dynamic creationprotected:HGLRCm_hrc;CClientDC*m_pDC;// Attributespublic:// Operationspublic:// Overrides// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(COpenGLWnd)protected:virtual BOOL PreCreateWindow(CREATESTRUCT& cs);//}}AFX_VIRTUAL// Implementationpublic:virtual ~COpenGLWnd();// Generated message map functions//{{AFX_MSG(COpenGLWnd)afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnSize(UINT nType, int cx, int cy);afx_msg void OnDestroy();afx_msg BOOL OnEraseBkgnd(CDC* pDC);afx_msg void OnPaint();//}}AFX_MSGDECLARE_MESSAGE_MAP()};///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}// Microsoft Developer Studio will insert additional declarations immediately before the previous line.#endif // !defined(AFX_OPENGLWND_H__3FB1AB28_0E70_11D2_9ACA_48543300E17D__INCLUDED_)主窗口类的实现(OpenGLWnd.cpp):// OpenGLWnd.cpp : implementation file//#include "stdafx.h"#include "OpenGLWnd.h"#include "SimpleGLApp.h"#include "gl/glu.h"#include "gl/gl.h"#include "gl/glaux.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// COpenGLWndIMPLEMENT_DYNCREATE(COpenGLWnd, CFrameWnd)COpenGLWnd::COpenGLWnd(){m_pDC = NULL;m_hrc = 0;LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,NULL,NULL );}COpenGLWnd::~COpenGLWnd(){}BEGIN_MESSAGE_MAP(COpenGLWnd, CFrameWnd)//{{AFX_MSG_MAP(COpenGLWnd)ON_WM_CREATE()ON_WM_SIZE()ON_WM_DESTROY()ON_WM_ERASEBKGND()ON_WM_PAINT()//}}AFX_MSG_MAPEND_MESSAGE_MAP()BOOL COpenGLWnd::PreCreateWindow(CREATESTRUCT& cs) {// TODO: Add your specialized code here and/or call the base classcs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW|CS_SAVEBITS |CS_NOCLOSE|                  CS_OWNDC,AfxGetApp( )-> LoadStandardCursor(IDC_ARROW), 0 ,AfxGetApp( )- >LoadStandardIcon(IDI_APPLICATION));return CFrameWnd::PreCreateWindow(cs);}int COpenGLWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {if (CFrameWnd::OnCreate(lpCreateStruct) == -1)return -1;    int pixelformat;    m_pDC = new CClientDC(this);//在客户区作图ASSERT(m_pDC != NULL);static PIXELFORMATDESCRIPTOR pfd ={        sizeof(PIXELFORMATDESCRIPTOR),  //固定值        1,                              //固定值        PFD_DRAW_TO_WINDOW |            // support window        PFD_SUPPORT_OPENGL |            // support OpenGL        PFD_TYPE_RGBA,                  // RGBA模式,不用调色板        16,                             //程序在16位色彩下运行        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        32,                             // 32-bit z-buffer        0,                              // no stencil buffer        0,                              // no auxiliary buffer        PFD_MAIN_PLANE,                 // main layer        0,                              // reserved        0, 0, 0                         // layer masks ignored    };if ( (pixelformat = ChoosePixelFormat(m_pDC- >GetSafeHdc(), &pfd)) == 0 )    {        MessageBox("在该DC上找不到与PFD接近的位图结构");        return -1;    }if (SetPixelFormat(m_pDC- >GetSafeHdc(), pixelformat, &pfd) == FALSE)    {        MessageBox("无法在该DC上设置位图结构");        return -1;    }    m_hrc = wglCreateContext(m_pDC- >GetSafeHdc());    wglMakeCurrent(m_pDC- >GetSafeHdc(), m_hrc);    glClearDepth(1.0f);    glEnable(GL_DEPTH_TEST);    glMatrixMode(GL_PROJECTION);    glLoadIdentity();    glMatrixMode(GL_MODELVIEW);return 0;//OpenGL窗口构造成功}void COpenGLWnd::OnSize(UINT nType, int cx, int cy) {CFrameWnd::OnSize(nType, cx, cy);// TODO: Add your message handler code here    if(cy > 0)    {            glViewport(0, 0, cx, cy);        glMatrixMode(GL_PROJECTION);        glLoadIdentity();if (cx < = cy)   glOrtho(-3.0,3.0,-3.0 * (GLfloat)cx/(GLfloat)cy,3.0 * (GLfloat)cx/(GLfloat)cy,-3.0,3.0);elseglOrtho(-3.0,3.0,-3.0 * (GLfloat)cy/(GLfloat)cx,3.0 * (GLfloat)cy/(GLfloat)cx,-3.0,3.0);        glMatrixMode(GL_MODELVIEW);    }}void COpenGLWnd::OnDestroy() {CFrameWnd::OnDestroy();    ::wglMakeCurrent(NULL,  NULL);    if (m_hrc)        ::wglDeleteContext(m_hrc);if (m_pDC)        delete m_pDC;// TODO: Add your message handler code here}BOOL COpenGLWnd::OnEraseBkgnd(CDC* pDC) {// TODO: Add your message handler code here and/or call defaultreturn TRUE;//return CFrameWnd::OnEraseBkgnd(pDC);}void COpenGLWnd::OnPaint() {CPaintDC dc(this); // device context for paintingGLfloat light_position[]={2.0f,0.0f,4.0f,0.0f};// TODO: Add your message handler code here    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glPushMatrix();        glTranslatef(0.0f, 0.0f, -2.0f);glLightfv(GL_LIGHT0,GL_POSITION,light_position);glEnable(GL_LIGHTING);glEnable(GL_LIGHT0);glDepthFunc(GL_LESS);glEnable(GL_DEPTH_TEST);auxSolidSphere(1.0);    glPopMatrix();    glFinish();// Do not call CFrameWnd::OnPaint() for painting messages}应用程序类的定义(SimpleGLApp.h):#if !defined(AFX_SIMPLEGLAPP_H__3FB1AB29_0E70_11D2_9ACA_48543300E17D__INCLUDED_)#define AFX_SIMPLEGLAPP_H__3FB1AB29_0E70_11D2_9ACA_48543300E17D__INCLUDED_#if _MSC_VER >= 1000#pragma once#endif // _MSC_VER >= 1000// SimpleGLApp.h : header file//#include < afxwin.h >#include "OpenGLWnd.h"#include "resource.h"/////////////////////////////////////////////////////////////////////////////// CSimpleGLApp threadclass CSimpleGLApp : public CWinApp{DECLARE_DYNCREATE(CSimpleGLApp)public:CSimpleGLApp();    // protected constructor used by dynamic creation// Attributespublic:// Operationspublic:// Overrides// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CSimpleGLApp)public:virtual BOOL InitInstance();virtual int ExitInstance();//}}AFX_VIRTUAL// Implementationpublic:virtual ~CSimpleGLApp();// Generated message map functions//{{AFX_MSG(CSimpleGLApp)afx_msg void OnAppExit();//}}AFX_MSGDECLARE_MESSAGE_MAP()};///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}// Microsoft Developer Studio will insert additional declarations immediately before the previous line.#endif // !defined(AFX_SIMPLEGLAPP_H__3FB1AB29_0E70_11D2_9ACA_48543300E17D__INCLUDED_)应用程序类的实现(SimpleGLApp.cpp):// SimpleGLApp.cpp : implementation file//#include "stdafx.h"#include "SimpleGLApp.h"#include "OpenGLWnd.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CSimpleGLAppIMPLEMENT_DYNCREATE(CSimpleGLApp, CWinApp)CSimpleGLApp::CSimpleGLApp(){}CSimpleGLApp::~CSimpleGLApp(){}BOOL CSimpleGLApp::InitInstance(){// TODO:  perform and per-thread initialization herem_pMainWnd = new COpenGLWnd();m_pMainWnd- >ShowWindow(m_nCmdShow);m_pMainWnd- >UpdateWindow();return TRUE;}int CSimpleGLApp::ExitInstance(){return CWinApp::ExitInstance();}BEGIN_MESSAGE_MAP(CSimpleGLApp, CWinApp)//{{AFX_MSG_MAP(CSimpleGLApp)ON_COMMAND(ID_APP_EXIT, OnAppExit)//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CSimpleGLApp message handlersvoid CSimpleGLApp::OnAppExit() {// TODO: Add your command handler code hereCWinApp::OnAppExit();}CSimpleGLApp SimpleGLApp; 
原创粉丝点击