assembly 8086汇编中的中点椭圆算法

mrfwxfqh  于 2023-05-29  发布在  其他
关注(0)|答案(1)|浏览(147)

我试图实现一个椭圆绘制算法与8086大会在VGA(320x200)模式,但形状是不正确的绘制更大的半径。

正如你所看到的,形状是凹的或直的,而不是椭圆形的。我得到可接受的结果时,轴有小的长度,即(10,15),但任何更多,然后,它停止类似椭圆。我使用FPU来计算所有值。

.387

SCREEN_WIDTH = 320
SCREEN_HEIGHT = 200
HALF_SCREEN_WIDTH = SCREEN_WIDTH / 2
HALF_SCREEN_HEIGHT = SCREEN_HEIGHT / 2

stack1 segment stack
            dw 300 dup(?)
stack_top   dw ?    ;stack_top pointer

stack1 ends

code1 segment
start1:
    mov ax,seg stack1 
    mov ss,ax                               ; initialize stack
    mov sp, offset stack_top

    mov al, 13h     
    mov ah, 0       ; change mode
    int 10h         ; enter graphics mode

    mov byte ptr cs:[color], 10
    
start_draw:
    call clear_screen
    call ellipse

wait_key:
    in  al, 60h ;take keyboard input
    cmp al, 1   ;if ESC end
    je end_program
    jmp wait_key

;-------------------------------------------------------------
;-------------------------------------------------------------
x_radius            dw 40   ;width of the ellipse
y_radius            dw 50   ;height of the ellipse

x_derivative        dw ?    ;derivates calculated from ellipse equation
y_derivative        dw ?

x_squared           dw ?    ;squared values for convenience
y_squared           dw ?

decision_param      dw ?    

four                dw 4    ;int values used in some of the expressions
two                 dw 2    ;storing them so I can load them to the FPU
;----------------------
calc_x_derivative:
;x_derivative = 2 * y_squared * x
;RPN: 2 y_squared x * *
    finit
    fild    word ptr cs:[y_squared]
    fimul   word ptr cs:[two] ;instead of multiplying by 2 
    fimul   word ptr cs:[x]
    fistp   word ptr cs:[x_derivative]
    ret
    
calc_y_derivative:
;y_derivative = 2 * x_squared * y
;RPN: 2 x_squared y * *
    finit
    fild    word ptr cs:[x_squared]
    fimul   word ptr cs:[two] 
    fimul   word ptr cs:[y]
    fistp   word ptr cs:[y_derivative]
    ret

ellipse:
    ;initialize x as 0 and y as y_radius
    mov     word ptr cs:[x], 0
    mov     ax, word ptr cs:[y_radius]
    mov     word ptr cs:[y], ax

x_radius_squared:
    finit 
    fild    word ptr cs:[y_radius]
    fimul   word ptr cs:[y_radius]
    fistp   word ptr cs:[y_squared]

y_radius_squared:
    finit
    fild    word ptr cs:[x_radius]
    fimul   word ptr cs:[x_radius]
    fistp   word ptr cs:[x_squared]

derivatives:
    call calc_x_derivative
    call calc_y_derivative
    
calc_decision_param_1:
;d1 = y_squared - (x_squared * ry) + (1/4 * x_squared)  
;RPN: y_squared x_squared ry * - x_squared 4 / +
    finit
    fild    word ptr cs:[y_squared]
    fild    word ptr cs:[x_squared]
    fild    word ptr cs:[y_radius]
    fmul
    fsub
    fild    word ptr cs:[x_squared]
    fidiv   word ptr cs:[four]
    fadd
    fistp   word ptr cs:[decision_param]

region_1_loop:
    call color_all_symmetries

    inc word ptr cs:[x] 
    call calc_x_derivative

    cmp word ptr cs:[decision_param], 0 ;compare decision_param to 0
    jge region_1_alternative_next       ;if its lower decrement y and calculate alternative decision_param

region_1_next:
;decision_param = decision_param + x_derivative + (y_squared)
;RPN: decision_param x_derivative + y_squared +
    finit
    fild word ptr cs:[decision_param]
    fild word ptr cs:[x_derivative]
    fadd
    fild word ptr cs:[y_squared]
    fadd
    fistp word ptr cs:[decision_param]
    jmp region_1_loop_end

region_1_alternative_next:
;decision_param = decision_param + x_derivative - y_derivative + (y_squared)
;RPN: decision_param x_derivative + y_derivative - y_squared +
    dec word ptr cs:[y]
    call calc_y_derivative
    finit
    fild word ptr cs:[decision_param]
    fild word ptr cs:[x_derivative]
    fadd
    fild word ptr cs:[y_derivative]
    fsub
    fild word ptr cs:[y_squared]
    fadd
    fistp word ptr cs:[decision_param]

region_1_loop_end:
    mov ax, word ptr cs:[x_derivative]
    cmp ax, word ptr cs:[y_derivative]     ;check if x_derivative < y_derivative
    jge calc_decision_param_2              ;if it is we are done with region 1
    jmp region_1_loop

calc_decision_param_2:
;decision_param = (y_squared * (x + 1/2) * (x + 1/2)) + (x_squared * (y - 1) * (y - 1)) - (x_squared * y_squared)
;RPN: y_squared x 1 2 / + * x 1 2 / + * x_squared y 1 - * y 1 - * + x_squared y_squared * -
    fild word ptr cs:[y_squared]
    fild word ptr cs:[x]
    fld1
    fidiv word ptr cs:[two]
    fadd
    fmul
    fild word ptr cs:[x]
    fld1
    fidiv word ptr cs:[two]
    fadd
    fmul
    fild word ptr cs:[x_squared]
    fild word ptr cs:[y]
    fld1
    fsub
    fmul
    fild word ptr cs:[y]
    fld1
    fsub
    fmul
    fadd
    fild word ptr cs:[x_squared]
    fimul word ptr cs:[y_squared]
    fsub
    fistp word ptr cs:[decision_param]

region_2_loop:
    call color_all_symmetries

    dec word ptr cs:[y]
    call calc_y_derivative

    cmp word ptr cs:[decision_param], 0 ;check if decision_param < 0
    jge alternative_region_2_next

region_2_next:
;decision_param = decision_param + x_squared - y_derivative
;RPN: decision_param x_squared + y_derivative -
    finit
    fild word ptr cs:[decision_param]
    fild word ptr cs:[x_squared]
    fadd
    fild word ptr cs:[y_derivative]
    fsub
    fistp word ptr cs:[decision_param]
    jmp region_2_loop_end

alternative_region_2_next:
    inc word ptr cs:[x]
    call calc_x_derivative

region_2_alternative_decision_param:
;decision_param = decision_param + x_derivative - y_derivative + (x_squared)
;RPN: decision_param x_derivative + y_derivative - x_squared +
    finit
    fild word ptr cs:[decision_param]
    fild word ptr cs:[x_derivative]
    fadd
    fild word ptr cs:[y_derivative]
    fsub
    fild word ptr cs:[x_squared]
    fadd
    fistp word ptr cs:[decision_param]

region_2_loop_end:
;y_derivative = y_derivative - (2 * x_squared)
;RPN: y_derivative 2 x_squared * -
    finit
    fild word ptr cs:[y_derivative]
    fild word ptr cs:[two]
    fild word ptr cs:[x_squared]
    fmul
    fsub
    fistp word ptr cs:[y_derivative]

    cmp word ptr cs:[y], 0      ; check if y <= 0
    jg region_2_loop       

end_ellipse:
    ret

;-------------------------------------------------------------
;---------------------  color_pixel  -------------------------

x       dw ?
y       dw ?

temp_y  dw ?
temp_x  dw ?

color   db ?
;---------------------
color_all_symmetries:
    ; Coloring points (xc + x, yc + y), (xc - x, yc + y), (xc + x, yc - y), (xc - x, yc - y)
    push ax

    ;Point (xc + x, yc - y)
    mov ax, HALF_SCREEN_HEIGHT
    sub ax, word ptr cs:[y]
    mov word ptr cs:[temp_y], ax
    mov ax, word ptr cs:[x]
    add ax, HALF_SCREEN_WIDTH
    mov word ptr cs:[temp_x], ax
    call color_pixel

    ;Point (xc - x, yc - y)
    mov ax, HALF_SCREEN_HEIGHT
    sub ax, word ptr cs:[y]
    mov word ptr cs:[temp_y], ax
    mov ax, HALF_SCREEN_WIDTH
    sub ax, word ptr cs:[x]
    mov word ptr cs:[temp_x], ax
    call color_pixel

    ;Point (xc + x, yc + y)
    mov ax, HALF_SCREEN_HEIGHT
    add ax, word ptr cs:[y]
    mov word ptr cs:[temp_y], ax
    mov ax, word ptr cs:[x]
    add ax, HALF_SCREEN_WIDTH
    mov word ptr cs:[temp_x], ax
    call color_pixel

    ;Point (xc - x, yc - y)
    mov ax, HALF_SCREEN_HEIGHT
    add ax, word ptr cs:[y]
    mov word ptr cs:[temp_y], ax
    mov ax, HALF_SCREEN_WIDTH
    sub ax, word ptr cs:[x]
    mov word ptr cs:[temp_x], ax
    call color_pixel

    pop ax
    ret

color_pixel:
    push ax
    push es
    ;position needs to be in a format y*320 + x
    mov ax, 0a000h
    mov es, ax
    mov ax, word ptr cs:[temp_y]    ;selecting a row
    mov bx, SCREEN_WIDTH            
    mul bx                          ;ax multiplying y by 320 to get proper position
    mov bx, word ptr cs:[temp_x]    ;selecting a column
    add bx, ax                      ;adding to the pixel position
    mov al, byte ptr cs:[color]     ;adding a color
    mov byte ptr es:[bx], al

    pop es
    pop ax
    ret
;-------------------------------------------------------------

end_program:
    mov al, 3h
    mov ah, 0
    int 10h

    mov ax, 4c00h
    int 21h

clear_screen:
    mov ax, 0a000h
    mov es, ax
    xor ax, ax
    mov di, ax
    mov cx, SCREEN_WIDTH * SCREEN_HEIGHT
    mov al, 0
    cld
    rep stosb   ;while cx != 0, mov byte ptr es:[di], al; di++; cx--
    ret

code1 ends

end start1

我尝试了许多不同版本的相同算法都没有成功。我想这可能是我的变量(特别是导数和决策参数)溢出的问题,我试图通过使用double words而不是words来声明变量来修复它,但我在算法中比较它们时遇到了麻烦,当我编译程序时,它仍然没有按预期工作。

wgx48brx

wgx48brx1#

我想这可能是我的变量(特别是导数和决策参数)溢出的问题
你对变量溢出的怀疑是正确的。
例如,考虑 calc_decision_param_1 的计算:

;d1 = y_squared - (x_squared * ry) + (1/4 * x_squared)

其结果为(50 * 50)-(40 * 40 * 50)+(40 * 40 / 4)= -77100
这不再适合有符号字,因此fistp word ptr cs:[decision_param]指令只能在字大小的目标中存储默认的“IntegerIndefinite value 8000 h”。
你应该做的是将一些变量定义为dword整数:x_derivativey_derivativedecision_param。所有其他变量将适合其当前的单词大小。
但我在算法中比较时遇到了麻烦
检查decision_param < 0是否应该简单地查看dword变量的符号位的代码:

test byte ptr cs:[decision_param+3], 80h
jz   alternative_region_2_next

以及检查x_derivative < y_derivative是否可以使用ficomp来比较这些有符号双字整数的代码。基于(冲突的)注解(;check if x_derivative < y_derivative;if it is we are done with region 1),它看起来像:

fninit
  fild    dword ptr cs:[x_derivative]
  ficomp  dword ptr cs:[y_derivative]
  fnstsw  ax
  sahf
  jb      calc_decision_param_2   ; done if x_derivative < y_derivative
  jmp     region_1_loop

calc_decision_param_2:

看起来x_radius_squared:y_radius_squared:做的事情与它们的名字告诉我们的完全相反!

相关问题