有没有办法在程序集(emu8086)中“读取”13h模式屏幕?
我想要做的是在13h模式下绘制一个形状(颜色A),然后让用户尝试跟踪它(颜色B),有效地重绘其他像素。之后我想做的是“读取”屏幕以检查颜色A中存在多少像素。假设用户进行了不错的工作跟踪,那么大多数A色像素比我原来的形状要少,通过这个指标,我会给用户打分。
有没有办法检查屏幕上是否有彩色像素,或者您是否建议另一种方法来实现“比较”痕迹的目标。
提前致谢。
答案 0 :(得分:1)
16b实模式(BIOS / DOS)中的13h VGA模式具有驻留在地址A000:0000
的视频ram,可随意读/写。
此外,您需要更复杂的评分算法,因为只需跟踪" A"不会告诉你,用户溢出了多少" B"在其他区域(即,用B填充整个屏幕的用户将获胜,因为A = 0)。
13h VGA模式下的视频ram操作示例(TASM语法):
;filename: so_13h.asm
.model small
.code
start:
mov ax,13h ; ah = 0 set mode, al = 13h 320x200 256col mode
int 10h ; set gfx mode
push 0A000h
pop es ; es = A000 (video ram segment)
; fill video ram with some pattern
xor di,di
mov bp,200
lines_loop:
mov dx,64
mov ax,1010h
shade_loop:
stosw ; write 5 pixels
stosw
stosb
; modify colours to create sort of "dither" pattern
xchg al,ah
inc ah
dec dx
jnz shade_loop ; write 320 pixels with different shades
; write 200 lines
dec bp
jnz lines_loop
; read pixel back example
mov di,(13*320 + 56) ; read pixel from [x, y] = [56, 13]
mov al,es:[di]
; here AL = 16h (colour of pixel at [56, 13] position)
; wait for any key
xor ax,ax
int 16h
; restore text mode
mov ax,3 ; ah = 0, al = 3 (text mode 80x25)
int 10h
; terminate code
mov ah,4Ch
int 21h
end start
要在dosbox下构建+运行我使用:
tasm so_13h.asm
tlink /x so_13h.obj
so_13h.exe
编辑:还有int 10h
"Read Graphics Pixel at Coordinates"的BIOS服务:
输入:
AH = 0D BH = page number, see VIDEO PAGES CX = column number (zero based) DX = row number (zero based)
返回时:
AL = color of pixel read
但一般来说,由于int
呼叫本身的性能损失,BIOS服务非常慢,而且BIOS必须从头再次计算每个像素的偏移量,而例如你的"评估跟踪&#34 ;可以使用一些预期的屏幕"缓冲区用于比较连续重复使用前一个偏移量的像素到达下一个像素,从而避免过多的计算。
因此,您应该尝试制作类似于我在示例中填充屏幕的方式,处理"批处理"中的像素。
即使是优化为单词(两个像素)与字节(一个像素)的读取确实对386时代的真实硬件有所帮助,但这可能使您的任务过于复杂,JFYI甚至这些微妙的细节确实带来了差异然后
edit2:关于评分算法:
取决于你想要得分的确切程度,但你可以这样做:
现在最终得分可能是:
得分= w0 *(toPaint - notPaint)+ w1 * overPaintL1 + w2 * overPaintL2 + w3 * overPaintL3
其中w0..w3是"权重"奖励/ malus,w0应该是最强的,因为用户确实绘制了像素完美的数量(比如50 ...也错过A像素也是-50然后),w1应该是非常小的malus,像-1(只有1个像素关闭),w2可能是-5(2像素关闭),w3可能像-10(像素完全脱离形状)。
因此,如果用户具有~200像素的形状(50x50像素的正方形),并且他透支了184个像素:notPaint = 16,并且基本上几乎到处都是+ -1 pix关闭(创建2px宽方形):overPaintL1 = 200 ,有时他会多走一点:overPaintL2 = 15,overPaintL3 = 35
然后得分= 50 *(200-16)+ -1 * 200 + -5 * 15 + -10 * 35 = 8575 (在这样的例子中,满分为50 * 200 = 10000)。
也许你需要重新调整重量和加厚,但我认为这种方法最终可以起作用。
编辑:关于加厚的另外一个注意事项...你必须在所有方向上均匀地加厚,以使" B"在每个方向上均匀地过度绘制,因此我原来的右/底检查无效,但在单个缓冲区中进行4方向检查也是不可能的。所以要么你需要引入第二个内部缓冲区,从一个到另一个加厚,或者先进行两遍加厚,然后向右延伸,向后延伸,向左延伸+向上延伸,或者你可以用&绘制形状#34; A"进入[-N .. + N,-N .. + N]位置的内部缓冲区,覆盖原始设计周围的+ -N像素。
双缓冲器检测任何" A"在源缓冲区中用于当前目标位置的3x3网格内部可能是最容易编码的。
我的原始描述确实只在左侧+顶部方向加厚了A形状,因此底部/右侧的透支比左侧/顶部的透支更加不利。
嗯...最后它变得更加棘手然后直观地预期,确保你用小部件编码,并分别和正确地调试每个部分,还包括角落情况和极端输入。