Windows NT 的OpenGL编程:入门(译)

本文来自MSDN的

Windows NT OpenGL: Getting Started

个人感觉对OpenGL编程有点用处,所以翻译了一下。虽说是Windows NT系统,但是对于这个Windows的OpenGL编程,个人感觉还是有不少帮助的。这些都是根据笔者自己的理解来翻译的,所以仅供参考,在翻译的过程中肯定有很多不足之处,就算是抛砖引玉吧,希望能有更好的译文。关于文章中多次提到的OpenGL例程,可以到此链接下载http://download.csdn.net/source/239316


Dennis Crain
Microsoft Developer Network Technology Group

Created: April 30, 1994

摘要:

OpenGL,工业标准的三维图形接口软件,现在已经成为了Windows NT 3.5 系统中的一部分。作为一个独立于硬件的接口软件,操作系统需要为其提供象素格式和渲染上下文的管理函数。为此,Windows NT提供了通用GDIDC。本文详细介绍了GDI和DC的应用,基于NT系统的OpenGL函数,以及在使用OpenGL函数向相关设备绘图之前所要做的一些前期工作。

 

引言:

我们知道3D图形成为MS操作系统的一部分只是时间问题,现在终于实现了,WindowsNT3.5包括OpenGL .那么什么是OpenGL呢?其原先是由Silicom Graphics 公司开发的一种工业标准的3D图形软件接口.它提供了大约120种函数用来在各种模式下绘制各种不同的图元,包括点,线,多边形.通过OpenGL你可以绘制出高质量的,生动地3D彩色图形.你对OpenGL还不是相当的熟练,对吗?如果你感觉自己还没有达到这种程度,那么去书店买本<OpenGL编程指南>和<OpenGL参考手册>吧.这两本书都是由OpenGLArchitecture Review Board 所著,如果想用OpenGL的话,最好看下这两本书.(这些书的ISBN号码可以看文章后面的参考文献)

这篇文章适合任何对OpenGL/NT感兴趣的人,不管你是已经写过几年的OpenGL程序还是刚刚接触OpenGLOpenGL是独立于硬件的3D图形接口软件,所以它的函数库里面没有初始化和管理设备显示的函数,这是包含OpenGL的操作系统的任务。因此,不管你有没有OpenGL的编程经验,任何一个新接触OpenGL的人都需要了解Windows NT的操作细节。

至此,你的希望也许会破灭,你可能一直在寻找的是一些描述如何产生3D图形的书籍。不要感到沮丧,以后的书籍将会对此进行详细的描述,正如所说的“在学会跑之前你得学会走”,每一个使用OpenGL的人都需要清楚在设备显示上如何得到3D图像。

这篇文章将频繁的讨论象素格式和渲染上下文的操作,这些操作将会提供OpenGL和硬件之间的有效的连接。在Windows NT系统中提供了两种这样的连接机制---------象素格式的操作API函数和WGL API函数,WGL API函数主要用来管理OpenGL的渲染上下文。

MYGL:一个简单的OpenGL/NT应用程序

MYGL是一个用VC编写的简单的OpenGL/NT的应用程序。类COpenGL封装了WGL和象素格式的API函数,并且为OpenGL/NT应用程序提供了大量实用的函数。本文用到的一些代码事例都来自于MYGLMYGL的接口函数允许你调用设置窗口的象素格式(MYGL是个SDI应用程序),显示象素格式,并且查询当前象素格式的性质。

通用格式和设备格式的比较

理解一种新事物的体系结构是很有用的,从开发者的角度来看,很好的理解其结构可以使开发过程变得容易,设计和应用思路也将变得相当的清晰。下面显示的就是OpenGL/NT的结构流程图:

                                1 OpenGL/NT的结构图

在你看到这里的时候,如果对这些结构理解不是很好,没关系,后面还会有详细的介绍。在你看这篇文章的时候,也许你还会反复的回头来看这一节。

如果你有一台像我的那台老古董式的机器,OpenGL应用程序所用的就是通用格式。所有的象素格式,双缓存和渲染上下文的控制操作都是通过OpenGL函数库和GDI来实现的。

如果你的机器的视频显示设备支持OpenGL的话,那么对于OpenGL函数的图形显示都将通过视频显示设备的驱动程序来完成,驱动程序将封装这些OpenGL和WGL函数来直接和硬件交互,驱动程序将连接包含分派函数,OpenGL代码和一些底层画图函数的库,这将使画图速度加快。下图2描述的是通用格式和设备格式之间的不同之处。

图2 通用格式和设备格式

为了进一步的描述两者之间的不同,我们来看一个新的有关象素格式的API 函数:

DescribePixelFormat

DescribePixelFormat函数包含了所被设备的象素格式的信息,这些信息包括诸如颜色位面板的数量,象素数据的类型等等(象素格式将在后面作详细讨论)。当一应用程序调用DescribePixelFormat函数的时候(此函数在GDI32.DLL),在通用格式情况下,函数读取象素格式索引表,快速执行大约300行代码,并根据索引表填充一个PIXELFORMATDESCRIPTOR结构表,函数的返回值为通用象素格式变量的最多数量。在设备格式下,象素格式索引表和设备格式的变量数目进行比较。如果象素格式是设备支持型的,其将会调用驱动程序的函数DrvDescribePixelFormat,因此DescribePixelFormat的返回值为通用格式和设备格式的变量的总和。

在没有涉及到通用格式的一些受限功能,我们讨论的这种格式还没有完。下面列出一些其限制功能,这些是从Windows NT OpenGL帮助文档中摘抄下来的。

     打印受限

在单色打印机中,应用程序不能直接打印OpenGL图像,即使有一个工作区应付这种情况。而在每象素提供4位或更多位的色彩信息的彩色打印机中,应用程序可以直接打印OpenGL图像

     在双缓存窗口中,OpenGLGDI图像不能混合显示

应用程序可以在单缓存的窗口中直接绘制OpenGLGDI图像,但是却不能够在双缓存的窗口中实现这样的功能

     没有窗口硬件调色板

Windows NT 有个单独的硬件调色板系统,它映射到这个显示屏幕上。一个OpenGL窗口没有它自己的硬件调色板,只有一个逻辑调色板。为了产生相应的硬件调色板,其需要变换成应用程序可识别的调色板。

     不直接支持剪切板,DDE,图元文件和OLE

包含OpenGL图像的窗口不直接支持Windows NT 这些性能,不过对于剪切板有一个专门的工作区。

     不包含Inventor 2.0 C++ 类库

Inventor 类库比OpenGL高层一点,其提供更高层次结构的3D图形编程,在Windows NTOpenGL1.0类库中不包含Inventor的类库。

     不支持象素格式的一些功能:覆盖和衬垫层,立体图像,alpha通道位面板和辅助缓存

但其支持其他的一些辅助型缓存:模版缓存,积累缓存,双缓存和深度缓存。

象素格式的管理

OpenGL的帧缓存是指所有被OpenGL所使用到的各种类型的缓存,这些缓存包括:颜色缓存,深度缓存,模版缓存以及积累缓存。颜色缓存包括象素值,这个数值可以是颜色索引值(不要将其解释为Windows的调色板),也可以是RGBA值。深度缓存包括每个象素的深度值,象素有更大的深度值则为“更深”,在显示屏幕上同一位置有两个不同深度的象素值是,深度值小的象素将覆盖掉深度值大的象素。模版缓存映射图形显示的屏幕位置。积累缓存主要用来积聚大量的图像象素来形成一个合成的图像。

在通用格式下,OpenGL/NT经常使用这些缓存,支持单双缓存,深度缓存,模版缓存和积累缓存,但是不支持立体缓存。为了更高效率的使用这些缓存,需要设定象素格式。每个使用OpenGL的窗口都有一个象素格式。下面将描述它的结构,功能和象素格式的一些操作。

PIXELFORMATDESCRIPTOR

下面这个PIXELFORMATDESCRIPTOR结构用来表示Windows NT下的象素格式。介绍一下在通用格式下这个结构的使用情况。硬件设备厂商也许会提高OpenGL的一些性能,支持一些在通用格式下不支持的象素格式的特性。

typedef struct tagPIXELFORMATDESCRIPTOR

{

    WORD  nSize;                  //sizeof(PIXELFORMATDESCRIPTOR)

    WORD  nVersion;               //1

    DWORD dwFlags;

    BYTE  iPixelType;             //rgba or color indexed

    BYTE  cColorBits;             //# of color bitplanes

    BYTE  cRedBits;               //# red bitplanes

    BYTE  cRedShift;              //shift count for red bitplanes

    BYTE  cGreenBits;             //# green bitplanes

    BYTE  cGreenShift;            //shift count for green bitplanes

    BYTE  cBlueBits;              //# blue bitplanes

    BYTE  cBlueShift;             //shift count for blue bitplanes

    BYTE  cAlphaBits;             //not used in generic format

    BYTE  cAlphaShift;            //not used in generic format

    BYTE  cAccumBits;             //total # accum buffer bitplanes

    BYTE  cAccumRedBits;          //# red bitplanes in accum buffer

    BYTE  cAccumGreenBits;        //# green bitplanes in accum buffer

    BYTE  cAccumBlueBits;         //# blue bitplanes in accum buffer

    BYTE  cAccumAlphaBits;        //# alpha bitplanes in accum buffer

    BYTE  cDepthBits;             //depth of depth (z) buffer

    BYTE  cStencilBits;           //depth of stencil buffer

    BYTE  cAuxBuffers;            //not used in generic format

    BYTE  iLayerType;             //PFD_MAIN_PLANE only in generic format

    BYTE  bReserved;              //must be 0

    DWORD dwLayerMask;

    DWORD dwVisibleMask;

    DWORD dwDamageMask;

} PIXELFORMATDESCRIPTOR;

下面是摘自OpenGL/NT的帮助文档,描述了PIXELFORMATDESCRIPTOR各成员变量。这些内容有点长,但是对于了解象素格式和渲染上下文有很大的帮助,所以如果你不熟悉PIXELFORMATDESCRIPTOR结构的话,最好仔细的阅读一下。

Member

Description

nSize

Specifies the size of this data structure. This value should be set to sizeof(PIXELFORMATDESCRIPTOR).

nVersion

Specifies the version of this data structure. This value should be set to 1.

dwFlags

A set of bit flags that specify properties of the pixel buffer. The properties are generally not mutually exclusive. The following bit flag constants are defined:

Value

Meaning

PFD_DRAW_TO_WINDOW

The buffer can draw to a window or device surface.

PFD_DRAW_TO_BITMAP

The buffer can draw to a memory bitmap.

PFD_SUPPORT_GDI

The buffer supports GDI drawing. This flag and PFD_DOUBLEBUFFER are mutually exclusive in the release 1.0 generic implementation.

PFD_SUPPORT_OPENGL

The buffer supports OpenGL drawing.

PFD_GENERIC_FORMAT

The pixel format is supported by the GDI software implementation. That implementation is also known as the generic implementation. If this bit is clear, the pixel format is supported by a device driver or hardware.

PFD_NEED_PALETTE

The buffer uses RGBA pixels on a palette-managed device. A logical palette is required to achieve the best results for this pixel type. Colors in the palette should be specified according to the values of the cRedBits, cRedShift, cGreenBits, cGreenShift, cBluebits, and cBlueShift members. The palette should be created and realized in the device context (DC) before calling wglMakeCurrent.

PFD_DOUBLEBUFFER

The buffer is double-buffered. This flag and PFD_SUPPORT_GDI are mutually exclusive in the release 1.0 generic implementation.

PFD_STEREO

The buffer is stereoscopic. This flag is not supported in the release 1.0 generic implementation.

PFD_NEED_SYSTEM_PALETTE

This flag is used by OpenGL hardware that supports only one hardware palette. To use hardware accelerations in such hardware, the hardware palette has to be in a fixed order (for example, 3-3-2 ) in RGBA mode or match the logical palette in color index mode. The current PFD_NEED_PALETTE flag does not have such a requirement. That is, if only PFD_NEED_PALETTE is set, an application can use a logical 3-3-2 palette; the logical-to-system-palette mapping is performed by the system. The system palette may not be 3-3-2 and may not have all the logical palette colors. However, if PFD_NEED_SYSTEM_PALETTE is set, an application should take over the system palette by calling SetSystemPaletteUse to force a 1-1 logical-to-system-palette mapping. If an application chooses to ignore PFD_NEED_SYSTEM_PALETTE because it does not want to mess up desktop colors, it will not get maximum performance but it should still work.

The PFD_NEED_SYSTEM_PALETTE flag is not needed if the OpenGL hardware supports multiple hardware palettes and the driver can allocate spare hardware palettes for OpenGL.

The generic pixel formats do not have this flag set.

 

另外在调用函数ChoosePixelFormat的时候,下面的位标志可以被设置

Value

Meaning

PFD_DOUBLE_BUFFER_DONTCARE

The requested pixel format can be either single- or double-buffered.

PFD_STEREO_DONTCARE

The requested pixel format can be either monoscopic or stereoscopic.

iPixelType

Specifies the type of pixel data. The following types are defined:

Value

Meaning

PFD_TYPE_RGBA

RGBA pixels. Each pixel has four components: red, green, blue, and alpha.

PFD_TYPE_COLORINDEX

Color index pixels. Each pixel uses a color index value

cColorBits

Specifies the number of color bitplanes in each color buffer. For RGBA pixel types, it is the size of the color buffer excluding the alpha bitplanes. For color index pixels, it is the size of the color index buffer.

cRedBits

Specifies the number of red bitplanes in each RGBA color buffer.

cRedShift

Specifies the shift count for red bitplanes in each RGBA color buffer.

cGreenBits

Specifies the number of green bitplanes in each RGBA color buffer.

cGreenShift

Specifies the shift count for green bitplanes in each RGBA color buffer.

cBlueBits

Specifies the number of blue bitplanes in each RGBA color buffer.

cBlueShift

Specifies the shift count for blue bitplanes in each RGBA color buffer.

cAlphaBits

Specifies the number of alpha bitplanes in each RGBA color buffer. Alpha bitplanes are not supported in the release 1.0 generic implementation.

cAlphaShift

Specifies the shift count for alpha bitplanes in each RGBA color buffer. Alpha bitplanes are not supported in the release 1.0 generic implementation.

cAccumBits

Specifies the total number of bitplanes in the accumulation buffer.

cAccumRedBits

Specifies the number of red bitplanes in the accumulation buffer.

cAccumGreenBits

Specifies the number of green bitplanes in the accumulation buffer.

cAccumBlueBits

Specifies the number of blue bitplanes in the accumulation buffer.

cAccumAlphaBits

Specifies the number of alpha bitplanes in the accumulation buffer.

cDepthBits

Specifies the depth of the depth (z-axis) buffer.

cStencilBits

Specifies the depth of the stencil buffer.

cAuxBuffers

Specifies the number of auxiliary buffers. Auxiliary buffers are not supported in release 1.0 of the generic implementation.

iLayerType

Specifies the type of layer. Although the following values are defined, version 1.0 supports only the main plane (there is no support for overlay or underlay planes):

Value

Meaning

PFD_MAIN_PLANE

The layer is the main plane.

PFD_OVERLAY_PLANE

The layer is the overlay plane.

PFD_UNDERLAY_PLANE

The layer is the underlay plane.

bReserved

Not used. Must be zero.

dwLayerMask

Specifies the layer mask. The layer mask is used in conjunction with the visible mask to determine if one layer overlays another.

dwVisibleMask

Specifies the visible mask. The visible mask is used in conjunction with the layer mask to determine if one layer overlays another. If the result of the bitwise AND of the visible mask of a layer and the layer mask of a second layer is nonzero, then the first layer overlays the second layer, and a transparent pixel value exists between the two layers. If the visible mask is 0, the layer is opaque.

dwDamageMask

Specifies whether more than one pixel format shares the same frame buffer. If the result of the bitwise AND of the damage masks between two pixel formats is nonzero, then they share the same buffers.

 

 

象素格式

一般的OpenGL/NT应用支持24种象素格式,尽管每种象素格式被标以1-24,但他们不是常数,所以不要依靠这些索引号的顺序来加以判别。象素格式有以下几种特性:

         Figure 3. Pixel format properties

象素格式的基本单位是每象素多少位(BPP),其支持五种位面板,包括32BPP24BPP16BPP8BPP4BPP。根据显示驱动设置的BPP,定义了八种象素格式,这些都是本地象素格式。其他16种象素格式被均匀的分配在其他的位面板中,并且都支持位图格式的图形。象素格式由象素类型(RGBA或颜色索引值),缓存(单或双缓存),以及深度缓存的深度值(3216)。由此,我们可以得到40种通用格式,但是,16种非本地格式将被忽略,因为他们对于双缓存的位图没有实际意义。表一列出了所有本地格式。

Table 1. Native Pixel Formats

Bits/Pixel

Pixel Type

Buffering

Depth (z) buffer

native

PFD_TYPE_RGBA

Single

32

native

PFD_TYPE_RGBA

Single

16

native

PFD_TYPE_RGBA

Double

32

native

PFD_TYPE_RGBA

Double

16

native

PFD_TYPE_COLORINDEX

Single

32

native

PFD_TYPE_COLORINDEX

Single

16

native

PFD_TYPE_COLORINDEX

Double

32

native

PFD_TYPE_COLORINDEX

Double

16

 

表二列出了其他的象素格式,这些非本地BPP格式被反复提起。

Table 2. Non-Native Pixel Formats

Bits/Pixel

Pixel Type

Buffering

Depth (z) buffer

non-native

PFD_TYPE_RGBA

Single

32

non-native

PFD_TYPE_RGBA

Single

16

non-native

PFD_TYPE_COLORINDEX

Single

32

non-native

PFD_TYPE_COLORINDEX

Single

16

 

枚举象素格式

枚举象素格式对于找到一个和应用程序相匹配的象素格式是很有必要的,而应用程序也有必要寻找一个合适的象素格式。MYGL查询的是本地象素格式,象素格式通过两个按钮来查询,一个用来增加象素格式的索引号,一个用来减小象素格式的索引号。下面一段代码是MYGL中的PIXFORM.CPP文件的,其主要是用来枚举象素格式,变量m_nNextID是象素格式的索引值。

void CPixForm::OnClickedLastPfd()

{

  COpenGL gl;

  PIXELFORMATDESCRIPTOR pfd;

  //

  //Get the hwnd of the view window.

  //

  HWND hwndview = GetViewHwnd();

  //

  //Get a DC associated with the view window.

  //

  HDC   hdc   = ::GetDC(hwndview);

  int nID = (m_nNextID > 1) ?  m_nNextID-- : 1;

  //

  //Get a description of the pixel format. If it is valid, then go and

  //update the controls in the dialog box, otherwise do nothing.

  //

  if (gl.DescribePixelFormat(hdc, nID, sizeof(PIXELFORMATDESCRIPTOR), &pfd))

    UpdateDlg(&pfd);

  //

  //Release the DC.

  //

  ::ReleaseDC(hwndview, hdc);

 

象素格式函数

下表三种的四个函数用来操作控制象素格式

Table 3. Pixel Format Functions

Win32 Function

Description

ChoosePixelFormat

Obtains a device context's pixel format that is the closest match to a specified pixel format.

SetPixelFormat

Sets a window’s or bitmap’s current pixel format to the pixel format specified by a pixel format index.

GetPixelFormat

Obtains the pixel format index of a window’s or bitmap’s current pixel format.

DescribePixelFormat

Given a device context and a pixel format index, fills in a PIXELFORMATDESCRIPTOR data structure with the pixel format's properties

 

图四是描述这些函数调用的一般型方法。

Figure 4. Calling pixel format functions

应用程序一般都会使用双缓存来显示图形,或支持GDI,这是上图 PIXELFORMATDESCRIPTOR方框的象素格式的类型。应用程序通过调用ChoosePixelFormat函数来寻找最接近应用程序所设置的象素格式(通用格式或者设备格式),或者直接调用它本身的象素格式的匹配函数。下面描述ChoosePixelFormat函数是如何寻找这种合适的象素格式的。

     首先,试着查找一个满足设定值的象素格式,这些象素格式的设定值如下:

PFD_DRAW_TO_WINDOW
  PFD_DRAW_TO_BITMAP
  PFD_SUPPORT_GDI
  PFD_SUPPORT_OPENGL

PFD_TYPE_RGBA
  PFD_TYPE_COLORINDEX
  PFD_DOUBLEBUFFER
  PFD_STEREO

     然后在下面特性中寻找最匹配的值:

  cColorBits
  cAlphaBits
  cAccumBits
  cDepthBits
  cStencilBits
  cAuxBuffers
  iLayerType

●最后,设备象素格式将优先于通用象素格式。

一旦拥有一个合适的象素格式,调用SetPixelFormat函数来设置象素格式值。如果函数是被窗口的设备上下文调用,那么也可以改变窗口的象素格式。窗口象素格式值只能设置一次,如果设置次数过多的话,将会使窗口的管理和多线程的应用程序变得很复杂。

确定格式类型

确定象素格式是通用型还是设备型是很简单的一件事情,下面一段代码通过查询PIXELFORMATDESCRIPTOR结构的dwFlags值来确定象素格式的类型。

BOOL COpenGL::IsDeviceIndex(HDC hdc, int idx)

{

  ASSERT (hdc);

  ASSERT (idx > 0);

 

  BOOL bRet = FALSE;

  PIXELFORMATDESCRIPTOR pfd;

  int ipfdmax = DescribePixelFormat(hdc, idx, sizeof(PIXELFORMATDESCRIPTOR),

                &pfd);

 

  if (!(pfd.dwFlags & PFD_GENERIC_FORMAT))

    bRet = TRUE;

  return (bRet);

}

 

如果PFD_GENERIC_FORMAT位被设置,那么象素格式就是通用型的。判断象素格式是本地还是非本地索引也是件很容易的事情。下面一段代码就是实现了这个功能。

BOOL COpenGL::IsNativeIndex(HDC hdc, int idx)

{

  ASSERT (hdc);

  ASSERT (idx > 0);

 

  BOOL bRet = FALSE;

  PIXELFORMATDESCRIPTOR pfd;

  int ipfdmax = DescribePixelFormat(hdc, idx, sizeof(PIXELFORMATDESCRIPTOR),

                &pfd);

 

  if (pfd.dwFlags & PFD_DRAW_TO_WINDOW)

    bRet = TRUE;

  return (bRet);

}

 

如果变量dwFlags被设置为PSD_DRAW_TO_WINDOW,那么象素格式就是本地的,它也许是通用型或是设备型的象素格式,如果没有设置PSD_DRAW_TO_WINDOW,则其为非本地的象素格式并且支持位图格式的图形。

OpenGL和设备上下文

当你开始在OpenGL/NT中使用设备上下文的时候,需要记住两件事:

一旦窗口象素格式被设定(通过窗口DC调用SetPixelFormat),则不能够再重新设置。

    用来创建渲染上下文(Rendering Context)的设备上下文(DC)都可以被释放或者删除,所有返回的或者是生成的DC都有各自相关的象素格式索引值。

获取当前设置的象素格式的索引值,可以通过调用GetPixelFormat函数来实现,这个函数在MYGL中调用了好几次,下面一段代码描述了它的用法,来自于COPENGL.CPP文件。

int COpenGL::GetCurPFDIndex()

{

  int icuridx = GetPixelFormat(wglGetCurrentDC());

  return (icuridx);

 

}

在这段代码中,函数GetPixelFormat被用来获取当前DC的象素格式的索引值,把索引值传给DescribePixelFormat函数就可以得到更多关于象素格式的信息。

 

如果想获得当前DC所支持的设备象素格式数量的最大值,可以调用DescribePixelFormat函数,下面代码中,DescribePixelFormat函数的返回值赋给变量ipfdmax

int COpenGL::GetMaxPFIndex(HDC hdc)

{

  PIXELFORMATDESCRIPTOR pfd;

 

  int ipfdmax = DescribePixelFormat(hdc, 1, sizeof(PIXELFORMATDESCRIPTOR),

                &pfd);

 

  return (ipfdmax);

}

设备格式的总数为:iDevMax=ipfdmax -24

 

OpenGL/NT 的渲染上下文

关于渲染上下文有以下三点需要注意一下:

     在产生渲染上下文之前必须首先设置好象素格式的值

     在调用OpenGL函数之前,渲染上下文必须和设备上下文相关联(调用wglMakeCurrent函数)。

     在产生渲染上下文之后,设备上下文应给被释放或者删除(除非DC所属窗口的类型是CS_OWNDC.

一个OpenGL的渲染上下文由这几部分组成:指向OpenGL/NT驱动程序的句柄(如果存在的话),用户句柄(HGLRC),当前象素格式的索引值,进程ID,指向与渲染上下文相关的设备上下文(DC)的句柄。

表四中有五个函数用来操作渲染上下文。

Table 4. OpenGL/NT Rendering Context Functions (WGL Functions)

WGL Function

Description

wglCreateContext

Creates a new rendering context.

wglMakeCurrent

Sets a thread's current rendering context.

wglGetCurrentContext

Obtains a handle to a thread's current rendering context.

wglGetCurrentDC

Obtains a handle to the device context that is associated with a thread's current rendering context.

wglDeleteContext

Deletes a rendering context.

 

 很显然,这些函数都是很有用的,函数wglMakeCurrent将会让你感到很困惑,这个函数可以使所有的绘图工作都在DC上进行,它使用户渲染上下文成为访问进程的当前渲染上下文,所有的OpenGL 命令都是通过这个当前渲染上下文来实现的。有关这些函数更详细的介绍,可以参考OpenGL/NT 的文档。

 一般,应用程序先调用函数wglCreateContext,然后调用函数wglMakeCurrent使渲染上下文和设备显示相联系,因此OpenGL 的绘图操作都可以在设备显示上完成。完成绘图以后,通过再一次调用函数wglMakeCurrent(参数设置为NULL)可以使渲染上下文释放DC,最后调用函数wglDeleteContext来删除渲染上下文。

设备上下文与渲染上下文的协同工作

  正如你所看到的,设备上下文(包括象素格式)和渲染上下文联系很紧密,那么它们是如何协同工作的呢?他们首先开始于设备上下文。

DC用来产生OpenGL 的渲染上下文,OpenGL使用这个渲染上下文在DC上绘图,最后DC把图形绘制在设备显示上。关于DC的使用有两种方式,分别如图五,图六所示。在图五当中,在应用程序初始化的时候产生DC,在程序结束的时候删除DC。在一个框图范围内我们并没有成对的使用GetDC/CreateDCReleaseDC/DeleteDC,你也许对此感到很困惑,但是,是的,我们已经习惯了。

Figure 5. First approach to use of device contexts with OpenGL

不过那也不是必须的,你也可以根据自己的习惯在使用DC之后马上删除它,图六所示的就是这种情况。在响应WM_CREATE消息的时候产生渲染上下文,并且马上释放或删除用来产生渲染上下文的DC。但是直到响应WM_PAINT消息的时候才把渲染上下文和此时的绘图DC联系在一起。需要注意的一点是,使用这这种方式是很不划算的,设置一个当前上下文是很重要的。有一点要注意的就是在OpenGL绘图功能有效之前需要渲染上下文绑定好设备上下文,你有权力决定在哪并且用哪种DC来绑定渲染上下文(只要这个DC和产生这个渲染上下文的DC具有同样的象素格式)。

Figure 6. Second approach to use of device contexts with OpenGL

Windows NT 3.5 中的SDK的OpenGL的例程中(GENGL)使用的是第一种方式,MYGL也是使用的第一种方式,尽管有一些小小的改动。渲染上下文在用户在对话框中输入的时候产生,当对话框消失的时候,视窗的句柄用来获取DC和设备上下文,当视窗消失的时候,渲染上下文也被删除。

有一个小问题将会阻止你设置设备上下文的象素格式,在使用OpenGL进行绘图之前,需要设置窗口的类型属性中的WS_CLIPCHILDRENWS_CLIPSIBLINGS,否则函数SetPixelFormat的调用将失败。下面一段代码显示的是在函数PreCreateWindow中设置这些窗口属性,这段源码来自于MYGLVIEW.CPP

BOOL CMyglView::PreCreateWindow(CREATESTRUCT& cs)

{

  //The view window style bits must include WS_CLIPSIBLINGS and

  //WS_CLIPCHILDREN so that the wgl functions will work.

  //

  cs.style = cs.style | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

 

  return CView::PreCreateWindow(cs);

}

当用户在选择象素格式的对话框(CPIXFORM.CPP)中输入PIXELFORMATDESCRIPTOR结构的初始值之后,按下OK按钮,然后响应函数OnOK被调用。在确认渲染上下文存在,并且有合适的象素格式的时候,下面一段代码被调用来设置象素格式并且产生渲染上下文。(COPENGL.CPP  MYGL

BOOL COpenGL::GetGLRC(HDC hdc)

{

   BOOL bRet = TRUE;

 

   ASSERT (m_pPixFmtDesc);

 

   if (SetupPixelFormat(hdc, m_pPixFmtDesc))

   {

     if ((m_hglrc = wglCreateContext(hdc)) != NULL)

     {

       if (!wglMakeCurrent(hdc, m_hglrc))

       {

         wglDeleteContext(m_hglrc);

         bRet = FALSE;

       }

     }

     else bRet = FALSE;

   }

   else

     bRet = FALSE;

 

   return bRet;

}

 

一旦DC的象素格式被设置,就可以调用函数wglCreateContext来产生一个渲染上下文,如果渲染上下文成功创建的话,它就会和当前DC绑定在一起,注意此时DC没有被释放,直到MYGL关闭以后才被释放。

在MYGL中,OpenGLMYGLVIEW.CPP文档中的OnDraw函数中进行绘图。

void CMyglView::OnDraw(CDC* pDC)

{

  CMyglDoc* pDoc = GetDocument();

  RECT rc;

  COpenGL gl;

  HGLRC hglrc = gl.wglGetCurrentContext();

 

  if (hglrc)

  {

    GetClientRect(&rc);

    DrawScene(rc);

  }

 

}

调用函数wglGetCurrentContext来确定渲染上下文的存在,如果渲染上下文不存在的话,将不会发生任何事情。需要注意的是pDC指针不会传递给函数DrawScene,原先DC被隐藏,使用的上下文是和原先DC相关的渲染上下文。

下面一段代码在MYGL关闭时执行。

BOOL COpenGL::ReleaseGLRC(HWND hwnd)

{

  BOOL bRet = TRUE;

  HDC   hdc;

  HGLRC hglrc;

 

  if (hglrc = wglGetCurrentContext())

  {

    //

    //Get the DC associated with the rendering context.

    //

    hdc = wglGetCurrentDC();

    //

    //Make the rendering context not current.

    //

    wglMakeCurrent(NULL, NULL);

    //

    //Nuke the DC.

    //

    ::ReleaseDC(hwnd, hdc);

   //

   //Nuke the rendering context.

   //

   wglDeleteContext(hglrc);

  }

  else bRet = FALSE;

  return bRet;

 

}

调用函数wglGetCurrentDC来获取当前DC,再释放DC,然后释放渲染上下文。

 

总结

Windows NT 3.5提供的OpenGL特性,在通用型的象素格式下,所有的象素格式和渲染上下文都是通过GDI来实现的。在设备型象素格式下,多数操作是通过设备来实现的。在OpenGL绘图的时候,窗口,位图或设备的象素格式必须设置好,然后产生一个渲染上下文,这之后绘图功能才能生效。现在Windows NT 所提供的3D图形的结构和功能函数,可以使应用程序开发者能够开发出出色的应用程序,以后的技术文章将集中在OpenGL编程细节,让我们拭目以待吧!

 

参考文献:

 

OpenGL Reference Manual, The Official Reference Document for OpenGL, Release 1. OpenGL Architecture Review Board, 1992, Addison Wesley, ISBN 0-201-63276-4.

OpenGL Programming Guide,The Official Guide to Learning OpenGL,Release 1. OpenGL Architecture Review Board, 1992, Addison Wesley, ISBN 0-201-63274-8.

 
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值