MFC单文档结构,实现OpenGL的绘图,移动,旋转,缩放 |
您所在的位置:网站首页 › cdc绘图缩放 › MFC单文档结构,实现OpenGL的绘图,移动,旋转,缩放 |
代码过旧,请参考最新的OpenGL可编程管线编程
代码过旧,请参考最新的OpenGL可编程管线编程 代码过旧,请参考最新的OpenGL可编程管线编程 MFC单文档结构,实现OpenGL的绘图,移动,旋转,缩放
基本知识: Windows应用程序是使用设备描述表(Device Context,简写为"DC")进行图形的绘制输出, 但OpenGL并不使用标准的设备描述表,它使用渲染描述表(Rendering Context,简写为"RC")完成图形图像的映射。 描述表的映射核心是像素格式的设置。 当进行OpenGL的绘图操作时,实际上是在进行设备像素的操作。OpenGL将数据转化为像素操作写入帧缓存中,就需要知道Windows的像素格式, 或者说需要与其一致起来。在初始化OpenGL时,需要一个叫做PIXELFORMATDESCRIPTOR的结构来完成对像素属性的设置。 Win32提 供了4个函数管理像素格式。 ①ChoosePixelFormat():返回和&pfd指定的像素格式最匹配的DC支持的像素格式的索引值,如果函数调用不成功,返回零。 ②SetPixelFormat():在DC中设置pixelformat指定的设备的像素格式,如果函数调用成功,返回TRUE。 ③GetPixelFormat():返回当前DC的像素格式的索引,如果函数调用不成功,返回零。 ④DescribePixelFormat():用n指定的DC的像素格式的数据设置&pfd,如果函数调用成功,返回DC的像素格式的最大索引,否则,返回零。 OpenGL的渲染描述表保存着在窗口中用来渲染一个场景所需的信息。一个OpenGL应用程序必须有一个渲染描述表,并且在OpenGL进行绘制之前它应该是当前的。在渲染描述表存入信息后,OpenGL就可以在Windows系统中更新一个窗口的图形状态。 Win32提供了5个函数管理渲染描述表。 ①wglCreateContext():创建一个与给定的DC兼容的RC,调用成功返回RC的句柄,不成功返回NULL。 ②wglMakeCurrent():使指定的RC成为当前的,调用成功返回GL_TRUE,否则返回GL_FALSE。 ③wglGetCurrentCotext():获得当前的RC句柄。 ④wglGetCurrentDC():获得和当前的RC联系的DC句柄。 ⑤wglDeleteContext():删除RC。 /* Pixel format descriptor */ typedef struct tagPIXELFORMATDESCRIPTOR { WORD nSize; WORD nVersion; DWORD dwFlags; BYTE iPixelType; BYTE cColorBits; BYTE cRedBits; BYTE cRedShift; BYTE cGreenBits; BYTE cGreenShift; BYTE cBlueBits; BYTE cBlueShift; BYTE cAlphaBits; BYTE cAlphaShift; BYTE cAccumBits; BYTE cAccumRedBits; BYTE cAccumGreenBits; BYTE cAccumBlueBits; BYTE cAccumAlphaBits; BYTE cDepthBits; BYTE cStencilBits; BYTE cAuxBuffers; BYTE iLayerType; BYTE bReserved; DWORD dwLayerMask; DWORD dwVisibleMask; DWORD dwDamageMask; } PIXELFORMATDESCRIPTOR, *PPIXELFORMATDESCRIPTOR, FAR *LPPIXELFORMATDESCRIPTOR; ============================================================= 创建一个单文档结构的MFC程序 ============================================================= 窗口创建之前我们须设置窗口风格 WS_CLIPCHILDREN(创建父窗口使用的Windows风格,用于重绘时裁剪子窗口所覆盖的区域)和 WS_CLIPSIBLINGS(创建子窗口使用的Windows风格,用于重绘时剪裁其他子窗口所覆盖的区域) 从而避免OpenGL绘制到其他窗口中去。 这些应该在窗口创建之前设置好,则代码位于PreCreateWindow()中。 BOOL CLDSView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: 在此处通过修改 // CREATESTRUCT cs 来修改窗口类或样式 cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; return CView::PreCreateWindow(cs); } ============================================================= 在窗口创建时,则需要将OpenGL的环境设置好 int CLDSView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 InitializeOpenGL(); return 0; } 定义如下变量: CClientDC* m_pDC; // Device Context 设备描述表 HGLRC m_hRC; // Render Context 着色描述表 Windows应用程序是使用设备描述表(Device Context,简写为"DC")进行图形的绘制输出, 但OpenGL并不使用标准的设备描述表,它使用渲染描述表(Rendering Context,简写为"RC") 初始化OpenGL如下: BOOL CLDSView::InitializeOpenGL() { m_pDC = new CClientDC (ThisWindow()); if(m_pDC == NULL) { AfxMessageBox(_T("new CClientDC ERROR!")); return FALSE; } // 设置当前的绘图像素格式 if(!SetupPixelFormat()) // 在初始化OpenGL环境的时候,必须要设置好像素格式 { return FALSE; } // 创建绘图描述表 m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ()); // DC转RC if(m_hRC == 0) { AfxMessageBox(_T("创建绘图描述表失败")); return FALSE; } // 使绘图描述表为当前调用线程的当前绘图描述表 if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE) { AfxMessageBox(_T("调用线程的当前绘图描述表失败")); return FALSE; } glClearColor(0.28f,0.28f,0.28f,0.0f); // 设置清屏颜色 glClearDepth(1.0f); // 指定清除深度缓存时使用的深度值 glEnable(GL_DEPTH_TEST); return TRUE; } 一般,应用程序先调用函数wglCreateContext,然后调用函数wglMakeCurrent使渲染上下文和设备显示相联系,因此OpenGL 的绘图操作都可以在设备显示上完成。完成绘图以后,通过再一次调用函数wglMakeCurrent(参数设置为NULL)可以使渲染上下文释放DC,最后调用函数wglDeleteContext来删除渲染上下文。(Windows NT 的OpenGL编程:入门(译)_chuajiang的博客-CSDN博客) 在创建一个图形操作表之前,首先必须设置像素格式。即产生一个RC的第一步是定义窗口的像素格式。 像素格式含有设备绘图界面的属性,这些属性包括绘图界面是用RGBA模式还是颜色表模式,像素缓存是用单缓存还是双缓存,以及颜色位数、深度缓存和模板缓存所用的位数,还有其它一些属性信息。像素格式决定窗口着所显示的图形在内存中是如何表示的。 在下面将在SetupPixelFormat()函数中对这些参数的设置。代码如下: BOOL CLDSView::SetupPixelFormat() { static 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 m_nPixelFormat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd); if ( m_nPixelFormat == 0 ) { return FALSE; } // 设置最匹配的像素格式为当前的像素格式 if ( ::SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd) == FALSE) { return FALSE; } return TRUE; } 上述则将OpenGL初始化成功 ============================================================= 视图设置 在初始化OpenGL环境后,我们需要对视图进行设置 窗口创建好后,我们需要将OpoenGL的视口与MFC的客户区进行覆盖,进行OpenGL的图形显示 而且当主程序窗口进行缩放后,会影响到OpenGL图形的显示 void CLDSView::OnSize( int cx, int cy ) { if ( 0 >= cx || 0 >= cy ) { return; } glViewport(0, 0, cx, cy); // 视口覆盖整个程序的客户区 glMatrixMode(GL_PROJECTION); // 随后的矩阵操作glOrtho应用于投影矩阵中 glLoadIdentity(); // 重置当前指定的矩阵为单位矩阵 glOrtho(-cx , cx, -cy, cy,-10000000,10000000); // 正交投影 } 我们还可以用透视投影操作: 将 glOrtho(-cx , cx, -cy, cy,-10000000,10000000); // 正交投影 转换为: GLfloat aspect_ratio = (GLdouble)cx/(GLdouble)cy; // 防止窗口缩放变形 gluPerspective(60.0f, aspect_ratio, 0.01f, 1500.0f); ============================================================= 将环境搭建好了,视口也设置好了,下面,我们就要进行图形绘制了 在 void CLDSView::OnDraw(CDC* /*pDC*/) { CLDSDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 RenderScene(); // 绘制图形 } void CLDSView::RenderScene() { //清除颜色缓冲区和深度缓冲区 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); if (!::wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC)) { return; } glMatrixMode(GL_MODELVIEW); // 图形绘制在模型视图中绘制 glLoadIdentity(); // 后面描述 glTranslated(m_dXPos, m_dYPos, 0.0); // XY方向上的移动 glRotated(m_dXAngle, 1.0, 0.0, 0.0); // 旋转 glRotated(m_dYAngle, 0.0, 1.0, 0.0); glScalef(m_dScale, m_dScale, m_dScale); // 缩放 GLfloat dAsixLen = 600.0f; glBegin(GL_LINES); // 绘制三根轴 glColor3f(1.0f, 0.0f, 0.0f); // X glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(dAsixLen, 0.0f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); // Y glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(0.0f, dAsixLen, 0.0f); glColor3f(0.0f, 0.0f, 1.0f); // Z glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(0.0f, 0.0f, dAsixLen); glEnd(); SwapBuffers( m_pDC->GetSafeHdc() ); } ============================================================= 按住左键后移动旋转图形 定义一个成员变量用于保存状态点 CPoint m_ptCurrent; void CLDSView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 SetCapture(); m_ptCurrent = point; __super::OnLButtonDown(nFlags, point); } void CLDSView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 ReleaseCapture(); mouseOpt = OTHER; __super::OnLButtonUp(nFlags, point); } void CLDSView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_dXAngle += (point.y - m_ptCurrent.y)/6; // 注意 X Y m_dYAngle += (point.x - m_ptCurrent.x)/6; m_ptCurrent = point; RedrawWindow(); __super::OnMouseMove(nFlags, point); } 在RedrawWindow();后,程序窗口进行刷新,刷新时,绘制图形, 则就调用了 glRotated(m_dXAngle, 1.0, 0.0, 0.0); glRotated(m_dYAngle, 0.0, 1.0, 0.0); 进行旋转 ============================================================= 按住中键后移动移动图形 void CLDSView::OnMButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 SetCapture(); m_ptCurrent = point; __super::OnMButtonDown(nFlags, point); } void CLDSView::OnMButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 ReleaseCapture(); __super::OnMButtonUp(nFlags, point); } void CLDSView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //if(this == GetCapture()) // return; m_dXPos += (point.x - m_ptCurrent.x)*2; // 因为glOrtho截取的是两倍的屏幕大小 m_dYPos += (m_ptCurrent.y - point.y )*2; m_ptCurrent = point; RedrawWindow(); __super::OnMouseMove(nFlags, point); } 还可以通过键盘的方向键进行图形的移动 void CLDSView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: 在此添加消息处理程序代码和/或调用默认值 switch(nChar) { case VK_UP: m_dYPos += 1; break; case VK_DOWN: m_dYPos -= 1; break; case VK_LEFT: m_dXPos -= 1; break; case VK_RIGHT: m_dXPos += 1; break; } RedrawWindow(); __super::OnKeyDown(nChar, nRepCnt, nFlags); } 在RedrawWindow();后,程序窗口进行刷新,刷新时,绘制图形, 则就调用了 glTranslated(m_dXPos, m_dYPos, -10.0); // 移动 进行移动 ============================================================= 鼠标中键滚动进行图形缩放 BOOL CLDSView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (m_dScale > 0.06 && m_dScale m_dScale -= (zDelta /120) * 0.02; } CString strDebugOut; strDebugOut.Format(_T("%.3f\n"), m_dScale); OutputDebugString(strDebugOut); mouseOpt = SCALE; RedrawWindow(); return __super::OnMouseWheel(nFlags, zDelta, pt); } ============================================================= 可以绘制,并进行一些简单的操作后,程序退出后呢? 我们需要做一些清理工作 void CLDSView::OnDestroy() { CView::OnDestroy(); // TODO: 在此处添加消息处理程序代码 if(::wglMakeCurrent (0,0) == FALSE) // 使渲染上下文释放DC { AfxMessageBox(_T("wglMakeCurrent Error!")); } if(::wglDeleteContext (m_hRC)==FALSE) // 删除渲染上下文 { AfxMessageBox(_T("不能删除RC-- wglDeleteContext Error")); } if(m_pDC) { delete m_pDC; } m_pDC = NULL; } ============================================================= 源代码下载: MFC中OpenGL移动缩放旋转.rar-C++代码类资源-CSDN下载 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |