MFC单文档结构,实现OpenGL的绘图,移动,旋转,缩放

您所在的位置:网站首页 cdc绘图缩放 MFC单文档结构,实现OpenGL的绘图,移动,旋转,缩放

MFC单文档结构,实现OpenGL的绘图,移动,旋转,缩放

#MFC单文档结构,实现OpenGL的绘图,移动,旋转,缩放| 来源: 网络整理| 查看: 265

代码过旧,请参考最新的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