我的编程环境是一个MS-DOS模拟器,我在Assembly 16位编程。
我正在使用常规文本模式,我可以在其中打印字符并使用属性。
在屏幕的一部分,我每秒都会画出很多角色,成千上万的角色,这会创造出一个漂亮的动画。
问题是,为了创建动画,首先我要删除旧的,我基本上打印空间字符大约1000次。 (!) 现在,因为我正在这样做,每次重绘动画时都会出现轻微的闪烁问题,这个问题很明显,并且非常很烦人。
我正在使用视频服务来完成所有输出和动画事务。所以我的第一个想法是以某种方式阻止屏幕刷新,重新绘制所有内容,让屏幕继续自我刷新。
因为这个程序每秒发生很多次,并且必须多次发生,所以我发现其他任何清洁方法都没有用处。
答案 0 :(得分:5)
基本问题是,如果只是一瞬间,你会向用户展示他们不想看的东西,一个空白的空白屏幕。这是导致闪烁的原因。您可以通过使用单个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 :(得分:3)
直接写入视频内存:
找出视频模式如下:
如果视频模式为7,则屏幕内存从B000:0000开始
存储器在字符的一个字节和"属性"的一个字节之间交替。 (粗体,下划线,反转,闪烁)
如果您使用的是物理硬件,最好在写入物理屏幕内存之前等待垂直回扫以避免" snow"。这可以通过在写入之前等待端口0x3DA变为奇数来完成。
有关此技术的局限性和可能的改进的讨论,请参阅此old Usenet thread。