diff --git a/main.asm b/main.asm index b4e97de..90e5d55 100644 --- a/main.asm +++ b/main.asm @@ -1,5 +1,7 @@ ; ----------------------------------------------------------- ; main.asm - C64 demo: giant TTG logo + credits scroller +; effects: color wash on the logo, smooth pixel scroll, +; pulsing title - all timed by polling the raster beam ; Build: acme -f cbm -o main.prg main.asm ; ----------------------------------------------------------- @@ -22,6 +24,7 @@ BORDER = $d020 ; border color register BG = $d021 ; background color register RASTER = $d012 ; current raster line +XCTRL = $d016 ; horizontal fine scroll + 38/40 column mode SCREEN = $0400 ; screen RAM (40x25 chars) COLRAM = $d800 ; color RAM @@ -40,7 +43,13 @@ TITLE_POS = 12*40 + 13 ; "TELETYPE GAMES" (14 chars, centered) SCROLLROW = 14 ; scroller row WWW_POS = 17*40 + 9 ; "WWW.TELETYPEGAMES.ORG" (21 chars) CITY_POS = 19*40 + 14 ; "SZEGED, 2026" (12 chars) -SCROLL_SPEED = 4 ; frames per scroll step + +; ---- timing ---- +SCROLL_STEP = 2 ; pixels per frame (8 px / 4 frames = 1 char) +RAS_SCRTOP = 160 ; just above the scroller row (row 14 = lines 162-169) +RAS_SCRBOT = 171 ; just below it (rows 13 and 15 are blank, so + ; a line of jitter here is invisible) +RAS_BOTTOM = 248 ; lower border: safe time for screen updates ; ---- zero page pointers ---- scrlo = $fb @@ -49,6 +58,8 @@ collo = $fd colhi = $fe start: + sei ; no KERNAL IRQ - raster polling must not jitter + lda #BLACK sta BORDER sta BG @@ -173,47 +184,120 @@ scrollcol_loop: dex bpl scrollcol_loop - lda #SCROLL_SPEED - sta framecnt + lda #6 ; multiple of SCROLL_STEP -> clean 4-frame cycle + sta xscroll lda #0 sta scrollidx + sta framectr + sta washphase -; ---- main loop: scroll the credits line ---- +; ============================================================ +; main loop - one iteration per frame, driven by the raster +; ============================================================ main: -wait_raster: ; wait for raster line $fe (bottom of screen) + ; switch on fine scroll + 38-column mode for the scroller row only +wait_scrtop: lda RASTER - cmp #$fe - bne wait_raster -wait_raster2: ; ...and wait until it passes -> exactly one frame + cmp #RAS_SCRTOP + bne wait_scrtop + lda xscroll ; bits 0-2 = x scroll, bit 3 = 0 -> 38 columns + sta XCTRL + +wait_scrbot: lda RASTER - cmp #$fe - beq wait_raster2 + cmp #RAS_SCRBOT + bne wait_scrbot + lda #$c8 ; back to default: 40 columns, no scroll + sta XCTRL - dec framecnt - bne main - lda #SCROLL_SPEED - sta framecnt + ; beam is in the lower border: do all updates now, invisibly +wait_bottom: + lda RASTER + cmp #RAS_BOTTOM + bne wait_bottom - ; shift scroller row one char to the left + inc framectr + + ; smooth scroll: move SCROLL_STEP pixels, shift chars on wrap + lda xscroll + sec + sbc #SCROLL_STEP + bcs xs_store ; still 0..7: just store + adc #8 ; wrap (carry clear, so this adds exactly 8) + sta xscroll + jsr shift_row + jmp xs_done +xs_store: + sta xscroll +xs_done: + + lda framectr ; wash moves one column every 2nd frame + and #1 + bne wash_hold + inc washphase +wash_hold: + + jsr do_wash + jsr do_pulse + jmp main + +; ---- shift the scroller row one char left, feed in the next char ---- +shift_row: ldx #0 -shift_loop: +sr_loop: lda SCREEN+SCROLLROW*40+1,x sta SCREEN+SCROLLROW*40,x inx cpx #39 - bne shift_loop - - ; fetch next char of the scrolltext into the rightmost column + bne sr_loop ldx scrollidx lda scrolltext,x sta SCREEN+SCROLLROW*40+39 inx cpx #scrolltext_end - scrolltext - bne no_wrap + bne sr_nowrap ldx #0 -no_wrap: +sr_nowrap: stx scrollidx - jmp main + rts + +; ---- color wash: gold gradient running across the logo columns ---- +do_wash: + ldx #27 ; 28 logo columns +dw_loop: + txa + clc + adc washphase + and #15 + tay + lda washtbl,y + sta COLRAM + (BIGROW+0)*40 + BIGCOL,x + sta COLRAM + (BIGROW+1)*40 + BIGCOL,x + sta COLRAM + (BIGROW+2)*40 + BIGCOL,x + sta COLRAM + (BIGROW+3)*40 + BIGCOL,x + sta COLRAM + (BIGROW+4)*40 + BIGCOL,x + sta COLRAM + (BIGROW+5)*40 + BIGCOL,x + sta COLRAM + (BIGROW+6)*40 + BIGCOL,x + sta COLRAM + (BIGROW+7)*40 + BIGCOL,x + dex + bpl dw_loop + rts + +; ---- pulsing title: grey-white ramp, one step per 8 frames ---- +do_pulse: + lda framectr + lsr + lsr + lsr + and #7 + tay + lda pulsetbl,y + ldx #txt_title_end - txt_title - 1 +dp_loop: + sta COLRAM+TITLE_POS,x + dex + bpl dp_loop + rts ; ---- data ---- @@ -229,6 +313,13 @@ bigfont: letter_off: ; column offset of each letter (8 wide + 2 gap) !byte 0, 10, 20 +washtbl: ; gold glow ramp (16 entries, cyclic) + !byte $09, $02, $08, $0a, $07, $07, $01, $01 + !byte $01, $01, $07, $07, $0a, $08, $02, $09 + +pulsetbl: ; grey-white pulse (8 entries, cyclic) + !byte $0b, $0c, $0f, $01, $01, $0f, $0c, $0b + ; texts in screen codes (!scr); lowercase source shows as uppercase on C64 txt_title: !scr "teletype games" @@ -251,5 +342,7 @@ scrolltext_end: letter: !byte 0 rowcount: !byte 0 curbits: !byte 0 -framecnt: !byte 0 +framectr: !byte 0 +xscroll: !byte 0 +washphase: !byte 0 scrollidx: !byte 0