hyde
路人甲
路人甲
  • 注册日期2003-09-24
  • 发帖数555
  • QQ
  • 铜币1457枚
  • 威望0点
  • 贡献值0点
  • 银元0个
阅读:1204回复:0

3D图形编程指南2续 - 硬件接口

楼主#
更多 发布于:2004-04-27 13:51
<b>1.2.1 MS-DOS
  </b>尽管MS-DOS在操作系统市场上不再是主要的一个,但在考虑操作系统历史远景时它仍然令人感兴趣,这种操作系统只对传统的操作系统函数有很基本的最低限度的支持。有时候这种操作系统仍然是要考虑的游戏平台之一,当然,3D图形也不例外。
  既然MS-DOS控制得很少并且允许以令人惊异的方式覆盖自身,它在相当程度上推进了快速的游戏图形的开发,成为许多开发人员选择平台。MS-DOS只提供了对显示和输入设备基本的支持,留给了应用程序大多数的硬件接口任务。
  由于IBM兼容机在办公和家用环境市场上占有极大的份额,相当数量的公司为MS-DOS开发了程序员工具。有很多不同的用于PC的C/C++编译器,每种都有自己的特别品质。最流行的是Borland公司的Borland C/C++,Microsoft公司的Visual C/C++,以及Watcom C/C++,最后一个是DJGPP,Dj Delorie编写的免费软件,也是unix的GNU C/C++/Objective C移植到MS-DOS的版本。
  MS-DOS的一个很大的问题是由于intel 8086处理器是16位的,因此操作系统也是16位的。在它下面运行的程序使用段存储器访问,这样内存中定位的地址存在2个寄存器中。基址寄存器包含了共1M允许内存空间的16位段索引,第二个寄存器包含了当前位置的偏移。不幸的是,这就意味着如果我们想要寻址超过64K内存(16位可以寻址的最大内存空间),就必须改变基址寄存器的内容。这种设计来自历史的原因,在过去,为了在某种程度上提供同早期的intel 8080处理器兼容,它是一种可以接受的方案。尽管处理器的升级换代非常频繁,但在这种情况下,64K的内存寻址空间是不够用的。仅仅在几年前,Borland和Microsoft的编译器还只能支持16位的MS-DOS代码。在这类程序中访问扩展内存(1MB以上的内存空间)是一个技巧;尝试把应用程序放入总共640K的DOS内存中同样也需要技巧。
  最近几年,首先是intel 80386开始出现在市场上,随着这些更高级的处理器的出现,使用新的保护模式寻址方式,开拓了编写32位MS-DOS应用程序的新纪元。大多数现代编译器在功能上能够支持32位的MS-DOS应用程序,无论使用什么途径。这些应用程序在DOS扩展器下工作, 系统程序因此而能够把处理器切换到保护模式下并管理内存。使用32位的寄存器寻址也减少了过去的许多限制。
  实际上,处理器在保护模式下使用比早期8086段模式更复杂的寻址方式。不是指向内存的位置,段寄存器要指向的是某个表格的一项,这个表格包含了段开始的物理地址以及长度。然而这种复杂性隐藏了从应用程序开始到允许在外部内存空间进行操作的大部分时间。
  作为能够得到的显示设备,PC硬件经历了许多次混乱的升级换代,从4色的CGA(Color Graphics Adapter)到16色的EGA(Extended Graphics Adapter), 再到256色的VGA(Video Gate Array)最后是SVGA(Super VGA)。不知何故,硬件厂商从来没有为SVGA建立一个标准的接口规范,因此显卡在涉及到吸引人的高分辨率的时候有相当大的不同。
  早先的IBM PC硬件在0xA000:0x0000和0xB000:0xFFFF(段:偏移)间映射显存地址 。辅助执行32位应用程序的DOS扩展器重新分配了内存空间,这样在Dos4gw(Rational Systems公司的的产品,用于同Watcom c/c++编译的程序一同使用)中,显存从0xA0000起始。在go32(用于DJGPP第一个版本)中从0xD0000000开始。DJGPP的第二个版本使用的是DPMI,DOS保护模式接口(DOS Protected Mode Interface),通过DPMI调用访问显存。
  但是,从0xA000:0x0000到0xB000:0xFFFF的地址只有128K存储空间, 大多数SVGA高分辨率模式,尤其是RGB模式,需要比这多得多的空间。为了通过小内存窗口访问大一些的存储器,发明了一种页面策略,称作“页(bank)切换”当我们想访问显存中一个特定的位置的时候,我们必须在一个128k的内存页中指定位置。然后,这个页能通过0xA000:0x0000窗口访问到。换句话说,窗口中的每个地址对应了显存中的几个位置,每个在一个页内,页切换用于指定确切的那一个。一些显卡支持提供大一些的寻址窗口以提供对保护模式特殊考虑的支持,这样页切换就可以避免了。但是,这种页切换的特性,其大小和数量每个显卡都不尽相同。目前正在通过制定VESA标准来对不同的SVGA卡提供通用接口。
  为了完成在1.2节中提到的三个显示接口函数,显卡必需被切换到具体的屏幕模式。这或者通过通讯端口操纵显卡上的寄存器来实现,或者通过0x10中断利用操作系统的例程。一旦完成了,就可以通过把位图传递给对应显示设备内存的地址窗显示一个图像。
  实现事件处理在MS-DOS下要么非常的复杂,要么就极其简单。最复杂的方式是在输入设备改变的时候产生硬件中断,再进行代码处理。对于键盘来说,这就意味着加入0x9中断代码。简单的方式是把这个任务交给操作系统(C标准库会完成这个)去做。后面这种方法允许应用程序查询被特别例程调用的设备的状态。
  总的来说,为MS-DOS开发的快速图形应用程序的例子(最普遍的是游戏)证明了有时候这么做是有好处的,停留在靠近硬件和避免高级操作系统带来的多余开销。虽然速度快,但这种方案往往是难以被移植的,并且在开发上耗费了相当多的时间。

  <B>1.2.2 MS-Windows
</B>  MS-Windows统治了今日的办公和家用环境。它是由Microsoft提供,在MS-DOS上构成的窗口系统。早期的Windows系统继承了DOS的问题,比如说16位段执行表等。早期只能得到多任务联合操作等特性。第一个版本发布后,Microsoft又推出了带有32位执行表的Windows NT,后来的Windows 95有了更好的多任务和改善了的图形界面。因此,在Windows下的快速的交互式图形应用程序,例如3D游戏变得非常吸引人了。Mirctsoft不断地推出新的库和特性。与其紧密联系的不断提高的处理器性能抵消了windows系统带来的附加开销。
  设计为在MS-Windows下运行的程序有着与MS-DOS非常不同的结构。举例来说,对每个被windows系统接受的事件必须有个规定。访问资源,包括分配窗口和显示图像,必须通过API(Application Program Interface,应用程序编程接口)集的调用完成。举例来说,为了显示图像,我们必须请求操作系统分配一个窗口,然后通过另外一系列的API调用,请求在这个窗口上显示位图。在程序清单1.3中介绍了这种执行方法。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/1.1/1-7.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>程序清单1.3 在MS-Windows中显示图形位图</B></FONT></TD></TR></TABLE>
  同样也有对应于维护调色板的API函数集,其中一些在程序清单1.3中已经出现过。基于调色板的模式有的时候对Windows系统来说有时处理起来有点复杂。有可能有许多颜色密集的应用程序同时运行,每个都需要不同的颜色集放置到主调色板中,主调色板的位置是有限的,通常比较小。为了解决这个问题,Windwos给出了用于颜色匹配和通知调色板状态改变的消息的API。当调色板不再有可用的项时,至少我们能够通过匹配例程找到最接近的颜色。当一些应用程序在根本上改变调色板的时候,其它的应用程序能够注意到这个,并相应地重新匹配颜色。主调色板也包含一系列保留的颜色用于绘制可视界面组件例如菜单、边框等等。保留的颜色也能被改变,只有两个例外,即纯粹的黑色和纯粹的白色。
  在Windows中的执行流程遵循事件驱动范例。代码的某段相应于特定的事件被执行。通常的应用程序首先要分配一个或多个窗口,然后进入事件循环,事件循环响应从队列中取得的消息,发送给相应的函数。这些函数通常与特定的窗口和动作相关联,对事件做出响应。
  在程序清单1.4中的代码演示了事件循环。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/1.1/1-8.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>程序清单1.4 MS-Windows事件循环</B></FONT></TD></TR></TABLE>
  在程序清单1.4的例子中,循环通过PeekMessage例程得到消息。消息被处理并发送给响应函数。在调用期间,一个MSG结构被填充,其中带有描述事件的信息。这个结构中的message字段制定了事件的类型。比如说,键按下被标示为WM_KEYDOWN。有两个函数被设计用来访问事件队列中的信息。GetMessage取得消息,如果没有的话则等待,直到消息在队列中出现。PeekMessage是一个非模块化的版本,如果没有消息,返回0值。这个对于交互式应用程序来说是非常重要的,因为它必须不断地生成和显示新帧,因此,即使在没有消息要处理的时候还要执行一些通常的工作。只要PeekMessage返回的值是0,出现在程序清单1.4中开始发送消息给处理函数,即事件循环的实现细节。
  InvalidateRect和后面的UpdateWindow导致分别发送WM_ERASEBKGND和WM_PAINT两个消息。这两个消息, 第一个发送给擦除窗口背景的处理函数,第二个发送给重绘整个窗口的函数。
  既然Windows尝试把显示设备存储器的花费减至最小, 应用程序必须通过调用InvalidateRect建议操作系统窗口的哪个部分要更新(即刷新),只有对应于特定区域的显存内容要改变。因此,虽然交互式应用程序没有明确地在每帧(一个接一个地覆盖前一个)间擦除显存内容,但在这种情况下,仍然可以调用InvalidateRect函数提示操作系统并随后简单地忽视WM_ERASEBKGN消息,而不是物理地擦除背景。
  程序清单1.5的代码阐释了处理函数。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/1.1/1-9.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>程序清单1.5 MS-Windows事件处理</B></FONT></TD></TR></TABLE>
<B></B>  正如清单1.5演示的那样,没有处理的消息被重新发送到特定的API函数进行缺省的处理。
  可能,MS-Windows所有的这些机构和约定看起来让人很费解。但是,对Windows或者其它的这类现代操作系统来说,吸引人的一点是理论上应用程序更喜欢这么与硬件打交道。其代价是性能可能会有所损失,这是因为使用了多余的代码层防止直接访问硬件。通常这种代价比起移植性增强和编程简单化来说是可以接受的。还要注意到,今天可以得到的用于Windows的接口构建工具,例如,Delphi,隐藏了许多同操作系统通信的细节,这就使以前的许多困难变得容易解决了。

  <B>1.2.3 X-Windows</B>
  X-Windows是一个GUI系统,实际上通常用于研究和教育的环境。它首先在MIT(麻省理工学院)开发出来,随后的改善和标准化以及维护工作由特别创建的X联盟完成,X联盟是一个联合了多个教育和商业机构的组织。
  X-Windows对从个人到超级计算机来说都是一个极其不寻常的平台。同一些其它的窗口式的系统一样,X-Windows不是一个操作系统,而是一个在UNIX上的图形用户界面。在极少数的情况下,它也是其它操作系统的图形用户界面,比如说NeXTStep,甚至MS-DOS。
  为X-Windows写的应用程序,通常指的是一个X客户(X client),发送请求到在其它地方甚至是通过网络连接的远端计算机上的窗口式的服务器。服务器解释请求并执行需要的动作,它也在队列里保留从本地输入设备接受到的信息。应用程序能够响应这些信息并相应地处理情况。
  当应用程序调用X库函数的时候,就产生了对服务器的请求。按照约定,这个库中所有的函数都有前缀“X”。
  在窗口中显示图像可以通过调用XPutImage函数来实现。通常的X应用程序首先会通过调用XOpenDisplay打开某个显示设备,然后分配必须的接口组件,比如说窗口,然后进入事件循环,取出队列中的消息,以特定的动作响应事件。在程序清单1.6中演示了事件循环。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/1.1/1-10.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>程序清单1.6 X-Windows事件循环片段</B></FONT></TD></TR></TABLE><B>
</B>  只有应用程序在XSelectInput调用中指定能够被处理的事件才会出现在队列中。应该注意到,基本的X-Windows只能得到基本的接口组件。但是,也有一些生产商在引进一些有用的特性的时候使用了一些扩展的规定。附加的库提供高级接口组件和模板用于编写面向对象的X应用程序。总的来说,在X-Windows中使用的约定和基本原理是非常直观的,允许以直截了当的简明方式编写代码,不象前面提到的系统,我们不能违反它的规定。

  <B>1.2.4 NeXTStep</B>
  NeXTStep首先随着NeXT公司一同出现,基于Motorola 68040处理器。很快,这种强有力的操作系统在使用Intel 80386的IBM PC兼容机上也出现了,后来HP也使用了这种操作系统。NeXTStep包含了基于Mach-O的操作系统函数,Mach-O是一种类似于UNIX的操作系统。
  同前面描述的操作系统不同,NeXTStep包含了与面向对象开发和代码重用更相容的支持。利用NeXTStep窗口系统优点的编写应用程序的主要语言是Objective C,同C++非常类似,Objective C扩展了基本的Kernighan和Ritchie的支持面向对象范例的C语法。但是在概念和语法级别上这两种语言有着多种不同。举例来说,成员函数调用(在objective C术语中叫做方法调用)在Objective C中附在方括号内,然而C++把这个语法用于访问结构体中的成员变量。在最后一章中关于应用程序设计部分,我们会再讨论C++和Objective C。NeXTStep支持同许多强大的工具一起开发,比如说Interface Builder中的多开发人员库,这是一个应用程序前端可视结构辅助工具。
  早期的NeXT硬件只提供四个灰色色调的显示器, 处理方式同XT中的CGA有些相同,是一个很大的家伙。操作系统提供所有需要的来自实际硬件的抽象层,这样用户的程序无需知道用户可视对象是什么类型。举例来说,在窗口中一个特定的显示位图的接口函数会根据有效的显示硬件调整格式。我们可以使用每像素层一个字节的方式渲染图像,操作系统会通过抖动转换它,如果需要的话,甚至在内部的硬件上完成合适的显示。在程序清单1.7中展示了在窗口中显示位图的方法。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/1.1/1-11.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>程序清单1.7 在NeXTStep中显示图像位图</B></FONT></TD></TR></TABLE>
  在程序清单1.7中要注意方括号中的方法引用。在方括号中的一个名字指定了哪个对象调用方法名跟踪的函数,以及在引用中使用的参数。NeXTStep应用程序的执行流程与MS-Windows和X-Windows应用程序都有很大的不同。也没有MS-Windows风格的事件处理函数。代替它的是,窗口系统本身在表达显示接口组件的对象中调用必须的方法。通常的应用程序分配需要的接口组件,然后调用在NXApp对象中运行的方法,这就相当于启动事件循环。(参看程序清单1.8)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/1.1/1-12.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>程序清单1.8 NeXTStep中的事件循环初始化</B></FONT></TD></TR></TABLE>
  在应用程序运行期间,用户的动作引起了应用程序可视接口对象中的方法引用。然而,应用程序直接检查事件队列中的状态并相应地采取动作也是可以的。
  许多交互式3D应用程序必须在连续不断的基础上生成和显示帧。对NeXTStep来说,可以通过通知操作系统定时地调用某个函数,比如说,调用DPSAddTimedEntry函数。
  全面地说来,NeXTStep提供了及其可靠的开发人员的平台,以一致的用户界面联合了UNIX的力量,同时支持面向对象开发,这一点还没有被竞争中的操作系统所超越。然而令人惊奇的是,NeXTStep看起来没有达到一个重要的市场份额,没有被广大的计算机用户集团所完全欣赏。

  <B>1.2.5 MacOS</B>
  Apple公司的Macintosh在微型计算机历史上和今天的市场都占有了一个主要的位置。由于它的出现,Macintosh领先倡导了许多与今天的桌面计算机不可分的技术。图形用户界面就是这类其中的一个技术,也许是最给人以深刻印象的。Macintosh本身图形用户界面的连贯性在桌面印刷等领域成为了令人喜爱的平台。
  传统的Macintosh操作系统(即MacOS)包括了一系列称之为“管理器”的模块成员,它们有基本的功能。文件管理器(File Manager)用于访问文件系统,虚拟内存管理器(Virtual Memory Manager)提供了相关寻址空间的服务。设备管理器(Device Manager)为配属的设备服务等。操作系统的管理器伴随着一系列来自工具盒(Toolbox)的接口函数集,它们为应用程序提供了某种高级功能。举例来说,QuickDraw完成所有的包括图元绘制在内的显示操作,窗口管理器(Window Manager)允许创建和管理窗口,事件管理器(Event Manager)提供对事件队列的访问,等等。
  在启动的时候,Macintosh应用程序相应地初始化计划使用的管理器。程序清单1.9展示了这个过程。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/1.1/1-13.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>程序清单1.9 初始化管理器</B></FONT></TD></TR></TABLE>
  一旦管理器被初始化了,应用程序就能够创建窗口,比如说,调用NewWindow函数。这个函数分配必须的结构并传递给窗口一个指针,这个指针将来用于为其它的接口函数标识创建的窗口。
  由于它比较早地支持GUI,Macintosh在显示硬件上有更好的优点。为了用于图形应用程序,硬件可以通过Quick Draw提供的服务被访问到。这些服务包括支持位图和演化超时。目前,对离屏缓冲的处理被封装在GWorld结构和关联的例程中。GWorld结构包含了所有必须的图形层和几何结构上的信息,并保持指针指向当前的像素数组。位块传输通过调用CopyBits函数复制这个数组到目的窗口帧缓冲区完成。
  在MacOS下处理事件同其它我们提到的基于窗口的系统非常类似。事件可以通过调用GetNextEvent函数从队列中取出,这个函数也能过滤事件,只把应用程序请求处理的事件发送过去。(参见程序清单1.10)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/1.1/1-14.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>程序清单1.10 MacOS的事件循环片段</B></FONT></TD></TR></TABLE><B>
</B>  总的说来,Macintosh对开发人员和用户提供了更舒适的环境。这种平台的缺点是缺少真正的多任务,只能得到联合操作多任务方式,以及缺少合适的内存保护。这种状况会得到改变,因为Apple已经提出了支持PowerMac特性的RISC处理器,并且为这种特性的使用考虑了操作系统的解决方案。

<B>  小结</B>
<FONT color=#993300><FONT face=隶书><FONT face=楷体_GB2312><FONT>  综上所述,我们已经讨论了图形应用程序使用的面向接口硬件和与用户通讯的一般策略。这种策略在不同的操作系统和硬件上的实现方式是不同的。为了实现交互式图形应用程序,我们集中考虑如何在屏幕上显示图像以及如何处理用户的响应。
  </FONT></FONT></FONT><FONT face=楷体_GB2312><FONT>在后面几章,我们接着讨论用来创建虚拟世界图像的算法。这些算法并不面对硬件,但依赖于硬件在屏幕上显示图像的能力。</FONT></FONT></FONT>
喜欢0 评分0
夜落了,风静了,我喜欢一本书,一杯茶,一粒摇曳的烛光...
游客

返回顶部