停止屏幕刷新-INT 0x10(视频服务)-程序集中



我的编程环境是MS-DOS模拟器,我在Assembly 16位中编程。

我使用的是常规文本模式,在这里我可以打印字符和使用属性。

在屏幕的一部分,我每秒钟都会画很多角色,成千上万,这创造了一个很好的动画。

问题是,为了创建动画,首先我必须删除旧的,我基本上要打印1000次左右的空间字符。(!)现在,因为我正在这样做,每次重新绘制动画时,都会有一个轻微的闪烁问题,这是显而易见的,而且非常讨厌。

我正在使用视频服务来做所有的输出和动画。所以我的第一个想法是以某种方式阻止屏幕刷新,重新绘制所有内容,让屏幕继续自己刷新。

因为这个过程每秒发生多次,而且必须发生多次,我发现任何其他清洁方法都没有太大帮助。

基本问题是,如果只是一瞬间,你向用户显示的是他们不想看到的东西,一个充满空格的空白屏幕。这就是导致闪烁的原因。你可以通过使用一个BIOS调用(例如INT 10h AX=0600h)更快地擦除屏幕来改进这一点,但更好的解决方案是只向用户显示他们想要看到的内容。

从上到下覆盖所有内容

一种方法是更改代码,以便在绘制新框架时完全覆盖旧框架。这样就不需要擦除屏幕。例如,不要在屏幕上的不同位置绘制文本,而是从左上角开始,从左到右,从上到下绘制文本。打印空格以将光标从一个位置移动到另一个位置。假设您只有两个可以使用的功能,一个是将光标移动到屏幕左上角,另一个是打印字符并推进光标。

在用户看不到的地方绘制

如果这太难了,你可以使用屏幕外的缓冲区来做你现在正在做的事情。擦除屏幕外的缓冲区,在上面绘制文本,然后显示。这样用户就永远看不到他们从未想过要看到的擦除屏幕。您可以在内存中创建一个屏幕外缓冲区,然后将其复制到屏幕上,也可以在视频内存中的页面之间切换。

绘制到内存中的屏幕外缓冲区

在内存中使用缓冲区意味着你不能使用BIOS功能来利用它,但根据具体情况,这可能会更方便。您可以使用普通的内存写入来擦除缓冲区并绘制文本,然后将整个缓冲区复制到屏幕上。本质上,这是一种从上到下完全覆盖所有内容的方式,正如我上面所描述的。

绘制到非活动视频页面

在视频页面之间切换可能会让您使用与现在相同的BIOS功能来绘制文本。也就是说,假设他们在BH中接受一个指定要使用哪个页面的参数。并不是所有的BIOS函数都有这个功能,特别是我前面提到的BIOS函数INT 10h,AH=06h没有。您将使用两个视频页面,0和1,并且您需要跟踪哪个页面当前处于活动状态并显示给用户。然后,你可以在非活动页面上擦除和绘制文本,完成后,你可以翻页,使非活动页面成为活动页面。为此,您可以使用INT 10h AX=05XX,其中XX是要激活的页码。

直接写入视频存储器

一种更先进的技术是直接写入视频存储器。在MS-DOS流行的时候,PC的速度太慢了,以至于使用BIOS绘制文本对于任何实际的动画来说都太慢了。相反,大多数这样做的应用程序都直接写入视频内存,绕过了速度较慢的BIOS例程。您可以将上面描述的任何技术与此结合使用。例如,您可以绘制到普通内存中的屏幕外缓冲区,然后使用REP MOVS指令将其复制("blit")到视频内存。

绕过BIOS的缺点是它会使代码的可移植性降低。例如,最初的IBM PC单色显示适配器(MDA)和彩色图形适配器(CGA)的视频内存位于不同的位置(分别为B000:0000和B800:0000)。其他不是100%PC兼容的第三方电脑更奇怪。有些不支持文本模式,BIOS会使用位图图形模式绘制文本。

直接写入视频存储器:

  • 如下查找视频模式:

    1. 将AH设置为0x0F
    2. 呼叫中断0x10(视频服务)
    3. 在AL中查找视频模式
  • 如果视频模式为7,则屏幕存储器从B000:0000 开始

  • 否则,屏幕内存从B800:0000开始

内存在字符的一个字节和"属性"(粗体、下划线、反转、闪烁)的一个字符字节之间交替

如果您使用的是物理硬件,最好在写入物理屏幕内存之前等待垂直回扫,以避免"下雪"。这可以通过在写入之前等待端口0x3DA变为奇数来完成。

请参阅这个旧的Usenet线程,了解该技术的局限性和可能的改进。

最新更新