标签归档:MFC

基于MFC的OpenGL绘图

1、首先创建工程

用AppWizard产生一个MFC EXE项目,其他默认即可。

2、将此工程所需的OpenGL文件和库加入到工程中

在工程菜单中,选择”Build”下的”Settings”项。单击”Link”标签,选择”General”目录,在Object/Library Modules的编辑框中输入”opengl32.lib glu32.lib glaux.lib glut.lib(注:glut.lib可能并不包含在默认库中,需要下载。或者此处不添加glut.lib)”(注意,输入双引号中的内容,各个库用空格分开;否则会出现链接错误),选择”OK”结束。然后打开文件”stdafx.h”,加入下列头文件:

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>

3、下面需要改写“OpenGLDemoView.cpp”这个文件

a)把OnPreCreate改写成如下所示:

BOOL COpenGLDemoView::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs
    cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
    return CView::PreCreateWindow(cs);
}

b)在项目资源管理器中,选择ClassView标签,在OpenGLDemoView类处单击右键,选择Add Member Function,类型为BOOL,函数声明为SetWindowPixelFormat(HDC hDC)。然后同理Add Member Variable,类型int,变量名m_GLPixelIndex。以上两者均声明为Private。

回到OpenGLDemoView.cpp中,编辑函数代码:

BOOL COpenGLDemoView::SetWindowPixelFormat(HDC hDC)
{
    PIXELFORMATDESCRIPTOR pixelDesc=
    {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|
        PFD_DOUBLEBUFFER|PFD_SUPPORT_GDI,
        PFD_TYPE_RGBA,
        24,
        0,0,0,0,0,0,
        0,
        0,
        0,
        0,0,0,0,
        32,
        0,
        0,
        PFD_MAIN_PLANE,
        0,
        0,0,0
    };
 
    this->m_GLPixelIndex = ChoosePixelFormat(hDC,&pixelDesc);
    if(this->m_GLPixelIndex==0)
    {
        this->m_GLPixelIndex = 1;
        if(DescribePixelFormat(hDC,this->m_GLPixelIndex,sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0)
        {
            return FALSE;
        }
    }
 
    if(SetPixelFormat(hDC,this->m_GLPixelIndex,&pixelDesc)==FALSE)
    {
        return FALSE;
    }
    return TRUE;
}

c)同理,继续添加函数BOOL CreateViewGLContext(HDC hDC)和成员变量HGLRC m_hGLContext,代码如下:

BOOL COpenGLDemoView::CreateViewGLContext(HDC hDC)
{<br>   this->m_hGLContext = wglCreateContext(hDC);
    if(this->m_hGLContext==NULL)
    {//创建失败
        return FALSE;
    }
 
    if(wglMakeCurrent(hDC,this->m_hGLContext)==FALSE)
    {//选为当前RC失败
        return FALSE;
    }
 
    return TRUE;
 
}

d)用ClassWizard添加WM_CREATE的消息处理函数OnCreate,编辑OnCreate函数代码如下:

int COpenGLDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;
     
    // TODO: Add your specialized creation code here
        HWND hWnd = this->GetSafeHwnd();   
        HDC hDC = ::GetDC(hWnd);
        if(this->SetWindowPixelFormat(hDC)==FALSE)
        {
            return 0;
        }
        if(this->CreateViewGLContext(hDC)==FALSE)
        {
            return 0;
        }
        return 0;
}

e)用ClassWizard添加WM_DESTROY的消息处理函数OnDestroy,编辑OnDestroy函数代码如下

void COpenGLDemoView::OnDestroy()
{
    CView::OnDestroy();
     
    // TODO: Add your message handler code here
        if(wglGetCurrentContext()!=NULL)
        {
            wglMakeCurrent(NULL,NULL);
        }
        if(this->m_hGLContext!=NULL)
        {
            wglDeleteContext(this->m_hGLContext);
            this->m_hGLContext = NULL;
        }  
}

f)编辑COpenGLDemoView的构造函数,使之如下所示:

COpenGLDemoView::COpenGLDemoView()
{
    // TODO: add construction code here
    this->m_GLPixelIndex = 0;
        this->m_hGLContext = NULL;
}

至此,我们已经构造好了框架,使程序可以利用OpenGL进行画图了。

4、下面给出一个简单的二维图形的例子(这个例子都是以上述框架为基础的)。

a)用Classwizard为COpenGLDemoView添加WMSIZE的消息处理函数OnSize,代码如下:

void COpenGLDemoView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);
     
    // TODO: Add your message handler code here
    GLsizei width,height;
        GLdouble aspect;
        width = cx;
        height = cy;
        if(cy==0)
        {
            aspect = (GLdouble)width;
        }
        else
        {
            aspect = (GLdouble)width/(GLdouble)height;
        }
        glViewport(0,0,width,height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(0.0,500.0*aspect,0.0,500.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
}

b)用ClasswizardCOpenGLDemoView添加WM_PAINT的消息处理函数OnPaint,代码如下:

void COpenGLDemoView::OnPaint()
{
    CPaintDC dc(this); // device context for painting  
    // TODO: Add your message handler code here
    // Do not call CView::OnPaint() for painting messages
    this->DrawScene();
    SwapBuffers(dc.m_hDC);
}

c)用ClasswizardCOpenGLDemoView添加WM_PAINT的消息处理函数OnDrawScene,代码如下:

int COpenGLDemoView::DrawScene()
{
    glLoadIdentity();
        glClear(GL_COLOR_BUFFER_BIT);
        glBegin(GL_POLYGON);
        glColor4f(1.0f,0.0f,0.0f,1.0f);
        glVertex2f(100.0f,50.0f);
        glColor4f(0.0f,1.0f,0.0f,1.0f);
        glVertex2f(450.0f,400.0f);
        glColor4f(0.0f,0.0f,1.0f,1.0f);
        glVertex2f(450.0f,50.0f);
        glEnd();
        glFlush();
        return TRUE;                                        // Everything Went OK                       
}

5、实现结果

251659298578307

MFC实现直线生成算法(DDA与Bresenham)

编译环境VC++ 6.0

1、新建“MFC Project(.exe)”,工程名“MFCDrawLine”,选择“Single Doc”,其他默认,Finish。

2、编辑菜单资源

在项目资源管理器中选择“ResourceView”标签,点开里面的“Menu”目录,双击“IDR_MAINFRAME”打开之,其中包含菜单Banner,之后编辑菜单资源。点击右侧空白处,在弹出对话框中Caption处填写菜单项标题“Drawline”,ID处为不可编辑状态。编辑完成后,编辑Drawline的子菜单,分别填写:

ID Caption
ID_DDA DDA
ID_BRESENHAM Bresenham

编辑完后,结果如下图:

251608174209522

3、添加消息处理函数

在菜单中选择”View –> ClassWizard” 在“Class name”选单中选择“CMFCDrawLineView”,然后在左侧“Object IDs”中选择刚才创建的两个ID分别添加Function。“Messages”均选择“COMMAND”;

具体如下表:

ID Message Function
ID_DDA COMMAND onDda
ID_BRESENHAM COMMAND onBresenham

4、添加具体代码

在项目资源管理器中选择“FileView标签”,打开”MFCDrawLine.cpp”文件,在代码的最末端可以看到刚才添加的两个Function,完成这两个函数的具体代码,编译通过即可。代码如下:

void CMFCDrawLineView::OnDda()
{
    // TODO: Add your command handler code here
    CClientDC dc(this);
    int x0,y0,x1,y1;
    float x,y;
    double k;
    x0=10;
    y0=5;
    x1=100;
    y1=200;
    k=(y1-y0)*1.0/(x1-x0);
    y=y0;
    for(x=x0;x<x1;x++)
    {
      dc.SetPixel(int(x),int(y+0.5),RGB(255,0,0));
          y+=k;  
    }
 
}
 
void CMFCDrawLineView::OnBresenham()
{
    // TODO: Add your command handler code here
    CClientDC dc(this);
    int x0=10,y0=5,x1=300,y1=200,x=x0,y=y0;
        double e=-0.5;
    int dx=x1-x0;
    int dy=y1-y0;
    double k=dy*1.0/dx;
    for(int i=0;i<=dx;i++)
    {
        dc.SetPixel(int(x),int(y),RGB(0,0,255));
        x=x+1;
        e=e+k;
        if(e>=0)
        {
            y++;
            e=e-1;
        }
    }
 
}

5、运行结果

251624246396732