OpenGL在MFC中的编程设置

9 篇文章 0 订阅
8 篇文章 0 订阅

MFC+OpenGL 编程入门

    OpenGL 作图非常方便,故日益流行,但对许多人来说,是在微机上  

进行的,首先碰到的问题是,如何适应微机环境。这往往是最关键的一步,  

虽然也是最初级的。  

    下面介绍如何在 VC++ 上进行 OpenGL 编程。其实相当简单明快,只  

因国内缺少这方面的资料与例子,致使许多小细节要一个一个地试,耗去  

大量时间。希望各位有什么心得体会,也公布出来,从而节省每个人都要  

试试的时间。  

    言归正传,下面以画一条 Bezier 曲线为例,详细介绍VC++ 上 OpenGL  

编程的方法。这里实际上也给出了个 C++ 良好封装性编程的范例。文中给  

出了详细注释,以便给初学者明确的指引。一步一步地按所述去做,你将顺  

利地画出第一个 OpenGL 平台上的图形来。  (本文例子以VC++ 5.0 为背景)  

一、产生程序框架 Test.dsw  

   New Project | MFC Application Wizard (EXE) | "Test" | OK  

     *注* : 加“”者指要手工敲入的字串  

二、导入 Bezier 曲线类的文件。用下面方法产生 BezierCurve.h  

   BezierCurve.cpp 两个文件:  

   WorkSpace | ClassView | Test Classes| <右击弹出> New Class  

   | Generic Class(不用MFC类) | "CBezierCurve" | OK  

   

三、编辑好 Bezier 曲线类的定义与实现。写好下面两个文件:  

   

   BezierCurve.h  

   BezierCurve.cpp  

   

四、设置编译环境:  

   

   1. 在 BezierCurve.h 和 TestView.h 内各加上:  

       #include <GL/gl.h>  

       #include <GL/glu.h>  

       #include <GL/glaux.h>  

   2. 在集成环境中,Project | Settings | Link | Object/library module  

       | "opengl32.lib glu32.lib glaux.lib" | OK  

   

五、设置 OpenGL 工作环境:(下面各个操作,均针对 TestView.cpp )  

   

   1.  处理 PreCreateWindow(): 设置 OpenGL 绘图窗口的风格  

   

        cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CS_OWNDC;  

   

   2.  处理 OnCreate():创建 OpenGL 的绘图设备。 OpenGL 绘图的机制  

       是: 先用 OpenGL 的绘图上下文 Rendering Context (简称为 RC )  

       把图画好,再把所绘结果通过 SwapBuffer() 函数传给 Window 的  

       绘图上下文 Device Context (简记为 DC).要注意的是,程序运行  

       过程中,可以有多个 DC,但只能有一个 RC。因此当一个 DC 画完图  

       后,要立即释放 RC,以便其它的 DC 也使用。在后面的代码中,将有  

       详细注释。  

   

int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)  

{  

        if (CView::OnCreate(lpCreateStruct) == -1)  

                return -1;  

   

        Init();  

        return 0;  

}  

   

void CTestView::Init()  

{  

    m_pDC = new CClientDC(this);  //创建 DC  

   

    ASSERT(m_pDC != NULL);  

   

    if (!bSetupPixelFormat())    //设定绘图的位图格式,函数下面列出  

        return;  

   

    m_hRC = wglCreateContext(m_pDC->m_hDC);//创建 RC  

    wglMakeCurrent(m_pDC->m_hDC, m_hRC);  //RC 与当前 DC 相关联  

}   //CClient *  m_pDC;  HGLRC m_hRC;  是 CTestView 的成员变量  

   

BOOL CTestView::bSetupPixelFormat()  

{  

    static PIXELFORMATDESCRIPTOR pfd =  

        {  

        sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd  

        1,                              // version number  

        PFD_DRAW_TO_WINDOW |            // support window  

          PFD_SUPPORT_OPENGL |          // support OpenGL  

          PFD_DOUBLEBUFFER,             // double buffered  

        PFD_TYPE_RGBA,                  // RGBA type  

        24,                             // 24-bit color depth  

        0, 0, 0, 0, 0, 0,               // color bits ignored  

        0,                              // no alpha buffer  

        0,                              // shift bit ignored  

        0,                              // no accumulation buffer  

        0, 0, 0, 0,                     // accum bits ignored  

        32,                             // 32-bit z-buffer  

        0,                              // no stencil buffer  

        0,                              // no auxiliary buffer  

        PFD_MAIN_PLANE,                 // main layer  

        0,                              // reserved  

        0, 0, 0                         // layer masks ignored  

    };  

    int pixelformat;  

   

    if ( (pixelformat = ChoosePixelFormat(m_pDC->m_hDC, &pfd)) == 0 )  

    {  

        MessageBox("ChoosePixelFormat failed");  

        return FALSE;  

    }  

   

    if (SetPixelFormat(m_pDC->m_hDC, pixelformat, &pfd) == FALSE)  

    {  

        MessageBox("SetPixelFormat failed");  

        return FALSE;  

    }  

   

    return TRUE;  

}  

   

    3. 处理 OnDestroy()  

   

void CTestView::OnDestroy()  

{  

    wglMakeCurrent(m_pDC->m_hDC,NULL);  //释放与m_hDC 对应的 RC  

    wglDeleteContext(m_hRC);   //删除 RC  

   

    if (m_pDC)  

        delete m_pDC;   //删除当前 View 拥有的 DC  

   

    CView::OnDestroy();  

}  

   

    4. 处理 OnEraseBkgnd()  

   

BOOL CTestView::OnEraseBkgnd(CDC* pDC)  

{  

        // TODO: Add your message handler code here and/or call default  

   

//      return CView::OnEraseBkgnd(pDC);//把这句话注释掉,若不然,Window  

                         //会用白色北景来刷新,导致画面闪烁  

        return TRUE;//只要空返回即可。  

}  

   

    5. 处理 OnDraw()  

   

void CTestView::OnDraw(CDC* pDC)  

{  

        wglMakeCurrent(m_pDC->m_hDC,m_hRC);//使 RC 与当前 DC 相关联  

   

        DrawScene( );   //具体的绘图函数,在 RC 中绘制  

        SwapBuffers(m_pDC->m_hDC);//把 RC 中所绘传到当前的 DC 上,从而  

                              //在屏幕上显示  

        wglMakeCurrent(m_pDC->m_hDC,NULL);//释放 RC,以便其它 DC 进行绘图  

}  

   

void CTestView::DrawScene( )  

{  

    glClearColor(0.0f,0.0f,0.0f,1.0f);//设置背景颜色为黑色  

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);  

    glPushMatrix();  

   

    glTranslated(0.0f,0.0f,-3.0f);//把物体沿(0,0,-1)方向平移  

                  //以便投影时可见。因为缺省的视点在(0,0,0),只有移开  

                  //物体才能可见。  

                  //本例是为了演示平面 Bezier 曲线的,只要作一个旋转  

                  //变换,可更清楚的看到其 3D 效果。  

                  //如?glRotated(30,1.0f,0.0f,0.0f); //绕 X 轴转 30 度  

                  //    glRotated(30,0.0f,1.0f,0.0f); //绕 Y 轴转 30 度  

   

  glBegin(GL_LINES);//画坐标系,由三条线段组成  

    glColor3f(1,0,0);  

    glVertex3f(0,0,0);  

    glVertex3f(1,0,0);//X坐标  

   

    glColor3f(0,1,0);  

    glVertex3f(0,0,0);  

    glVertex3f(0,1,0);//Y坐标  

   

    glColor3f(0,0,1);  

    glVertex3f(0,0,0);  

    glVertex3f(0,0,1);//Z坐标  

  glEnd();//end draw the 3D axis  

   

  //下面画一条 Bezier 曲线  

    bezier_curve.myPolygon();//画Bezier曲线的控制多边形  

   

    bezier_curve.myDraw();  //CBezierCurve bezier_curve  

                            //是 CTestView 的成员变量  

                            //具体的函数见附录  

   

   glPopMatrix();  

   glFinish();   //结束 RC 绘图  

   return;  

}  

   

    6. 处理 OnSize()  

   

void CTestView::OnSize(UINT nType, int cx, int cy)  

{  

        CView::OnSize(nType, cx, cy);  

   

        VERIFY(wglMakeCurrent(m_pDC->m_hDC,m_hRC));//确认RC与当前DC关联  

        GLResize(cx, cy);//具体的响应 WM_SIZE 消息,对投影进行修正  

   

        VERIFY(wglMakeCurrent(NULL,NULL));//确认DC释放RC  

}  

   

void GLResize(GLsizei w, GLsizei h)   //GLResize() 是一个全局函数  

{  

        // Prevent a divide by zero  

        if(h == 0)  

                h = 1;  

   

    glViewport(0, 0, w, h);  //设置视口  

   

        glMatrixMode(GL_PROJECTION);//进入投影变换状态  

        glLoadIdentity();  

   

         //重新进行投影变换  

        gluPerspective (20.0f, (GLdouble)w/(GLdouble)h, 1.0, 40.0f);  

        glMatrixMode(GL_MODELVIEW);//结束投影变换  

        glLoadIdentity();  

}  

   

     7 处理 OnLButtonDown()  

   

void CTestView::OnLButtonDown(UINT nFlags, CPoint point)  

{  

        CView::OnLButtonDown(nFlags, point);  

   

     if(bezier_curve.m_N>MAX-1)  

        {  

                MessageBox("顶点个数超过了最大数MAX=50");  

                return;  

        }  

   

        //以下为坐标变换作准备,  

        //说明:OpenGL 有一个更有力处理方式,即用 gluUnProject()  

        //这里为了证券交易起见,自己处理。  

        GetClientRect(&m_ClientRect);//获取视口区域大小  

        w=m_ClientRect.right-m_ClientRect.left;//视口宽度 w  

        h=m_ClientRect.bottom-m_ClientRect.top;//视口高度 h  

                                     //w,h 是CTestView的成员变量  

        centerx=(m_ClientRect.left+m_ClientRect.right)/2;//中心位置,  

        centery=(m_ClientRect.top+m_ClientRect.bottom)/2;//取之作原点  

                            //centerx,centery 是 CTestView 的成员变量  

        GLdouble tmpx,tmpy;  

        tmpx=scrx2glx(point.x);//屏幕上点坐标转化为OpenGL画图的规范坐标  

        tmpy=scry2gly(point.y);  

   

        bezier_curve.m_Vertex[bezier_curve.m_N].x=tmpx;//加一个顶点  

        bezier_curve.m_Vertex[bezier_curve.m_N].y=tmpy;  

   

        bezier_curve.m_N++;//顶点数加一  

        InvalidateRect(NULL,TRUE);//发送刷新重绘消息  

}  

   

   

double CTestView::scrx2glx(int scrx)  //可能有毛病,因为点到的位置总  

{                                     //总画不到,望指正  

        return (double)(scrx-centerx)/double(h);  

}  

   

double CTestView::scry2gly(int scry)  

{  

        return (double)(centery-scry)/double(h);  

}  

   

附录:  

1.CBezierCurve 的声明: (BezierCurve.h)  

class CBezierCurve  

{  

public:  

        CBezierCurve();  

        virtual ~CBezierCurve();  

   

        void bezier_generation(myPOINT2D P[MAX],int level);  

               //算法的具体实现  

        void myDraw();//画曲线函数  

   

public:  

        void myPolygon(); //画控制多边形  

        myPOINT2D m_Vertex[MAX];//控制顶点,以数组存储  

                        //myPOINT2D 是一个存二维点的结构  

                        //成员为Gldouble x,y  

        int m_N;  //控制顶点的个数  

};  

   

2. CBezierCurve 的实现: (BezierCurve.cpp)  

   

CBezierCurve::CBezierCurve()  

{  

        m_N=4;  

    m_Vertex[0].x=-0.5f;  

        m_Vertex[0].y=-0.5f;  

        m_Vertex[1].x=-0.5f;  

        m_Vertex[1].y=0.5f;  

        m_Vertex[2].x=0.5f;  

        m_Vertex[2].y=0.5f;  

        m_Vertex[3].x=0.5f;  

        m_Vertex[3].y=-0.5f;  

}  

   

CBezierCurve::~CBezierCurve()  

{  

   

}  

void CBezierCurve::myDraw()  

{  

        bezier_generation(m_Vertex,LEVEL);  

}  

   

void CBezierCurve::bezier_generation(myPOINT2D P[MAX], int level)  

{                 //算法的具体描述,请参考相关书本  

        int i,j;  

   

        level--;  

   

        if(level<0)return;  

   

        if(level==0) //不要写成level=0!!!  

        {  

                glColor3f(1.0f,1.0f,1.0f);  

                glBegin(GL_LINES);  //画出线段  

                  glVertex2d(P[0].x,P[0].y);  

                  glVertex2d(P[m_N-1].x,P[m_N-1].y);  

                glEnd();//结束画线段  

                return;  //递归到了最底层,跳出递归  

        }  

   

        myPOINT2D Q[MAX],R[MAX];  

   

        for(i=0;i<m_N;i++)  

        {  

                Q[i].x=P[i].x;  

                Q[i].y=P[i].y;  

        }  

   

        for(i=1;i<m_N;i++)  

        {  

                R[m_N-i].x=Q[m_N-1].x;  

   

                R[m_N-i].y=Q[m_N-1].y;  

   

                for(j=m_N-1;j>=i;j--)  

                {  

                        Q[j].x=(Q[j-1].x+Q[j].x)/double(2);  

                        Q[j].y=(Q[j-1].y+Q[j].y)/double(2);  

                }  

        }  

   

    R[0].x=Q[m_N-1].x;  

    R[0].y=Q[m_N-1].y;  

   

    bezier_generation(Q,level);  

    bezier_generation(R,level);  

}  

   

void CBezierCurve::myPolygon()  

{  

   

        glBegin(GL_LINE_STRIP); //画出连线段  

          glColor3f(0.2f,0.4f,0.4f);  

          for(int i=0;i<m_N;i++)  

          {  

                  glVertex2d(m_Vertex[i].x,m_Vertex[i].y);  

          }  

        glEnd();//结束画连线段  

  

}  

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值