;
; Forty years of the Atari Bit Byter User Club
;
; Written by Norman Feske at Fujiama 2025 with
; the help of Krill, Jac!, Insane, and Dr. Irata.
;
; Public domain
;

*       = $80
        .dsection zeropage

*       = $2000
        .dsection code
        .dsection bss


.section zeropage

orig_chbase: .byte ?

; zeropage variables
src:   .word ?
dst:   .word ?
i:     .byte ?
j:     .byte ?
k:     .byte ?
l:     .byte ?
page:  .byte ?
orig_y:.byte ?
frame: .byte ?
step:  .word ?


.endsection zeropage


.section code

CHBASE  = 756   ; pointer to char map
COLPF1  = $d017 ; foreground color
RND     = $d20a
VDSLST  = 512   ; display-list interrupt vector
SDLSTL  = 560   ; display-list address lo/hi
NMIEN   = $d40e
WSYNC   = $d40a
SETVBV  = $e45c
XITVBV  = $e462

font = $6000
scr1 = $7000
scr2 = $8000

	lda CHBASE
	sta orig_chbase

	lda CHBASE
	sta src+1
	lda #>font
	sta dst+1
	jsr copy_4_pages_from_src_to_dst

	lda #>font  ; switch to copied font
	sta CHBASE

	jsr generate_gradient_font

; install VBL handler

	ldx #>vbl_handler
	ldy #<vbl_handler
	lda #$7
	jsr SETVBV

; install custom display list

	lda #<display_list
	sta SDLSTL
	lda #>display_list
	sta SDLSTL+1

	lda #<display_list_irq
	sta VDSLST
	lda #>display_list_irq
	sta VDSLST+1
	lda #$80
	ora NMIEN    ; enable DLI
	sta NMIEN

-
	jsr drive_timing_vars
	jsr randomise_font
	jsr blur
	jsr plot_moving_char
	jsr swap_screens
	jmp -


drive_timing_vars:
	lda #0
	inc frame
	lda frame
	cmp #18    ; one step is 0.36 sec at 50Hz
	bcc +
	inc step
	lda #0
	sta frame  ; reset frame

	lda step
	lsr a
	bcc +

	inc char_idx
	lda char_idx
	cmp #str_end-str_start
	bcc +
	lda #0
	sta char_idx
+
	rts


swap_screens:
	jsr select_dst_for_frame
	lda dst+1
	sta SCRBASE+1
	rts


randomise_font:
	ldx #4
	stx k
randomize_char_loop:
	jsr randomize_random_char
	dec k
	bne randomize_char_loop
	rts


vbl_handler:
	lda #5   ; gradient start offset
	sta fg_cnt
	ldy fg_cnt
	lda fg_tab,y
	sta COLPF1
	jmp XITVBV


fg_cnt: .byte 0


display_list_irq:
	pha
	php
	sty orig_y
	sta WSYNC

	inc fg_cnt
	ldy fg_cnt
	lda fg_tab,y
	sta COLPF1

	ldy orig_y
	plp
	pla
	rti


select_dst_for_frame:
	lda #0
	sta dst
	ldx #>scr1
	lda #1
	bit frame
	bne +
	ldx #>scr2
+	stx dst+1
	rts

select_src_for_frame:
	lda #0
	sta src
	ldx #>scr2
	lda #1
	bit frame
	bne +
	ldx #>scr1
+	stx src+1
	rts


plot_moving_char:
	lda #$1
	bit step
	beq +
	rts
+

	ldy char_idx
	lda str_start,y
	sta $d01f
	asl a
	asl a
	asl a
	sta src

	and #$f0
	ora #$04
	sta 710

	lda str_start,y
	lsr a
	lsr a
	lsr a
	lsr a
	lsr a
	clc
	adc orig_chbase
	sta src+1

	jsr select_dst_for_frame
	lda dst

	sec
	sbc frame

	and #31
	clc
	adc #70
	sta dst

	lda #0
	clc
	adc dst+1
	sta dst+1

	jsr plot_glyph
	rts

generate_gradient_font:

	lda #0
	sta dst
	lda #>font
	sta dst+1

	ldx #0       ; x: char index

	lda #2
	sta page
gen_page_loop:

	lda #32      ; char counter per page
	sta k

	ldy #0       ; y: dst offset

gen_char_loop:

	lda #64      ; bit counter
	sta j

-	lda #8       ; loop over 8 bits
	sta i
-
	cpx j        ; shift carry bit into a
	rol a

	dec j
	dec i        ; 8-bit loop
	bne -

	sta (dst),y
	iny

	lda j
	bne --

	inx
	dec k
	bne gen_char_loop

	inc dst+1    ; next page
	dec page
	bne gen_page_loop

	lda #$ff     ; clamp last char to full white
	sta font+63*8

	; set upper half to white
	lda #>font + $100
	sta dst+1
	jsr fill_page

	rts


fill_page:
	lda #0
	sta dst
	lda #$ff
	ldy #0
-
	sta (dst),y
	dey
	bne -
	rts


copy_4_pages_from_src_to_dst:

	lda #0     ; clear low byte
	sta src
	lda #0
	sta dst

	ldx #4
-
	ldy #0
-
	lda (src),y
	sta (dst),y
	iny
	bne -

	inc src+1  ; next page
	inc dst+1
	dex
	bne --
	rts


blur:
	jsr select_src_for_frame
	jsr select_dst_for_frame

blur_pass:
	lda #0
	;ldx #2*40 + 3
	ldx #1*40 - 5

	ldy src+1
	sta blur_read1_lo ; patch first lda
	sty blur_read1_hi
	stx blur_read2_lo ; patch second lda
	sty blur_read2_hi
	ldy dst+1
	stx blur_write_lo ; patch sta
	sty blur_write_hi

	ldy #4
blur_page_loop:

	ldx #0
-
blur_read1_lo = *+1
blur_read1_hi = *+2
	lda $ff00,x

	clc
blur_read2_lo = *+1
blur_read2_hi = *+2
	adc $ff00,x
	lsr a


blur_write_lo = *+1
blur_write_hi = *+2
	sta $ff00,x
+
	dex
	bne -

	inc blur_read1_hi
	inc blur_read2_hi
	inc blur_write_hi

	dey
	bne blur_page_loop
	rts


randomize_random_char:

	lda #0
	sta dst
	lda #>font
	sta dst+1
	sta src+1

	lda RND
	ror a        ; pick first or second page
	bcc +
	inc dst+1
	inc src+1
+
	asl a        ; pick 8-byte character
	asl a
	asl a
	sta dst
	sta src

	lda #7       ; pick two bytes of character
	and RND
	clc
	adc dst
	sta dst

	lda #7
	and RND
	clc
	adc src
	sta src

	lda #7       ; select two bits
	and RND
	tax
	lda bits_tab,x
	sta i        ; i: mask of bit for src

	lda #7
	and RND
	tax
	lda bits_tab,x
	sta j        ; j: mask of bit for dst

	ldy #0

	lda (src),y
	bit i
	bne swap_bits_src_set

	lda (dst),y
	bit j
	bne swap_bits_differ

	rts                 ; both bits clear

swap_bits_src_set:

	lda (dst),y
	bit j
	beq swap_bits_differ

	rts                 ; both bits set

swap_bits_differ:

	eor j
	sta (dst),y
	lda (src),y         ; clear bit in src
	eor i
	sta (src),y

	rts


; src: glyph (8 bytes font data)
; dst: screen with 40 bytes per line
plot_glyph:

	ldy #0

	lda #7
	sta j        ; j: y-loop count
plot_glyph_yloop:

	lda (src),y
	sta k        ; k: glyph line (8 bits)

	ldx #7       ; x: x-loop count
-
	rol k
	bcc +
	lda #32
	sta (dst),y
+
	lda #1       ; advance dst x pos
	clc
	adc dst
	sta dst
	lda #0
	adc dst+1
	sta dst+1

	dex
	bpl -

	inc src

	lda #40-8    ; advance dst line
	clc
	adc dst
	sta dst
	lda #0
	adc dst+1
	sta dst+1

	dec j
	bpl plot_glyph_yloop
	rts

display_list:
	.byte $70,$70,$70   ; upper border
	.byte $42           ; gr.0
SCRBASE .word scr1
	; trigger DLI ($82) every now and then
	.byte 2,$82,2,2,$82,2,2,$82,2,2
	.byte $82,2,2,$82,2,2,$82,2,2,$82
	.byte 2,2,2
	.byte $41           ; jmp
	.word display_list
	.byte 0

char_idx: .byte 0

bits_tab: .byte $1,$2,$4,$8,$10,$20,$40,$80

fg_tab: .byte 6,7,8,9,10,11,12,13
	.byte 13,12,11,10,9,8,7,6
	.byte 6,7,8,9,10,11,12,13

str_start:
str_abbuc:   .byte 33 ,34 ,34 ,53 ,35 ,0  ,0
str_forty:   .byte 102,111,114,116,121,0  ,0
str_years:   .byte 121,101,97 ,114,115,0  ,0
str_helmut:  .byte 40 ,101,108,109,117,116,0
str_forever: .byte 102,111,114,101,118,101,114
             .byte 0,0,0,0,0,0,0
str_end:

.endsection code

.section bss

.endsection bss
