Ack Egad Newbie needs help with his line drawing algorithm

From: Frogbert (frogbert_at_host.sk)
Date: 05/19/04


Date: Wed, 19 May 2004 17:38:56 +0000 (UTC)

I'm trying to write my first assembly program (well first of any
value) for my comp arch and assembler course. Basicaly my program
accepts 2 lots of x,y coodinates and then draws a line between them. I
have the input stages all correct however I can't seem to get my line
drawing algorithm to work correctly. I am porting the algorithm found
here: http://www.gamedev.net/reference/articles/article1275.asp and as
far as I can see I've done it correctly but that is not the case. I
was hopeing a fresh pair of eyes might be able to spot a logic error.

;-------------------------------------------------------------------------------------------
;DrawLine calculates the steps inbetween and then draws a line on the
screen
;-------------------------------------------------------------------------------------------
DrawLine PROC X1:word, Y1:word, X2:word, Y2:word ;Calculates and draws
a line on the screen
        LOCAL deltaX:word ;Distance between the x points
        LOCAL deltaY:word ;Distanve between the y points
        LOCAL X:word ;X counter, starts at the first x point
        LOCAL Y:word ;Y counter, starts at the first y point
        LOCAL xIncrement1:word ;Two X increment variables are needed
        LOCAL xIncrement2:word
        LOCAL yIncrement1:word ;as are two Y increment variables
        LOCAL yIncrement2:word
        LOCAL den:word ;denominator
        LOCAL num:word ;numerator
        LOCAL numadd:word ;number add
        LOCAL numPixels:word ;number of pixels
        
        mov ax, X1 ;start off at X1
        mov X, ax
        mov ax, Y1 ;and start off at Y1
        mov Y, ax
        
        mov ax, X2 ;
        sub ax, X1 ;
        call ABS ;
        mov deltaX, ax ; deltaX = abs(x2-x1)
        
        mov ax, Y2 ;
        sub ax, Y1 ;
        call ABS ;
        mov deltaY, ax ; deltaY = abs(y2-y1)
        
        
        mov ax, X2 ;put X2 into eax register to test
        cmp ax, X1 ;test to see if x values are increasing
        jge xIncreasing ;if they are jump to xIncreasing
        mov xIncrement1, -1 ;else x is decreasing
        mov xIncrement2, -1
        jmp testY ;jump to testY
xIncreasing:
        mov xIncrement1, 1 ;X is increasing
        mov xIncrement2, 1
        
testY:
        mov ax, Y2
        cmp ax, Y1 ;test to see if y values are increasing
        jge yIncreasing ;if they are jump to yIncreasing
        mov yIncrement1, 1 ;else
        mov yIncrement2, 1
        jmp testRatio ;jump to the test ratio part
yIncreasing:
        mov yIncrement1, -1 ;Y is increasing
        mov yIncrement2, -1

testRatio: ;Tests the ratio of x to y pixels
        
        mov ax, deltaX
        cmp ax, deltaY ;if deltaX >= deltaY
        jge oneXforEveryY
                                ;else
        mov bx, 0
        mov xIncrement1, bx
        mov yIncrement2, bx
        mov ax, deltaX
        mov den, ax ;denominator = deltaX
        shr ax, 1 ;divide deltaX by 2
        mov num, ax ;and make it the numerator
        mov ax, deltaY
        mov numadd, ax ; numAdd = deltaY
        mov ax, deltaX
        mov numPixels, ax ; numPixles = deltaX
        
        jmp drawPixels
        
oneXforEveryY:
        mov ebx, 0
        mov xIncrement2, bx
        mov yIncrement1, bx
        mov ax, deltaY
        mov den, ax ;denominator = deltaY
        shr ax, 1 ;divide deltaY by 2
        mov num, ax ;and make it the numerator
        mov ax, deltaX
        mov numadd, ax ; numAdd = deltaX
        mov ax, deltaY
        mov numPixels, ax ; numPixles = deltaY
        
drawPixels:

        mov cx, numPixels
                                
        mov ah,0Fh ; Save the current video mode
        int 10h
        mov saveMode,al
        
        mov ah,0 ; Switch to a graphics mode
        mov al,0Dh ; set video mode
        int 10h
        
drawLoop:
        INVOKE putPixel, X, Y ;draw pixel at x, y
        mov ax, num ;increase the numerator by the top of the fraction
        add ax, numadd ;add numadd to the numerator
        mov num, ax ;put it back into numerator
        
        cmp ax, den ;compare to the denominator to check if the numerator is
greater
        jl changeValues ;change values
        
        sub ax, den
        mov num, ax ;numerator = numerator - denominator
        mov ax, X
        add ax, xIncrement1 ; increment x
        mov X, ax
        mov ax, Y
        add ax, yIncrement1 ; increment y
        mov Y, ax

changeValues:
        
        mov ax, X
        add ax, xIncrement2
        mov X, ax
        mov ax, Y
        add ax, yIncrement2 ; increment y
        mov Y, ax
        loop drawLoop
        
        mov ah,0 ;wait for a key to be pressed
        int 16h

        ret
DrawLine ENDP

;-------------------------------------------------------------------------------------------
;ABS calcuates the absolute value of ax
;-------------------------------------------------------------------------------------------

ABS PROC
        cmp ax, 0 ;compare to zero
        jge ABS_end ;if the numbers positive return
        neg ax ;else times by -1 to make positive
ABS_end:
        ret ;ta-da absolute value!
ABS ENDP

;-------------------------------------------------------------------------------------------
;putPixel places a pixel on the screen given two coodinates x and y
;-------------------------------------------------------------------------------------------

putPixel PROC uses cx dx, x:WORD, y:WORD ;draws a pixel to the
screen

        mov ah, 0Ch ;select draw a pixel function
        mov al, 2 ;colour of pixel
        mov bh, 0 ;video page 0
        mov cx, x ;x coords
        mov dx, y ;y coords
        int 10h ;draw it

        ret
putPixel ENDP

Mind the comments they are a little outdated due to my tinkering (I've
converted the thing from using 32 bit registers to 16 for example so
all these references to eax mean ax).

Anyway thankyou in advance for any tips and hints, and please keep the
mocking of the slow code to a dull roar ;)