2016-07-21 1 views
3

Pour un projet scolaire, j'écris un programme de peinture en assemblage pour DOSBOX. Dans mon programme, l'utilisateur utilise le bouton gauche de la souris pour peindre des pixels dans une certaine couleur. J'utilise des écritures directes en mode 13 pour ça. L'utilisateur peut changer cette couleur en cliquant avec le bouton droit de la souris, qui lit la couleur du pixel pointé par la souris.Données erronées lors de la lecture des pixels en mode 13 (386 Assembly - DOS)

Cela fonctionne parfaitement bien, jusqu'à ce que l'utilisateur initie un certain sous-programme qui est destiné à effacer l'écran, et montrer une palette de couleurs à choisir (avec la même fonctionnalité clic-droit). Ensuite, l'utilisateur clique avec le bouton droit sur une couleur dans la palette, et int 10h, 0dh est utilisé pour lire la couleur. Peu importe où l'utilisateur clique avec le bouton droit de la souris sur l'écran de la palette, la couleur qui est écrite à l'écran par l'utilisateur est toujours blanche. Un clic droit n'importe où change la couleur de la brosse correctement, mais si elle est effectuée en mode palette, la couleur suivante est toujours blanche. Voici mon code:

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 

captures d'écran pour plus de clarté: Using the blue brush in drawing mode. aide de la brosse bleue en mode dessin. Après avoir basculé en mode palette, j'ai cliqué avec le bouton droit sur le carré vert brillant. Après le retour au mode dessin, la brosse dessinait des pixels blancs. After switching back to drawing mode, the brush was drawing white pixels. Right clicking a blue pixel in drawing mode. Clic droit sur un pixel bleu en mode dessin. Brush color properly switches to blue. La couleur du pinceau passe correctement au bleu.

J'ai utilisé int 10h, 0dh pour lire le pixel, mais le même problème s'est produit lorsque j'ai essayé de lire directement le segment A000 (qui, pendant le débogage, semblait complètement rempli de zéros lorsque l'écran était clairement pas vide). Je suis passé à int 10h pour voir si la lecture directe était le problème.

J'ai cependant utilisé des écritures directes.

La dernière question: qu'est-ce que je fais de mal à lire ces pixels? Pourquoi mon programme lit-il correctement les couleurs de pixels initialement, mais après avoir essentiellement effacé l'écran, changé un curseur et dessiné un tas de carrés de couleur, il ne lit que le blanc? Pourquoi cela fonctionne-t-il à nouveau après avoir effacé ces carrés et rétabli l'état précédent de l'écran?

+0

Oh, je vois maintenant la pile de relâchement 'ret # n' dans les procédures ... hmm .. toujours à la recherche de quoi que ce soit. (désolé) – Ped7g

+0

Je ne vois aucun bug de la lecture de la source. Mais je ne vois pas non plus comment la VRAM peut contenir tous les zéros alors que la palette y est dessinée. Je pense qu'à l'adresse 654 (? 2 * 320 + 2 + 10 + 2) il devrait y avoir le premier "1". Le comportement décrit n'a pas beaucoup de sens pour moi, et je n'ai pas de TASM pour le compiler. Je cherchais un problème avec ds/es, mais on dirait que vous avez correctement configuré le tout partout (bien que je me demande pourquoi vous ne les sauvegardez/restaurez pas avec des procédures push/pop, où vous devez définir les choses différemment, comme vous le faites déjà avec d'autres registres, mais ce n'est pas un bug – Ped7g

+0

@ Ped7g Ce qui se passe avec les zéros de la VRAM, c'est quand je vérifie la VRAM en mode dessin.J'ai lu quelque chose sur le fait de devoir passer à une sorte de mode de lecture pour être en mesure de faire des lectures directes à partir de la VRAM, ce qui pourrait être le cas. Pas sûr cependant. Merci d'avoir signalé la divergence avec les registres de sauvegarde dans la pile pendant les procédures. J'ai oublié que je suis autorisé à pousser et à ouvrir des registres de segment, parce que j'avais l'impression que je ne pouvais les changer qu'en déplaçant les données d'autres registres comme AX. Suis-je autorisé à enregistrer des segments XCHG? – Itamar

Répondre

6

Votre problème est que le pilote de la souris utilise un curseur logiciel. Les cartes VGA ne prennent pas en charge un curseur matériel, ce qui signifie que pour afficher le curseur, le pilote de la souris doit le peindre dans le tampon de trame VGA. Cela signifie que lorsque le curseur du sélecteur est affiché et que vous lisez le pixel à la position actuelle de la souris, vous lisez en fait la couleur du point chaud du curseur sélecteur, qui est blanc. Le problème ne se produit pas lorsque vous utilisez le curseur de pinceau car le pixel de son point d'accès est transparent.

+0

Est-ce que DOSBOX émule autre chose que VGA? Si oui, quelles mesures dois-je prendre pour ne pas avoir le curseur stocké dans le tampon de trame? – Itamar

+0

@Itamar: vous pouvez dessiner le curseur par vous-même, pour éviter les fonctions de la carte gfx (qui à la fin sera probablement le meilleur). Dosbox émule ces 'machine = hercules | cga | tandy | cga | tandy | pcjr | ega | vgaonly | svga_s3 | svga_et3000 | svga_et4000 | svga_paradise | vesa_nolfb | vesa_oldvbe' (IIRC aucun des premiers a un support matériel pour les sprites gfx/curseur de la souris, peut-être svga a quelque chose, mais je ne parierais pas dessus) – Ped7g

+2

@Itamar La solution simple serait de temporairement cacher le curseur de la souris avant de lire le tampon de trame. –