Line
Line
Line is a screensaver-like program similar to squares. It generates a line and move it around on the screen. Not much - but it is a funny little program anyway. It uses some external procedures from the module 'rand'. You must include the module in a library, and then include the library when linking the program. See this page for more details.
The procedure 'draw_line' is a candidate to get its own module, so I
can use it in other programs, but in its current incarnation it call
the rather primitive procedure 'plot_char', so I will wait until I have
a maked a version that can plot pixels in graphical video modes. It's
not a big project, I just haven't done it yet.
line.asm
;------------------------------------------------------------------------
%TITLE "line.asm"
;------------------------------------------------------------------------
IDEAL
MODEL small
STACK 256
;------------------------------------------------------------------------
; EQU's
;------------------------------------------------------------------------
X_MAX EQU 79
Y_MAX EQU 24
X_HALF_MAX EQU 39
Y_HALF_MAX EQU 12
R_MIN EQU 1
X_R_MAX EQU 20
Y_R_MAX EQU 6
COLOR_MIN EQU 1
COLOR_MAX EQU 7
MAXPAUSE EQU 30
MINPAUSE EQU 1
NumRows EQU 25
NumCols EQU 80
BytesPerRow = NumCols * 2
row = 0
;------------------------------------------------------------------------
DATASEG
;------------------------------------------------------------------------
pause DW 10 vbase DW 0B800h
LABEL scRow Word
REPT NumRows
DW (row * BytesPerRow)
row = row + 1
ENDM
excode DB 0h
char DB 'X'
attr DB 07h
;------------------------------------------------------------------------
UDATASEG
;------------------------------------------------------------------------
vbuffer DW 2000 DUP(?)
vmode DB ?
fgcolor DB ?
bgcolor DB ?
startxr DB ?
startyr DB ?
endxr DB ?
endyr DB ?
startx DB ?
starty DB ?
endx DB ?
endy DB ?
distx DB ?
disty DB ?
distx_abs DB ?
disty_abs DB ?
distx_sign DB ?
disty_sign DB ?
x DB ?
y DB ?
px DB ?
py DB ?
;------------------------------------------------------------------------
CODESEG
;------------------------------------------------------------------------
;----> From the object 'rand' in my library 'tj'
EXTRN seed_random:proc, get_random:proc
Start:
mov ax, @data ; Initialize DS to address
mov ds, ax ; of segment
mov es, ax ; Make es=ds
;------------------------------------------------------------------------
;----> get and set videomode
;------------------------------------------------------------------------
mov ah, 0Fh ; get videomode
int 10h
mov [vmode], al ;
mov ah, 00h ; set videomode 3
mov al, 03h ;
int 10h ;
;------------------------------------------------------------------------
;----> init
;------------------------------------------------------------------------
;----> clear mem area
mov ax, ds
mov es, ax
mov di, offset vbuffer
mov ax, 0
mov cx, 2000
rep stosw
call seed_random
;----> make starting points
xor cx, cx
mov bx, X_HALF_MAX
call get_random
mov [startx], dl
mov bx, Y_HALF_MAX
call get_random
mov [starty], dl
mov cx, X_HALF_MAX
mov bx, X_MAX
call get_random
mov [endx], dl
mov cx, Y_HALF_MAX
mov bx, Y_MAX
call get_random
mov [endy], dl
mov cx, COLOR_MIN
mov bx, COLOR_MAX
call get_random
mov [fgcolor], dl
mov [attr], dl
;----> make random values
mov cx, R_MIN
mov bx, X_R_MAX
call get_random
mov [startxr], dl
call get_random
mov [endxr], dl
mov bx, Y_R_MAX
call get_random
mov [startyr], dl
call get_random
mov [endyr], dl
;------------------------------------------------------------------------
;----> the 'main' loop
;------------------------------------------------------------------------
@@L10:
mov ah, 00h ; get ticks
int 1ah ; return ticks in dx
push dx ; save
;----> add random value and see
;----> if startx is near the edges
mov al, [startx]
add al, [startxr]
cmp al, 79
jg @@L21
cmp al, 0
jl @@L22
mov [startx], al
jmp short @@L24
@@L21:
mov [startx], 79
jmp short @@L23
@@L22:
mov [startx], 0
@@L23:
neg [startxr]
mov cx, 1
mov bx, 7
call get_random
mov [fgcolor], dl
@@L24:
;----> add random value and see
;----> if starty is near the edges
mov al, [starty]
add al, [startyr]
cmp al, 24
jg @@L25
cmp al, 0
jl @@L26
mov [starty], al
jmp short @@L28
@@L25:
mov [starty], 24
jmp short @@L27
@@L26:
mov [starty], 0
@@L27:
neg [startyr]
mov cx, 1
mov bx, 7
call get_random
mov [fgcolor], dl
@@L28:
;----> add random value and see
;----> if endx is near the edges
mov al, [endx]
add al, [endxr]
cmp al, 79
jg @@L29
cmp al, 0
jl @@L30
mov [endx], al
jmp short @@L32
@@L29:
mov [endx], 79
jmp short @@L31
@@L30:
mov [endx], 0
@@L31:
neg [endxr]
mov cx, 1
mov bx, 7
call get_random
mov [fgcolor], dl
@@L32:
;----> add random value and see
;----> if endy is near the edges
mov al, [endy]
add al, [endyr]
cmp al, 24
jg @@L33
cmp al, 0
jl @@L34
mov [endy], al
jmp short @@L36
@@L33:
mov [endy], 24
jmp short @@L35
@@L34:
mov [endy], 0
@@L35:
neg [endyr]
mov cx, 1
mov bx, 7
call get_random
mov [fgcolor], dl
@@L36:
;---->
call draw_line ; draw line in vbuffer
mov si, offset vbuffer ; copy line to vbase
mov es, [vbase]
xor di, di
mov cx, 2000
rep movsw
pop bx ; restore saved ticks
@@L50:
mov ah, 00h ; get new ticks
int 1Ah
sub dx, bx ; substract, to get num of ticks
cmp dx, [pause] ; since first start of looph,
jb @@L50 ; and compare to the num in PAUSE
; loop while below
mov [attr], 0 ; draw line again with black
; to erase current line
call draw_line
mov si, offset vbuffer ; copy to vbase
mov es, [vbase]
xor di, di
mov cx, 2000
rep movsw
mov al, [fgcolor] ; restore fgcolor to attribute
mov [attr], al
mov ah, 11h ; see if key has been pressed
int 16h ;
jnz @@L80 ; break if key pressed
jmp @@L10 ; loop
@@L80:
mov ah, 10h ; see what's in keyb buffer
int 16h
cmp al, 1Bh ; Esc?
je @@L90
cmp ah, 50h ; down arrow?
jne @@L82
cmp [pause], MAXPAUSE
je @@L89 ; is pause = MAXPAUSE?
inc [pause] ; if not, increase pause
jmp @@L10 ; and continue loop
@@L82:
cmp ah, 48h ; up arrow?
jne @@L89 ; if not, ignore and continue loop
cmp [pause], MINPAUSE ; is pause = MINPAUSE
je @@L89 ; if yes, continue loop
dec [pause] ; else decrease pause
@@L89:
jmp @@L10
@@L90:
;------------------------------------------------------------------------
;----> set videmode back to original
;------------------------------------------------------------------------
mov ah, 00h ; set videomode
mov al, [vmode] ;
int 10h ;
Exit:
mov ah, 04Ch ; DOS function: Exit program
mov al, [excode] ; Return exit code value
int 21h ; Call DOS. Terminate program
;========================================================================
;------------------------------------------------------------------------
;
; DRAW_LINE
;
; * lines.c
; * written by David Brackeen
; * http://www.brackeen.com/home/vga/
;
; void line_fast(int x1, int y1, int x2, int y2, byte color)
; {
; int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;
;
; dx=x2-x1; /* the horizontal distance of the line */
; dy=y2-y1; /* the vertical distance of the line */
; dxabs=abs(dx);
; dyabs=abs(dy);
; sdx=sgn(dx);
; sdy=sgn(dy);
; x=dyabs>>1;
; y=dxabs>>1;
; px=x1;
; py=y1;
;
; VGA[(py<<8)+(py<<6)+px]=color;
;
; if (dxabs>=dyabs) /* the line is more horizontal than vertical */
; {
; for(i=0;i<dxabs;i++)
; {
; y+=dyabs;
; if (y>=dxabs)
; {
; y-=dxabs;
; py+=sdy;
; }
; px+=sdx;
; plot_pixel(px,py,color);
; }
; }
; else /* the line is more vertical than horizontal */
; {
; for(i=0;i<dyabs;i++)
; {
; x+=dxabs;
; if (x>=dyabs)
; {
; x-=dyabs;
; px+=sdx;
; }
; py+=sdy;
; plot_pixel(px,py,color);
; }
; }
; }
;
;------------------------------------------------------------------------
PROC draw_line
;---> distx=ensx-startx
mov al, [endx]
sub al, [startx]
mov [distx], al
;---> disty=endy-starty
mov bl, [endy]
sub bl, [starty]
mov [disty], bl
;---> distx_abs=abs(distx)
;---> distx_sign=sgn(distx)
mov bl, [distx]
xor al, al
cmp [distx], 0
jg @@dxg
jl @@dxl
je @@dx
@@dxg:
inc al
jmp short @@dx
@@dxl:
dec al
neg bl
@@dx:
mov [distx_sign], al
mov [distx_abs], bl
;---> disty_abs=abs(disty)
;---> disty_sign=sgn(disty)
mov al, [disty]
xor bl, bl
cmp [disty], 0
jg @@dyg
jl @@dyl
je @@dy
@@dyg:
inc bl
jmp short @@dy
@@dyl:
dec bl
neg al
@@dy:
mov [disty_sign], bl
mov [disty_abs], al
;---> x=disty_abs>>1
mov al, [disty_abs]
shr al, 1
mov [x], al
;---> y=distx_abs>>1
mov bl, [distx_abs]
shr bl, 1
mov [y], bl
;---> px=startx
mov al, [startx]
mov [px], al
;---> py=starty
mov bl, [starty]
mov [py], bl
call plot_char
;---> if (distx_abs>=disty_abs)
;---> /* the line is more horizontal than vertical */
;---> {
mov al, [distx_abs]
cmp al, [disty_abs]
jbe @@vertical
xor ch, ch
mov cl, [distx_abs]
@@h1:
mov al, [disty_abs]
add [y], al
mov al, [distx_abs]
cmp [y], al
jb @@h2
mov al, [distx_abs]
sub [y], al
mov al, [disty_sign]
add [py], al
@@h2:
mov al, [distx_sign]
add [px], al
call plot_char
loop @@h1
jmp short @@L99
;---> else /* the line is more vertical than horizontal */
@@vertical:
xor ch, ch
mov cl, [disty_abs]
@@v1:
mov al, [distx_abs]
add [x], al
mov al, [disty_abs]
cmp [x], al
jb @@v2
mov al, [disty_abs]
sub [x], al
mov al, [distx_sign]
add [px], al
@@v2:
mov al, [disty_sign]
add [py], al
call plot_char
loop @@v1
@@L99:
ret
ENDP draw_line
;========================================================================
;------------------------------------------------------------------------
;
; PLOT_CHAR
;
;
;------------------------------------------------------------------------
PROC plot_char
mov ax, ds
mov es, ax
mov di, offset vbuffer
xor bh, bh
mov bl, [py]
shl bx, 1
add di, [scRow+bx]
xor dh, dh
mov dl, [px]
shl dx, 1
add di, dx
mov al, [char]
mov ah, [attr]
stosw
@@L99:
ret
ENDP plot_char
;========================================================================
END Start ; End of program / entry point
;------------------------------------------------------------------------