《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 Context
3     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 Context
16     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;  // 除非将焦点设置到控件,否则返回 TRUE
135 }
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     else
145     {
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     else
174     {
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 } 

步骤四: 运行调试

    运行结果如下所示:

 

posted @ 2014-12-12 11:16  wiener_在路上  阅读(6419)  评论(0编辑  收藏  举报