Assembly 在模式13(386汇编-DOS)下读取像素时数据错误
对于一个学校项目,我正在为DOSBOX编写汇编中的绘画程序。在我的程序中,用户使用鼠标左键以特定颜色绘制像素。我在模式13中使用直接写入。用户可以通过右键单击更改该颜色,这将读取鼠标指向的像素的颜色 这可以很好地工作,直到用户启动一个特定的子例程来擦拭屏幕,并显示一个调色板来选择颜色(具有相同的右键单击功能)。然后,用户右键单击调色板中的颜色,使用int 10h,0dh读取颜色。无论用户在调色板屏幕中的何处单击鼠标右键,用户稍后写入屏幕的颜色始终为白色 tl;dr右键单击任意位置可正确更改笔刷颜色,但如果在调色板模式下执行,则后续颜色始终为白色。 这是我的密码:Assembly 在模式13(386汇编-DOS)下读取像素时数据错误,assembly,graphics,colors,dosbox,Assembly,Graphics,Colors,Dosbox,对于一个学校项目,我正在为DOSBOX编写汇编中的绘画程序。在我的程序中,用户使用鼠标左键以特定颜色绘制像素。我在模式13中使用直接写入。用户可以通过右键单击更改该颜色,这将读取鼠标指向的像素的颜色 这可以很好地工作,直到用户启动一个特定的子例程来擦拭屏幕,并显示一个调色板来选择颜色(具有相同的右键单击功能)。然后,用户右键单击调色板中的颜色,使用int 10h,0dh读取颜色。无论用户在调色板屏幕中的何处单击鼠标右键,用户稍后写入屏幕的颜色始终为白色 tl;dr右键单击任意位置可正确更改笔刷颜
GRAPHICS equ 13h
H_HOTSPOT equ 7
V_HOTSPOT equ 7
H_RES equ 320
V_RES equ 200
PIXELCOUNT equ H_RES*V_RES
DISPLAY_SEG equ 0A000h
EXIT_KEY equ 1071h ; q key
COLORPICKER_KEY equ 1177h ; w key
PALETTE_SIZE equ 16
SQUARE_SIZE equ 10
SQUARE_PADDING equ 2
SQUARE_ROW_JUMP equ H_RES - SQUARE_SIZE
PALETTE_ROW_JUMP equ H_RES - (SQUARE_PADDING + SQUARE_SIZE)*PALETTE_SIZE
sseg SEGMENT
db 256 dup(?)
sseg ENDS
dseg SEGMENT
stdBrushMask dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 0000000100000000b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 1111111011111111b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 1111111011111111b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
dw 0000000100000000b
stdBrushHotSpots dw 7
dw 7
pickerToolMask dw 1111100001000001b
dw 1111100000000000b
dw 1111100000000000b
dw 1111100000000000b
dw 1111100000000000b
dw 1111000000000000b
dw 1110000000000000b
dw 1100000000000000b
dw 1000000000000000b
dw 1000000000000000b
dw 1000000000000000b
dw 1000000000011111b
dw 0000000000111111b
dw 0000000001111111b
dw 0000000011111111b
dw 0000111111111111b
dw 0000000000000000b
dw 0000001100011100b
dw 0000001111111110b
dw 0000000111111110b
dw 0000000111111110b
dw 0000001111111100b
dw 0000011111111100b
dw 0000111111111100b
dw 0001111111111110b
dw 0011111111100110b
dw 0001111111000000b
dw 0001111110000000b
dw 0011111100000000b
dw 0111001000000000b
dw 0110000000000000b
dw 0000000000000000b
pickerToolHotSpots dw 1
dw 14
foreground_color dw 000fh
background_color dw 0000h
colorpicker_flag db 00
prev_position dw H_RES ; Cache of the last drawn pixel's coordinates, to avoid duplicate writes.
dw V_RES
pos_backup dw H_RES/2
dw V_RES/2 ; Cache of the mouse position before switching to palette mode or back.
video_mode_not_available db "Mode 13h is not supported on this computer. To use this program, get a VGA or MCGA graphics card / monitor.$"
display_backup db PIXELCOUNT dup(?)
dseg ENDS
cseg SEGMENT
assume cs:cseg, ds:dseg, ss:sseg
;---------------Mouse Procs-------------
stdBrush PROC
push bx cx ax dx
mov ax, dseg
mov es, ax
mov bx, stdBrushHotSpots
mov cx, stdBrushHotSpots + 2
mov ax, 9
mov dx, offset stdBrushMask
int 33h
mov ax, DISPLAY_SEG
mov es, ax
pop dx ax cx bx
ret
stdBrush ENDP
pickerTool PROC
push bx cx ax dx
mov ax, dseg
mov es, ax
mov bx, pickerToolHotSpots
mov cx, pickerToolHotSpots + 2
mov ax, 9
mov dx, offset pickerToolMask
int 33h
mov ax, DISPLAY_SEG
mov es, ax
pop dx ax cx bx
ret
pickerTool ENDP
mouseReset PROC
push ax
mov ax, 0
int 33h
pop ax
ret
mouseReset ENDP
showCursor PROC
push ax
mov ax, 1
int 33h
pop ax
ret
showCursor ENDP
hideCursor PROC
push ax
mov ax, 2
int 33h
pop ax
ret
hideCursor ENDP
getCursorStat PROC
push ax
mov ax, 3
int 33h
pop ax
ret
getCursorStat ENDP
initCursor PROC
mov ax, dseg
mov es, ax
call mouseReset
call stdBrush
call showCursor
mov ax, DISPLAY_SEG
mov es, ax
ret
initCursor ENDP
;--------------------Graphics Procs-------------
graphicsCompat PROC
; Checks if mode 13h is supported on this machine.
mov ax, 1a00h
int 10h ; Get display combination
cmp al, 1ah
je mode_13_supported
mov ah, 9
mov dx, offset video_mode_not_available
int 21h ; Display error message
inc sp ; Discard the return address
inc sp
push offset exit ; Replace return address with exit procedure address
ret ; Return to exit procedure.
mode_13_supported:
;No error, mode 13 is supported
ret
graphicsCompat ENDP
graphicsMode PROC
mov ah, 0
mov al, GRAPHICS
int 10h
ret
graphicsMode ENDP
pixel PROC
push bp
mov bp, sp
push ax bx cx dx
xor bx, bx
mov cx, ss:[bp+6] ; x coord
mov dx, ss:[bp+4] ; y coord
cmp cx, H_RES
jnc pixel_outofbounds
cmp dx, V_RES
jnc pixel_outofbounds
mov ax, H_RES
mul dx
add ax, cx
mov di, ax ; Puts the pixel's offset in di
mov ax, ss:[bp+8] ; read color argument
stosb
pixel_outofbounds:
pop dx cx bx ax bp
ret 6
pixel ENDP
backupScreen PROC
push ax di si
mov ax, DISPLAY_SEG
mov ds, ax
mov ax, dseg
mov es, ax
mov cx, PIXELCOUNT
mov si, 0
mov di, offset display_backup
call hideCursor
rep movsb
call showCursor
mov ds, ax
mov ax, DISPLAY_SEG
mov es, ax
pop si di ax
ret
backupScreen ENDP
restoreScreen PROC
push di si
mov cx, PIXELCOUNT
mov si, offset display_backup
mov di, 0
rep movsb
pop si di
ret
restoreScreen ENDP
;-------------------Colorpicker Procs----------
paletteModeToggle PROC
push ax
call hideCursor
mov pos_backup, cx
mov pos_backup+2, dx
mov al, colorpicker_flag
not al
mov colorpicker_flag, al
test al, al
jz palette_mode_off
palette_mode_on:
call backupScreen
call graphicsMode
call paletteDraw
call showCursor
call pickerTool
pop ax
jmp input_loop
palette_mode_off:
call graphicsMode
call restoreScreen
call showCursor
call stdBrush
pop ax
jmp input_loop
paletteModeToggle ENDP
paletteSquareDraw PROC
push bp
mov bp, sp
push ax cx dx
mov dx, ss:[bp+4] ; retrieves ypos
mov cx, ss:[bp+6] ; retrieves xpos
mov ax, H_RES
mul dx
add ax, cx
mov di, ax ; Puts the real pixel address in di.
mov ax, ss:[bp+8] ;retrieves color
xor ch, ch
square_loop:
xor cl, cl
square_row_loop:
stosb
inc cl ; increment horizontal counter
cmp cl, SQUARE_SIZE
jb square_row_loop
inc ch ; increment the vertical counter
add di, SQUARE_ROW_JUMP ; move di to the start of the next row
cmp ch, SQUARE_SIZE
jb square_loop
pop dx cx ax bp
ret 6
paletteSquareDraw ENDP
paletteDraw PROC
xor cx, cx ; xpos = 0
xor dx, dx ; ypos = 0
xor ax, ax ; color = 0
xor bx, bx ; squarecounter = 0
palette_loop: ; for i in paletterows:
xor bl, bl
add dx, SQUARE_PADDING
palette_row_loop: ; for j in palettecols:
add cx, SQUARE_PADDING ; xpos += padding
push ax
push cx
push dx
call paletteSquareDraw ; DrawSquare()
add cx, SQUARE_SIZE
inc ax ; next color
inc bl ; squarecounter++
cmp bl, PALETTE_SIZE
jb palette_row_loop
; prep for new row
xor bl, bl
xor cx, cx
add dx, SQUARE_SIZE
inc bh
cmp bh, PALETTE_SIZE
jb palette_loop
ret
paletteDraw ENDP
pickColor PROC
push bp
mov bp, sp
push ax dx si
mov dx, ss:[bp+4]
mov cx, ss:[bp+6]
xor bh, bh
mov ah, 0dh
int 10h
mov foreground_color, ax
pop si dx ax bp
ret 4
pickColor ENDP
;--------------------------Program Entry-------------------------
main:
mov ax, dseg
mov ds, ax
mov ax, sseg
mov ss, ax
mov ax, DISPLAY_SEG
mov es, ax
call graphicsCompat
call graphicsMode
call mouseReset
call stdBrush
call showCursor
mov ax, DISPLAY_SEG
mov es, ax
input_loop:
;------------Mouse Input Detection------------------------------------
call getCursorStat
shr bx, 1
jnc no_left_click
; Left click detected
mov al, colorpicker_flag
test al, al
jnz no_left_click ; no left clicks in palette mode.
shr cx, 1
cmp cx, prev_position
jnz draw_pixel
cmp dx, prev_position + 2
jz no_left_click
draw_pixel:
call hideCursor
mov ax, foreground_color
mov prev_position, cx
mov prev_position + 2, dx
push ax cx dx
call pixel
call showCursor
no_left_click:
mov bx, 1
mov ax, 6
int 33h
test bx, bx
jz keyboard_detection
; Right click detected
shr cx, 1
push cx dx
call pickColor
keyboard_detection:
;------------Keyboard Input Detection----------------------------------
mov ah, 1
int 16h
jz no_keystroke
xor ah, ah
int 16h
cmp ax, EXIT_KEY
je exit
cmp ax, COLORPICKER_KEY
jne no_palette_toggle
jmp paletteModeToggle
no_palette_toggle:
no_keystroke:
jmp input_loop
exit:
mov al, 3
mov ah, 0
int 10h
mov ax, 4c00h
int 21h
cseg ENDS
end main
为清晰起见,屏幕截图:
在绘图模式下使用蓝色笔刷。
切换到调色板模式后,我右键单击亮绿色的正方形。
切换回绘图模式后,笔刷绘制白色像素。
在绘图模式下的蓝色像素上单击鼠标右键。
正确地将笔刷颜色切换为蓝色
在这个版本中,我使用int 10h,0dh来读取像素,但是当我尝试直接读取段A000时,出现了相同的问题(在调试期间,当屏幕明显不是空的时候,段A000似乎完全被零填充)。我转而使用int10h来查看是否存在直接读取的问题
不过,我确实使用了直接书写
底线问题:我读这些像素有什么不对?为什么我的程序最初正确读取像素颜色,但在基本上清除屏幕、更改光标并绘制一组彩色方块后,它只读取白色?清除这些方块并将屏幕恢复到以前的状态后,为什么它会再次工作?您的问题是鼠标驱动程序使用了软件光标。VGA卡不支持硬件光标,这意味着为了显示光标,鼠标驱动程序需要将光标绘制到VGA帧缓冲区。这意味着当显示拾取光标时,您在当前鼠标位置读取像素时,您实际上是在读取拾取光标热点的颜色,即白色。使用画笔光标时不会出现问题,因为其热点处的像素是透明的。哦,我现在看到了
ret\n
在过程中释放堆栈。。。隐马尔可夫模型。。还在寻找什么。(抱歉)我没有从源代码读取中看到任何错误。但我也不明白在绘制调色板时,VRAM如何包含所有零。我想在地址654(?2*320+2+10+2)应该有第一个“1”。所描述的行为对我来说没有多大意义,我也没有TASM来编译它。我一直在寻找ds/es的一些问题,但看起来您在任何地方都设置正确(虽然我有点想知道为什么你不使用push/pop-in过程保存/恢复它们,在这里你需要对它们进行不同的设置,就像你对其他寄存器所做的那样。但这不是错误。@Ped7g关于VRAM中的零的事情真的让我很困扰。当我在绘图模式下检查VRAM时也会发生这种情况。我读到一些关于必须切换的内容。)到某种读取模式,以便能够从VRAM进行直接读取,所以可能就是这样。虽然不确定。感谢您指出在过程中在堆栈中保存寄存器的差异。我忘记了我可以推送和弹出段寄存器,因为我的印象是,我只允许通过移动t来更改它们他从其他寄存器(如AX)获取数据。我可以使用XCHG段寄存器吗?我认为即使在单面上,XCHG
也没有段寄存器作为操作数,但你为什么不直接编写它,让TASM告诉你呢?我记得我在256B简介中经常使用推0A000h
pop es
,所以它可能是最短的(而且只是稍微慢一点)初始化es
的方法(除非您意外地在某些寄存器中已经有0xA000,那么mov-es,reg
当然更好)。我认为VGA VRAM在调试期间应该是完全可读的,没有任何问题,所以这是令人不安的。您使用什么调试器,以及如何使用?也许它会给其他人敲响警钟(我不再使用DOS工具)。哦,等等..可能是,如果您使用的是在同一台机器上运行的文本模式调试器,那么当您在调试器UI中时,VRAM会被部分修改。但是dosbox有内置调试器,现在我终于回忆起来了,因此不需要切换gfx模式(因为td.exe
必须),并且应该显示真实的内存内容。但是,如果有关于内存查看的注意事项,可以先检查文档。DOSBOX模拟VGA以外的任何东西吗?如果是,我必须采取什么步骤才能不将光标存储在帧缓冲区中?@Itamar:您可以自己绘制光标,以避免使用gfx卡功能Dosbox模拟了这些machine=hercules | cga | tandy | cga | tandy | pcjr | ega | vgaonly | svga | u et3000 | svga | u et4000 | svga | u天堂| vesa | u nolfb | vesa | oldvbe
(IIRC早期版本中没有一款硬件支持gfx精灵/鼠标光标,也许svga有什么功能,但我不敢打赌)@Itamar简单的解决方案是在读取帧缓冲区之前暂时隐藏鼠标光标。@Itamar可能将热点设置为(0,15)也可以。