18
I'm working on a small plasma in TASM. It's very vanilla and not very interesting except for the sine generator. I was struggling with a big list of sine constants (originally I'd exported them from c#, double d = 32 + 32 * Math.Cos((i * 6.28) / 256)) when I came upon this generator in a prod by insomniac/matrix. But I'm not good enough at asm to tell exactly how it's working, except that wally/rage (??) was pretty darn clever. 188 bytes but I'm also getting some annoying color banding from stosw
; tasm /m2
; tlink /t
cseg segment
assume cs:cseg
org 0100h
.286
start:
mov ax,13h ; set mode 13
int 10h
push 0a000h ; stick video segment in es
pop es
mov dx,3c8h ; set color index port
xor ax,ax
out dx,al ; output color index 0
inc dx ; inc dx = 3C9h, color write port
@redup: ; Set colors 0-62, ramp up red
out dx,al ; set red to value in al
xchg al,ah ; ah is 0, so exchange it with al
out dx,al ; set green and blue = 0
out dx,al
xchg al,ah ; swap ah/al so al is again non-zero
inc al ; al +=1
cmp al,63
jne @redup
@reddn: ;set colors 63-127, ramp down red
out dx,al
xchg al,ah
out dx,al
out dx,al
xchg al,ah
dec al
jnz @reddn
@blueup: ;set colors 127-194, ramp up blue
xchg al,ah
out dx,al
out dx,al
xchg al,ah
out dx,al
inc al
cmp al,63
jne @blueup
@bluedn: ;set 194-256, ramp down blue
xchg al,ah
out dx,al
out dx,al
xchg al,ah
out dx,al
dec al
jnz @bluedn
; sin generator from argon by insomnia/matrix
; who got it from Wally/Rage, but I'm not sure
; who that was. There was a Rage demogroup
; in the amiga scene. Anyway, credit to the
; original author. My big list of sin constants
; was taking up ~200 bytes
mov cx,783Fh ; [30783]
xor si,si
sin1:
mov ax,65497
imul cx ;[2016194151]
add si,dx ; results of imul are stored in dx:ax [782C AE67, si+=30764]
add cx,si ; [783F + 782C,cx=30783+30764=61547=F06B]
mov [bx],ch ; [[bx]=F0=240]
sar byte ptr [bx],1 ; divide the value by 2, only store a byte [bx=120?]
dec bx
cmp bx,16383
jne sin1
; inc bx ; BX points to the sine/cos-values [comment by insomnia but this step isn't needed and saves a byte]
mov si,bx ; move it to SI since I need BX
main:
;------- main program ------------
xor di,di ; Reset vga position
mov cl,[p_pos1] ; stick plasma position values into ch,cl
mov ch,[p_pos2]
mov ah,200 ; 200 rows in mode 13
Y_LOOP:
push ax ; ax is also our x counter, so save
; the y vals to test later
mov dl,[p_pos3] ; the other position values in dh,dl
mov dh,[p_pos4] ; now the plasma position vals are in cx/dx
mov ah,160 ; X counter. since we're using stosw we only have to loop 320/2 times
X_LOOP:
xor al,al ; al holds the color, so clear it
; x = SinTable[p_pos1] + SinTable[p_pos2] + SinTable[p_pos3] + SinTable[p_pos4]
mov bl,dl ; mov p_pos3 into bl
add al,si[bx] ; x += Sin[p_pos3]
mov bl,dh ; mov p_pos4 into bl
add al,si[bx] ; x += Sin[p_pos4]
mov bl,cl ; mov p_pos1 into bl
add al,si[bx] ; x += Sin[p_pos1]
mov bl,ch ; mov p_pos2 into bl
add al,si[bx] ; x += Sin[p_pos2]
; push cx ; save the position vals
; mov cx,4 ; write 4 pixels at a time
; rep stosb ; put pixel cx times in es:di, advancing the screen pointer
; pop cx ; restore position vals
stosw ; stosw is smaller than that noise
add dl,2 ; add movement var to p_pos3
add dh,1 ; add movement var to p_pos4
dec ah ; decrement the x counter
jnz X_LOOP ; test for 0
add cl,2 ; add movement var to p_pos1
add ch,3 ; add movement var to p_pos2
pop ax ; restore the y counter
dec ah ; Next vertical line
jnz Y_LOOP ; test for 0
add [p_pos1],2 ; add some vals to the position vars
add [p_pos2],3 ; speed up/slow down the plasma
sub [p_pos3],1
add [p_pos4],4
jmp main ; do it all again
p_pos1 db 0
p_pos2 db 0
p_pos3 db 0
p_pos4 db 0
; SinTable db 64,63,63,63,63,63,63,63,63,63
; db 63,62,62,62,62,61,61,61,60,60
; db 60,59,59,59,58,58,57,57,56,56
; db 55,55,54,54,53,52,52,51,51,50
; db 49,49,48,47,47,46,45,44,44,43
; db 42,42,41,40,39,39,38,37,36,35
; db 35,34,33,32,32,31,30,29,28,28
; db 27,26,25,25,24,23,22,21,21,20
; db 19,19,18,17,16,16,15,14,14,13
; db 12,12,11,11,10,9,9,8,8,7
; db 7,6,6,5,5,4,4,4,3,3
; db 3,2,2,2,1,1,1,1,0,0
; db 0,0,0,0,0,0,0,0,0,0
; db 0,0,0,0,0,0,0,0,0,1
; db 1,1,1,2,2,2,3,3,3,4
; db 4,4,5,5,6,6,7,7,8,8
; db 9,9,10,11,11,12,12,13,14,14
; db 15,16,16,17,18,18,19,20,21,21
; db 22,23,24,24,25,26,27,28,28,29
; db 30,31,31,32,33,34,35,35,36,37
; db 38,38,39,40,41,41,42,43,44,44
; db 45,46,47,47,48,49,49,50,50,51
; db 52,52,53,54,54,55,55,56,56,57
; db 57,58,58,58,59,59,60,60,60,61
; db 61,61,62,62,62,62,63,63,63,63
; db 63,63,63,63,63,63
cseg ends
End Start