图形设备接口(GDI,Graphics Device Interface)的主要目标之一是支持在输出设备(如视频显示器、打印机和绘图仪)上的与设备无关的图形。 GDI通过将应用程序与不同输出设备特性相隔离,使Windows应用程序能够毫无问题地在Windows支持的任何图形输出设备上运行。
Windows中的图形基本上是由从GDI.EXE模块中输出的函数处理的(尽管一些绘制函数实际上具有USER.EXE的入口点),GDI.EXE模块调用在不同驱动程序文件中的例程,其中有一个.DRV驱动程序文件用于控制显示屏幕,并且可能有一个或多个其他的.DRV驱动程序文件用来控制打印机或绘图仪。
Windows GDI使用两种坐标系统。使用虚拟坐标系统可以使程序不依赖于具体的硬件,使用设备坐标系统可以使程序和硬件紧密相联。
GDI含有在Windows应用程序内部执行、且与设备无关的图形操作函数,这些函数可产生各种各样的线、正文和位图,它们可以输出到许多不同的输出设备上。GDI允许一个应用程序产生笔、刷子、字体和位图,以供特定的输出操作使用。下面列出GDI中几组比较常用的函数:
·设备上下文函数
·椭圆和多边形函数
·绘图工具函数
·位图函数
·绘图属性函数
·正文函救
·映射函数。
·坐标函数
·元文件(metafile)函数
·区域函数
·裁剪(clipping)函数·
窗口应用程序输出图形的操作步骤如下:
①取得指定窗口的当前显示设备上下丈,显示设备上下文实际上是一个数据结构,它包括该窗口的参数及各种图形、文字属性的现行设定值,它们对以后的图形、文字输 出命令起控制作用。
②选择用户坐标系及映射方式。
③设定用户坐标系中的观察窗口和设备坐标系中的显示视区。
④输出图形、文字和图象。
⑤释放所使用的显示设备上下文。
当想要在图形输出设备(例如屏幕或打印机)上绘制图形时,必须首先获得设备上下文的句柄。先给出这个句柄,Windows才允许程序使用设备,在GDI函数中将句柄作为一个参数传入,向Windows标明需要使用的设备。
设备上下文中包含许多属性,当GDI在不同的设备上工作时都要用到这些属性。使用这些属性可使GDI只关心起始和终止坐标的大小,而不必关心有关对象的其他属性,如颜色、背景等等,因为这些都是设备上下文的一部分。当需要修改这些属性时,只需调用一个修改设备上下文中属性的参数,以后的程序中都使用修改后的设备上下文属性。设备上下文是连接Windows应用程序、设备驱动程序以及输出设备的纽带。
获取设备上下文句柄有多种方法。最一般的方法是当处理一条消息时获得了设备上下文、并在退出窗口之前释放它。一般的处理方法如下:
在处理WM_PAINT消息时
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps)
EndPaint (hwnd,&ps);
其数据结构为:
HDC hWnd;
PAINTSTRUCT ps;
而在windows.h中定义了PAINTSTRUCT的数据结构。
type struct tagPAINTSTRUCT {
HDC hdC;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL flncUpdate;
BYTE rgbReserved[16];
}PAINTSTRUCT;
其中,hdc用于标识显式上下文,fErase指出背景是否重画,rcPaint是涂色矩形,其余的域均为保留。这里的hdc是BeginPaint返回的设备上下文句柄,有了从DeginPaint获取的设备上下文句柄,就可以也只能在ps指出的rcPaint的矩形内绘图,EndPaint调用使这一区域有效。
第二种方法如下所示,使用这种方法获取和释放设备上下文可以在整个用户区内画图,图形在整个用户区域内都有效:
hdC=GetDc (hwnd );
…画图操作…
ReleaseDC (hwnd , hdc );
使用下面第三种方法获取和释放设备上下文,可以在整个窗口内画图,图形在整个窗口内有效:
hdC=GetWindowDc(hwnd);
…画图操作…
ReleaseDc(hwnd,hdc);
使用下面第四种方法获取和释放设备上下文,可以在整个显示器区域内画图,图形在整个显示器区域内部有效:
hdc=CreateDC (lpszDriver ,lpszDevice ,lpszOutput , lpData);
…画图操作…
ReleaseDC(hdc);
其中lpszDriver指向设备驱动程序的DOS文件名(不带扩展名),lpszDevice指向专用设备名(例如Epson Fx-80),lpszOutput指向物理输出介质(文件或输出端口)的DOS文件名或设备名,lpData指向含有设备驱动程序的设备专用的初始化数据的DEVMODE数据结构。例如:
hdc=CreateDC("DISPLAY",NULL,NULL,NULL);
使用屏幕画图,而:
hdc= CreateDC ("IBMGRX","IBM Graphics","LPT1",NULL );
在打印机上输出图形,这里的lpData置为默认值,可以在WIN.INI中找到初始化值。
如果不需要获取设备上下文,即不需要在设备上下文中操作,只需了解有关设备上下文的信息,可以用如下语句:
hdcInfo = CreateDC (lpszDriver, lpszDevice,lpszOutput, lpData );
……
DeteteDC (hdcInfo);
另外,还可以使用设备上下文来对位图的内存进行控制,如下所示:
hdcMem = CreateCompatibleDC (hdc)
OeleteDc(hdcMem );
一个元文件是以二进制形式编码的GDI调用集合,可通过获取一个元文件设备上下文来建立一个文件:
hdcMeta=CreateMetaFile(lpszFilename);
……
hmf=CloseMetaFile(hdCMeta);
在元文件设备上下文有效期间,使用hdcMeta所进行的任何GDI调用都成为元文件的一部分,当调用CloseMetaFile时,设备上下文句柄变化无效,函数返回元文件(hmf)的句柄。
一个设备上下文通常涉及物理设备,如视频显示器、打印机等,所以需要获取有关该设备的信息,如显示器大小和彩色能力等。可以通过调用GetDeviceCaps函数来获取这样的信息:
nValue=GetDeviceCaps (hdc,nIndex);
这里的hdc标识设备上下文,nIndex确定返回值,它可以是window.h中所定义的28个标识符中的一个,例如nIndex=DRIVEVERSION,则该函数返回的是版本号。
真正影响在用户区域上绘制过程的设备上下文属性是“映射方式”,与映射方式属性密切相关的还有如下四个设备上下义属性:窗口原点、视窗原点、窗口范围和视窗范围。
Windows定义了八种映射方式,即:
这里的TWIP指的是1/1440英寸,in.代表英寸。
可以调用函数setMapMode(hdc,MapMode)来设置这八种映射方式中的一种。hdc用来标识设备上下文,nMapMode可以取MM_TEXT、MM_LOMETRIC、MM_HIMETRIC等八个值中的一个。在设置了映射方式之后,到下一次设置映射方式之前,Windows一直使用这种映射方式。如果想要获取当前的映射方式,可用:
nMapMode= GetMapMode (hdc)
在设置了映射方式之后,就规定了逻辑单位的大小和增量的方式,在GDI画图函数中,可以不必考虑这些内容而直接使用逻辑数字,如:
SetMapMode(hdc ,MM_TEXT);
TextOut(hdc,8 ,16,szBuffer ,nLength)
即正文从用户区域左起第八个象素,顶边起第16个象素的位置开始写操作。不管映射方式如何,Windows函数中所有坐标规定为-32768 到 32767之间的带符号短整救。
注意映射方式只是一个设备上下文属性,因此映射方式唯一起作用的是将映射方式作为设备上下文句柄属性,而将该句柄当作参数的GDI函数,因此象GetSystemMetrics这样的非GDI函数,将继续以设备单位(象素值)返回尺寸值。
用GDI的SetPixel函数可以绘制一特定颜色的象素:
rgbActualColor =SetPixel (hdc,x,y,rgbColor);
这里hdc标识设备上下文,x ,y表示点坐标,rgbColor为一无符号的长整数,其结构为:
COLORREF rgbColor;
其中低位字节为红基色的相对亮度值,第二个字节包含绿基色的相对亮度值,第三个字节包含蓝基色的相对亮度值,高位字节必须为零。可以使用RGB函数来获取rgbColor。
rgbColor =RGB(byRed ,byGreen,byBlue);
这里的byRed、byGreen、byBlue取值范围为0~255,分别代表红色、绿色、蓝色的亮度。给出正确的参数之后,SetPixel返回的是调色板中最靠近所需彩色的颜色。还可以使用如下方法来取得一个特定象素的颜色:
rgbCotor= GetPixel(hdc,x,y);
画线函数主要有三种, LineTo、Polyline 和 Arc。还有五个设备上下文属性会影响这些函数画出的线的外观:笔的当前位置(仅对LineTo有影响)、笔、背景方式(对非实心笔有影响)、背景颜色(对 OPAQUE背景方式)以及绘制方式。
在这些设备上下文的属性中,笔的当前位置影响画线的起点,笔影响线的粗细等形状,背景方式影响非实心笔画出的线的模板图形,背景颜色影响线模板背景色,绘制方式影响实心线、虚线等线属性。
以下是典型的画线操作步骤:
MoveTo(hdc,xStart,yStart);
LineTo(hdc ,xEnd ,yEnd);
上面两句画出一条从(xStart,yStart)到(xEnd,yEnd)的直线。
可以使用语句:
dwPoint = GetCurrentPosition (hdc);
获得笔的当前位置。这里,dwPoint返回值是一个无符号长整数(或双倍长字),其中低位字含有X坐标,高位字含有Y坐标。
可以使用MAKEPOINT函数将dwPoint转换为POINT结构;
point = MAKEPOINT (dwPoint);
point的类型为POINT:
typedef struct togPOINT {kk1}
int x;
int y;
}POINT;
Polyline用于绘制折线,例:
Polyline(hdc,&pt,5)
将数组pt中的5个点之间用线段相连。
Arc用于画椭圆的周边:
Arc (hdc,xLeft,yTop,xRight,yBottom,xStart,yStart,XEnd,yEnd );
画出的椭圆以左上角为(xLeft,yTop),右下角为(xRight,yBottom)的矩形为界,圆弧开始于椭圆和(xStart,yStart)与椭圆中心的连线的交点处,沿着椭圆周边的过时针方向绘制,并终止于椭圆和(xEnd,yEnd)与椭圆中小的连线的交点处。
当调用LineTo、Polyline和Arc时,Windows使用当前在设备上下文中选择的笔来画线,笔决定了线的颜色、密度和型式,而线型可以是实线、点线或短划(虚)线,缺省设备上下文中的笔叫做BLACK_PEN,不管映射方式如何选支笔以一个象素的宽度画黑色的实线, BLACK_PEN是Windows提供的三支“备用笔”之一,其他两支是WHITE_PEN和NULL_PEN,NULL_PEN是一支什么都不画的空笔,当然用户也可以自己建立定制的笔。
可以通过一个句柄来引用所需的笔:
HPEN hPen;
hPen =GetStockObject(WHITE_PEN);
SelectObjeCt (hdc ,hPen) ;
调用GetStockObject获得一支备用笔(WHITE_PEN)的句柄,调用SelectObject使这支笔成为设备上下文中当前选择的用CreatePen或CreatePenIndirect函数建立一支“逻辑笔”,这逻辑笔只是一支笔的描述。
hPen = CreatePen (nPenStyle ,nWidth ,rgbColor );
其中nPenStyle参数确定笔是绘制实线还是由点或短划组成的线。该参数可取下列标识符之一: PS_SOLID、PS_DASH、Ps_DOT、PS_DASHDOT、 PS_DASHDOT DOT。nWidth表示笔宽(采用逻辑单位),rgbColor表示笔的颜色,如果函数执行成功,则返回值标识一支逻辑笔,否则返回值为NULL。
另外还有一种方法来建立逻辑笔:
typedef struct tagLOGPEN { kk1}
POINT lopnWidth;
COLORREF lopnColor;
}LOGPEN;
以上是Windows. h中对LOGPEN结构的定义。lopnStyle规定笔的型式,lopnWidth规定笔的宽度,lopnColor规定笔的颜色。然后将logpen定义为LOGPEN类型:
LOGPEN logpen;
再使用
hPen = CreatePenlndirect (&logpen);
就可以建立自定义的笔了。
因为用以上两种方式建立的笔不是设备上下文有关的,所以可以同时建立多支笔,并用多支笔画图。
hpenl =CreatePen(PS_SOLID,1,0L);
hpen2=CreatePen(PS_SOLID,3,RGB(255,0,255)),
selectObject (hdc ,hpenl )
//LineTo调用
SelectObject (hdc , hpen2 )
//Polyline调用
DeleteObject(hpenl);
DeleteObject(hpen2);
在点线笔和短划笔的空隙间的着色取决于设备上下文中定义的背景方式和背景颜色这两种属性。缺省的背景方式是 OPAQUE ,即用背景颜色来填充空隙,缺省的背景颜色是白色。可用:
SetBkColor (hdc,rgbColor );
来改变填充空隙的背景颜色。可用:
SetBkMode(hdc,mode);
来改变背景方式,这里的mode可为OPAQUE或TRANSPARENT。
在设备上下文中可设置口种新的绘制方式。nDrawMode参数定义绘制方式。可用下列函数获得当前绘制方式:
nDrowMode = GetRop2 (hdc);
使用这种绘制方式实际上是在笔的象素和目标显示表面的象素之间执行一种逐位布尔运算。
下面列出了Windows的六个函数,用于绘制带有边框的填充区域:
Rectangle, 带有方形角的矩形
Ellipse, 椭圆
RoundRect, 带有圆形角的矩形
Chord, 在椭圆周边上的弧,其断 . 点用一条弦相连接
Pie, 在椭圆周边上的饼形楔
Polygon, 多边形
PolyPolygon, 多个多边形
图形要用设备上下文中选择的当前刷子进行填充, 例:
HBRUSH hBrush;
hBrush=GetStockObject(GRAY_BRUSH)
SelectObject (hdc,hBrush)
对于矩形填充对象,使用:
Rectangle(hdc,xLeft,yTop,xRight,yBottom);
点(xLeft,yTop)是矩形的左上角,而(xRight,yBottom)是右下角(这两点均以逻辑坐标给出)。同时还要考虑这两点坐标的合理性,例如,在MM_TEXT映射方式下,xRight必须大于xLeft,yBottom必须大于yTop。
对于椭圆填充对象,使用:
Ellipse(hdc,xLeft,yTop,xRight,yBottom);
画圆角矩形的填充对象,使用:
RoundRect (hdc,xLeft,yTop,xRight,yBottom,xCornerEllipse,yCornerEllipse);
rgbColor为指定刷子的前景颜色,即阴影线的颜色。
③第三种方法:
hBrush = CreatePatternBrush ( hBitmap ) ;
本函数建立一把具有由hBitmap参数指定图案的逻辑刷子,该刷子以后可被任何支持光栅操作的设备所选用。hBitmap标识位图,该位图可用函数CreateBitmap、CreateBitmapIndirect、LoadBitmap或CreateCompatibleBitmap创建。用于填充图案的位图的最小尺寸为8×8。
④第四种方法:
hBrush = CreateBrushIndirect ( &logbrush )
变量logbrush为一个LOGBRUSH(“逻辑刷”)类型的结构。建立了逻辑刷子之后,可以使用:
SelectObject (hdc , hBrush ) ;
将逻辑刷送入设备上下文中。如果使用结束,可以用:
DeletObject (hBrush ) ;
删除一把已建立的刷子,如果在程序中需要获取有关于刷子的信息,则可以调用:
GetObject (hBrush , sizeof (LOGBRUSH ) , (LPSTR ) & (logBrush ) ) ;
其中logbrush为一个LOGBRUSH类型的结构。
前面提到使用位图作为逻辑刷子的图案,这样就需要一个位图的句柄。位图必须至少是8象素高和8象素宽,如果位图太大,Windows就取位图的左上部分作为刷子。获取位图句柄也有四种方法。
①获取位图句柄的第一种方法是:
首先用Windows提供的SDKPAINT生成一个位图文件(扩展名为.BMP),并把文件名包括在资源文件(.rc文件)中的一个BITMAP语句中,如:
lpszBitmap BITMAP " BitmOPName.Bmp"
(假设SDKPAINT中产生的位图名为BitmapName.Bmp),然后将位图装入:
hBitmap = LoadBitmap (hInstance , lpszBitmap ) ;
这里hBitmap即为位图句柄。
②第二种获取位图句柄的方法是:
hBitmap= createBitmop(nWidth,nHeight ,nPlanes ,nBitsPixel,lpBits);
本函数可生成一个具有指定的宽度、高度和位图案(bit pattern)并与设备有关的内存位图。其中的参数nWidth指定位图的宽度(以象素为单位),nHeight指定位图的高度(也以象素为单位),nPlanes指定位图中的彩色位平面的个数,每个彩色位平面有nWidthXnHeight XnBitsPixel位。
nBitsPixel指定每个显示象素的颜色位数。lpBits指向一个含有初始位图位值的短整型数组,它的值与BITMAP结构中的bmBits值相类似,有关BITMAP结构的内容已在前面
的章节中提到。
③第三种获取位图句柄的方法:
hBitmap= CreateCompatibleBitmap (hdc,nWidth,nHeight);
本函数生成一个与由hdc参数指定的设备相兼容的位图,此位图具有与其他设备相同数值的彩色位平面或相同的每象素位数的格式。它的彩色信息同样由hdc指定的设备所确定。hdc标识设备上下文,nWidth和nHeight分别指定位图的宽和高(以位数表示)。
④第四种获取位图句柄的方法:
hBitmop = CreateBitmapIndirect (&bitmap):
本函数生成一个具有由lpBitmap参数所指定的数据结构给出的宽度、高度和位图图案的位图。这里的bitmap的结构为BITMAP类型。
当拥有一个位图句柄之后,还可以调用:
GetObject(hBitmap,sizeof(BITMAP),(LPSTR)&bitmap);
来获得有关位图的信息,这里返回的bitmap为一个BITMAP类型的结构。
还可以调用:
GetBitmapBits (hBitmap,dwCount,lpBits);
将位图hBitmap的dwCount个字节复制到地址为lpBits的数组中。同样还可以使用
SetBitmopBits (hBitmap,dwCount,lpBits);
将 lpBits 标识的彩色位值放置到 hBitmap 标识的位图中去。
当Windows用刷子填充一个区域时,它在水平和垂直两个方向上重复地使用8×8位图,刷子的外观可能会有细微的变化,这取决于Windows如何将位图的左上角与显示表面对齐,设备上下文中将这种对齐的属性称为“刷子原点”。
大多数情况下,绘图时不必如此精细地调整刷子原点;但在某种情况下,为了产生某种特定的视觉效果,需要这么做。可以通过下面步骤来达到这个效果:
①对刷子调用UnrealizeObject(但不能对备用刷子调用UnrealizeObject);
UnrealizeObject(hObject );
此函数表示GDI在下次给定的刷子被选中时,使它的原点复位。
②用SetBrushOrg设置刷子原点:
BrushOrg=SetBrushOrg(hDc,x ,y);。
此函数用于设置当前选人给定的设备上下文中的刷子的原点。其中,hDc标识设备上下文,x规定新原点的x 坐标(采用设备坐标),该值范围必须在0~7之间,y规定新原点的y坐标(采用设备坐标),该值范围必须在0~7之间,该函数返回一个双字,先前的x坐标放在低位字,先前的y坐标放在高位字。
除了画点、画线、区域填充这些绘图函数之外,Windows还包括几个附加的绘图函数,用以处理RECT(矩形)结构和“区域”,区域是屏幕的一个由矩形、其他多边形和椭圆组合而成的部分。
FillRect(hdc ,&rect,hBrush);
此函数是用选定的刷子填充给定的矩形,FillRect函数填充整个矩形,还包括左边线和顶边线,但不包括右边线和底边线。hdc标识设备上下文,rect为RECT数据结构类型,此数据结构存放要填充的矩形的逻辑坐标。hBrush用来标识填充此矩形的刷子。
FrameRect (hdc ,&rect);
本函数在 lpRect 参数指定的矩形周围画出一个边框,FrameRect 函数采用给定的刷子绘制边框,边框的高和宽总是用逻辑单位表示。hdc标识窗口的设备上下文, rect 标明左上角和右下角的逻辑坐标,hBrush标识画矩形边框用的刷子。
InvertRect (hdc,&rect);
该函数反视频显示给定矩形的内容。
前面提到的rect可用以下语句取得:
SetRect(&rect,xLeft,yTop,xRight,yBottom);
区域用以描述显示器上的一个由矩形、其他多边形和椭圆组合而成的部分、可以用区域进行绘制或裁剪。
可用:
hRgn=CreateRgn(xLeft,yTop,xRight,yBottom);
或
hRgn = CreateRectRgnIndirect (&rect );
来建立矩形区域,也可以用:
hRgn= CreatEllipseRgn (xLeft,yTop,xRight,yBOttom);
或:
hRgn =CreateEllipseRgnIndirect (&rect);
来建立椭圆形区域;还可以用:
hRgn=CreatePolygonRgn (Upoint,nCount,nPolyFillMode);
来建立多边形区域,用:
hRgn=CreateRoundRectRgn(xl,yl,x2,y2,x3,y3);
来建立一个带有圆角的矩形区域,(xl,y1)表示区域左上角,(x2,y2)表示区域右下角,x3和y3分别用于指定产生圆角的椭圆的宽度和高度。
各个特定区域的句柄产生之后,
还可以使用:
nRgnType= CombineRgn (hDestRgn,hSrcRgnl,hSrcRgn2,nCombine);
通过组合两个已存在区域而产生一个新的区域。组合区域的方法由nCombine参数加以说明:
这里的hSrcRgnl和hSrcRgn2标识两个已存在的区域,hDestRgn标识将被新区域替换的作为目标的已存在区域。
一个区域用完后,可用DeleteObject(hRgn)删除它。
FloodFiLL (hdc,xStart,yStart,rgbColor);
本函数用当前刷子填充显示表面的一个区域,该区域假定由rgbColor多数指定的颜色边界确定,FloodFill函数由xStart,yStart参数指定的,点开始向各个方向进行填充,直到颜色边界为止。
ExtFLoodFill(hdc,xStart,yStart,rgbColor,wFill );
此函数用当前刷子填充显示表面上的某一区域,若wFill被设置成FLOODFILLBORDER,此区域将完全用rgbColor设定的颜色作为边界,ExtFloodFill从(xStart,yStart)点开始向各个方向填充,直到该颜色边界为止。若wFill被设置成FLOODFILLSURFACE,则ExtFLOODFILL函数从(xStart,yStart)点开始,向各个方向对所有包含由rgbColor参数设定的颜色的相邻区域进行填充。
DrowIcon(hdc,xStort,yStart,hIcon) ;
本函数在指定设备上画一个图标。(xStart,yStart)为图标的左上角,hIcon标识要画的图标,它与hBitmap一样,可以由SDKPAINT画出,在. rc文件中定义,用LoadIcon获得。
ScrollWindow (hwnd,xScroll,yScroll,&rectScroll,&rectClip) ;
本函数通过移动一个窗口用户区域的内容来滚动该窗口,沿X轴移动xScroll个单位,沿Y轴移动yScroll个单位,rectScroll表示用户区域要滚动的那一部分内容,rectClip表示要滚动的裁剪矩形。
ScrollDC(hdc,dx,dy,lprcScroll,lprcClip, hrgnUpdate,lprcUpdate);
此函数水平地和垂直地滚动由位构成的矩形。lprcScroll指向要滚动的矩形,dx表示水平滚动单位,dy表示垂直滚动单位,lprcClip指向裁剪矩形,hrgnUpdate返回滚动过程没有覆盖的区域,lprcUpdate返回需要重画的最大矩形区域。
OpenGL是近几年发展起来的一个性能卓越的三维图形标准,它是在SGI等多家 世界闻名的计算机公司的倡导下,以SGI的GL三维图形库为基础制定的一个通用共享的开放式三维图形标准。目前,包括Microsoft、SGI、IBM、DEC、SUN、HP等大公司都采用了OpenGL做为三维图形标准,许多软件厂商也纷纷以OpenGL 为基础开发出自己的产品,其中比较著名的产品包括动画制作软件Soft Image 和3D Studio MAX、仿真软件Open Inventor、VR软件World Tool Kit、CAM软件ProEngineer、GIS软ARC/INFO等等。值得一提的是,随着Microsoft公司在Windows NT和最新的Windows 95中提供了OpenGL标准及OpenGL三维图形加速卡(如北京黎明电子技术公司的AGC-3D系列三维图形加速卡)的推出,OpenGL将在微机中有广泛地应用,同时也为广大用户提供了在微机上使用以前只能在高性能图形工作站上运行的各种软件的机会。
OpenGL实际上是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL可以与Visual C++紧密接口,便于实现机械手的有关计算和图形算法,可保证算法的正确性和可靠性。
OpenGL使用简便,效率高。它具有七大功能:
1) 建模 OpenGL图形库除了提供基本的点、线、多边形的绘制函数外,还提供了复杂的三维物体(球、锥、多面体、茶壶等)以及复杂曲线和曲面 (如Bezier、Nurbs等曲线或曲面)绘制函数。
2) 变换 OpenGL图形库的变换包括基本变换和投影变换。基本变换有平移、旋转、变比镜像四种变换,投影变换有平行投影(又称正射投影)和透视投影两种变换。其变换方法与机器人运动学中的坐标变换方法完全一致,有利于减少算法的运行时间,提高三维图形的显示速度。
3) 颜色模式设置 OpenGL颜色模式有两种,即RGBA模式和颜色索引(Color Index)。
4) 光照和材质设置OpenGL光有辐射光(Emitted Light)、环境光(Ambient Light)、漫反射光(Diffuse Light)和镜面光(Specular Light)。
材质是用光反射率来表示。场景(Scene)中物体最终反映到人眼的颜色是光的红绿蓝分量与材质红绿蓝分量的反射率相乘后形成的颜色。
5) 纹理映射(Texture Mapping) 利用OpenGL纹理映射功能可以十分逼真地表达物体表面细节。
6) 位图显示和图象增强 图象功能除了基本的拷贝和像素读写外,还提供融合(Blending)、反走样(Antialiasing)和雾(fog)的特殊图象效果处理。
以上这三条可使被仿真物更具真实感,增强图形显示的效果。
7) 双缓存(Double Buffering)动画 双缓存即前台缓存和后台缓存,简而言之,后台缓存计算场景、生成画面,前台缓存显示后台缓存已画好的画面。
此外,利用OpenGL还能实现深度暗示(Depth Cue)、运动模糊(Motion Blur)等特殊效果。从而实现了消隐算法。
OpenGL图形库一共有100多个函数。其中核心函数有115个,它们是最基本的函数,其前缀是gl,OpenGL实用库(OpenGL utility library , GLU)的函数功能更高一些,如绘制复杂的曲线曲面、高级坐标变换、多边形分割等,共有43个,前缀为glu;OpenGL辅助库(OpenGL auxiliary library ,GLAUX)的函数是一些特殊的函数,包括简单的窗口管理、输入事件处理、某些复杂三维物体绘制等函数,共有31个,前缀为aux。
此外,还有六个WGL函数非常重要,专门用于OpenGL和Windows 95窗口系统的联接,其前缀为wgl,主要用于创建和选择图形操作描述表(rendering contexts)以及在窗口内任一位置显示字符位图。这些功能是Windows 95 对OpenGL的唯一补充。
另外,还有五个Win32函数用来处理像素格式(pixel formats)和双缓存。由于它们是对Win32系统的扩展,因此不能应用在其它OpenGL平台上。
OpenGL for Windows 95的设计与OpenGL for UNIX的程序设计有一点小区别,关键就在于如何将OpenGL与不同的操作系统下的窗口系统联系起来。
如果调用OpenGL辅助库窗口管理函数,则不用考虑这些问题。下面简要介绍在 Windows 95下 OpenGL 的程序设计关键。
1.图形操作描述
在Windows 95下窗口程序必须首先处理设备描述表(Device Contexts ,DC),DC包括许多如何在窗口上显示图形的信息,既指定画笔和刷子的颜色,设置绘图模式、调色板、映射模式以及其它图形属性。同样,OpenGL for Windows 95的程序也必须使用DC,这与其它Windows 95程序类似。但是,OpenGL for Windows 95必须处理特殊的DC图形操作描述表,这是DC中专为OpenGL使用的一种。一个OpenGL应用图形操作描述表内有OpenGL与Windows 95窗口系统相关的各种信息。一个OpenGL应用首先必须创建一个图形操作描述表,然后再启动它,最后在所定义的窗口内按常规方式调用OpenGL函数绘制图形。
一个图形操作描述表不同于其它DC,它们调用每个GDI函数都需要一个句柄,而图形操作描述表方式下只需一个句柄就可以任意调用OpenGL函数。也就是说,只要当前启用了某个图形操作描述表,那么在未删除图形操作描述表之前可以调用任何OpenGL函数,进行各种操作。
2.像素格式
在创建一个图形操作表之前,首先必须设置像素格式。像素格式含有设备绘图界面的属性,这些属性包括绘图界面是用RGBA模式还是颜色表模式,像素缓存是用单缓存还是双缓存,以及颜色位数、深度缓存和模板缓存所用的位数,还有其它一些属性信息。
3.像素格式结构
每个OpenGL显示设备都支持一种指定的像素格式。一般用一个名为PIXELFORMATDESCRIPTOR的结构来表示某个特殊的像素格式,这个结构包含26个属性信息。Win32定义PIXELFORMATDESCRIPTOR如下所示:
typedef struct tagPIXELFORMATDESCRIPTOR
{ kk1}
// pfd
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;
4.初始化PIXELFORMATDESCRIPTOR结构
PIXELFORMATDESCRIPTOR中每个变量值的具体含义和设置可以参考有关资料,下面举出一个PIXELFORMATDESCRIPTOR初始化例子来简要说明相关变量的意义。定义PIXELFORMATDESCRIPTOR结构的pfd如下:
PIXELFORMATDESCRIPTOR pfd = { kk1}
sizeof(PIXELFORMATDESCRIPTOR), . //size of this pfd 1
PFD_DRAW_TO_WINDOW| // support window
PFD_SUPPORT_OPENGL| // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0,0,0,0,0,0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buff
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
};
在这个结构里,前两个变量的含义十分明显。第三个变量dwFlags的值是
PFD_DRAW_TO_WINDOW |PFD_SUPPORT_OPENGL ,
表明应用程序使用OpenGL函数来绘制窗口
第四个:
PFD_DOUBLEBUFFER,
表明当前采用RGBA颜色模式,第五个采用24位真彩色,既1.67千万种颜色,如果是256色系统则自动实现颜色抖动;因为没有使用alpha缓存和累计缓存,所以从变量cAlphaBits到cAccumAlphaBits都设置为0;深度缓存设置为32位,这个缓存能解决三维场景的消隐问题;变量cAuxBuffers设置为0,在Windows 95下不支持辅助缓存;Windows 95下针对OpenGL变量ilayerType只能设置为PFD_MAIN_PLANE,但在其它平台也许支持PFD_MAIN_PLANE或PFD_MAIN_UNDERLAYPLANE;接下来bReserved变量只能设为0,而最后三个变量Windows 95都不支持,故全设置为0。
5.设置像素结构
当初始化PIXELFORMATDESCRIPTOR结构后,就要设置像素格式。下面举例说明如何设置像素格式。
CClientDC clientDC(this);
int PixelFormat = ChoosePixelFormat(clientDC.m_hDC,&pfd);
BOOL result=SetPixelFormat(clientDC.m_hDC,PixelFormat,&pfd);
第一行语句说明如何得到一个应用窗口客户区的设置描述表。
第一行调用ChoosePixelFormat( )选择一个像素格式,并将像素格式索引号返回给pixelFormat变量;函数中第一个参数是选择像素格式的设备描述表的句柄,第二个参数是PIXELFORMATDESCRIPTOR结构的地址。如果调用失败则返回0;否则返回像素格式索引号。
第三行调用SetPixelFormat( )设置像素格式,三个参数分别是设备描述表的句柄、像素格式索引号和PIXELFORMATDESCRIPTOR结构的地址。如果调用成功则返回TRUE,否则返回FALSE。
6.创建图形操作描述表
正如前所述,必须创建图形操作描述表并启用它后,才能调用OpenGL函数在窗口内进行各种图形操作。一般来说,利用 MFC 中增补的管理图形操作描述表方法来编程比较方便。即在视类 (CView) 的消息 OnCreat( ) 中创建图形操作描述表。
Windows中的图形基本上是由从GDI.EXE模块中输出的函数处理的(尽管一些绘制函数实际上具有USER.EXE的入口点),GDI.EXE模块调用在不同驱动程序文件中的例程,其中有一个.DRV驱动程序文件用于控制显示屏幕,并且可能有一个或多个其他的.DRV驱动程序文件用来控制打印机或绘图仪。
Windows GDI使用两种坐标系统。使用虚拟坐标系统可以使程序不依赖于具体的硬件,使用设备坐标系统可以使程序和硬件紧密相联。
GDI含有在Windows应用程序内部执行、且与设备无关的图形操作函数,这些函数可产生各种各样的线、正文和位图,它们可以输出到许多不同的输出设备上。GDI允许一个应用程序产生笔、刷子、字体和位图,以供特定的输出操作使用。下面列出GDI中几组比较常用的函数:
·设备上下文函数
·椭圆和多边形函数
·绘图工具函数
·位图函数
·绘图属性函数
·正文函救
·映射函数。
·坐标函数
·元文件(metafile)函数
·区域函数
·裁剪(clipping)函数·
窗口应用程序输出图形的操作步骤如下:
①取得指定窗口的当前显示设备上下丈,显示设备上下文实际上是一个数据结构,它包括该窗口的参数及各种图形、文字属性的现行设定值,它们对以后的图形、文字输 出命令起控制作用。
②选择用户坐标系及映射方式。
③设定用户坐标系中的观察窗口和设备坐标系中的显示视区。
④输出图形、文字和图象。
⑤释放所使用的显示设备上下文。
当想要在图形输出设备(例如屏幕或打印机)上绘制图形时,必须首先获得设备上下文的句柄。先给出这个句柄,Windows才允许程序使用设备,在GDI函数中将句柄作为一个参数传入,向Windows标明需要使用的设备。
设备上下文中包含许多属性,当GDI在不同的设备上工作时都要用到这些属性。使用这些属性可使GDI只关心起始和终止坐标的大小,而不必关心有关对象的其他属性,如颜色、背景等等,因为这些都是设备上下文的一部分。当需要修改这些属性时,只需调用一个修改设备上下文中属性的参数,以后的程序中都使用修改后的设备上下文属性。设备上下文是连接Windows应用程序、设备驱动程序以及输出设备的纽带。
获取设备上下文句柄有多种方法。最一般的方法是当处理一条消息时获得了设备上下文、并在退出窗口之前释放它。一般的处理方法如下:
在处理WM_PAINT消息时
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps)
EndPaint (hwnd,&ps);
其数据结构为:
HDC hWnd;
PAINTSTRUCT ps;
而在windows.h中定义了PAINTSTRUCT的数据结构。
type struct tagPAINTSTRUCT {
HDC hdC;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL flncUpdate;
BYTE rgbReserved[16];
}PAINTSTRUCT;
其中,hdc用于标识显式上下文,fErase指出背景是否重画,rcPaint是涂色矩形,其余的域均为保留。这里的hdc是BeginPaint返回的设备上下文句柄,有了从DeginPaint获取的设备上下文句柄,就可以也只能在ps指出的rcPaint的矩形内绘图,EndPaint调用使这一区域有效。
第二种方法如下所示,使用这种方法获取和释放设备上下文可以在整个用户区内画图,图形在整个用户区域内都有效:
hdC=GetDc (hwnd );
…画图操作…
ReleaseDC (hwnd , hdc );
使用下面第三种方法获取和释放设备上下文,可以在整个窗口内画图,图形在整个窗口内有效:
hdC=GetWindowDc(hwnd);
…画图操作…
ReleaseDc(hwnd,hdc);
使用下面第四种方法获取和释放设备上下文,可以在整个显示器区域内画图,图形在整个显示器区域内部有效:
hdc=CreateDC (lpszDriver ,lpszDevice ,lpszOutput , lpData);
…画图操作…
ReleaseDC(hdc);
其中lpszDriver指向设备驱动程序的DOS文件名(不带扩展名),lpszDevice指向专用设备名(例如Epson Fx-80),lpszOutput指向物理输出介质(文件或输出端口)的DOS文件名或设备名,lpData指向含有设备驱动程序的设备专用的初始化数据的DEVMODE数据结构。例如:
hdc=CreateDC("DISPLAY",NULL,NULL,NULL);
使用屏幕画图,而:
hdc= CreateDC ("IBMGRX","IBM Graphics","LPT1",NULL );
在打印机上输出图形,这里的lpData置为默认值,可以在WIN.INI中找到初始化值。
如果不需要获取设备上下文,即不需要在设备上下文中操作,只需了解有关设备上下文的信息,可以用如下语句:
hdcInfo = CreateDC (lpszDriver, lpszDevice,lpszOutput, lpData );
……
DeteteDC (hdcInfo);
另外,还可以使用设备上下文来对位图的内存进行控制,如下所示:
hdcMem = CreateCompatibleDC (hdc)
OeleteDc(hdcMem );
一个元文件是以二进制形式编码的GDI调用集合,可通过获取一个元文件设备上下文来建立一个文件:
hdcMeta=CreateMetaFile(lpszFilename);
……
hmf=CloseMetaFile(hdCMeta);
在元文件设备上下文有效期间,使用hdcMeta所进行的任何GDI调用都成为元文件的一部分,当调用CloseMetaFile时,设备上下文句柄变化无效,函数返回元文件(hmf)的句柄。
一个设备上下文通常涉及物理设备,如视频显示器、打印机等,所以需要获取有关该设备的信息,如显示器大小和彩色能力等。可以通过调用GetDeviceCaps函数来获取这样的信息:
nValue=GetDeviceCaps (hdc,nIndex);
这里的hdc标识设备上下文,nIndex确定返回值,它可以是window.h中所定义的28个标识符中的一个,例如nIndex=DRIVEVERSION,则该函数返回的是版本号。
真正影响在用户区域上绘制过程的设备上下文属性是“映射方式”,与映射方式属性密切相关的还有如下四个设备上下义属性:窗口原点、视窗原点、窗口范围和视窗范围。
Windows定义了八种映射方式,即:
这里的TWIP指的是1/1440英寸,in.代表英寸。
可以调用函数setMapMode(hdc,MapMode)来设置这八种映射方式中的一种。hdc用来标识设备上下文,nMapMode可以取MM_TEXT、MM_LOMETRIC、MM_HIMETRIC等八个值中的一个。在设置了映射方式之后,到下一次设置映射方式之前,Windows一直使用这种映射方式。如果想要获取当前的映射方式,可用:
nMapMode= GetMapMode (hdc)
在设置了映射方式之后,就规定了逻辑单位的大小和增量的方式,在GDI画图函数中,可以不必考虑这些内容而直接使用逻辑数字,如:
SetMapMode(hdc ,MM_TEXT);
TextOut(hdc,8 ,16,szBuffer ,nLength)
即正文从用户区域左起第八个象素,顶边起第16个象素的位置开始写操作。不管映射方式如何,Windows函数中所有坐标规定为-32768 到 32767之间的带符号短整救。
注意映射方式只是一个设备上下文属性,因此映射方式唯一起作用的是将映射方式作为设备上下文句柄属性,而将该句柄当作参数的GDI函数,因此象GetSystemMetrics这样的非GDI函数,将继续以设备单位(象素值)返回尺寸值。
用GDI的SetPixel函数可以绘制一特定颜色的象素:
rgbActualColor =SetPixel (hdc,x,y,rgbColor);
这里hdc标识设备上下文,x ,y表示点坐标,rgbColor为一无符号的长整数,其结构为:
COLORREF rgbColor;
其中低位字节为红基色的相对亮度值,第二个字节包含绿基色的相对亮度值,第三个字节包含蓝基色的相对亮度值,高位字节必须为零。可以使用RGB函数来获取rgbColor。
rgbColor =RGB(byRed ,byGreen,byBlue);
这里的byRed、byGreen、byBlue取值范围为0~255,分别代表红色、绿色、蓝色的亮度。给出正确的参数之后,SetPixel返回的是调色板中最靠近所需彩色的颜色。还可以使用如下方法来取得一个特定象素的颜色:
rgbCotor= GetPixel(hdc,x,y);
画线函数主要有三种, LineTo、Polyline 和 Arc。还有五个设备上下文属性会影响这些函数画出的线的外观:笔的当前位置(仅对LineTo有影响)、笔、背景方式(对非实心笔有影响)、背景颜色(对 OPAQUE背景方式)以及绘制方式。
在这些设备上下文的属性中,笔的当前位置影响画线的起点,笔影响线的粗细等形状,背景方式影响非实心笔画出的线的模板图形,背景颜色影响线模板背景色,绘制方式影响实心线、虚线等线属性。
以下是典型的画线操作步骤:
MoveTo(hdc,xStart,yStart);
LineTo(hdc ,xEnd ,yEnd);
上面两句画出一条从(xStart,yStart)到(xEnd,yEnd)的直线。
可以使用语句:
dwPoint = GetCurrentPosition (hdc);
获得笔的当前位置。这里,dwPoint返回值是一个无符号长整数(或双倍长字),其中低位字含有X坐标,高位字含有Y坐标。
可以使用MAKEPOINT函数将dwPoint转换为POINT结构;
point = MAKEPOINT (dwPoint);
point的类型为POINT:
typedef struct togPOINT {kk1}
int x;
int y;
}POINT;
Polyline用于绘制折线,例:
Polyline(hdc,&pt,5)
将数组pt中的5个点之间用线段相连。
Arc用于画椭圆的周边:
Arc (hdc,xLeft,yTop,xRight,yBottom,xStart,yStart,XEnd,yEnd );
画出的椭圆以左上角为(xLeft,yTop),右下角为(xRight,yBottom)的矩形为界,圆弧开始于椭圆和(xStart,yStart)与椭圆中心的连线的交点处,沿着椭圆周边的过时针方向绘制,并终止于椭圆和(xEnd,yEnd)与椭圆中小的连线的交点处。
当调用LineTo、Polyline和Arc时,Windows使用当前在设备上下文中选择的笔来画线,笔决定了线的颜色、密度和型式,而线型可以是实线、点线或短划(虚)线,缺省设备上下文中的笔叫做BLACK_PEN,不管映射方式如何选支笔以一个象素的宽度画黑色的实线, BLACK_PEN是Windows提供的三支“备用笔”之一,其他两支是WHITE_PEN和NULL_PEN,NULL_PEN是一支什么都不画的空笔,当然用户也可以自己建立定制的笔。
可以通过一个句柄来引用所需的笔:
HPEN hPen;
hPen =GetStockObject(WHITE_PEN);
SelectObjeCt (hdc ,hPen) ;
调用GetStockObject获得一支备用笔(WHITE_PEN)的句柄,调用SelectObject使这支笔成为设备上下文中当前选择的用CreatePen或CreatePenIndirect函数建立一支“逻辑笔”,这逻辑笔只是一支笔的描述。
hPen = CreatePen (nPenStyle ,nWidth ,rgbColor );
其中nPenStyle参数确定笔是绘制实线还是由点或短划组成的线。该参数可取下列标识符之一: PS_SOLID、PS_DASH、Ps_DOT、PS_DASHDOT、 PS_DASHDOT DOT。nWidth表示笔宽(采用逻辑单位),rgbColor表示笔的颜色,如果函数执行成功,则返回值标识一支逻辑笔,否则返回值为NULL。
另外还有一种方法来建立逻辑笔:
typedef struct tagLOGPEN { kk1}
POINT lopnWidth;
COLORREF lopnColor;
}LOGPEN;
以上是Windows. h中对LOGPEN结构的定义。lopnStyle规定笔的型式,lopnWidth规定笔的宽度,lopnColor规定笔的颜色。然后将logpen定义为LOGPEN类型:
LOGPEN logpen;
再使用
hPen = CreatePenlndirect (&logpen);
就可以建立自定义的笔了。
因为用以上两种方式建立的笔不是设备上下文有关的,所以可以同时建立多支笔,并用多支笔画图。
hpenl =CreatePen(PS_SOLID,1,0L);
hpen2=CreatePen(PS_SOLID,3,RGB(255,0,255)),
selectObject (hdc ,hpenl )
//LineTo调用
SelectObject (hdc , hpen2 )
//Polyline调用
DeleteObject(hpenl);
DeleteObject(hpen2);
在点线笔和短划笔的空隙间的着色取决于设备上下文中定义的背景方式和背景颜色这两种属性。缺省的背景方式是 OPAQUE ,即用背景颜色来填充空隙,缺省的背景颜色是白色。可用:
SetBkColor (hdc,rgbColor );
来改变填充空隙的背景颜色。可用:
SetBkMode(hdc,mode);
来改变背景方式,这里的mode可为OPAQUE或TRANSPARENT。
在设备上下文中可设置口种新的绘制方式。nDrawMode参数定义绘制方式。可用下列函数获得当前绘制方式:
nDrowMode = GetRop2 (hdc);
使用这种绘制方式实际上是在笔的象素和目标显示表面的象素之间执行一种逐位布尔运算。
下面列出了Windows的六个函数,用于绘制带有边框的填充区域:
Rectangle, 带有方形角的矩形
Ellipse, 椭圆
RoundRect, 带有圆形角的矩形
Chord, 在椭圆周边上的弧,其断 . 点用一条弦相连接
Pie, 在椭圆周边上的饼形楔
Polygon, 多边形
PolyPolygon, 多个多边形
图形要用设备上下文中选择的当前刷子进行填充, 例:
HBRUSH hBrush;
hBrush=GetStockObject(GRAY_BRUSH)
SelectObject (hdc,hBrush)
对于矩形填充对象,使用:
Rectangle(hdc,xLeft,yTop,xRight,yBottom);
点(xLeft,yTop)是矩形的左上角,而(xRight,yBottom)是右下角(这两点均以逻辑坐标给出)。同时还要考虑这两点坐标的合理性,例如,在MM_TEXT映射方式下,xRight必须大于xLeft,yBottom必须大于yTop。
对于椭圆填充对象,使用:
Ellipse(hdc,xLeft,yTop,xRight,yBottom);
画圆角矩形的填充对象,使用:
RoundRect (hdc,xLeft,yTop,xRight,yBottom,xCornerEllipse,yCornerEllipse);
rgbColor为指定刷子的前景颜色,即阴影线的颜色。
③第三种方法:
hBrush = CreatePatternBrush ( hBitmap ) ;
本函数建立一把具有由hBitmap参数指定图案的逻辑刷子,该刷子以后可被任何支持光栅操作的设备所选用。hBitmap标识位图,该位图可用函数CreateBitmap、CreateBitmapIndirect、LoadBitmap或CreateCompatibleBitmap创建。用于填充图案的位图的最小尺寸为8×8。
④第四种方法:
hBrush = CreateBrushIndirect ( &logbrush )
变量logbrush为一个LOGBRUSH(“逻辑刷”)类型的结构。建立了逻辑刷子之后,可以使用:
SelectObject (hdc , hBrush ) ;
将逻辑刷送入设备上下文中。如果使用结束,可以用:
DeletObject (hBrush ) ;
删除一把已建立的刷子,如果在程序中需要获取有关于刷子的信息,则可以调用:
GetObject (hBrush , sizeof (LOGBRUSH ) , (LPSTR ) & (logBrush ) ) ;
其中logbrush为一个LOGBRUSH类型的结构。
前面提到使用位图作为逻辑刷子的图案,这样就需要一个位图的句柄。位图必须至少是8象素高和8象素宽,如果位图太大,Windows就取位图的左上部分作为刷子。获取位图句柄也有四种方法。
①获取位图句柄的第一种方法是:
首先用Windows提供的SDKPAINT生成一个位图文件(扩展名为.BMP),并把文件名包括在资源文件(.rc文件)中的一个BITMAP语句中,如:
lpszBitmap BITMAP " BitmOPName.Bmp"
(假设SDKPAINT中产生的位图名为BitmapName.Bmp),然后将位图装入:
hBitmap = LoadBitmap (hInstance , lpszBitmap ) ;
这里hBitmap即为位图句柄。
②第二种获取位图句柄的方法是:
hBitmap= createBitmop(nWidth,nHeight ,nPlanes ,nBitsPixel,lpBits);
本函数可生成一个具有指定的宽度、高度和位图案(bit pattern)并与设备有关的内存位图。其中的参数nWidth指定位图的宽度(以象素为单位),nHeight指定位图的高度(也以象素为单位),nPlanes指定位图中的彩色位平面的个数,每个彩色位平面有nWidthXnHeight XnBitsPixel位。
nBitsPixel指定每个显示象素的颜色位数。lpBits指向一个含有初始位图位值的短整型数组,它的值与BITMAP结构中的bmBits值相类似,有关BITMAP结构的内容已在前面
的章节中提到。
③第三种获取位图句柄的方法:
hBitmap= CreateCompatibleBitmap (hdc,nWidth,nHeight);
本函数生成一个与由hdc参数指定的设备相兼容的位图,此位图具有与其他设备相同数值的彩色位平面或相同的每象素位数的格式。它的彩色信息同样由hdc指定的设备所确定。hdc标识设备上下文,nWidth和nHeight分别指定位图的宽和高(以位数表示)。
④第四种获取位图句柄的方法:
hBitmop = CreateBitmapIndirect (&bitmap):
本函数生成一个具有由lpBitmap参数所指定的数据结构给出的宽度、高度和位图图案的位图。这里的bitmap的结构为BITMAP类型。
当拥有一个位图句柄之后,还可以调用:
GetObject(hBitmap,sizeof(BITMAP),(LPSTR)&bitmap);
来获得有关位图的信息,这里返回的bitmap为一个BITMAP类型的结构。
还可以调用:
GetBitmapBits (hBitmap,dwCount,lpBits);
将位图hBitmap的dwCount个字节复制到地址为lpBits的数组中。同样还可以使用
SetBitmopBits (hBitmap,dwCount,lpBits);
将 lpBits 标识的彩色位值放置到 hBitmap 标识的位图中去。
当Windows用刷子填充一个区域时,它在水平和垂直两个方向上重复地使用8×8位图,刷子的外观可能会有细微的变化,这取决于Windows如何将位图的左上角与显示表面对齐,设备上下文中将这种对齐的属性称为“刷子原点”。
大多数情况下,绘图时不必如此精细地调整刷子原点;但在某种情况下,为了产生某种特定的视觉效果,需要这么做。可以通过下面步骤来达到这个效果:
①对刷子调用UnrealizeObject(但不能对备用刷子调用UnrealizeObject);
UnrealizeObject(hObject );
此函数表示GDI在下次给定的刷子被选中时,使它的原点复位。
②用SetBrushOrg设置刷子原点:
BrushOrg=SetBrushOrg(hDc,x ,y);。
此函数用于设置当前选人给定的设备上下文中的刷子的原点。其中,hDc标识设备上下文,x规定新原点的x 坐标(采用设备坐标),该值范围必须在0~7之间,y规定新原点的y坐标(采用设备坐标),该值范围必须在0~7之间,该函数返回一个双字,先前的x坐标放在低位字,先前的y坐标放在高位字。
除了画点、画线、区域填充这些绘图函数之外,Windows还包括几个附加的绘图函数,用以处理RECT(矩形)结构和“区域”,区域是屏幕的一个由矩形、其他多边形和椭圆组合而成的部分。
FillRect(hdc ,&rect,hBrush);
此函数是用选定的刷子填充给定的矩形,FillRect函数填充整个矩形,还包括左边线和顶边线,但不包括右边线和底边线。hdc标识设备上下文,rect为RECT数据结构类型,此数据结构存放要填充的矩形的逻辑坐标。hBrush用来标识填充此矩形的刷子。
FrameRect (hdc ,&rect);
本函数在 lpRect 参数指定的矩形周围画出一个边框,FrameRect 函数采用给定的刷子绘制边框,边框的高和宽总是用逻辑单位表示。hdc标识窗口的设备上下文, rect 标明左上角和右下角的逻辑坐标,hBrush标识画矩形边框用的刷子。
InvertRect (hdc,&rect);
该函数反视频显示给定矩形的内容。
前面提到的rect可用以下语句取得:
SetRect(&rect,xLeft,yTop,xRight,yBottom);
区域用以描述显示器上的一个由矩形、其他多边形和椭圆组合而成的部分、可以用区域进行绘制或裁剪。
可用:
hRgn=CreateRgn(xLeft,yTop,xRight,yBottom);
或
hRgn = CreateRectRgnIndirect (&rect );
来建立矩形区域,也可以用:
hRgn= CreatEllipseRgn (xLeft,yTop,xRight,yBOttom);
或:
hRgn =CreateEllipseRgnIndirect (&rect);
来建立椭圆形区域;还可以用:
hRgn=CreatePolygonRgn (Upoint,nCount,nPolyFillMode);
来建立多边形区域,用:
hRgn=CreateRoundRectRgn(xl,yl,x2,y2,x3,y3);
来建立一个带有圆角的矩形区域,(xl,y1)表示区域左上角,(x2,y2)表示区域右下角,x3和y3分别用于指定产生圆角的椭圆的宽度和高度。
各个特定区域的句柄产生之后,
还可以使用:
nRgnType= CombineRgn (hDestRgn,hSrcRgnl,hSrcRgn2,nCombine);
通过组合两个已存在区域而产生一个新的区域。组合区域的方法由nCombine参数加以说明:
这里的hSrcRgnl和hSrcRgn2标识两个已存在的区域,hDestRgn标识将被新区域替换的作为目标的已存在区域。
一个区域用完后,可用DeleteObject(hRgn)删除它。
FloodFiLL (hdc,xStart,yStart,rgbColor);
本函数用当前刷子填充显示表面的一个区域,该区域假定由rgbColor多数指定的颜色边界确定,FloodFill函数由xStart,yStart参数指定的,点开始向各个方向进行填充,直到颜色边界为止。
ExtFLoodFill(hdc,xStart,yStart,rgbColor,wFill );
此函数用当前刷子填充显示表面上的某一区域,若wFill被设置成FLOODFILLBORDER,此区域将完全用rgbColor设定的颜色作为边界,ExtFloodFill从(xStart,yStart)点开始向各个方向填充,直到该颜色边界为止。若wFill被设置成FLOODFILLSURFACE,则ExtFLOODFILL函数从(xStart,yStart)点开始,向各个方向对所有包含由rgbColor参数设定的颜色的相邻区域进行填充。
DrowIcon(hdc,xStort,yStart,hIcon) ;
本函数在指定设备上画一个图标。(xStart,yStart)为图标的左上角,hIcon标识要画的图标,它与hBitmap一样,可以由SDKPAINT画出,在. rc文件中定义,用LoadIcon获得。
ScrollWindow (hwnd,xScroll,yScroll,&rectScroll,&rectClip) ;
本函数通过移动一个窗口用户区域的内容来滚动该窗口,沿X轴移动xScroll个单位,沿Y轴移动yScroll个单位,rectScroll表示用户区域要滚动的那一部分内容,rectClip表示要滚动的裁剪矩形。
ScrollDC(hdc,dx,dy,lprcScroll,lprcClip, hrgnUpdate,lprcUpdate);
此函数水平地和垂直地滚动由位构成的矩形。lprcScroll指向要滚动的矩形,dx表示水平滚动单位,dy表示垂直滚动单位,lprcClip指向裁剪矩形,hrgnUpdate返回滚动过程没有覆盖的区域,lprcUpdate返回需要重画的最大矩形区域。
OpenGL是近几年发展起来的一个性能卓越的三维图形标准,它是在SGI等多家 世界闻名的计算机公司的倡导下,以SGI的GL三维图形库为基础制定的一个通用共享的开放式三维图形标准。目前,包括Microsoft、SGI、IBM、DEC、SUN、HP等大公司都采用了OpenGL做为三维图形标准,许多软件厂商也纷纷以OpenGL 为基础开发出自己的产品,其中比较著名的产品包括动画制作软件Soft Image 和3D Studio MAX、仿真软件Open Inventor、VR软件World Tool Kit、CAM软件ProEngineer、GIS软ARC/INFO等等。值得一提的是,随着Microsoft公司在Windows NT和最新的Windows 95中提供了OpenGL标准及OpenGL三维图形加速卡(如北京黎明电子技术公司的AGC-3D系列三维图形加速卡)的推出,OpenGL将在微机中有广泛地应用,同时也为广大用户提供了在微机上使用以前只能在高性能图形工作站上运行的各种软件的机会。
OpenGL实际上是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL可以与Visual C++紧密接口,便于实现机械手的有关计算和图形算法,可保证算法的正确性和可靠性。
OpenGL使用简便,效率高。它具有七大功能:
1) 建模 OpenGL图形库除了提供基本的点、线、多边形的绘制函数外,还提供了复杂的三维物体(球、锥、多面体、茶壶等)以及复杂曲线和曲面 (如Bezier、Nurbs等曲线或曲面)绘制函数。
2) 变换 OpenGL图形库的变换包括基本变换和投影变换。基本变换有平移、旋转、变比镜像四种变换,投影变换有平行投影(又称正射投影)和透视投影两种变换。其变换方法与机器人运动学中的坐标变换方法完全一致,有利于减少算法的运行时间,提高三维图形的显示速度。
3) 颜色模式设置 OpenGL颜色模式有两种,即RGBA模式和颜色索引(Color Index)。
4) 光照和材质设置OpenGL光有辐射光(Emitted Light)、环境光(Ambient Light)、漫反射光(Diffuse Light)和镜面光(Specular Light)。
材质是用光反射率来表示。场景(Scene)中物体最终反映到人眼的颜色是光的红绿蓝分量与材质红绿蓝分量的反射率相乘后形成的颜色。
5) 纹理映射(Texture Mapping) 利用OpenGL纹理映射功能可以十分逼真地表达物体表面细节。
6) 位图显示和图象增强 图象功能除了基本的拷贝和像素读写外,还提供融合(Blending)、反走样(Antialiasing)和雾(fog)的特殊图象效果处理。
以上这三条可使被仿真物更具真实感,增强图形显示的效果。
7) 双缓存(Double Buffering)动画 双缓存即前台缓存和后台缓存,简而言之,后台缓存计算场景、生成画面,前台缓存显示后台缓存已画好的画面。
此外,利用OpenGL还能实现深度暗示(Depth Cue)、运动模糊(Motion Blur)等特殊效果。从而实现了消隐算法。
OpenGL图形库一共有100多个函数。其中核心函数有115个,它们是最基本的函数,其前缀是gl,OpenGL实用库(OpenGL utility library , GLU)的函数功能更高一些,如绘制复杂的曲线曲面、高级坐标变换、多边形分割等,共有43个,前缀为glu;OpenGL辅助库(OpenGL auxiliary library ,GLAUX)的函数是一些特殊的函数,包括简单的窗口管理、输入事件处理、某些复杂三维物体绘制等函数,共有31个,前缀为aux。
此外,还有六个WGL函数非常重要,专门用于OpenGL和Windows 95窗口系统的联接,其前缀为wgl,主要用于创建和选择图形操作描述表(rendering contexts)以及在窗口内任一位置显示字符位图。这些功能是Windows 95 对OpenGL的唯一补充。
另外,还有五个Win32函数用来处理像素格式(pixel formats)和双缓存。由于它们是对Win32系统的扩展,因此不能应用在其它OpenGL平台上。
OpenGL for Windows 95的设计与OpenGL for UNIX的程序设计有一点小区别,关键就在于如何将OpenGL与不同的操作系统下的窗口系统联系起来。
如果调用OpenGL辅助库窗口管理函数,则不用考虑这些问题。下面简要介绍在 Windows 95下 OpenGL 的程序设计关键。
1.图形操作描述
在Windows 95下窗口程序必须首先处理设备描述表(Device Contexts ,DC),DC包括许多如何在窗口上显示图形的信息,既指定画笔和刷子的颜色,设置绘图模式、调色板、映射模式以及其它图形属性。同样,OpenGL for Windows 95的程序也必须使用DC,这与其它Windows 95程序类似。但是,OpenGL for Windows 95必须处理特殊的DC图形操作描述表,这是DC中专为OpenGL使用的一种。一个OpenGL应用图形操作描述表内有OpenGL与Windows 95窗口系统相关的各种信息。一个OpenGL应用首先必须创建一个图形操作描述表,然后再启动它,最后在所定义的窗口内按常规方式调用OpenGL函数绘制图形。
一个图形操作描述表不同于其它DC,它们调用每个GDI函数都需要一个句柄,而图形操作描述表方式下只需一个句柄就可以任意调用OpenGL函数。也就是说,只要当前启用了某个图形操作描述表,那么在未删除图形操作描述表之前可以调用任何OpenGL函数,进行各种操作。
2.像素格式
在创建一个图形操作表之前,首先必须设置像素格式。像素格式含有设备绘图界面的属性,这些属性包括绘图界面是用RGBA模式还是颜色表模式,像素缓存是用单缓存还是双缓存,以及颜色位数、深度缓存和模板缓存所用的位数,还有其它一些属性信息。
3.像素格式结构
每个OpenGL显示设备都支持一种指定的像素格式。一般用一个名为PIXELFORMATDESCRIPTOR的结构来表示某个特殊的像素格式,这个结构包含26个属性信息。Win32定义PIXELFORMATDESCRIPTOR如下所示:
typedef struct tagPIXELFORMATDESCRIPTOR
{ kk1}
// pfd
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;
4.初始化PIXELFORMATDESCRIPTOR结构
PIXELFORMATDESCRIPTOR中每个变量值的具体含义和设置可以参考有关资料,下面举出一个PIXELFORMATDESCRIPTOR初始化例子来简要说明相关变量的意义。定义PIXELFORMATDESCRIPTOR结构的pfd如下:
PIXELFORMATDESCRIPTOR pfd = { kk1}
sizeof(PIXELFORMATDESCRIPTOR), . //size of this pfd 1
PFD_DRAW_TO_WINDOW| // support window
PFD_SUPPORT_OPENGL| // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0,0,0,0,0,0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buff
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
};
在这个结构里,前两个变量的含义十分明显。第三个变量dwFlags的值是
PFD_DRAW_TO_WINDOW |PFD_SUPPORT_OPENGL ,
表明应用程序使用OpenGL函数来绘制窗口
第四个:
PFD_DOUBLEBUFFER,
表明当前采用RGBA颜色模式,第五个采用24位真彩色,既1.67千万种颜色,如果是256色系统则自动实现颜色抖动;因为没有使用alpha缓存和累计缓存,所以从变量cAlphaBits到cAccumAlphaBits都设置为0;深度缓存设置为32位,这个缓存能解决三维场景的消隐问题;变量cAuxBuffers设置为0,在Windows 95下不支持辅助缓存;Windows 95下针对OpenGL变量ilayerType只能设置为PFD_MAIN_PLANE,但在其它平台也许支持PFD_MAIN_PLANE或PFD_MAIN_UNDERLAYPLANE;接下来bReserved变量只能设为0,而最后三个变量Windows 95都不支持,故全设置为0。
5.设置像素结构
当初始化PIXELFORMATDESCRIPTOR结构后,就要设置像素格式。下面举例说明如何设置像素格式。
CClientDC clientDC(this);
int PixelFormat = ChoosePixelFormat(clientDC.m_hDC,&pfd);
BOOL result=SetPixelFormat(clientDC.m_hDC,PixelFormat,&pfd);
第一行语句说明如何得到一个应用窗口客户区的设置描述表。
第一行调用ChoosePixelFormat( )选择一个像素格式,并将像素格式索引号返回给pixelFormat变量;函数中第一个参数是选择像素格式的设备描述表的句柄,第二个参数是PIXELFORMATDESCRIPTOR结构的地址。如果调用失败则返回0;否则返回像素格式索引号。
第三行调用SetPixelFormat( )设置像素格式,三个参数分别是设备描述表的句柄、像素格式索引号和PIXELFORMATDESCRIPTOR结构的地址。如果调用成功则返回TRUE,否则返回FALSE。
6.创建图形操作描述表
正如前所述,必须创建图形操作描述表并启用它后,才能调用OpenGL函数在窗口内进行各种图形操作。一般来说,利用 MFC 中增补的管理图形操作描述表方法来编程比较方便。即在视类 (CView) 的消息 OnCreat( ) 中创建图形操作描述表。