OpenGL学习2
Posted by
蒋波涛
12 August,2006 Views
(0)Comment
下面介绍在MFC中进行开发(进入正题了):
1. OpenGL起步
u 将OpenGL与OS的窗口系统进行关联
我们早说过,这是很重要的一步,也是一个SDI的OpenGL程序在初始化的过程中必须做的工作,因此下面需要介绍一些相关概念:
图形操作描述
在Windows窗口程序必须首先处理设备描述表(Device Contexts,DC),DC包括许多如何在窗口上显示图形的信息,如指定画笔和刷子的颜色,设置绘图模式、调色板、映射模式以及其它图形属性。同样,OpenGL的程序也必须使用DC,这与其它Windows程序类似。但是,OpenGL必须处理特殊的DC渲染描述表,这是DC中专为OpenGL使用的一种“渲染描述表(RC)”。一个OpenGL渲染描述表内有OpenGL与Windows 窗口系统相关的各种信息。一个OpenGL应用首先必须创建一个渲染描述表,然后再启动它,最后在所定义的窗口内按常规方式调用OpenGL函数绘制图形。
在Windows窗口程序必须首先处理设备描述表(Device Contexts,DC),DC包括许多如何在窗口上显示图形的信息,如指定画笔和刷子的颜色,设置绘图模式、调色板、映射模式以及其它图形属性。同样,OpenGL的程序也必须使用DC,这与其它Windows程序类似。但是,OpenGL必须处理特殊的DC渲染描述表,这是DC中专为OpenGL使用的一种“渲染描述表(RC)”。一个OpenGL渲染描述表内有OpenGL与Windows 窗口系统相关的各种信息。一个OpenGL应用首先必须创建一个渲染描述表,然后再启动它,最后在所定义的窗口内按常规方式调用OpenGL函数绘制图形。
一个渲染描述表RC不同于其它DC,后者调用每个GDI函数都需要一个句柄,而RC方式下只需一个句柄就可以任意调用OpenGL函数。也就是说,只要当前启用了某个渲染描述表,那么在未删除渲染描述表之前可以调用任何OpenGL函数,进行各种操作。在程序中也可以看到,除了在初始化和卸载过程中使用RC外,其余的代码我们几乎没有再遇到过RC。
像素格式
在创建一个图形操作表之前,首先必须设置像素格式。像素格式含有设备绘图界面的属性,这些属性包括绘图界面是用RGBA模式还是颜色表模式,像素缓存是用单缓存还是双缓存,以及颜色位数、深度缓存和模板缓存所用的位数,还有其它一些属性信息。
在创建一个图形操作表之前,首先必须设置像素格式。像素格式含有设备绘图界面的属性,这些属性包括绘图界面是用RGBA模式还是颜色表模式,像素缓存是用单缓存还是双缓存,以及颜色位数、深度缓存和模板缓存所用的位数,还有其它一些属性信息。
像素格式结构
每个OpenGL显示设备都支持一种指定的像素格式。一般用一个名为PIXELFORMATDESCRIPTOR的结构来表示某个特殊的像素格式,这个结构包含26个属性信息。Win32定义PIXELFORMATDESCRIPTOR如下所示:
每个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;
{
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代码,首先产生一个SDI的MFC程序,然后必须引入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
Comments
Leave a comment
Or, take a look at Archives and Categories