转自网上一篇文章,稍有修改。另可参见超级宝典3th的第13章,有详细论述。
 
---- Windows操作系统对OpenGL的支持

在Windows下用GDI作图必须通过设备上下文(Device Context简写DC)调用相应的函数;用OpenGL作图也是类似,OpenGL函数是通过"渲染上下文"(Rendering Context简写RC)完成三维图形的绘制。Windows下的窗口和设备上下文支持"位图格式"(PIXELFORMAT)属性, 和RC有着位图结构上的一致。只要在创建RC时与一个DC建立联系(RC也只能通过已经建立了位图格式的DC来创建),OpenGL的函数就以通过RC对应的DC画到相应的显示设备上。这里还有以下需要注意的方面:

1.一个线程只能拥有一个渲染上下文RC,也就是说,用户如果在一个线程内对不同设备作图,只能通过更换与RC对应的DC来完成,而RC在线程保持不变(当然,删除旧的RC后再创建新的是可以的)。与此对应,一个RC也只能属于一个线程,不能被不同线程同时共享。

2.设定DC位图格式等于设定了相应的窗口的位图格式,并且DC和窗口的位图格式一旦确定就不能再改变。

3.一个RC虽然可以更换DC,在任何时刻只能利用一个DC(这个DC称为RC的当前DC),但由于一个窗口可以让多个DC作图从而可以让多个线程利用多个RC在该窗口上执行OpenGL操作。

4.现在的Windows下的OpenGL版本对OpenGL和GDI在同一个DC上作图有一定的限制。当使用双缓存用OpenGL产生动画时,不能使用GDI函数向该DC作图。
 
5.不建议用ANSI C在Windows下编写OpenGL程序。这样的程序虽然具有跨平台的可移植性(比如很多SGI的例子程序),但是它们不能利用Windows操作系统的很多特性,实用价值不大。

---- 用VC来编写OpenGL程序

经过上面的分析,用VC来调用OpenGL作图的方法就很显然了。步骤如下:

1.先设置显示设备DC的位图格式(PIXELFORMAT)属性。这通过填充一个PIXELFORMATDESCRIPTOR的结构来完成,该结构决定了OpenGL作图的物理设备的属性,比如该结构中的数据项dwFlags中PFD_DOUBLEBUFFER位如果没有设置(置1),通过该设备的DC上作图的OpenGL命令就不可能使用双缓冲来做动画。有一些位图格式(PIXELFORMAT)是DC支持的,而有一些DC就不支持了。所以程序必须先用ChoosePixelFormat来选择DC所支持的与指定位图格式最接近的位图格式,然后用SetPixelFormat设置DC的位图格式。

2.利用刚才的设备DC建立渲染上下文RC(wglCreateContext),使得RC与DC建立联系(wglMakeCurrent)。

3.调用OpenGL函数作图。由于线程与RC一一对应,OpenGL函数的参数中都不指明本线程RC的句柄。

4.作图完毕以后,先通过置当前线程的RC为NULL(::wglMakeCurrent(NULL, NULL);),断开当前线程和该渲染上下文的联系,由此断开与DC的联系。此时RC句柄的有效性在微软自己的文档中也没有讲清楚,所以在后面删除RC的时候要先判断以下RC句柄的有效性(if (m_hrc) ::wglDeleteContext(m_hrc);)。再根据情况释放(ReleaseDC)或者删除(DeleteDC)DC。

---- 程序说明

所附的程序用MFC完成了一个简单的OpenGL作图,用OpenGL的辅助库画了一个有光照的实心圆球。

1.一旦设定一个DC的位图格式,该DC所联系的窗口的位图格式随之设定。该窗口若含有子窗口或者有兄弟窗口,这些兄弟/子窗口的位图格式没有设成与对应RC一致的格式,OpenGL在它们上面作图就容易出错。故而OpenGL作图的窗口必须具有WS_CLIPCHILDREN(创建父窗口使用的Windows风格,用于重绘时裁剪子窗口所覆盖的区域)和WS_CLIPSIBLINGS(创建子窗口使用的Windows风格,用于重绘时剪裁其他子窗口所覆盖的区域)风格。程序中在主框窗的构造函数中用LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,NULL,NULL);指定了主窗口的风格。也可以在PreCreateWindow(CREATESTRUCT& cs)中用cs.style |= (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);来指定。

2.在ANSI C的OpenGL编程中,由auxReshapeFunc定义设置OpenGL视口大小和作图尺寸的回调函数。在MFC中应该由WM_SIZE消息的处理函数来完成。在ANSI C的OpenGL编程中,由EauxMainLoop定义作图的回调函数。在MFC中应该由WM_PAINT消息的处理函数来处理。相应的,OpenGL的键盘、鼠标处理函数都应该由相应的Windows处理函数来响应。

3.OpenGL自己有刷新背景的函数glClear,故而应禁止Windows刷新窗口背景。否则,当窗口需要重画时,Windows会自动先发送WM_ERASEBKGND,而缺省的处理函数使用白色的背景刷。当OpenGL使用的背景颜色不是白色时,作图时有一帧白色的闪烁。这种现象在做动画时特别明显。程序中只需要在WM_ERASEBKGND的消息处理函数中禁止父窗口类的消息处理,简单的返回一个TRUE即可。

4.由于OpenGL的跨平台性,它必须用操作系统的调色板。所以如果GL_INDEX_MODE作图时,必须用VC自己定义调色板。不过一般情况下,用GL_RGBA_MODE模式比较方便,很少用到GL_INDEX_MODE模式。

5.在OpenGL作图期间,RC对应的DC不能删除或者释放。

6.由于OpenGL作图时需要长时间占用DC,所以最好把作图窗口类设成CS_OWNDC。MFC缺省的窗口类风格中没有设这一属性,程序中在主窗口C++类的PreCreateWindow方法中自己注册了一个窗口类,除了设定了CS_OWNDC属性以外,还设定了CS_HREDRAW、CS_VREDRAW 和CS_SAVEBITS。设定CS_HREDRAW、CS_VREDRAW是为了让窗口缩放时产生WM_PAINT消息,修正OpenGL视口和作图尺寸;由于OpenGL作图需要很多计算,设定CS_SAVEBITS是为了在OpenGL窗口被遮盖后显现出来时,不产生WM_PAINT消息,用内存存储的图象来填充,从而用空间消耗换取计算时间。CS_OWNDC很重要,详情见超级宝典第13章。

7.本程序中没有对OpenGL函数的出错情况作出处理。OpenGL出错后返回错误码,不会抛出异常;而且在某一个函数出错以后,后继函数也一般不会出现异常,只是返回错误码,一不小心就可能忽略某些错误。而对每一个OpenGL函数都做出错与否的判断比较麻烦,所以编程序时对OpenGL的函数应当非常小心。

---- 附 程 序:
    
主窗口类定义(OpenGLWnd.h):

s#if !defined(AFX_OPENGLWND_H__3FB1AB28_0E70
_11D2_9ACA_48543300E17D__INCLUDED_)
#define AFX_OPENGLWND_H__3FB1AB28_0E70_11D2
_9ACA_48543300E17D__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#include < afxwin.h >
#include "SimpleGLApp.h"
#include "resource.h"
// OpenGLWnd.h : header file
//
///
//
// COpenGLWnd frame

class COpenGLWnd : public CFrameWnd
{
 DECLARE_DYNCREATE(COpenGLWnd)
public:
 COpenGLWnd(); 
// protected constructor used by dynamic creation
protected:
 HGLRC m_hrc;
 CClientDC *m_pDC;
// Attributes
public:

// Operations
public:

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(COpenGLWnd)
 protected:
 virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
 //}}AFX_VIRTUAL

// Implementation
public:
 virtual ~COpenGLWnd();

// Generated message map functions
 //{{AFX_MSG(COpenGLWnd)
 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
 afx_msg void OnSize(UINT nType, int cx, int cy);
 afx_msg void OnDestroy();
 afx_msg BOOL OnEraseBkgnd(CDC* pDC);
 afx_msg void OnPaint();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};

///
//

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert
additional declarations immediately before the previous line.

#endif // !defined(AFX_OPENGLWND_H__3FB1AB28_
0E70_11D2_9ACA_48543300E17D__INCLUDED_)
主窗口类的实现(OpenGLWnd.cpp):
// OpenGLWnd.cpp : implementation file
//

#include "stdafx.h"
#include "OpenGLWnd.h"
#include "SimpleGLApp.h"
#include "gl\glu.h"
#include "gl\gl.h"
#include "gl\glaux.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///
//
// COpenGLWnd

IMPLEMENT_DYNCREATE(COpenGLWnd, CFrameWnd)

COpenGLWnd::COpenGLWnd()
{
 m_pDC = NULL;
 m_hrc = 0;
 LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW
 | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,NULL,NULL );
}

COpenGLWnd::~COpenGLWnd()
{
}

BEGIN_MESSAGE_MAP(COpenGLWnd, CFrameWnd)
 //{{AFX_MSG_MAP(COpenGLWnd)
 ON_WM_CREATE()
 ON_WM_SIZE()
 ON_WM_DESTROY()
 ON_WM_ERASEBKGND()
 ON_WM_PAINT()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL COpenGLWnd::PreCreateWindow(CREATESTRUCT& cs)
{
 // TODO: Add your specialized code here and/or call the base class
cs.lpszClass = AfxRegisterWndClass( CS_DBLCLKS |
     CS_HREDRAW |
     CS_VREDRAW |
     CS_SAVEBITS |
     CS_NOCLOSE |
                   CS_OWNDC ,AfxGetApp( )-> LoadStandardCursor(IDC_ARROW), 0 ,
AfxGetApp( )->LoadStandardIcon(IDI_APPLICATION));
 return CFrameWnd::PreCreateWindow(cs);
}

int COpenGLWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
  return -1;
 
    int pixelformat;

m_pDC = new CClientDC(this);//在客户区作图
 ASSERT(m_pDC != NULL);

static PIXELFORMATDESCRIPTOR pfd =
 {
        sizeof(PIXELFORMATDESCRIPTOR),  //固定值
        1,                              //固定值
        PFD_DRAW_TO_WINDOW |            // support window
        PFD_SUPPORT_OPENGL |            // support OpenGL
 PFD_DOUBLEBUFFER,  // Double  buffer mode
        PFD_TYPE_RGBA,                  // RGBA模式,不用调色板
        16,                             //程序在16位色彩下运行
        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
    };

if ( (pixelformat = ChoosePixelFormat
(m_pDC- >GetSafeHdc(), &pfd)) == 0 )
    {
        MessageBox("在该DC上找不到与PFD接近的位图结构");
        return -1;
    }

if (SetPixelFormat(m_pDC- >
GetSafeHdc(), pixelformat, &pfd) == FALSE)
    {
        MessageBox("无法在该DC上设置位图结构");
        return -1;
    }
    m_hrc = wglCreateContext(m_pDC- >GetSafeHdc());
    wglMakeCurrent(m_pDC- >GetSafeHdc(), m_hrc);
 
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);

glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
 
    return 0;//OpenGL窗口构造成功
}

void COpenGLWnd::OnSize(UINT nType, int cx, int cy)
{
 CFrameWnd::OnSize(nType, cx, cy);
 
 // TODO: Add your message handler code here
    if(cy > 0)
    {   
        glViewport(0, 0, cx, cy);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
  if (cx < = cy)
    glOrtho(-3.0,3.0,-3.0 * (GLfloat)cx/(GLfloat)cy,
  3.0 * (GLfloat)cx/(GLfloat)cy,-3.0,3.0);
  else
 glOrtho(-3.0,3.0,-3.0 * (GLfloat)cy/(GLfloat)cx,
  3.0 * (GLfloat)cy/(GLfloat)cx,-3.0,3.0);
        glMatrixMode(GL_MODELVIEW);
    }
}

void COpenGLWnd::OnDestroy()
{

CFrameWnd::OnDestroy();
    ::wglMakeCurrent(NULL,  NULL);
    if (m_hrc)
        ::wglDeleteContext(m_hrc);
 if (m_pDC)
        delete m_pDC;
 // TODO: Add your message handler code here
}

BOOL COpenGLWnd::OnEraseBkgnd(CDC* pDC)
{
 // TODO: Add your message
 handler code here and/or call default
 return TRUE;
 //return CFrameWnd::OnEraseBkgnd(pDC);
}

void COpenGLWnd::OnPaint()
{
 CPaintDC dc(this); // device context for painting

GLfloat light_position[]={2.0f,0.0f,4.0f,0.0f};
 
 // TODO: Add your message handler code here

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();

glTranslatef(0.0f, 0.0f, -2.0f);
  glLightfv(GL_LIGHT0,GL_POSITION,light_position);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glDepthFunc(GL_LESS);
  glEnable(GL_DEPTH_TEST);
  auxSolidSphere(1.0);

glPopMatrix();

glFinish();

// Do not call CFrameWnd::OnPaint() for painting messages
}
应用程序类的定义(SimpleGLApp.h):
#if !defined(AFX_SIMPLEGLAPP_H__3FB1AB29
_0E70_11D2_9ACA_48543300E17D__INCLUDED_)
#define AFX_SIMPLEGLAPP_H__3FB1AB29_0E70
_11D2_9ACA_48543300E17D__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// SimpleGLApp.h : header file
//
#include < afxwin.h >
#include "OpenGLWnd.h"
#include "resource.h"

///
//
// CSimpleGLApp thread

class CSimpleGLApp : public CWinApp
{
 DECLARE_DYNCREATE(CSimpleGLApp)
public:
 CSimpleGLApp();
   // protected constructor used by dynamic creation

// Attributes
public:

// Operations
public:

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CSimpleGLApp)
 public:
 virtual BOOL InitInstance();
 virtual int ExitInstance();
 //}}AFX_VIRTUAL

// Implementation
public:
 virtual ~CSimpleGLApp();

// Generated message map functions
 //{{AFX_MSG(CSimpleGLApp)
 afx_msg void OnAppExit();
 //}}AFX_MSG

DECLARE_MESSAGE_MAP()
};

///
//

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert
additional declarations
immediately before the previous line.

#endif // !defined(AFX_SIMPLEGLAPP_H__3FB1AB29_
0E70_11D2_9ACA_48543300E17D__INCLUDED_)
应用程序类的实现(SimpleGLApp.cpp):
// SimpleGLApp.cpp : implementation file
//

#include "stdafx.h"
#include "SimpleGLApp.h"
#include "OpenGLWnd.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///
//
// CSimpleGLApp

IMPLEMENT_DYNCREATE(CSimpleGLApp, CWinApp)

CSimpleGLApp::CSimpleGLApp()
{
}

CSimpleGLApp::~CSimpleGLApp()
{
}

BOOL CSimpleGLApp::InitInstance()
{
 // TODO:  perform and per-thread initialization here
 m_pMainWnd = new COpenGLWnd();
 m_pMainWnd- >ShowWindow(m_nCmdShow);
 m_pMainWnd- >UpdateWindow();
 return TRUE;
}

int CSimpleGLApp::ExitInstance()
{
 return CWinApp::ExitInstance();
}

BEGIN_MESSAGE_MAP(CSimpleGLApp, CWinApp)
 //{{AFX_MSG_MAP(CSimpleGLApp)
 ON_COMMAND(ID_APP_EXIT, OnAppExit)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

///
//
// CSimpleGLApp message handlers
void CSimpleGLApp::OnAppExit()
{
 // TODO: Add your command handler code here
 CWinApp::OnAppExit();
}

CSimpleGLApp SimpleGLApp;

---- Windows操作系统对OpenGL的支持 (另参见超级宝典3th的第13章)

在Windows下用GDI作图必须通过设备上下文(Device Context简写DC)调用相应的函数;用OpenGL作图也是类似,OpenGL函数是通过"渲染上下文"(Rendering Context简写RC)完成三维图形的绘制。Windows下的窗口和设备上下文支持"位图格式"(PIXELFORMAT)属性, 和RC有着位图结构上的一致。只要在创建RC时与一个DC建立联系(RC也只能通过已经建立了位图格式的DC来创建),OpenGL的函数就以通过RC对应的DC画到相应的显示设备上。这里还有以下需要注意的方面:

1.一个线程只能拥有一个渲染上下文RC,也就是说,用户如果在一个线程内对不同设备作图,只能通过更换与RC对应的DC来完成,而RC在线程保持不变(当然,删除旧的RC后再创建新的是可以的)。与此对应,一个RC也只能属于一个线程,不能被不同线程同时共享。

2.设定DC位图格式等于设定了相应的窗口的位图格式,并且DC和窗口的位图格式一旦确定就不能再改变。

3.一个RC虽然可以更换DC,在任何时刻只能利用一个DC(这个DC称为RC的当前DC),但由于一个窗口可以让多个DC作图从而可以让多个线程利用多个RC在该窗口上执行OpenGL操作。

4.现在的Windows下的OpenGL版本对OpenGL和GDI在同一个DC上作图有一定的限制。当使用双缓存用OpenGL产生动画时,不能使用GDI函数向该DC作图。
 
5.不建议用ANSI C在Windows下编写OpenGL程序。这样的程序虽然具有跨平台的可移植性(比如很多SGI的例子程序),但是它们不能利用Windows操作系统的很多特性,实用价值不大。

---- 用VC来编写OpenGL程序

经过上面的分析,用VC来调用OpenGL作图的方法就很显然了。步骤如下:

1.先设置显示设备DC的位图格式(PIXELFORMAT)属性。这通过填充一个PIXELFORMATDESCRIPTOR的结构来完成,该结构决定了OpenGL作图的物理设备的属性,比如该结构中的数据项dwFlags中PFD_DOUBLEBUFFER位如果没有设置(置1),通过该设备的DC上作图的OpenGL命令就不可能使用双缓冲来做动画。有一些位图格式(PIXELFORMAT)是DC支持的,而有一些DC就不支持了。所以程序必须先用ChoosePixelFormat来选择DC所支持的与指定位图格式最接近的位图格式,然后用SetPixelFormat设置DC的位图格式。

2.利用刚才的设备DC建立渲染上下文RC(wglCreateContext),使得RC与DC建立联系(wglMakeCurrent)。

3.调用OpenGL函数作图。由于线程与RC一一对应,OpenGL函数的参数中都不指明本线程RC的句柄。

4.作图完毕以后,先通过置当前线程的RC为NULL(::wglMakeCurrent(NULL, NULL);),断开当前线程和该渲染上下文的联系,由此断开与DC的联系。此时RC句柄的有效性在微软自己的文档中也没有讲清楚,所以在后面删除RC的时候要先判断以下RC句柄的有效性(if (m_hrc) ::wglDeleteContext(m_hrc);)。再根据情况释放(ReleaseDC)或者删除(DeleteDC)DC。

---- 程序说明

所附的程序用MFC完成了一个简单的OpenGL作图,用OpenGL的辅助库画了一个有光照的实心圆球。

1.一旦设定一个DC的位图格式,该DC所联系的窗口的位图格式随之设定。该窗口若含有子窗口或者有兄弟窗口,这些兄弟/子窗口的位图格式没有设成与对应RC一致的格式,OpenGL在它们上面作图就容易出错。故而OpenGL作图的窗口必须具有WS_CLIPCHILDREN(创建父窗口使用的Windows风格,用于重绘时裁剪子窗口所覆盖的区域)和WS_CLIPSIBLINGS(创建子窗口使用的Windows风格,用于重绘时剪裁其他子窗口所覆盖的区域)风格。程序中在主框窗的构造函数中用LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,NULL,NULL);指定了主窗口的风格。也可以在PreCreateWindow(CREATESTRUCT& cs)中用cs.style |= (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);来指定。

2.在ANSI C的OpenGL编程中,由auxReshapeFunc定义设置OpenGL视口大小和作图尺寸的回调函数。在MFC中应该由WM_SIZE消息的处理函数来完成。在ANSI C的OpenGL编程中,由EauxMainLoop定义作图的回调函数。在MFC中应该由WM_PAINT消息的处理函数来处理。相应的,OpenGL的键盘、鼠标处理函数都应该由相应的Windows处理函数来响应。

3.OpenGL自己有刷新背景的函数glClear,故而应禁止Windows刷新窗口背景。否则,当窗口需要重画时,Windows会自动先发送WM_ERASEBKGND,而缺省的处理函数使用白色的背景刷。当OpenGL使用的背景颜色不是白色时,作图时有一帧白色的闪烁。这种现象在做动画时特别明显。程序中只需要在WM_ERASEBKGND的消息处理函数中禁止父窗口类的消息处理,简单的返回一个TRUE即可。

4.由于OpenGL的跨平台性,它必须用操作系统的调色板。所以如果GL_INDEX_MODE作图时,必须用VC自己定义调色板。不过一般情况下,用GL_RGBA_MODE模式比较方便,很少用到GL_INDEX_MODE模式。

5.在OpenGL作图期间,RC对应的DC不能删除或者释放。

6.由于OpenGL作图时需要长时间占用DC,所以最好把作图窗口类设成CS_OWNDC。MFC缺省的窗口类风格中没有设这一属性,程序中在主窗口C++类的PreCreateWindow方法中自己注册了一个窗口类,除了设定了CS_OWNDC属性以外,还设定了CS_HREDRAW、CS_VREDRAW 和CS_SAVEBITS。设定CS_HREDRAW、CS_VREDRAW是为了让窗口缩放时产生WM_PAINT消息,修正OpenGL视口和作图尺寸;由于OpenGL作图需要很多计算,设定CS_SAVEBITS是为了在OpenGL窗口被遮盖后显现出来时,不产生WM_PAINT消息,用内存存储的图象来填充,从而用空间消耗换取计算时间。CS_OWNDC很重要,详情见超级宝典第13章。

7.本程序中没有对OpenGL函数的出错情况作出处理。OpenGL出错后返回错误码,不会抛出异常;而且在某一个函数出错以后,后继函数也一般不会出现异常,只是返回错误码,一不小心就可能忽略某些错误。而对每一个OpenGL函数都做出错与否的判断比较麻烦,所以编程序时对OpenGL的函数应当非常小心。

---- 附 程 序:
    
主窗口类定义(OpenGLWnd.h):

s#if !defined(AFX_OPENGLWND_H__3FB1AB28_0E70
_11D2_9ACA_48543300E17D__INCLUDED_)
#define AFX_OPENGLWND_H__3FB1AB28_0E70_11D2
_9ACA_48543300E17D__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#include < afxwin.h >
#include "SimpleGLApp.h"
#include "resource.h"
// OpenGLWnd.h : header file
//
///
//
// COpenGLWnd frame

class COpenGLWnd : public CFrameWnd
{
 DECLARE_DYNCREATE(COpenGLWnd)
public:
 COpenGLWnd(); 
// protected constructor used by dynamic creation
protected:
 HGLRC m_hrc;
 CClientDC *m_pDC;
// Attributes
public:

// Operations
public:

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(COpenGLWnd)
 protected:
 virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
 //}}AFX_VIRTUAL

// Implementation
public:
 virtual ~COpenGLWnd();

// Generated message map functions
 //{{AFX_MSG(COpenGLWnd)
 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
 afx_msg void OnSize(UINT nType, int cx, int cy);
 afx_msg void OnDestroy();
 afx_msg BOOL OnEraseBkgnd(CDC* pDC);
 afx_msg void OnPaint();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};

///
//

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert
additional declarations immediately before the previous line.

#endif // !defined(AFX_OPENGLWND_H__3FB1AB28_
0E70_11D2_9ACA_48543300E17D__INCLUDED_)
主窗口类的实现(OpenGLWnd.cpp):
// OpenGLWnd.cpp : implementation file
//

#include "stdafx.h"
#include "OpenGLWnd.h"
#include "SimpleGLApp.h"
#include "gl\glu.h"
#include "gl\gl.h"
#include "gl\glaux.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///
//
// COpenGLWnd

IMPLEMENT_DYNCREATE(COpenGLWnd, CFrameWnd)

COpenGLWnd::COpenGLWnd()
{
 m_pDC = NULL;
 m_hrc = 0;
 LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW
 | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,NULL,NULL );
}

COpenGLWnd::~COpenGLWnd()
{
}

BEGIN_MESSAGE_MAP(COpenGLWnd, CFrameWnd)
 //{{AFX_MSG_MAP(COpenGLWnd)
 ON_WM_CREATE()
 ON_WM_SIZE()
 ON_WM_DESTROY()
 ON_WM_ERASEBKGND()
 ON_WM_PAINT()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL COpenGLWnd::PreCreateWindow(CREATESTRUCT& cs)
{
 // TODO: Add your specialized code here and/or call the base class
cs.lpszClass = AfxRegisterWndClass( CS_DBLCLKS |
     CS_HREDRAW |
     CS_VREDRAW |
     CS_SAVEBITS |
     CS_NOCLOSE |
                   CS_OWNDC ,AfxGetApp( )-> LoadStandardCursor(IDC_ARROW), 0 ,
AfxGetApp( )->LoadStandardIcon(IDI_APPLICATION));
 return CFrameWnd::PreCreateWindow(cs);
}

int COpenGLWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
  return -1;
 
    int pixelformat;

m_pDC = new CClientDC(this);//在客户区作图
 ASSERT(m_pDC != NULL);

static PIXELFORMATDESCRIPTOR pfd =
 {
        sizeof(PIXELFORMATDESCRIPTOR),  //固定值
        1,                              //固定值
        PFD_DRAW_TO_WINDOW |            // support window
        PFD_SUPPORT_OPENGL |            // support OpenGL
 PFD_DOUBLEBUFFER,  // Double  buffer mode
        PFD_TYPE_RGBA,                  // RGBA模式,不用调色板
        16,                             //程序在16位色彩下运行
        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
    };

if ( (pixelformat = ChoosePixelFormat
(m_pDC- >GetSafeHdc(), &pfd)) == 0 )
    {
        MessageBox("在该DC上找不到与PFD接近的位图结构");
        return -1;
    }

if (SetPixelFormat(m_pDC- >
GetSafeHdc(), pixelformat, &pfd) == FALSE)
    {
        MessageBox("无法在该DC上设置位图结构");
        return -1;
    }
    m_hrc = wglCreateContext(m_pDC- >GetSafeHdc());
    wglMakeCurrent(m_pDC- >GetSafeHdc(), m_hrc);
 
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);

glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
 
    return 0;//OpenGL窗口构造成功
}

void COpenGLWnd::OnSize(UINT nType, int cx, int cy)
{
 CFrameWnd::OnSize(nType, cx, cy);
 
 // TODO: Add your message handler code here
    if(cy > 0)
    {   
        glViewport(0, 0, cx, cy);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
  if (cx < = cy)
    glOrtho(-3.0,3.0,-3.0 * (GLfloat)cx/(GLfloat)cy,
  3.0 * (GLfloat)cx/(GLfloat)cy,-3.0,3.0);
  else
 glOrtho(-3.0,3.0,-3.0 * (GLfloat)cy/(GLfloat)cx,
  3.0 * (GLfloat)cy/(GLfloat)cx,-3.0,3.0);
        glMatrixMode(GL_MODELVIEW);
    }
}

void COpenGLWnd::OnDestroy()
{

CFrameWnd::OnDestroy();
    ::wglMakeCurrent(NULL,  NULL);
    if (m_hrc)
        ::wglDeleteContext(m_hrc);
 if (m_pDC)
        delete m_pDC;
 // TODO: Add your message handler code here
}

BOOL COpenGLWnd::OnEraseBkgnd(CDC* pDC)
{
 // TODO: Add your message
 handler code here and/or call default
 return TRUE;
 //return CFrameWnd::OnEraseBkgnd(pDC);
}

void COpenGLWnd::OnPaint()
{
 CPaintDC dc(this); // device context for painting

GLfloat light_position[]={2.0f,0.0f,4.0f,0.0f};
 
 // TODO: Add your message handler code here

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();

glTranslatef(0.0f, 0.0f, -2.0f);
  glLightfv(GL_LIGHT0,GL_POSITION,light_position);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glDepthFunc(GL_LESS);
  glEnable(GL_DEPTH_TEST);
  auxSolidSphere(1.0);

glPopMatrix();

glFinish();

// Do not call CFrameWnd::OnPaint() for painting messages
}
应用程序类的定义(SimpleGLApp.h):
#if !defined(AFX_SIMPLEGLAPP_H__3FB1AB29
_0E70_11D2_9ACA_48543300E17D__INCLUDED_)
#define AFX_SIMPLEGLAPP_H__3FB1AB29_0E70
_11D2_9ACA_48543300E17D__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// SimpleGLApp.h : header file
//
#include < afxwin.h >
#include "OpenGLWnd.h"
#include "resource.h"

///
//
// CSimpleGLApp thread

class CSimpleGLApp : public CWinApp
{
 DECLARE_DYNCREATE(CSimpleGLApp)
public:
 CSimpleGLApp();
   // protected constructor used by dynamic creation

// Attributes
public:

// Operations
public:

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CSimpleGLApp)
 public:
 virtual BOOL InitInstance();
 virtual int ExitInstance();
 //}}AFX_VIRTUAL

// Implementation
public:
 virtual ~CSimpleGLApp();

// Generated message map functions
 //{{AFX_MSG(CSimpleGLApp)
 afx_msg void OnAppExit();
 //}}AFX_MSG

DECLARE_MESSAGE_MAP()
};

///
//

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert
additional declarations
immediately before the previous line.

#endif // !defined(AFX_SIMPLEGLAPP_H__3FB1AB29_
0E70_11D2_9ACA_48543300E17D__INCLUDED_)
应用程序类的实现(SimpleGLApp.cpp):
// SimpleGLApp.cpp : implementation file
//

#include "stdafx.h"
#include "SimpleGLApp.h"
#include "OpenGLWnd.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///
//
// CSimpleGLApp

IMPLEMENT_DYNCREATE(CSimpleGLApp, CWinApp)

CSimpleGLApp::CSimpleGLApp()
{
}

CSimpleGLApp::~CSimpleGLApp()
{
}

BOOL CSimpleGLApp::InitInstance()
{
 // TODO:  perform and per-thread initialization here
 m_pMainWnd = new COpenGLWnd();
 m_pMainWnd- >ShowWindow(m_nCmdShow);
 m_pMainWnd- >UpdateWindow();
 return TRUE;
}

int CSimpleGLApp::ExitInstance()
{
 return CWinApp::ExitInstance();
}

BEGIN_MESSAGE_MAP(CSimpleGLApp, CWinApp)
 //{{AFX_MSG_MAP(CSimpleGLApp)
 ON_COMMAND(ID_APP_EXIT, OnAppExit)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

///
//
// CSimpleGLApp message handlers
void CSimpleGLApp::OnAppExit()
{
 // TODO: Add your command handler code here
 CWinApp::OnAppExit();
}

CSimpleGLApp SimpleGLApp;

转载于:https://www.cnblogs.com/tony3d/archive/2006/04/16/376627.html

OpenGL在MFC下编程原理相关推荐

  1. Win32环境下动态链接库(DLL)编程原理

    Win32环境下动态链接库(DLL)编程原理 比较大应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作.其中可能存在一些模块的功能较为通用,在构造其它软件系 ...

  2. MFC下CSocket编程详解

    MFC下CSocket编程详解:  1. 常用的函数和注意事项(详细的函数接口说明请查看MSDN): CSocket::Create 初始化(一般写服务器程序都不要用为好,用下面的 CSocket:: ...

  3. MFC 网络编程小结

    最近对MFC的网络编程方面研究了一下..现在想对学习过程中的问题和一些想法做下总结. 1.现说下socket(套接字)吧,初学者刚看到这个东西的时候一定觉得很神秘,我也一样,现在也只是有一点皮毛的理解 ...

  4. linux系统编程需要什么,若想成为一名Linux下编程高手,必须能对各种系统调用有透彻的了解...

    原标题:若想成为一名Linux下编程高手,必须能对各种系统调用有透彻的了解 什么是系统调用? Linux内核中设置了一组用于实现各种系统功能的子程序,称为系统调用.用户可以通过系统调用命令在自己的应用 ...

  5. Winsock编程原理——面向连接

    Winsock编程原理--面向连接 Windows Sockets使用套接字进行编程,套接字编程是面向客户端/服务器模型而设计的,因此系统中需要客户端和服务器两个不同类型的进程,根据连接类型的不同,对 ...

  6. Socket编程原理概述

    1 问题的引入  UNIX系统的I/O命令集,是从Maltics和早期系统中的命令演变出来的,其模式为打开一读/写一关闭(open-write-read-close).在一个用户进程进行I/O操作时, ...

  7. 量子计算机编程原理简介 和 机器学习

    量子计算机编程原理简介 和 机器学习 本文翻译自D-Wave公司网站 www.dwavesys.com/en/dev-tutorial-intro.html D-wave公司在2007年就声称实现了1 ...

  8. MFC下绘制曲线工具Teechart使用

    Teechart版本为TeeChart.Pro.v5.ActiveX 一.简单应用: 1.    安装完毕之后,给工程添加一个类,选择来自Typelib的MFC 类,选择TeeChart Active ...

  9. TeeChart替代品,MFC下好用的高速绘图控件-(Hight-Speed Charting)

    相关链接: C++ GUI 绘图控件目录 MFC VS2010 使用TeeChart绘图控件 - 之一 - 控件和类的导入 VS2010 使用TeeChart绘图控件 - 之二 - 绘制图形(折线图, ...

最新文章

  1. js 事件流的事件冒泡和事件捕获与阻止事件传播
  2. 第四百一十四节,python常用算法学习
  3. React从入门到精通系列之(12)深入理解JSX
  4. ubuntu11.04 安装sun-java6-jdk_Ubuntu下安装sun-java6-jdk和eclipse
  5. 在Java中使用DOM,SAX和StAX解析器解析XML
  6. C++11 学习笔记 lambda表达式
  7. 576. 出界的路径数
  8. SWIFT4.0学习01 - 函数的命名、调用以及注意事项
  9. php mysql_fetch_array 函数大全,深入探讨PHP mysql_fetch_array()函数
  10. 用于制作app store的截图的工具:Brief Wrapper —— 最便捷的应用商店屏幕快照
  11. Hive新特性reflect函数介绍
  12. Ubuntu 下安装VirtualBox主要步骤及出现的问题的解决方案
  13. 软件开发过程中的环境简介
  14. 机器学习笔记 - 行列式
  15. 在家里赚钱的工作,在家利用互联网赚钱,应该这样干!
  16. 删除linux 中压缩文件
  17. wx网罗系列之翔实:使用C++开发wxWidgets程序
  18. Nexus因异常重启导致OrientDB数据库变为只读的问题修复
  19. 程序员学炒股(4) 早晨十字星靠不靠谱
  20. O037、Rebuild Instance 操作详解

热门文章

  1. Eclipse中错误为 Access restriction 的解决方案
  2. 【Elasticsearch】如何使用minimum_should_match
  3. 【Kafka】kafka消费者参数
  4. 【Spring】Spring lazy-init:bean延迟初始化
  5. 【MySQL】ERROR 1412 (HY000) Table definition has changed, please retry transaction
  6. Spring : @EnableConfigurationProperties注解
  7. 计算机技术在工程施工中的应用,浅析计算机技术及网络在工程施工中的应用
  8. linux拷贝文件时如果想保留文件原有的时间属性,可以使用选项,Linux考试题.doc
  9. 面试必会之LinkedList源码分析
  10. 在Docker中安装和部署MongoDB集群