OpenGL学习2

Posted by 蒋波涛 12 August,2006 Views (0)Comment
下面介绍在MFC中进行开发(进入正题了):
1.        OpenGL起步
u       OpenGLOS的窗口系统进行关联
我们早说过,这是很重要的一步,也是一个SDIOpenGL程序在初始化的过程中必须做的工作,因此下面需要介绍一些相关概念:
图形操作描述
  在Windows窗口程序必须首先处理设备描述表(Device ContextsDC),DC包括许多如何在窗口上显示图形的信息,如指定画笔和刷子的颜色,设置绘图模式、调色板、映射模式以及其它图形属性。同样,OpenGL的程序也必须使用DC,这与其它Windows程序类似。但是,OpenGL必须处理特殊的DC渲染描述表,这是DC中专为OpenGL使用的一种“渲染描述表(RC)。一个OpenGL渲染描述表内有OpenGLWindows 窗口系统相关的各种信息。一个OpenGL应用首先必须创建一个渲染描述表,然后再启动它,最后在所定义的窗口内按常规方式调用OpenGL函数绘制图形。
一个渲染描述表RC不同于其它DC,后者调用每个GDI函数都需要一个句柄,而RC方式下只需一个句柄就可以任意调用OpenGL函数。也就是说,只要当前启用了某个渲染描述表,那么在未删除渲染描述表之前可以调用任何OpenGL函数,进行各种操作。在程序中也可以看到,除了在初始化和卸载过程中使用RC外,其余的代码我们几乎没有再遇到过RC
像素格式
  在创建一个图形操作表之前,首先必须设置像素格式。像素格式含有设备绘图界面的属性,这些属性包括绘图界面是用RGBA模式还是颜色表模式,像素缓存是用单缓存还是双缓存,以及颜色位数、深度缓存和模板缓存所用的位数,还有其它一些属性信息。
像素格式结构
  每个OpenGL显示设备都支持一种指定的像素格式。一般用一个名为PIXELFORMATDESCRIPTOR的结构来表示某个特殊的像素格式,这个结构包含26个属性信息。Win32定义PIXELFORMATDESCRIPTOR如下所示:
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;
 
好,了解了这些,我们开始写MFC代码,首先产生一个SDIMFC程序,然后必须引入OpenGL的库,方法与前例相同(这些都不难),然后在StdAfx.h中键入下列的代码:
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>
这样我们就可以在程序的任何地方都使用OpenGL的函数了。
我新建的SDI项目名为COpenGLDemo,在CCOpenGLDemoView类中添加如下方法和变量:
public:
      BOOL InitOpenGL(CDC* pDC);
      void SetLogicalPalette();
      BOOL SetupPixelFormat();
      BOOL RenderScene();
private:
      HPALETTE m_hPalette;
      CDC* m_pDC;
      HGLRC m_hRC;
 
添加完以后,我们必须修改SDI的窗口类型,使之与OpenGL相匹配,这个更改是在窗口产生以前,代码如下(灰色部分):
BOOL CCOpenGLDemoView::PreCreateWindow(CREATESTRUCT& cs)
{
      // TODO: Modify the Window class or styles here by modifying
      // the CREATESTRUCT cs
      cs.style|=WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
 
      return CView::PreCreateWindow(cs);
}
然后该在OnCreate里面进行初始化了,其实这个初始化在OnInitialUpdate中实现也可以,我们就选择前者。添加一个WM_Create的响应函数(这个要是不会的话,您该先看看MFC再来),然后键入代码:
int CCOpenGLDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
      if (CView::OnCreate(lpCreateStruct) == -1)
             return -1;
      // TODO: Add your specialized creation code here
      //产生一个DC
      m_pDC=new CClientDC(this);
      //使用窗口DC来设置RC
      InitOpenGL(m_pDC);            
      //产生一个Timer进程,程序每20ms就产生一个WM_TIMER事件,作用后面讲
      SetTimer(0,20,NULL);    
 
      return 0;
}
上面的代码中我们使用了InitOpenGL函数来对OpenGL进行初始化,其函数具体实现如下:
BOOL CCOpenGLDemoView::InitOpenGL(CDC *pDC)
{
      m_pDC=pDC;
      //设置像素格式
      SetupPixelFormat();
      //产生一个RC
      m_hRC::wglCreateContext(m_pDC->GetSafeHdc());
      //设置该RC为当前使用的RC
      ::wglMakeCurrent(m_pDC->GetSafeHdc(),m_hRC);
      return TRUE;
}
注意上面使用了SetupPixelFormat函数来设置OS的像素格式,该函数详细为:
BOOL CCOpenGLDemoView::SetupPixelFormat()
{
      PIXELFORMATDESCRIPTOR *pfd=new PIXELFORMATDESCRIPTOR();
      pfd->nSize=sizeof(PIXELFORMATDESCRIPTOR);
      pfd->nVersion=1;
      pfd->dwFlags=PFD_DRAW_TO_WINDOW|
             PFD_SUPPORT_OPENGL|
             PFD_DOUBLEBUFFER|
             PFD_STEREO_DONTCARE;
      pfd->iPixelType=PFD_TYPE_RGBA;
      pfd->cColorBits=32;
      pfd->cRedBits=8;
      pfd->cRedShift=16;
      pfd->cGreenBits=8;
      pfd->cGreenShift=8;
      pfd->cBlueBits=8;
      pfd->cBlueShift=0;
      pfd->cAlphaBits=0;
      pfd->cAlphaShift=0;
      pfd->cAccumBits=64;
      pfd->cAccumRedBits=16;
      pfd->cAccumGreenBits=16;
      pfd->cAccumBlueBits=16;
      pfd->cAccumAlphaBits=0;
      pfd->cDepthBits=32;
      pfd->cStencilBits=8;
      pfd->cAuxBuffers=0;
      pfd->iLayerType=PFD_MAIN_PLANE;
      pfd->bReserved=0;
      pfd->dwLayerMask=0;
      pfd->dwVisibleMask=0;
      pfd->dwDamageMask=0;
//选择一个像素索引
      int m_GLPixelIndex=::ChoosePixelFormat(m_pDC->GetSafeHdc(),pfd);
//设置像素索引
      ::SetPixelFormat(m_pDC->GetSafeHdc(),m_GLPixelIndex,pfd);
 
      if (pfd->dwFlags&PFD_NEED_PALETTE)
      {
             SetLogicalPalette();       //有必要的话设置逻辑调色板
      }
      return TRUE;
}
好长一个函数啊,不过主要是一个结构体的设置,关于这个结构体的具体属性,请大家自己去查阅,在设置了一个结构体后,我们选择了一个像素索引并设置为当前像素结构。至于逻辑调色板,其代码如下:
void CCOpenGLDemoView::SetLogicalPalette()
{
      struct 
      {
             WORD Version;
             WORD NumberOfEntries;
             PALETTEENTRY aEntries[256];
      } logicalPalette={0x300,256};
      BYTE reds[]={0,36,72,109,145,182,218,255};
      BYTE greens[]={0,36,72,109,145,182,218,255};
      BYTE blues[]={0,85,170,255};
 
      for (int colorNum=0;colorNum<256;++colorNum)
      {
             logicalPalette.aEntries[colorNum].peRed=reds[colorNum&0x07];
             logicalPalette.aEntries[colorNum].peGreen=greens[(colorNum>>0x03)&0x07];
             logicalPalette.aEntries[colorNum].peBlue=blues[(colorNum>>0x06)&0x03];
             logicalPalette.aEntries[colorNum].peFlags=0;
      }
      m_hPalette=CreatePalette((LOGPALETTE*)&logicalPalette);
}
好了,初始化工作已经全部完成了,让我们再考虑下程序卸载时必须做的内存释放工作,在WM_DESTORY响应函数中设置:
void CCOpenGLDemoView::OnDestroy()
{
      CView::OnDestroy();
     
      // TODO: Add your message handler code here
      //RC与现在的DC脱钩
      ::wglMakeCurrent(NULL,NULL);
      //删除RC
      ::wglDeleteContext(m_hRC);
      //删除DC
      if (m_pDC->GetSafeHdc())
      {
             DeleteObject(m_pDC);
      }
      //删除逻辑调色板
      if (m_hPalette)
      {
             DeleteObject(m_hPalette);
      }
      KillTimer(0);
}
最后的KillTimer(0)是什么?别忘了我们曾经开过一个Timer进程,要关闭啊。
 
可以绘图了吧?现在可以了,我们在OnDraw中键入一个函数:
void CCOpenGLDemoView::OnDraw(CDC* pDC)
{
      CCOpenGLDemoDoc* pDoc = GetDocument();
      ASSERT_VALID(pDoc);
      // TODO: add draw code for native data here
      RenderScene();
}
RenderScene是一个专门的绘制函数:
BOOL CCOpenGLDemoView::RenderScene()
{
      glClearColor(0.0f,0.0f,0.0f,0.0f);
      glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
      glColor3f(0.2f,0.6f,1.0f);
      auxWireSphere(1.0f);
      ::SwapBuffers(m_pDC->GetSafeHdc());
      return TRUE;
}
编译程序,执行,大家可以看到一个黑底的白色圆形图形。

Related Items

Categories : OpenGL Tags : 计算机图形学  OpenGL  
Comments
Leave a comment

Or, take a look at Archives and Categories

目录

存档