;******************************************************;
;* PLASMA.ASM -- Simple plasma display, with rotating *;
;* palette. Requires VGA, 186. *;
;******************************************************;
.Model Tiny
.186
.Code
Org 100h
Prog Proc
mov ax,13h ;Set video mode 13h
int 10h
mov di,offset Palette ;Zero the palette
xor al,al
mov cx,576
rep stosw
mov ax,3F00h ;AL = 0, AH = 63, BX = 0
xor bx,bx
PalLoop: mov Palette[bx],ah ;Set palette values
mov Palette[bx+2],al
mov word ptr Palette[bx+193],ax
mov word ptr Palette[bx+384],ax
add bx,3 ;Advance pointers
inc al
dec ah ;Loop back
jns PalLoop
xor bx,bx ;Set initial palette
call setpal
push 40h ;ES = 40h
pop es
mov ax,es:[6Ch] ;Seed RNG
mov bx,es:[6Eh]
mov RandNum[0],ax
mov RandNum[2],bx
push 0A000h ;ES = 0A000h
pop es
call rand192 ;Set corner pixels to random colors
mov es:[0],al
call rand192
mov es:[319],al
call rand192
mov es:[63360],al
call rand192
mov es:[63999],al
push 199 ;Draw plasma
push 319
push 0
push 0
call Plasma
push cs ;ES = CS
pop es
mov si,offset Palette ;Double palette for rotation
mov di,offset Palette+576
mov cx,576
rep movsb
xor bx,bx ;BX = 0
Rotate: mov ah,1 ;Check for Escape key
int 16h
jnz Done
mov dx,03DAh ;Status port
VRTloop1: in al,dx ;Wait for next retrace
test al,8
jnz VRTloop1
VRTloop2: in al,dx
test al,8
jz VRTloop2
call setpal ;Set palette
add bx,3 ;Advance palette
cmp bx,576 ;Check for wrap
jne Rotate ;Loop back...
xor bx,bx
jmp Rotate
Done: mov ax,3 ;Set text mode
int 10h
ret ;Return
rand192: mov ax,192 ;Get random number 1-192
call Rand
inc ax
ret
setpal: mov dx,03C8h ;Index port
mov al,1 ;Set register 1
out dx,al
inc dx ;Data port
lea si,Palette[bx] ;Send palette
mov cx,576
rep outsb
ret ;Return
Prog EndP
;**************************** Plasma -- Recursive plasma procedure
Plasma Proc
push bp ;Set up stack frame
mov bp,sp
pusha ;Save all registers
mov ax,[bp+4] ;Get values
mov bx,[bp+6]
mov cx,[bp+8]
mov dx,[bp+10]
mov si,cx ;x2 - x1 < 2, done
sub si,ax
cmp si,2
jnb P_Cont
jmp P_Done
P_Cont: mov si,ax ;x = (x1 + x2) / 2
add si,cx
sar si,1
mov di,bx ;y = (y1 + y2) / 2
add di,dx
sar di,1
pusha ;Save registers
push bx ;Adjust top side
push si
push bx
push cx
push bx
push ax
call Adjust
push dx ;Adjust bottom side
push si
push dx
push cx
push dx
push ax
call Adjust
push di ;Adjust left side
push ax
push dx
push ax
push bx
push ax
call Adjust
push di ;Adjust right side
push cx
push dx
push cx
push bx
push cx
call Adjust
push si ;Center pixel on, recurse
push di
call GetPixel
test al,al
jnz P_Recurse
xor ah,ah ;Zero AH
push [bp+4] ;DX = sum of corners
push [bp+6]
call GetPixel
mov dx,ax
push [bp+8]
push [bp+6]
call GetPixel
add dx,ax
push [bp+4]
push [bp+10]
call GetPixel
add dx,ax
push [bp+8]
push [bp+10]
call GetPixel
add dx,ax
shr dx,2 ;DX = average of corners
mov al,dl
push si ;Set center pixel
push di
call SetPixel
P_Recurse: popa ;Restore registers
push di ;Plasma x1, y1, x, y
push si
push bx
push ax
call Plasma
push di ;Plasma x, y1, x2, y
push cx
push bx
push si
call Plasma
push dx ;Plasma x, y, x2, y2
push cx
push di
push si
call Plasma
push dx ;Plasma x1, y, x, y2
push si
push di
push ax
call Plasma
P_Done: popa ;Restore registers
pop bp ;Delete stack frame
ret 8 ;Return, pop args
Plasma EndP
;**************************** Adjust -- Random adjust pixel midpoint
Adjust Proc
push bp ;Set up stack frame
mov bp,sp
pusha ;Save all registers
mov si,[bp+12] ;Get values
mov di,[bp+14]
push si ;Check pixel
push di
call GetPixel
test al,al ;Already on, done
jnz A_Done
mov ax,[bp+8] ;BX = |x2 - x1| + |y2 - y1|
sub ax,[bp+4]
mov bx,[bp+10]
sub bx,[bp+6]
test ax,ax ;get absolute values...
jge $+4
neg ax
test bx,bx
jge $+4
neg bx
add bx,ax
imul ax,bx,2 ;AX = BX * 2 + 1
inc ax
mov bx,ax ;Get random number
call Rand ;positive and negative
sar bx,1
sub ax,bx
xchg dx,ax ;in DX
push [bp+4] ;AX = average of ends + DX
push [bp+6]
call GetPixel
push ax
push [bp+8]
push [bp+10]
call GetPixel
pop bx
xor ah,ah
add al,bl
adc ah,0
sar ax,1
add ax,dx
test ax,ax ;Make sure it's in range
jg $+5
mov ax,1
cmp ax,192
jle $+5
mov ax,192
push si ;Set center pixel
push di
call SetPixel
A_Done: popa ;Restore registers
pop bp ;Delete stack frame
ret 12 ;Return, pop args
Adjust EndP
;**************************** Rand -- Random number generator
Rand Proc
push bx ; This RNG routine was
push cx ;taken from the TurboC
push dx ;runtime library, but
push ax ;it is a big kludge.
mov ax,RandNum[0] ; I do not know how
mov dx,4E35h ;it really works.
mul dx
mov cx,dx
mov bx,ax
imul ax,RandNum[0],015Ah
add cx,ax
imul ax,RandNum[2],4E35h
add ax,cx
inc bx
mov RandNum[0],bx
mov RandNum[2],ax
add ax,ax
and bl,1
or al,bl
pop bx
xor dx,dx
div bx
mov ax,dx
pop dx
pop cx
pop bx
ret
Rand EndP
;**************************** GetPixel -- Read a pixel
GetPixel Proc
push bp
mov bp,sp
imul bx,[bp+4],320
add bx,[bp+6]
mov al,es:[bx]
pop bp
ret 4
GetPixel EndP
;**************************** SetPixel -- Write a pixel
SetPixel Proc
push bp
mov bp,sp
imul bx,[bp+4],320
add bx,[bp+6]
mov es:[bx],al
pop bp
ret 4
SetPixel EndP
;**************************** DATA section
RandNum dw ?,?
Palette db 1152 dup(?)
End Prog