Code:
;--------------------------------
PlotPixel PROC USES ax bx di dx,
x:WORD,
y:WORD,
color:BYTE
;
; Plots a single pixel at given coords in the given color
;--------------------------------
mov ax, y ; store y coord
mov bx, SCREEN_WIDTH
mul bx ; y * screen width
add ax, x ; + x
mov di, ax ; pixel's VRAM address
mov al, color
mov BYTE PTR es:[di], al ; plot the pixel
ret
PlotPixel ENDP
;---------------------------
DrawLine PROC USES eax bx cx dx di si,
x0:WORD,
y0:WORD,
x1:WORD,
y1:WORD,
color:BYTE
;
; An implementation of the Bresenham line-drawing algorithm
; Translated to ASM by Adam Ward, 10/12/05
;
; NOTES:
; - Treats horizontal and vertical lines separately for extra speed.
; - Horizontal lines with a length that is a multiple of 4 will be the most efficient.
; - Single pixels are the least efficient (Use PlotPixel instead)
;---------------------------
LOCAL deltax:WORD,
deltay:WORD,
xstep:WORD,
ystep:WORD
; validate all the arguments (both coords are on screen)
mov ax, SCREEN_WIDTH
mov bx, SCREEN_HEIGHT
xor cx, cx
cmp x0, ax
jae DONE
cmp x1, ax
jae DONE
cmp y0, bx
jae DONE
cmp y1, bx
jae DONE
mov ax, y0
cmp ax, y1
je LINE_IS_HORIZONTAL
mov ax, x0
cmp ax, x1
je LINE_IS_VERTICAL
;####################################
;### START OF BRESENHAM ALGORITHM ###
;####################################
; cx = abs(y1 - y0) > abs(x1 - x0) ####################
mov ax, y1
sub ax, y0
jns ABS_Y_DONE
neg ax ; number is negative, so make it positive
ABS_Y_DONE:
mov bx, x1
sub bx, x0
jns ABS_X_DONE
neg bx ; number is negative, so make it positive
ABS_X_DONE:
cmp ax, bx
jbe ELSE1
; ax > bx
mov cx, 1
jmp ENDIF1
ELSE1:
; ax <= bx
mov cx, 0
ENDIF1:
; if cx then ####################
jcxz ELSE2
; swap(x0, y0)
mov ax, x0
xchg ax, y0
mov x0, ax
; swap(x1, y1)
mov ax, x1
xchg ax, y1
mov x1, ax
INVOKE PlotPixel, y0, x0, color
jmp ENDIF2
ELSE2:
INVOKE PlotPixel, x0, y0, color
ENDIF2:
; deltax = abs(x1 - x0) ###########
mov ax, x1
sub ax, x0
jns ABS_X2_DONE
neg ax ; number is negative, so make it positive
ABS_X2_DONE:
mov deltax, ax
; deltay = abs(y1 - y0) ###########
mov ax, y1
sub ax, y0
jns ABS_Y2_DONE
neg ax ; number is negative, so make it positive
ABS_Y2_DONE:
mov deltay, ax
; si = 0 ##########
xor si, si
; bx = x0 #########
mov bx, x0
; dx = y0 #########
mov dx, y0
; if x0 < x1 then #########
cmp bx, x1
jae ELSE3
; xstep = 1
mov xstep, 1
jmp ENDIF3
ELSE3:
; xstep = -1
mov xstep, -1
ENDIF3:
; if y0 < y1 then #########
cmp dx, y1
jae ELSE4
; ystep = 1
mov ystep, 1
jmp ENDIF4
ELSE4:
; ystep = -1
mov ystep, -1
ENDIF4:
; while bx != x1 ###############
L1:
cmp bx, x1
je DONE
; bx = bx + xstep
add bx, xstep
; er = er + deltay
add si, deltay
; if 2 * er > deltax ##########
mov ax, si
shl ax, 1 ; er * 2
cmp ax, deltax
jle ENDIF5
; dx = dx + ystep
add dx, ystep
; er = er - deltax
sub si, deltax
ENDIF5:
; if cx then #############
jcxz ELSE6
; plot(dx, bx)
INVOKE PlotPixel, dx, bx, color
jmp L1 ; SHORTCUT TO BEGINNING OF WHILE LOOP
ELSE6:
; plot(bx, dx)
INVOKE PlotPixel, bx, dx, color
jmp L1 ; continue the while loop
;########################################
LINE_IS_HORIZONTAL:
; find the length of the line
mov ax, x1
sub ax, x0
jz LINE_IS_VERTICAL ; single-pixel lines are better handled by the vertical algorithm
jns LH_OK
LH_SWAP:
neg ax ; we can change the sign of ax without having to subtract again
mov bx, x0
xchg bx, x1
mov x0, bx
LH_OK:
; AX now contains the length of the line (pixels)
inc ax
mov bx, TYPE DWORD
div bx
push dx ; the remainder, which is used as the second loop number
push ax ; the quotient which is used as the first loop number
; calculate the left-hand end of the line
mov ax, y0
mov bx, SCREEN_WIDTH
mul bx
add ax, x0
mov di, ax
; fill eax with color bytes
mov bl, color
mov bh, bl
mov ax, bx
shl eax, 16
mov ax, bx
; draw chunks of 4 pixels at a time to accelerate horizontal lines
pop cx
mov bx, TYPE DWORD
jcxz LH_REMAINDER ; avoid cx=0 looping error
LH1:
mov DWORD PTR es:[di], eax
add di, bx
Loop LH1
; draw the remaining 1 - 3 bytes if required
LH_REMAINDER:
pop cx ; remainder (so 1 pixel at a time)
jcxz DONE ; avoid cx=0 looping error
LH2:
mov BYTE PTR es:[di], al
inc di
Loop LH2
jmp DONE
;########################################
LINE_IS_VERTICAL:
; find the length of the line
mov ax, y1
sub ax, y0
jns LV_OK
LV_SWAP:
neg ax ; we can change the sign of ax without having to subtract again
mov bx, y0
xchg bx, y1
mov y0, bx
LV_OK:
; AX now contains the length of the line (pixels)
inc ax ; add 1 because its zero-based
mov cx, ax
; calculate the top end of the line
mov ax, y0
mov bx, SCREEN_WIDTH
mul bx
add ax, x0
mov di, ax
mov al, color ; source byte
; draw chunks of 4 pixels at a time to accelerate horizontal lines
mov bx, SCREEN_WIDTH
LV1:
mov BYTE PTR es:[di], al ; draw the pixel
add di, bx
Loop LV1
;########################################
DONE:
ret
DrawLine ENDP