Search code examples
animationassemblyx86-16tasm

Why in this code a rectangle doesn't move when its coordinates are changed?


I recently started learning assembly (TASM) and I'm currently learning how to properly change the positions of different shapes.

I have the following code:

.model small
 
.stack 100h
 
.data

    ; codes returned int 16h ah = 00h
    ; the arrows we control 
        kbArrowUp       equ     4800h
        kbArrowDown     equ     5000h
        kbArrowLeft     equ     4B00h
        kbArrowRight    equ     4D00h
        kbEsc           equ     011Bh
        
        ; color codes of symbols and points in graphic mode
        Red             equ     4
        Gray            equ     7
        Blue            equ     1
        White           equ     15
 
        Mode0D_W        equ     320     ; screen width in pixels for video mode 0Dh
        Mode0D_H        equ     200     ; screen height in pixels for video mode 0Dh
        Mode0D_C        equ     16      ; number of colors for video mode 0Dh
        Mode0D_A        equ     0A000h  ; starting address of video memory for video mode 0Dh
 
        VideoPage       db      ?       ;video page number
 
        Xstart          dw      100     ; coordinates of the beginning of the square
        Ystart          dw      70

 
        sqColor         dw      1       ; color of the rendered rectangle
        sqWidth         dw      40      ; rectangle width
        sqHeight        dw      40      ; height of the rectangle


        XstartS          dw      150     ;coordinates of the beginning of the square
        YstartS          dw      70
 
        sqColorS         dw      1       ;color of the rendered rectangle
        sqWidthS         dw      15      ;rectangle width
        sqHeightS        dw      80      ;height of the rectangle
 

; macro to simplify calling procedures with parameters
    invoke  macro   CallProc, Params
            IRP     P, <Params>
                    mov     ax,     P
                    push    ax
            endm
            call    CallProc
    endm
 
.code
 
main    proc
        mov     ax,     @data
        mov     ds,     ax
 
       
       ; setting graphics video mode
        mov     ax,     000Dh
        int     10h
 
        mov     ah,     0Fh     ; clarification of video mode parameters
        int     10h
        mov     [VideoPage],    bh
 
        invoke  Bar, <[sqHeight], [sqWidth], [Ystart], [Xstart], [sqColor] >
 
        @@GetCmd:
               ; waiting for any key
                mov     ah,     00h
                int     16h
                ;обработка команды
        @@TestCmd1:
                cmp     ax,     kbArrowUp
                jne     @@TestCmd2
                mov     dx,     [Ystart]
                cmp     dx,     0
                je      @@GetCmd
                dec     dx
                mov     cx,     [Xstart]
                jmp     @@Redraw
        @@TestCmd2:
                cmp     ax,     kbArrowDown
                jne     @@TestCmd3
                mov     dx,     [Ystart]
                add     dx,     [sqWidth]
                cmp     dx,     Mode0D_H
                jae     @@GetCmd
                mov     dx,     [Ystart]
                inc     dx
                mov     cx,     [Xstart]
                jmp     @@Redraw
        @@TestCmd3:
                cmp     ax,     kbArrowLeft
                jne     @@TestCmd4
                mov     cx,     [Xstart]
                cmp     cx,     0
                je      @@GetCmd
                dec     cx
                mov     dx,     [Ystart]
                jmp     @@Redraw
        @@TestCmd4:
                cmp     ax,     kbArrowRight
                jne     @@TestCmd5
                mov     cx,     [Xstart]
                add     cx,     [sqWidth]
                cmp     cx,     Mode0D_W
                jae     @@GetCmd
                mov     cx,     [Xstart]
                inc     cx
                mov     dx,     [Ystart]
                jmp     @@Redraw
        @@TestCmd5:
                cmp     ax,     kbEsc
                jne     @@TestCmd1S
                jae     @@GetCmdS

        invoke  Bar, <[sqHeightS], [sqWidthS], [YstartS], [XstartS], [sqColorS] >
        @@GetCmdS:
                ;ожидание нажатия любой клавиши
                mov     ah,     00h
                int     16h
                ;обработка команды
        @@TestCmd1S:
                cmp     ax,     kbArrowUp
                jne     @@TestCmd2S
                mov     dx,     [YstartS]
                cmp     dx,     0
                jae      @@GetCmdS
                dec     dx
                mov     cx,     [XstartS]
                jmp     @@Redraw
        @@TestCmd2S:
                cmp     ax,     kbArrowDown
                jne     @@TestCmd3S
                mov     dx,     [YstartS]
                add     dx,     [sqWidthS]
                cmp     dx,     Mode0D_H
                jae     @@GetCmdS
                mov     dx,     [YstartS]
                inc     dx
                mov     cx,     [XstartS]
                jmp     @@Redraw
        @@TestCmd3S:
                cmp     ax,     kbArrowLeft
                jne     @@TestCmd4S
                mov     cx,     [XstartS]
                cmp     cx,     0
                je      @@GetCmdS
                dec     cx
                mov     dx,     [YstartS]
                jmp     @@Redraw
        @@TestCmd4S:
                cmp     ax,     kbArrowRight
                jne     @@TestCmd5S
                mov     cx,     [XstartS]
                add     cx,     [sqWidthS]
                cmp     cx,     Mode0D_W
                jae     @@GetCmdS
                mov     cx,     [XstartS]
                inc     cx
                mov     dx,     [YstartS]
                jmp     @@Redraw
        @@TestCmd5S:
                cmp     ax,     kbEsc
                jne     @@GetCmdS
                jmp     @@StopCmdLoop
        @@Redraw:
                invoke  Bar, <[sqHeight], [sqWidth], [Ystart], [Xstart], 0>
                mov     ax,     [sqColor]
                inc     ax                      ;Color++
                cmp     ax,     Mode0D_C        ;if (Color>MaxColor)
                sbb     bx,     bx              ;  Color=1
                and     ax,     bx
                cmp     ax,     1
                adc     ax,     0
                mov     [sqColor],      ax
                mov     [Xstart],       cx
                mov     [Ystart],       dx
                invoke  Bar, <[sqHeight], [sqWidth], dx, cx, [sqColor]>
        jmp     @@GetCmd
        @@RedrawS:
                invoke  BarS, <[sqHeightS], [sqWidthS], [YstartS], [XstartS], 0>
                mov     ax,     [sqColorS]
                inc     ax                      ;Color++
                cmp     ax,     Mode0D_C        ;if (Color>MaxColor)
                sbb     bx,     bx              ;  Color=1
                and     ax,     bx
                cmp     ax,     1
                adc     ax,     0
                mov     [sqColorS],      ax
                mov     [XstartS],       cx
                mov     [YstartS],       dx
                invoke  BarS, <[sqHeightS], [sqWidthS], dx, cx, [sqColor]>
        jmp     @@GetCmdS
@@StopCmdLoop:
        ;переключение в текстовый режим
        mov     ax,     0003h
        int     10h
        ;завершение программы
        mov     ax,     4C00h
        int     21h
main    endp
 
;рисование полосы (залитого прямоугольника)
;на входе:
; color - цвет заливки
; x_pos, y_pos - координаты левого верхнего угла
; x_size, y_size - размеры прямоугольника
;на выходе:
; -
Bar     proc    color: word, x_pos:word, y_pos: word, x_size: word, y_size: word
        push    bp                      ;формирование кадра параметров
        mov     bp,     sp
 
        push    ax                      ;сохранение регистров
        push    bx
        push    cx
        push    dx
        push    si
        push    di
 
        mov     ah,     0Ch             ; настройка параметров для вызова функции 0Ch
        mov     al,     byte ptr color           ;цвет точек
        mov     bh,     0               ;номер видеостраницы
        mov     dx,     y_pos           ;строка
        mov     cx,     x_pos           ;колонка
 
        mov     di,     y_size
@@Vertical:
 
        mov     cx,     x_pos           ;колонка
        mov     si,     x_size          ;вывести x_size точек в горизонтальной линии
@@Horizontal:
        int     10h                     ;вывести точку
        inc     cx                      ;прирастить координату x
        dec     si
        jnz     @@Horizontal
 
        inc     dx                      ;переход к следующей горизонтальной линии с
        dec     di
        jnz     @@Vertical
 
        pop     di                      ;восстановление рагистров
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
 
        pop     bp
        ret     10                      ;удаление параметров из стека
Bar     endp

BarS     proc    colorS: word, x_posS:word, y_posS: word, x_sizeS: word, y_sizeS: word
        push    bp                      ;формирование кадра параметров
        mov     bp,     sp
 
        push    ax                      ;сохранение регистров
        push    bx
        push    cx
        push    dx
        push    si
        push    di
 
        mov     ah,     0Ch             ; настройка параметров для вызова функции 0Ch
        mov     al,     byte ptr colorS           ;цвет точек
        mov     bh,     0               ;номер видеостраницы
        mov     dx,     y_posS           ;строка
        mov     cx,     x_posS          ;колонка
 
        mov     di,     y_sizeS
@@VerticalS:
 
        mov     cx,     x_posS           ;колонка
        mov     si,     x_sizeS         ;вывести x_size точек в горизонтальной линии
@@HorizontalS:
        int     10h                     ;вывести точку
        inc     cx                      ;прирастить координату x
        dec     si
        jnz     @@Horizontal
 
        inc     dx                      ;переход к следующей горизонтальной линии с
        dec     di
        jnz     @@Vertical
 
        pop     di                      ;восстановление рагистров
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
 
        pop     bp
        ret     10                      ;удаление параметров из стека
BarS     endp
 
end     main

There's one thing I don't understand:
When I change the coordinates of the rectangle (XstartS and YstartS), the rectangle's position does not change.

what I have

I want the rectangle to be centered and under the square, like this:

what I need

Could you explain me a couple of things:

  1. Why in this code a rectangle doesn't move when its coordinates are changed?
  2. What should correct code look like, so that the result is displayed as in the second screenshot?

Solution

  • Your program is never drawing the second shape!

    What you see on the screen is an irregular redrawing of the first shape due to a number of errors that I have listed below:

    @@TestCmd2:
        cmp     ax,     kbArrowDown
        jne     @@TestCmd3
        mov     dx,     [Ystart]
        add     dx,     [sqWidth]
    

    Here you need to add the height [sqHeight] instead of the width [sqWidth].
    Because for the 1st shape width equals height (it's a square after all), you don't see this error reflected on the screen. But, you made the same error for the 2nd shape where the width is different from the height, and that you will see once the 2nd shape finally gets drawn.


    @@TestCmd5:
        cmp     ax,     kbEsc    (*)
        jne     @@TestCmd1S      (*)
        jae     @@GetCmdS        (*)
    
        invoke  Bar, <[sqHeightS], [sqWidthS], [YstartS], [XstartS], [sqColorS] >
    @@GetCmdS:
        mov     ah,     00h
        int     16h
    @@TestCmd1S:
    

    The 2nd bar is never drawn here! If the key is not ESC then you jump to TestCmd1S and if the key is ESC you jump to GetCmdS. The invoke Bar ... cannot execute.

    I have followed your program flow and as it turns out you don't need to test for ESC here at all. You can simply remove the 3 instructions that I've marked with an asterisk (*).


    @@TestCmd1S:
        cmp     ax,     kbArrowUp
        jne     @@TestCmd2S
        mov     dx,     [YstartS]
        cmp     dx,     0
        jae      @@GetCmdS
    

    The conditional jump jae here acts like an unconditional jump because of the 'above' condition being always true with the numbers in use! You need the je instruction here.


    Your program contains 8 jmp @@Redraw instructions and not a single jmp @@RedrawS!
    The top part needs 4 jmp @@Redraw instructions and the bottom part needs 4 jmp @@RedrawS instructions.


    invoke  BarS, <[sqHeightS], [sqWidthS], dx, cx, [sqColor]>
    

    The color is in [sqColorS] for the 2nd shape.


    I'm confident that once the above errors are corrected the program will work as intended (moving rectangles).


    [Late catch]
    You don't need 2 identical procedures Bar and BarS in your program!

    Instead of

    invoke  Bar, <[sqHeight], [sqWidth], dx, cx, [sqColor]>
    invoke  BarS, <[sqHeightS], [sqWidthS], dx, cx, [sqColorS]>
    

    you can safely use

    invoke  Bar, <[sqHeight], [sqWidth], dx, cx, [sqColor]>
    invoke  Bar, <[sqHeightS], [sqWidthS], dx, cx, [sqColorS]>