Search code examples
assemblydrawnasmangledos

Assembly calculate sine example. nasm 16 dos


I'm looking for example how to calculate sine using coprocessor. I've found function:

CalcSin 
        fld     long [angle]            ; st(0) = angle 
        fsin                            ; st(0) = sin(angle)  (angle is in radians) 
        fstp    long [SinX]             ; SinX = sin(angle) 

I want to draw sine and I need to Y in ax and X in bx. X will be no problem, because I will make loop for, but with Y I have a problem. X will be from example 0 to 350 (like a pixels). How to calculate it and have Y for pixel if for example sin (30 deg) is 1/2. How to round result to have good coordinate?


Edit: I'm sorry, but I when I run your code it shows me no sinus, but 2 lines. I don't know what I'm doing wrong now

    segment .data

    segment .code
..start:
    mov ax, 13h 
    int 10h               ; switch to 320x200 mode

    mov ax, 0a000h        ; The offset to video memory
    mov es, ax            ; We load it to ES through AX,
                          ; because immediate operation
                          ; is not allowed on ES

;;;;;;;;;;;;;;;;;;;;;;

DrawWave:
    mov ebx, y  ; EBX = &y
    mov ecx, 0

    ; let st(1) = 2*PI/640
    fldpi               ; st(0) = PI
    fidiv dword [step]  ; st(0)/160 = 0.009817...
    fldz                ; st(0) = 0.0, st(1) = 0.00045...

    .loop:
        fld st0   ; duplicate the x on the top
        fsin        ; st(0) = sin x

        fimul dword [imgHeight]     ; st(0) = y*240
        fiadd dword [imgHeight]     ; eliminate negative coordinate by translating the wave vertically          
        fistp dword [y]             ; store y to ´y´

        fadd st0, st1           ; add the step value to x, doing the step

        ;draw pixel at [*EAX:ECX]
        push ax
        push bx
        push cx
        call DrawPixel
        pop cx
        pop bx
        pop ax

        inc ecx
        cmp ecx, 320    ; perform 640 steps to draw a single sine wave
        jl .loop

        fstp st0  ;clean up
        fstp st0  ;clean up
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;

    xor ah, ah
    int 16h               ; keyboard (wait for key)

    mov ax, 3
    int 10h               ; go to text mode

    mov ax, 4c00h
    int 21h               ; return to DOS, exit code 0

;;;;;;;;;;;;;;;;;;;;;

; EBX = in &CoordY
; ECX = CoordX  
;DrawPixel:
    ; draw a pixel at [*EBX:ECX]
 ;   ret 
DrawPixel:
    push dx               ; mul changes dx too
    mov ax, cx            ; ax is X coord copy from cx
    mov cx, 320
    mul cx                ; multiply Y (ax) by 320 (one row)
    add ax, bx            ; and add X (bx) (result= dx:ax)
    mov di, ax
    pop dx
    mov dl, 4
    mov [es:di], dl       ; store color/pixel
    ret

    ;CONSTANTS:

step: dw 160        ; 2/320 = 160
imgWidth: dw 320    ; 320px
imgHeight: dw 200/2 ; 200px on half, because Y also gets negative
;VARIABLES:
x: dw 0     ; a tmp place to save X
y: dw 0     ; a tmp place to save Y

Solution

  • If I understand your correctly, you want to draw a sine wave without any translations and scaling. Therefore you can take the angle as your X coordinate, and the value you get from function f(x) = sin x is your Y coordinate.

    ; EAX = in &CooordX
    ; EBX = out &CoordY
    SinX:
        fld     qword [eax]           ; st(0) = angle 
        fsin                         ; st(0) = sin(angle)
        fstp    qword [ebx]           ; *ebx = sin(angle) 
        ret
    

    Now let's say you want to draw a single wave. That means that x == 2*PI rad (a full wave) must be true exactly when drawing the last pixel. With a screen 640 pixels wide, your single step for x in drawing loop is 2*PI/640 = 0.009817. The rest is simple.

    ;CONSTANTS:
    step: dw 320        ; 2/640 = 320, omitted PI
    imgWidth: dw 640    ; 640px
    imgHeight: dw 480/2 ; 480px on half, because Y also gets negative
    
    ;VARIABLES:
    y: dw 0     ; a tmp place to save Y
    
    DrawWave:
        mov ebx, y  ; EBX = &y
        mov ecx, 0
    
        ; let st(1) = 2*PI/640
        fldpi               ; st(0) = PI
        fidiv dword [step]  ; st(0)/320 = 0.009817...
        fldz                ; st(0) = 0.0, st(1) = 0.009817...
    
        .loop:
            fld st(0)   ; duplicate the x on the top
            fsin        ; st(0) = sin x
    
            fimul dword [imgHeight]     ; st(0) = y*240
            fiadd dword [imgHeight]     ; eliminate negative coordinate by translating the wave vertically          
            fistp dword [y]             ; store y to ´y´
    
            fadd st(0), st(1)           ; add the step value to x, doing the step
    
            ;draw pixel at [*EAX:ECX]
            call DrawPixel
    
            inc ecx
            cmp ecx, 640    ; perform 640 steps to draw a single sine wave
            jl .loop
    
            fstp st(0)  ;clean up
            fstp st(0)  ;clean up
        ret
    
    ; EBX = in &CoordY
    ; ECX = CoordX  
    DrawPixel:
        ; draw a pixel at [*EBX:ECX]
        ret