; CMLINE 2.0 Public domain by Celso Minnitti Jr. October 29, 1994.
;
; CMLINE is a heavily optimized line drawing routine that has the
; fastest possible inner loop for the 386+ family.
_TEXT segment para public 'CODE'
assume cs:_TEXT, ds:_TEXT
org 100h
.386
MY_X1 EQU 100
MY_Y1 EQU 100
MY_X2 EQU 149
MY_Y2 EQU 109
MY_COLOR EQU 14
start: mov ax,13h ;enter mode 13h
int 10h ;320x200 w/ 256 colors
push MY_COLOR
push MY_Y2
push MY_X2
push MY_Y1
push MY_X1
call _line
add sp,10
mov ah,0 ;wait for a key
int 16h ;
mov ax,3 ;return to mode 3
int 10h ;80x25 16/colors
int 20h ;exit to DOS
align 16
;-----------------------------------------------------------------------
; void line(int x1, int y1, int x2, int y2, int color);
;
; Draws a line from (x1,y1) to (x2,y2) including endpoints.
;
; This routine is heavily optimized for Pentium and 486s CPUs...
;-----------------------------------------------------------------------
_line PROC NEAR
@@x1 EQU [bp+4]
@@y1 EQU [bp+6]
@@x2 EQU [bp+8]
@@y2 EQU [bp+10]
@@color EQU [bp+12]
push bp
mov bp,sp
push eax ;
push ecx ;
push edx ;save all registers that we
push bx ;are going to use
push esi ;
push di ;
push ds ;
xor ecx,ecx
mov ax,[@@y1]
mul [_screenWidth]
mov di,ax
mov cx,word ptr [@@x2]
add di,[@@x1] ;di = y1*_screenWidth + x1
mov ax,1 ;xinc = 1
sub cx,[@@x1] ;deltaX = x2 - x1
jnc line_1
neg ax ;if (x1 < x2) xinc = -1
neg cx ;deltaX
line_1: mov si,[@@y2]
mov bx,[_screenWidth] ;yinc = 320
sub si,[@@y1] ;deltaY = y2 - y1
jnc line_2
neg bx ;if (y1 < y2) yinc = -320
neg si ;deltaY
line_2: cmp cx,si ;is deltaX >= deltaY?
jae line_3
xchg ax,bx ;swap(xinc, yinc)
xchg cx,si ;swap(deltaX, deltaY)
line_3: mov word ptr [line_xyinc+2],ax ; guess what this does...
mov word ptr [line_yxinc+2],bx ;
inc cx ;deltaX++
mov ax,si
shl esi,16
inc ax ;ax = deltaY+1
xor edx,edx ;
shl eax,16
div ecx ;(deltaY << 16) / deltaX
test edx,edx ;if (remainder != 0) ax++
jz line_4 ;
inc ax ;
line_4: test ax,ax ;if (quotient == 0)
jnz line_5 ; ax = si = -1
dec ax ;ax = -1
dec si ;si = -1
line_5: mov word ptr [line_xyloop+2],ax
mov al,[@@color]
mov ds,[_vidseg]
jmp short line_xyseg ;flush prefetch queue to avoid
;problems with self-modifying
;code...
;Because ($ & 15) < 8 no align 16 is necessary... See your pentium
; notes...
; !!!! Beatiful line inner loop !!!! ; 486 clocks....
line_xyseg: mov [di],al ; 1 cycle
line_xyinc: add di,0ff00h ;1,-1,320,-320 1 cy
line_xyloop: add si,0ff00h ; 1 cy
jnc line_xyseg ; 3,1 cy
line_yxinc: add di,0ff00h ;320,-320,1,-1 1
sub esi,10000h ; 1
jnc line_xyseg ; 3,1
pop ds ;
pop di ;
pop esi ;
pop bx ;restore registers
pop edx ;
pop ecx ;
pop eax ;
pop bp ;
ret
_line ENDP
_vidseg dw 0a000h
_screenWidth dw 320
_TEXT ends
end start