;------------------------------------------------
;'my beloved berlin' by Kuemmel for Deadline 2019
;------------------------------------------------
colour_tower = 43
org 100h
use16

;---screen init
sub al,-(0x13+0x80)		;no screen clearing but doesn't matter and provides address (by Hellmood)
mov fs,word[si] 		;backbuffer 1 (results in 0x6d2c which is okay as an address)
int 10h

;---sound init
xor bp,bp				;init bp, as bp is the top timer
mov dx,irq				;new handler address
mov al,110				;PIT counter divisor => 108 equals 11050 Hz
out 40h,al
salc					;=> al=0; carry flag clear due to xor bp,bp
out 40h,al
mov ax,2508h
int 21h

;---screen address init
push 0a000h
pop es
push 09000h				;backbuffer 2
pop gs

;---main intro loop
main:
mov cl,byte[si]			;ray movement
mov ch,cl				;ray colour adjust
and ch,16
shr ch,4
;---screen loop
screen_loop:
	mov ax,0xcccd
	mul	di					; => dl=x, dh=y, ah = fragment of x
	;---rays
	push dx
	mov ax,dx
	xor dh,dh
	add ax,51*256			;offset, needs to be <52*256 or crashes
	div ax					;(x*256)/(y+offset) al=quot/ah=rem
	add al,cl				;add ray movement
	and al,64+32		
	shr al,2
    add al,ch				;add ray colour adjust
	pop dx
	xchg ax,bx				;init colour from rays
	;---place x for tower position and center by abs
	sub dl,198
	jns skip_abs
		neg dl					
	skip_abs:
	;---tower and upper rectangle
	push dx
	cmp dh,80
	ja skip_clamp_y
	   cmp dh,55
	   jb skip_clamp_y
		   mov dh,120		;clamp y for rectangle
	skip_clamp_y:
	mov ax,dx
	xor dh,dh
	inc ax					;prevent div by zero
	div ax
	pop dx 
	cmp ax,16
	ja skip_colour_tower
	   mov bl,colour_tower	;draw tower...or not
	skip_colour_tower:
	;---circle
	mov al,dl				;al=x
	mul al					;x*x
	xchg ax,dx				;backup x*x
	mov al,ah				;al=y
	sub al,100				;center y
	imul al					;y*y
	add ax,dx				;r*r=(x-...)*(x-...)+(y-...)*(y-...)
	cmp ax,800				;(r*r) > ... ?
	ja skip_colour_circle
	   mov bl,colour_tower	;draw circle...or not
	skip_colour_circle:
	;---plot
	mov byte[fs:di],bl
	mov byte[gs:di],bl
	inc di
jnz screen_loop

;---copy screen to half size, adjust colour and wobble to the sound
mov cx,99
y_loop:
   mov bl,157
   x_loop:
	  imul di,cx,640					;lazy coding...but overall shorter
      add di,bx
	  mov al,byte[irq.sample-1]			;make it wobble depending on current sample
      shr ax,5
      add di,ax
	  mov al,byte[gs:di+bx] 			;(x*2)+(y*2)*320
	  imul di,cx,320					;lazy coding ;-) push/shift/pop will also work
	  shr al,1							;colour adjust
	  mov byte[fs:di+bx+15+87*320],al	;(x+y*320)
	  dec bx
   jnz x_loop
loop y_loop

;---vsync for timing & flicker reduce
mov dx,03dah
vsync:
  in al,dx
  test al,8
jz vsync

;---copy buffer to screen
;needs di=0,cx=0 / di,cx zero here from previous loops/calc
copy_buffer_loop:
	mov al,byte[fs:di]
	stosb
loop copy_buffer_loop

;---key check and exit			
in al,60h
dec ax		;ah seems zero most of the time...
jnz main	;shortcut would remove 2 bytes here, but then ch,cl sound stuff has to move after screen loop
ret

;---bytebeat interrupt subroutine
irq:
pusha
mov dx,0378h				;LPT1 parallel port address
mov al,0					;al=sample => self modifying code, play after calc => better sound quality
.sample:
out dx,al
mov ax,0					;ax: timer => self modifying code, inc'ed after each irq call
.counter:
;---Math.sqrt(t&(4095-(t>>13)))<<7 and Math.sqrt(~t&(4095-(t>>13)))<<7
;---top timer of 0....7 defines the sequence 0...3 => reverse 4...7 => non reverse
mov bx,ax
cmp bp,3
ja skip_reverse_bass_drum
   not bx
skip_reverse_bass_drum:
shrd ax,bp,13
and al,11111b				;mask in only Bit 0 and 1 of bp, ah is zero due to shift
neg ax
add ax,4095
and ax,bx
mov word[si],ax
fild word[si]
fsqrt
fistp word[si]
mov al,byte[si]				;also serves as sound visualisation
shl al,7
;---
inc word[irq.counter-2]		;inc timer each interrupt call within code
mov byte[irq.sample-1],al	;store sample for playback next interrupt
mov al,20h
out 20h,al					;end of irq
popa
jnz skip_inc_top_timer
	inc bp
	and bp,111b				;limit range
skip_inc_top_timer: 
iret
