《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 }
步骤四: 运行调试
运行结果如下所示:
时间: 2024-10-13 11:53:29