• MFC中添加OpenGL


    WINDOWS下展示OpenGL有多种形式:

    MFC 或 win32,该如何向MFC中添加OpenGL?下面是介绍最简单OpenGL框架。

    1、首先通过VS建立MFC应用程序-MyOpenGL,选择单文档结构视图。

    2、添加控制台窗体,帮助输出调试信息。

    CMyOpenGLView.cpp添加头文件

    #include <conio.h>
    #include <iostream>
    #include <fcntl.h> 
    #include <io.h>

    CMyOpenGLView::CMyOpenGLView()添加如下代码,使标准输入输出流和控制台建立连接。

    其中MFC环境下cout和C语言的都可以使用,而WIN32下只能使用C语言的标准输出。

    	if ( AllocConsole() ) 
    	{ 
    		int hCrt=_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT);
    		*stdout = *(::_fdopen(hCrt, "w")); 
    		::setvbuf(stdout, NULL, _IONBF, 0); 
    		*stderr = *(::_fdopen(hCrt, "w")); 
    		::setvbuf(stderr, NULL, _IONBF, 0); 
    	} 
    

    CMyOpenGLView::~CMyOpenGLView()中添加

    FreeConsole()
    

    2、规定设备显示时的像素格式,并建立OpenGL上下文,(什么?你不知道什么叫做WINDOWS设备和OpenGL上下文?出门右转 孙鑫VC++和OpenGL红宝书

    通过MFC类向导添加CMyOpenGLView类的WM_CREATE消息,生成

     int CMyOpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct),在里面添加

    	PIXELFORMATDESCRIPTOR pfd;
    	int n;
    	HGLRC hrc;
    
    	pmDC=new CClientDC(this);
    	if(!bSetupPixelFormat(pmDC))
    		return false;
    
    	n=::GetPixelFormat(pmDC->GetSafeHdc());
    
    	::DescribePixelFormat(pmDC->GetSafeHdc(), n,sizeof(pfd),&pfd);
    
    	hrc=wglCreateContext(pmDC->GetSafeHdc());
    	wglMakeCurrent(pmDC->GetSafeHdc(),hrc);
    

     其中

    bSetupPixelFormat()的定义如下:
    bool bSetupPixelFormat(CClientDC * pmDC)
    {
    	static PIXELFORMATDESCRIPTOR pfd = 
    	{
    		sizeof(PIXELFORMATDESCRIPTOR),
    		1,
    		PFD_DRAW_TO_WINDOW |
    		PFD_SUPPORT_OPENGL|
    		PFD_DOUBLEBUFFER, 
    		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
    	};
    	int pixelformat;
    
    	if((pixelformat = ChoosePixelFormat(pmDC->GetSafeHdc(), &pfd)) == 0)
    	{
    		cout<<"ChoosePixelFormat failed"<<endl;
    		return FALSE;
    	}
    
    	if(SetPixelFormat(pmDC->GetSafeHdc(), pixelformat, &pfd) == FALSE)
    	{
    		cout<<"SetPixelFormat failed"<<endl;
    		return FALSE;
    	}
    
    	return TRUE;
    }
    

      

     还要记得销毁,释放资源。

    在OnDestroy中添加

    void CMyOpenGLView::OnDestroy()
    {
    	CView::OnDestroy();
    
    	// TODO: 在此处添加消息处理程序代码
    	HGLRC hrc;
    	hrc = ::wglGetCurrentContext();
    	::wglMakeCurrent(NULL,NULL);
    	if(hrc)
    		::wglDeleteContext(hrc);
    
    	if(pmDC)
    		delete pmDC;
    
    }
    

     这样 我们的上下文及设备就建立完毕,下面可以专注于OpenGL的事情了

    3、OpenGL的初始化

    在stdafx.h添加头文件

    #include "glew.h"
    #include "glut.h"
    

     并通过工程属性设置添加 

    glew32.lib glut.lib glut32.lib  这些就是OpenGL的函数库了

    再次在OnCreate(..)函数中添加 代码初始化 glew和设置OpenGL的环境

    	GLenum err=glewInit();
    	if(GLEW_OK!=err)
    	{
    		return -1;
    	}
    
    	glEnable(GL_TEXTURE_2D);							// Enable Texture Mapping ( NEW )
    	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
    	glClearColor(0.0f, 0.0f,0.0f,1.0f);				// Black Background
    	glClearDepth(1.0f);									// Depth Buffer Setup
    	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
    	glDepthFunc(GL_LESS);								// The Type Of Depth Testing To Do
    	//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	
    	glDisable(GL_BLEND);
    	::glDisable( GL_CULL_FACE );  // 开启表面剔除
    

     

    然后在OnSize函数中添加代码建立投影矩阵和模型矩阵

    	
    
    	// TODO: 在此处添加消息处理程序代码
    	int w=cx;
    	int h=cy;
    	if(h==0)
    		h=1;
    	//设置视口与窗口匹配
    	glViewport(0,0,w,h);
    
    	//重新设置坐标系统
    	//投影矩阵
    	glMatrixMode(GL_PROJECTION);
    	glLoadIdentity();
    	gluPerspective(45.0f,(GLfloat)w/(GLfloat)h,10.0f,100000.0f);
    	//模型矩阵
    	glMatrixMode(GL_MODELVIEW);
    
    	glLoadIdentity();  
    
    	
    
    

      4、完成DrawScreen的接口

    我们希望绘制可以不断被调用,这里运用MFC的OnIdle()函数,(这个函数不懂?详见VC++)

    在MyOpenGL.cpp里的CMyOpenGLApp类中用VS的MFC向导添加重载函数,然后在里面添加如下代码

    BOOL CMyOpenGLApp::OnIdle(LONG lCount)
    {
    	// TODO: 在此添加专用代码和/或调用基类
    	CWinApp::OnIdle(lCount);
    
    	if(CMyOpenGLView::mOpenView)
    	{
    		CMyOpenGLView::mOpenView->DrawScene();
    	}
    	return true;
    }
    

     其中mOPenView是CMyOpenGLView的静态类公共成员

    在类CMyOpenGLView中添加

    static CMyOpenGLView * mOpenView;
    

     并在MyOpenGLView.cpp的头部添加静态成员变量的初始化语句,详见C++静态成员变量初始化 

    CMyOpenGLView * CMyOpenGLView::mOpenView=0;
    

     然后在 OnCreate中再次添加代码

    mOpenView=this;
    

      这样我们在其他类中就可以调用CMyOpenGLView类的自定义成员函数DrawScreen了

    然后在CMyOpenGLApp类的OnIdle()中调用

    5、书写DrawScreen()

    void CMyOpenGLView::DrawScene()
    {
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
    	glMatrixMode(GL_MODELVIEW);	
    	//glLoadIdentity();
    
    	glBegin(GL_TRIANGLES);
    
    	glVertex3f(-10,10,-30);
    	glColor3f(1.0,0.0,0.0);
    
    	glVertex3f(10,10,-30);
    	glColor3f(0.0,1.0,0.0);
    
    	glVertex3f(0,0,-30);
    	glColor3f(0.0,0.0,1.0);
    
    	glEnd();
    
    	SwapBuffers(wglGetCurrentDC());
    }
    

      其意义详见 OpenGL  NeHe教程,以后的绘制函数都可以写在这里了。

    6、是不是大功告成了?但是拖拉窗体时,还会有错误,那是因为MFC默认会用白刷子刷新窗体,

    而OpenGL的SwapBuffers已经帮我们刷新了,所以应该把MFC的禁制掉

    怎么做呢?

    6.1、重载CMyOpenGLView的消息响应函数WM_ERASEBKGND,改为如下形式

    BOOL CMyOpenGLView::OnEraseBkgnd(CDC* pDC)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    return true;
    }
    

    6.2、在OnSize中也调用绘制函数,这样窗体在变形时也能绘制

    DrawScene();
    

     这样就成功了!

     

     

  • 相关阅读:
    20151019
    20151013
    20150810
    20150626
    20150625
    20150530
    HTML特殊字符大全
    label标签跳出循环
    IIS 负载均衡
    .NET代码执行效率优化
  • 原文地址:https://www.cnblogs.com/lydyy/p/4693932.html
Copyright © 2020-2023  润新知