assemblymousex86-16

Drag and Drop project in assembly 8086 (move a square with the mouse)


I'm a cs student and I need to build a project for my architecture class. I have tried to build a simple drag and drop program in asm. The whole idea would be to draw a sqaure somewhere on the screen and then drag it somewhere else using the mouse just like you would on a regular desktop.

I have tried using a buffer but it was to no avail. I'm too much of a beginner to make it work. so I tried some functions to redraw the square. Here is the best I've got using Copilot:

.model small
.stack 100h
.data
    x dw 100           ; Initial x position of square
    y dw 100           ; Initial y position of square
    size_square dw 50  ; Size of the square
    isDragging db 0    ; Flag to check if the square is being dragged
    prev_x dw 100      ; Previous x position of square
    prev_y dw 100      ; Previous y position of square

.code
start:
    ; Initialize graphics mode
    mov ax, 13h
    int 10h

    ; Initialize mouse
    mov ax, 0
    int 33h
    mov ax, 1
    int 33h

    ; Hide mouse cursor
    mov ax, 2
    int 33h

    ; Draw initial square
    call draw_square

main_loop:
    ; Show mouse cursor
    mov ax, 1
    int 33h

    ; Get mouse status
    mov ax, 3
    int 33h

    ; Check if left button is pressed
    test bx, 1
    jz no_drag

    ; Start dragging
    mov isDragging, 1
    mov prev_x, cx
    mov prev_y, dx

dragging:
    ; Hide mouse cursor while dragging
    mov ax, 2
    int 33h

    ; Get mouse status
    mov ax, 3
    int 33h

    ; Check if button is still pressed
    test bx, 1
    jz stop_drag

    ; Clear previous square position
    call clear_square

    ; Update square position
    mov x, cx
    mov y, dx

    ; Draw square at new position
    call draw_square

    ; Store current position as previous position
    mov prev_x, x
    mov prev_y, y

    jmp dragging

no_drag:
    ; If not dragging, wait for next mouse event
    jmp main_loop

stop_drag:
    ; Stop dragging
    mov isDragging, 0
    ; Show mouse cursor
    mov ax, 1
    int 33h
    jmp main_loop

draw_square:
    ; Draw the square
    push si
    push di
    push cx
    push bx
    push dx
    mov cx, 0
draw_loop1:
    mov dx, 0
draw_loop2:
    mov ax, y
    add ax, cx
    mov si, ax
    mov ax, x
    add ax, dx
    mov di, ax
    mov al, 15
    mov ah, 0Ch
    int 10h

    inc dx
    cmp dx, size_square
    jl draw_loop2

    inc cx
    cmp cx, size_square
    jl draw_loop1

    pop dx
    pop bx
    pop cx
    pop di
    pop si
    ret

clear_square:
    ; Clear the previous square position
    push si
    push di
    push cx
    push bx
    push dx
    mov cx, 0
clear_loop1:
    mov dx, 0
clear_loop2:
    mov ax, prev_y
    add ax, cx
    mov si, ax
    mov ax, prev_x
    add ax, dx
    mov di, ax
    mov al, 0
    mov ah, 0Ch
    int 10h

    inc dx
    cmp dx, size_square
    jl clear_loop2

    inc cx
    cmp cx, size_square
    jl clear_loop1

    pop dx
    pop bx
    pop cx
    pop di
    pop si
    ret

exit_program:
    ; Restore text mode
    mov ax, 3
    int 10h
    ret

end start

Please help me understand what went wrong ;(


Solution

  • Please help me understand what went wrong ;(

    So many things that are wrong in this program! The AI wasn't even able to draw a solid square at (x,y) using BIOS.WritePixel. (A solid white square could get displayed in the upper left corner of the screen). And why a different code was needed to wipe the square is beyond me. Same procedure, other set of arguments.

    push bx
    pop  bx
    

    BX wasn't initialized to anything, so why waste bytes on preserving BX.

    mov ax, y
    add ax, cx
    mov si, ax
    

    BIOS.WritePixel expects its Y coordinate in the DX register, so very much not SI.

    mov ax, x
    add ax, dx
    mov di, ax
    

    BIOS.WritePixel expects its X coordinate in the CX register, so very much not DI.

    My version:

      mov  cx, x
      mov  dx, y
      mov  al, 15           ; To 'clear' the square, you pass AL=0
      call PaintSquare
    
      ...
    
    ; IN (al,cx,dx)
    PaintSquare:
      push bx               ; AL is Color=[0,255]
      push si               ; CX is X=[0,319]
      push di               ; DX is Y=[0,199]
    
      mov  bh, 0            ; DisplayPage
      mov  di, size_square  ; Height
    .OuterLoop:
      mov  si, size_square  ; Width
    .InnerLoop:
      mov  ah, 0Ch          ; BIOS.WritePixel
      int  10h
      inc  cx               ; X++
      dec  si
      jnz  .InnerLoop
      sub  cx, size_square
      inc  dx               ; Y++
      dec  di
      jnz  .OuterLoop
      sub  dx, size_square
    
      pop  di
      pop  si
      pop  bx
      ret
    
    prev_x dw 100      ; Previous x position of square
    prev_y dw 100      ; Previous y position of square
    

    The AI is loading prev_x and prev_y with the coordinates where the mouse click was registered. This is unrelated to where the square needs to be erased!
    Moreover, before any dragging can begin, you still need to check whether the mouse is actually on top of the current square.

    exit_program:
      ; Restore text mode
      mov ax, 3
      int 10h
      ret
    

    Although the AI included this nice 'exit_program' part, this code is unreachable and if jumped at, its ret could only return to DOS is this were a .COM executable. Sadly, the .model small says this is going to be an .EXE executable, for which additionally the DS segment register wasn't setup and therefore addressing the memory-based variables will fail completely.

    The list goes on...


    My suggestion then would be that you forget about using the mouse for now, and that, with the help of my PaintSquare procedure, you try your hand at a version of the program that moves the square based on the arrow keys on the keyboard. In the intrest of flicker-free graphics you could use a double buffer like you described in one of your comments. Good luck.