Unable to keep a square a full square while moving it

僤鯓⒐⒋嵵緔 提交于 2019-12-01 22:54:09

If, by not moving well, you mean the edges seem to move at different times, that's an issue (tearing) usually solved by double buffering. The problem is caused by the fact that you're rendering to an active (visible) surface so the screen may show half-modified frames.

An illustration may help. Let's say you're trying to change from the left image to the right:

~   ~             ^   ^
O   O             O   O
  ^      ---->      ^
|---|             \___/

If the image is updated left to right and the data is sent to the screen halfway through your update process, you will see something like:

^   ~
O   O
  ^
\_--|

This is what's known as tearing.

To solve it, you can construct the next frame in a separate memory block (you can use rep stosb to construct the next frame in minimal time) then use rep movsb, or something similarly speedy, to transfer that to video memory. That will slow down your frame rate a little but should alleviate any tearing you may be seeing.


Here's an example showing this in action. It's similar functionality to yours but uses double buffering to get around the tearing issue, and it's also a little better structured (in my opinion anyway) in terms of functions doing specific things:

stacksg segment stack
    db 0fffeh dup(?)
stacksg ends

datasg segment
    buffer dw 32000 dup(0)
datasg ends

codesg segment
assume cs:codesg, es: datasg, ds:datasg, ss:stacksg

doline: ; ax = line, bx = column, cx = width
    push        di            ; preserve
    push        ax
    push        dx            ; imul hits this

    push        bx            ; get byte offset to di
    mov         bx, 320
    imul        bx
    pop         bx
    add         ax, bx
    mov         di, ax

    push        cx            ; blat line
    mov         al, 9    
    cld
    rep stosb
    pop         cx

    pop         dx            ; restore and return
    pop         ax
    pop         di
    ret

dosquare: ; ax = line, bx = column, cx = width, dx = height
    push        ax            ; preserve
    push        bx
    push        cx
    push        dx

    push        di            ; clear buffer to black
    push        ax
    push        cx
    xor         di, di
    xor         ax, ax
    mov         cx, 32000
    cld
    rep stosw
    pop         cx
    pop         ax
    pop         di

makeline:
    call        doline
    inc         ax
    dec         dx
    jnz         makeline

    push        es            ; blat double buffer to screen
    push        si
    push        di
    xor         si, si
    mov         ax, 0a000h
    mov         es, ax
    xor         di, di
    mov         cx, 32000
    cld
    rep movsw    
    pop         di
    pop         si
    pop         es

    pop         dx            ; restore and return
    pop         cx
    pop         bx
    pop         ax
    ret

start:
    mov         ax, datasg
    mov         ds, ax
    mov         es, ax

    mov         ah, 0         ; set display mode 13h, 320x200, 8bbp
    mov         al, 13h
    int         10h

    mov         ax, 10        ; line
    mov         bx, 10        ; start column
    mov         cx, 40        ; width
    mov         dx, 40        ; height

printSquare:
    call        dosquare      ; do the square
    inc         bx            ; move right but reset at end
    cmp         bx, 310 - 40
    jne         printSquare
    mov         bx, 10
    jmp         printSquare

codesg ends
end start

Plug that into GNU Turbo Assembler and check it out. I ran both your original (tearing) code and this variant and the latter was much smoother animation.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!