"Read" 汇编 13h 模式下的图形屏幕
"Read" the graphics screen in assembly 13h mode
有没有办法 "read" Assembly (emu8086) 中的 13h 模式屏幕?
我想要做的是在 13h 模式下绘制一个形状(颜色 A),然后让用户尝试描绘它(颜色 B),有效地在其他像素上重绘。之后我想做的是 "read" 屏幕检查颜色 A 中存在多少像素。假设用户进行了不错的跟踪工作,大多数 A 色像素比我原来形状的像素少,通过这个指标我会给用户打分。
有没有办法检查屏幕上是否有彩色像素,或者您是否提出了另一种实现 "comparing" 痕迹目标的方法。
提前致谢。
16b实模式下的13h VGA模式(BIOS/DOS)的显存地址为A000:0000
,随意read/write即可。
此外,您还需要更复杂的评分算法,因为仅跟踪“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 服务:
input:
AH = 0D
BH = page number, see VIDEO PAGES
CX = column number (zero based)
DX = row number (zero based)
on return:
AL = color of pixel read
但由于 int
调用本身的性能下降,BIOS 服务通常非常慢,而且 BIOS 必须从头开始重新计算每个像素的偏移量,而例如您的“评估跟踪”可以使用一些“预期屏幕”缓冲区来比较连续重复使用前一个像素的偏移量以到达下一个像素,避免过多的计算。
所以您应该尝试生成类似于我在示例中填充屏幕的方式,“批量”处理像素的方式。
即使阅读优化为字(两个像素)与字节(一个像素)在 386 时代确实对真正的 HW 有所帮助,但这可能使您的任务过于复杂,仅供参考,即使如此细微的细节在当时也确实有所不同。
edit2:关于评分算法:
取决于你想要得分的准确程度,但你可以这样做:
- 内存中有原始的“A”缓冲区
- 计算屏幕上“A”的数量 = toPaint
- 让用户用“B”绘图
- 计算屏幕上“A”的数量 = notPaint
- 从缓冲区中“0”上方的屏幕计算“B”= overPaintL1
- re-运行 inside internal buffer [0,0]..[maxX-2,maxY-2] 如果右侧有“A”,则将每个像素更改为“A”或当前像素的底部 = 这将使“A”形更厚(可能 运行 两倍三次覆盖 +-2 或 +-3 像素)
- 在缓冲区 = overPaintL2 中计算“B”超过 0
- 再把“A”加粗一次
- 在缓冲区 = overPaintL3 中计算“B”超过 0
现在最终得分可能是这样的:
score = w0 * (toPaint - notPaint) + w1 * overPaintL1 + w2 * overPaintL2 + w3 * overPaintL3
其中 w0..w3 是 bonus/malus 的“权重”,w0 应该是最强的,因为这是用户绘制的完美像素数量(比如 50 ......每个错过的 A 像素是-50 那么),w1 应该是非常小的 malus,例如 -1(仅偏离 1 个像素),w2 可能类似于 -5(偏离 2 个像素),w3 可能类似于 -10(完全偏离形状的像素) .
因此,如果用户的形状约为 200 像素(50x50 像素的正方形),并且他透支了 184 像素:notPaint = 16,并且基本上几乎所有地方都命中 +-1 像素偏移(创建 2px 宽的正方形):overPaintL1 = 200,有时他会稍微偏离一点:overPaintL2 = 15, overPaintL3 = 35
那么得分=50*(200-16)+-1*200+-5*15+-10*35=8575
(这个例子中的满分是50*200 = 10000)
也许你需要重新调整权重和加厚很多,但我认为这种方法最终可以奏效。
编辑:关于增厚的更多注意事项...您必须在所有方向上均等地增厚,以使“B”在每个方向上的透支成本均等,因此我原来的 right/bottom 检查无效,但正在做单缓冲区中的 4 方向检查也是不可能的。所以要么你需要引入第二个内部缓冲区,从一个到另一个增厚,或者做两次增厚,首先向前并向右+底部延伸,然后向后向后并向左+顶部延伸,或者你可以用“绘制形状” A" 到 [-N..+N,-N..+N] 位置的内部缓冲区,以覆盖原始设计周围的 +-N 像素。
检测当前目标位置的源缓冲区中 3x3 网格内的任何“A”的双缓冲区可能最容易编写代码。
我原来的描述确实只在左+上方向加厚了A形,所以在bottom/right上的透支比在left/top上的透支更受惩罚。
嗯...最终证明它比直觉预期的更棘手,请确保按小部分编写代码,并分别正确地调试每个部分,还包括极端情况和极端输入。
有没有办法 "read" Assembly (emu8086) 中的 13h 模式屏幕?
我想要做的是在 13h 模式下绘制一个形状(颜色 A),然后让用户尝试描绘它(颜色 B),有效地在其他像素上重绘。之后我想做的是 "read" 屏幕检查颜色 A 中存在多少像素。假设用户进行了不错的跟踪工作,大多数 A 色像素比我原来形状的像素少,通过这个指标我会给用户打分。
有没有办法检查屏幕上是否有彩色像素,或者您是否提出了另一种实现 "comparing" 痕迹目标的方法。
提前致谢。
16b实模式下的13h VGA模式(BIOS/DOS)的显存地址为A000:0000
,随意read/write即可。
此外,您还需要更复杂的评分算法,因为仅跟踪“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 服务:
input:
AH = 0D BH = page number, see VIDEO PAGES CX = column number (zero based) DX = row number (zero based)
on return:
AL = color of pixel read
但由于 int
调用本身的性能下降,BIOS 服务通常非常慢,而且 BIOS 必须从头开始重新计算每个像素的偏移量,而例如您的“评估跟踪”可以使用一些“预期屏幕”缓冲区来比较连续重复使用前一个像素的偏移量以到达下一个像素,避免过多的计算。
所以您应该尝试生成类似于我在示例中填充屏幕的方式,“批量”处理像素的方式。
即使阅读优化为字(两个像素)与字节(一个像素)在 386 时代确实对真正的 HW 有所帮助,但这可能使您的任务过于复杂,仅供参考,即使如此细微的细节在当时也确实有所不同。
edit2:关于评分算法:
取决于你想要得分的准确程度,但你可以这样做:
- 内存中有原始的“A”缓冲区
- 计算屏幕上“A”的数量 = toPaint
- 让用户用“B”绘图
- 计算屏幕上“A”的数量 = notPaint
- 从缓冲区中“0”上方的屏幕计算“B”= overPaintL1
- re-运行 inside internal buffer [0,0]..[maxX-2,maxY-2] 如果右侧有“A”,则将每个像素更改为“A”或当前像素的底部 = 这将使“A”形更厚(可能 运行 两倍三次覆盖 +-2 或 +-3 像素)
- 在缓冲区 = overPaintL2 中计算“B”超过 0
- 再把“A”加粗一次
- 在缓冲区 = overPaintL3 中计算“B”超过 0
现在最终得分可能是这样的:
score = w0 * (toPaint - notPaint) + w1 * overPaintL1 + w2 * overPaintL2 + w3 * overPaintL3
其中 w0..w3 是 bonus/malus 的“权重”,w0 应该是最强的,因为这是用户绘制的完美像素数量(比如 50 ......每个错过的 A 像素是-50 那么),w1 应该是非常小的 malus,例如 -1(仅偏离 1 个像素),w2 可能类似于 -5(偏离 2 个像素),w3 可能类似于 -10(完全偏离形状的像素) .
因此,如果用户的形状约为 200 像素(50x50 像素的正方形),并且他透支了 184 像素:notPaint = 16,并且基本上几乎所有地方都命中 +-1 像素偏移(创建 2px 宽的正方形):overPaintL1 = 200,有时他会稍微偏离一点:overPaintL2 = 15, overPaintL3 = 35
那么得分=50*(200-16)+-1*200+-5*15+-10*35=8575 (这个例子中的满分是50*200 = 10000)
也许你需要重新调整权重和加厚很多,但我认为这种方法最终可以奏效。
编辑:关于增厚的更多注意事项...您必须在所有方向上均等地增厚,以使“B”在每个方向上的透支成本均等,因此我原来的 right/bottom 检查无效,但正在做单缓冲区中的 4 方向检查也是不可能的。所以要么你需要引入第二个内部缓冲区,从一个到另一个增厚,或者做两次增厚,首先向前并向右+底部延伸,然后向后向后并向左+顶部延伸,或者你可以用“绘制形状” A" 到 [-N..+N,-N..+N] 位置的内部缓冲区,以覆盖原始设计周围的 +-N 像素。
检测当前目标位置的源缓冲区中 3x3 网格内的任何“A”的双缓冲区可能最容易编写代码。
我原来的描述确实只在左+上方向加厚了A形,所以在bottom/right上的透支比在left/top上的透支更受惩罚。
嗯...最终证明它比直觉预期的更棘手,请确保按小部分编写代码,并分别正确地调试每个部分,还包括极端情况和极端输入。