首页 > 代码库 > MFC dialog程序中加入OpenGL窗体

MFC dialog程序中加入OpenGL窗体

《MFC dialog中加入OpenGL窗体》

    最近学习了如何在MFC对话框程序中加入OpenGL窗体的方法,在这里将自己的实现过程归纳一下。

 

步骤零: 加入PictureControl控件

    新建MFC对话框程序,删除对话框上的按钮控件的Label控件,然后向窗体添加PictureControl控件,作为绘制的窗体。

    将该控件的ID设置为:IDC_RENDER

 

步骤一: 加入OpenGL的lib文件和头文件

    在项目上单击右键,添加OpenGL的lib文件,freeglut_static.lib和gltools.lib,如下。

 

    然后在stdafx.h中包含相关的头文件如下:

步骤二: 设置对话框的头文件***Dlg.h

    在对话框头文件中声明相关的变量:

1     HDC hrenderDC;  //设备上下文2     HGLRC hrenderRC;  //渲染上下文3     float m_yRotate;  //转速4     int PixelFormat;    //像素格式

    在对话框头文件中声明相关方法:

1     BOOL SetWindowPixelFormat(HDC hDC);  //设定像素格式2     BOOL CreateViewGLContext(HDC hDC);   //view GL Context3     void RenderScene();  //绘制场景

    加入消息映射函数:

 1 afx_msg void OnTimer(UINT nIDEvent); 

    具体的对话框头文件如下:

 1 // OpenGLTest1Dlg.h : 头文件 2 // 3  4 #pragma once 5  6  7 // COpenGLTest1Dlg 对话框 8 class COpenGLTest1Dlg : public CDialogEx 9 {10 // 构造11 public:12     COpenGLTest1Dlg(CWnd* pParent = NULL);    // 标准构造函数13 14     BOOL SetWindowPixelFormat(HDC hDC);  //设定像素格式15     BOOL CreateViewGLContext(HDC hDC);   //view GL Context16     void RenderScene();  //绘制场景17 18     HDC hrenderDC;  //设备上下文19     HGLRC hrenderRC;  //渲染上下文20     float m_yRotate;  //转速21     int PixelFormat;    //像素格式22 23 // 对话框数据24     enum { IDD = IDD_OPENGLTEST1_DIALOG };25 26     protected:27     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持28 29 30 // 实现31 protected:32     HICON m_hIcon;33 34 35     // 生成的消息映射函数36     virtual BOOL OnInitDialog();37     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);38     afx_msg void OnPaint();39     afx_msg HCURSOR OnQueryDragIcon();40     afx_msg void OnTimer(UINT nIDEvent);41     DECLARE_MESSAGE_MAP()42 };

步骤三: 设置对话框的源文件***Dlg.cpp

    a. 开启定时器消息循环

    在消息循环的代码块中加入ON_WM_TIMER()消息循环:

1 BEGIN_MESSAGE_MAP(COpenGLTest1Dlg, CDialogEx)2     ON_WM_SYSCOMMAND()3     ON_WM_PAINT()4     ON_WM_QUERYDRAGICON()5     ON_WM_TIMER() 6 END_MESSAGE_MAP()

    这里的OnTimer函数用于相应SetTimer消息。当SetTimer设置的时间到了,就会自动调用OnTimer()函数。

    写OnTimer函数的函数体,如下所示:

1 void COpenGLTest1Dlg::OnTimer(UINT nIDEvent) //实时绘制场景 2 { 3  // TODO: Add your message handler code here and/or call default 4  RenderScene(); 5  m_yRotate +=3; 6  CDialog::OnTimer(nIDEvent); 7 } 

 

     b. 写函数SetWindowPixelFormat,用于生成像素格式

    函数体如下所示:

 

 1 BOOL COpenGLTest1Dlg::SetWindowPixelFormat(HDC hDC)  2 {  3 PIXELFORMATDESCRIPTOR pixelDesc;  4  5 pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);  6 pixelDesc.nVersion = 1;  7  8 pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW |   9      PFD_SUPPORT_OPENGL | 10      PFD_DOUBLEBUFFER | 11      PFD_TYPE_RGBA; 12 13 pixelDesc.iPixelType = PFD_TYPE_RGBA; 14 pixelDesc.cColorBits = 32; 15 pixelDesc.cRedBits = 0; 16 pixelDesc.cRedShift = 0; 17 pixelDesc.cGreenBits = 0; 18 pixelDesc.cGreenShift = 0; 19 pixelDesc.cBlueBits = 0; 20 pixelDesc.cBlueShift = 0; 21 pixelDesc.cAlphaBits = 0; 22 pixelDesc.cAlphaShift = 0; 23 pixelDesc.cAccumBits = 0; 24 pixelDesc.cAccumRedBits = 0; 25 pixelDesc.cAccumGreenBits = 0; 26 pixelDesc.cAccumBlueBits = 0; 27 pixelDesc.cAccumAlphaBits = 0; 28 pixelDesc.cDepthBits = 0; 29 pixelDesc.cStencilBits = 1; 30 pixelDesc.cAuxBuffers = 0; 31 pixelDesc.iLayerType = PFD_MAIN_PLANE; 32 pixelDesc.bReserved = 0; 33 pixelDesc.dwLayerMask = 0; 34 pixelDesc.dwVisibleMask = 0; 35 pixelDesc.dwDamageMask = 0; 36 37 PixelFormat = ChoosePixelFormat(hDC,&pixelDesc); 38 if(PixelFormat==0) // Choose default 39 { 40  PixelFormat = 1; 41  if(DescribePixelFormat(hDC,PixelFormat, 42   sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0) 43  { 44   return FALSE; 45  } 46 } 47 48 if(SetPixelFormat(hDC,PixelFormat,&pixelDesc)==FALSE) 49 50 {  51  return FALSE; 52 } 53 54 return TRUE; 55 } 

 

     c. 写函数CreateViewGLContext,用于生成渲染上下文

    具体函数体如下:

 1 BOOL COpenGLTest1Dlg::CreateViewGLContext(HDC hDC)  2 {  3 hrenderRC = wglCreateContext(hDC);  4  5 if(hrenderRC==NULL)  6  return FALSE;  7  8 if(wglMakeCurrent(hDC,hrenderRC)==FALSE)  9  return FALSE; 10 11   12 13 return TRUE; 14 } 

    d. 写函数RenderScene,用于绘制场景

    具体函数体如下:

 1 void COpenGLTest1Dlg::RenderScene()     2 {  3  4  5  /////////////////////////////////////////////////  6  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  7  8    9  glLoadIdentity(); 10  glTranslatef(0.0f,0.0f,-6.0f);      // Move Left 1.5 Units And Into The Screen 6.0 11  glRotated(m_yRotate, 0.0, 1.0, 0.0); 12  glBegin(GL_TRIANGLES); // Drawing Using Triangles 13   14   glVertex3f( 0.0f, 1.0f, 0.0f);     // Top 15   glVertex3f(-1.0f,-1.0f, 0.0f);     // Bottom Left 16   glVertex3f( 1.0f,-1.0f, 0.0f);     // Bottom Right 17  glEnd();           // Finished Drawing The Triangle 18  SwapBuffers(hrenderDC); 19 } 

    e. 在对话框初始化程序OnInitDialog中添加初始化代码

    具体代码如下:

 1 ///////////////////////OPENGL INIT/////////////////////////  2     CWnd *wnd=GetDlgItem(IDC_RENDER);  3     hrenderDC=::GetDC(wnd->m_hWnd);  4     if(SetWindowPixelFormat(hrenderDC)==FALSE)  5       return 0;  6    7      if(CreateViewGLContext(hrenderDC)==FALSE)  8       return 0;  9 10     glPolygonMode(GL_FRONT,GL_FILL); 11     glPolygonMode(GL_BACK,GL_FILL); 12     /////////////////////////////////////////// 13     glEnable(GL_TEXTURE_2D); 14     glShadeModel(GL_SMOOTH); 15     glViewport(0,0,259,231); 16     glMatrixMode(GL_PROJECTION); 17     glLoadIdentity(); 18     gluPerspective(45,1,0.1,100.0); 19     glMatrixMode(GL_MODELVIEW); 20     glLoadIdentity(); 21     glShadeModel(GL_SMOOTH);       // Enable Smooth Shading 22     glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    // Black Background 23     glClearDepth(1.0f);         // Depth Buffer Setup 24     glEnable(GL_DEPTH_TEST);       // Enables Depth Testing 25     glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do 26     ///////////////////////////////////////////////////////////////////////// 27     glEnableClientState(GL_VERTEX_ARRAY); 28     glEnableClientState(GL_TEXTURE_COORD_ARRAY); 29 30     SetTimer(1,10,0); 31 32     //////////////////////////////////////////////////////////////// 

    f. 整个.cpp源代码

  1 // OpenGLTest1Dlg.cpp : 实现文件  2 //  3   4 #include "stdafx.h"  5 #include "OpenGLTest1.h"  6 #include "OpenGLTest1Dlg.h"  7 #include "afxdialogex.h"  8   9  10 #ifdef _DEBUG 11 #define new DEBUG_NEW 12 #endif 13  14  15 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 16  17 class CAboutDlg : public CDialogEx 18 { 19 public: 20     CAboutDlg(); 21  22 // 对话框数据 23     enum { IDD = IDD_ABOUTBOX }; 24  25     protected: 26     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持 27  28 // 实现 29 protected: 30     DECLARE_MESSAGE_MAP() 31 }; 32  33 CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) 34 { 35 } 36  37 void CAboutDlg::DoDataExchange(CDataExchange* pDX) 38 { 39     CDialogEx::DoDataExchange(pDX); 40 } 41  42 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) 43 END_MESSAGE_MAP() 44  45  46 // COpenGLTest1Dlg 对话框 47  48  49  50  51 COpenGLTest1Dlg::COpenGLTest1Dlg(CWnd* pParent /*=NULL*/) 52     : CDialogEx(COpenGLTest1Dlg::IDD, pParent) 53 { 54     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 55 } 56  57 void COpenGLTest1Dlg::DoDataExchange(CDataExchange* pDX) 58 { 59     CDialogEx::DoDataExchange(pDX); 60 } 61  62 BEGIN_MESSAGE_MAP(COpenGLTest1Dlg, CDialogEx) 63     ON_WM_SYSCOMMAND() 64     ON_WM_PAINT() 65     ON_WM_QUERYDRAGICON() 66     ON_WM_TIMER()  67 END_MESSAGE_MAP() 68  69  70 // COpenGLTest1Dlg 消息处理程序 71  72 BOOL COpenGLTest1Dlg::OnInitDialog() 73 { 74     CDialogEx::OnInitDialog(); 75  76     // 将“关于...”菜单项添加到系统菜单中。 77  78     // IDM_ABOUTBOX 必须在系统命令范围内。 79     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 80     ASSERT(IDM_ABOUTBOX < 0xF000); 81  82     CMenu* pSysMenu = GetSystemMenu(FALSE); 83     if (pSysMenu != NULL) 84     { 85         BOOL bNameValid; 86         CString strAboutMenu; 87         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 88         ASSERT(bNameValid); 89         if (!strAboutMenu.IsEmpty()) 90         { 91             pSysMenu->AppendMenu(MF_SEPARATOR); 92             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 93         } 94     } 95  96     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 97     //  执行此操作 98     SetIcon(m_hIcon, TRUE);            // 设置大图标 99     SetIcon(m_hIcon, FALSE);        // 设置小图标100 101     // TODO: 在此添加额外的初始化代码102     ///////////////////////OPENGL INIT///////////////////////// 103     CWnd *wnd=GetDlgItem(IDC_RENDER); 104     hrenderDC=::GetDC(wnd->m_hWnd); 105     if(SetWindowPixelFormat(hrenderDC)==FALSE) 106       return 0; 107   108      if(CreateViewGLContext(hrenderDC)==FALSE) 109       return 0; 110 111     glPolygonMode(GL_FRONT,GL_FILL); 112     glPolygonMode(GL_BACK,GL_FILL); 113     /////////////////////////////////////////// 114     glEnable(GL_TEXTURE_2D); 115     glShadeModel(GL_SMOOTH); 116     glViewport(0,0,259,231); 117     glMatrixMode(GL_PROJECTION); 118     glLoadIdentity(); 119     gluPerspective(45,1,0.1,100.0); 120     glMatrixMode(GL_MODELVIEW); 121     glLoadIdentity(); 122     glShadeModel(GL_SMOOTH);       // Enable Smooth Shading 123     glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    // Black Background 124     glClearDepth(1.0f);         // Depth Buffer Setup 125     glEnable(GL_DEPTH_TEST);       // Enables Depth Testing 126     glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do 127     ///////////////////////////////////////////////////////////////////////// 128     glEnableClientState(GL_VERTEX_ARRAY); 129     glEnableClientState(GL_TEXTURE_COORD_ARRAY); 130 131     SetTimer(1,10,0); 132 133     //////////////////////////////////////////////////////////////// 134     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE135 }136 137 void COpenGLTest1Dlg::OnSysCommand(UINT nID, LPARAM lParam)138 {139     if ((nID & 0xFFF0) == IDM_ABOUTBOX)140     {141         CAboutDlg dlgAbout;142         dlgAbout.DoModal();143     }144     else145     {146         CDialogEx::OnSysCommand(nID, lParam);147     }148 }149 150 // 如果向对话框添加最小化按钮,则需要下面的代码151 //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,152 //  这将由框架自动完成。153 154 void COpenGLTest1Dlg::OnPaint()155 {156     if (IsIconic())157     {158         CPaintDC dc(this); // 用于绘制的设备上下文159 160         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);161 162         // 使图标在工作区矩形中居中163         int cxIcon = GetSystemMetrics(SM_CXICON);164         int cyIcon = GetSystemMetrics(SM_CYICON);165         CRect rect;166         GetClientRect(&rect);167         int x = (rect.Width() - cxIcon + 1) / 2;168         int y = (rect.Height() - cyIcon + 1) / 2;169 170         // 绘制图标171         dc.DrawIcon(x, y, m_hIcon);172     }173     else174     {175         CDialogEx::OnPaint();176     }177 }178 179 //当用户拖动最小化窗口时系统调用此函数取得光标180 //显示。181 HCURSOR COpenGLTest1Dlg::OnQueryDragIcon()182 {183     return static_cast<HCURSOR>(m_hIcon);184 }185 186 BOOL COpenGLTest1Dlg::SetWindowPixelFormat(HDC hDC) 187 { 188 PIXELFORMATDESCRIPTOR pixelDesc; 189 190 pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR); 191 pixelDesc.nVersion = 1; 192 193 pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW |  194      PFD_SUPPORT_OPENGL | 195      PFD_DOUBLEBUFFER | 196      PFD_TYPE_RGBA; 197 198 pixelDesc.iPixelType = PFD_TYPE_RGBA; 199 pixelDesc.cColorBits = 32; 200 pixelDesc.cRedBits = 0; 201 pixelDesc.cRedShift = 0; 202 pixelDesc.cGreenBits = 0; 203 pixelDesc.cGreenShift = 0; 204 pixelDesc.cBlueBits = 0; 205 pixelDesc.cBlueShift = 0; 206 pixelDesc.cAlphaBits = 0; 207 pixelDesc.cAlphaShift = 0; 208 pixelDesc.cAccumBits = 0; 209 pixelDesc.cAccumRedBits = 0; 210 pixelDesc.cAccumGreenBits = 0; 211 pixelDesc.cAccumBlueBits = 0; 212 pixelDesc.cAccumAlphaBits = 0; 213 pixelDesc.cDepthBits = 0; 214 pixelDesc.cStencilBits = 1; 215 pixelDesc.cAuxBuffers = 0; 216 pixelDesc.iLayerType = PFD_MAIN_PLANE; 217 pixelDesc.bReserved = 0; 218 pixelDesc.dwLayerMask = 0; 219 pixelDesc.dwVisibleMask = 0; 220 pixelDesc.dwDamageMask = 0; 221 222 PixelFormat = ChoosePixelFormat(hDC,&pixelDesc); 223 if(PixelFormat==0) // Choose default 224 { 225  PixelFormat = 1; 226  if(DescribePixelFormat(hDC,PixelFormat, 227   sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0) 228  { 229   return FALSE; 230  } 231 } 232 233 if(SetPixelFormat(hDC,PixelFormat,&pixelDesc)==FALSE) 234 235 {  236  return FALSE; 237 } 238 239 return TRUE; 240 } 241 242 243 BOOL COpenGLTest1Dlg::CreateViewGLContext(HDC hDC) 244 { 245 hrenderRC = wglCreateContext(hDC); 246 247 if(hrenderRC==NULL) 248  return FALSE; 249 250 if(wglMakeCurrent(hDC,hrenderRC)==FALSE) 251  return FALSE; 252 253   254 255 return TRUE; 256 } 257 258 void COpenGLTest1Dlg::RenderScene()    259 { 260 261 262  ///////////////////////////////////////////////// 263  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 264 265   266  glLoadIdentity(); 267  glTranslatef(0.0f,0.0f,-6.0f);      // Move Left 1.5 Units And Into The Screen 6.0 268  glRotated(m_yRotate, 0.0, 1.0, 0.0); 269  glBegin(GL_TRIANGLES); // Drawing Using Triangles 270   271   glVertex3f( 0.0f, 1.0f, 0.0f);     // Top 272   glVertex3f(-1.0f,-1.0f, 0.0f);     // Bottom Left 273   glVertex3f( 1.0f,-1.0f, 0.0f);     // Bottom Right 274  glEnd();           // Finished Drawing The Triangle 275  SwapBuffers(hrenderDC); 276 } 277 278 void COpenGLTest1Dlg::OnTimer(UINT nIDEvent) //实时绘制场景 279 { 280  // TODO: Add your message handler code here and/or call default 281  RenderScene(); 282  m_yRotate +=3; 283  CDialog::OnTimer(nIDEvent); 284 } 

步骤四: 运行调试

    运行结果如下所示:

 

MFC dialog程序中加入OpenGL窗体