我在90年代的时候也使用了类似的方法,采用了两种不同的方式。
第一种方法涉及“窗口化”,这是VESA SVGA标准支持的。某些卡片正确地实现了它。基本上,如果你有一个帧缓冲区/视频RAM大于可显示区域,你可以绘制一个大位图并给系统坐标,以显示该区域内的窗口。通过改变这些坐标,您可以进行滚动而无需重新填充帧缓冲区。
另一种方法依靠操作BLT方法,该方法用于将已完成的帧传输到帧缓冲区。将与屏幕大小相同的页面传输到帧缓冲区非常容易和高效。
我找到了一些旧的286汇编代码(在一个正常运行的17年老软盘上!),该代码将64000字节(320x200)屏幕从屏幕外页复制到了视频缓冲区:
Procedure flip
{ This copies the entire screen at "source" to destination }
asm
push ds
mov ax, [Dest]
mov es, ax
mov ax, [Source]
mov ds, ax
xor si, si
xor di, di
mov cx, 32000
rep movsw
pop ds
end
rep movsw
指令移动CX个字(在此情况下,每个字是两个字节)。由于这基本上是一条指令,它告诉CPU尽可能快地移动整个东西,因此非常高效。
然而,如果您有一个更大的缓冲区(比如侧向滚动游戏中的1024 * 200),您可以很容易地使用嵌套循环,并且每次循环复制一行像素。例如,在1024像素宽的缓冲区中,您可以复制字节:
start count
0+left 320
1024+left 320
...
255*1024+left 320
其中left
是您想要从大背景图像的哪个x坐标(屏幕左侧)开始的位置。
当然,在16位模式下,需要对段指针(ES、DS)进行一些魔法和操作才能获得大于64KB的缓冲区(实际上是多个相邻的64k缓冲区),但它运行得非常好。
这个问题可能有更好的解决方案(今天肯定有更好的解决方案),但对我来说它起作用了。