; ;################################### ;# silky smooth sideways scrolling # ;# AS65 source # ;# public domain 13 Mar 1997 # ;# by B.W. van Schooten # ;################################### ;This program demonstrates a smooth scrolling algorithm with double buffering. ;The method can be modified to support bidirectional scrolling. However, it ;won't work for eight-directional scroll. In that case, you'll have to have ;non-smooth scrolling in one of the two axes, or employ a different method for ;that axis. (for example, you could smooth-scroll horizontally using this ;method, and smooth-scroll vertically by using the panning registers). ; ;The method ;---------- ; ;Normally, one would define a background by using the characters in the Vic's ;character matrix as tiles. However, if you want to scroll, you'll normally ;have to scroll one whole tile position at a time. This is quite a jump, and ;won't look smooth unless you scroll *very* fast. ; ;This method does allow smooth scrolling using a similar kind of tile map; ;however, the number of different tile shapes you can use in the scroll area is ;limited. The basic idea is that one uses a separate character for each ;possible transition between two neighbouring tiles in the scroll direction. ; ;For example, if we have two tiles A and B, we have to allocate four ;characters, say 0(AA), 1(AB), 2(BA), 3(BB). In general, if you want to use N ;tile definitions, you will need to allocate N^2 characters. The theoretical ;maximum is 16(16^2=256), unless you specifically disallow certain pairings ;of tile shapes, which will however make the algorithm more complicated. ; ;The screen is built up by pairing these 'transition' characters side-to-side, ;like dominoes. For example, if we scroll horizontally, ; ;A A B B ?A AA AB BB B? ;A B A B would become ?A AB BA AB B? ;B A B A ?B BA AB BA A? ; ;Note that the tile shapes at the very left and right are not defined. ;Normally, we would put the characters we are scrolling off, or are about to ;scroll onto the screen in place of the '?'s. ; ;In this program, we scroll to the left. What we do with each of these ;domino characters is ; ;1 load them first with the tile shape that corresponds to the left side of ; the domino, ; ;2 then, shift in, bit by bit, the right side tile shape. ; ;3 When we have shifted 8 bits, the left side will have been replaced by the ; right side, and we have scrolled 8 pixels. Instead of shifting the 8th bit, ; we reload the characters with the left side again, and scroll the screen one ; character to the left, so the screen looks exactly the same as when we ; would have shifted the 8th bit. In this case however, we are effectively ; back at step one and we can repeat the process. ; ; ; ;Initial load pattern ; (left side tile) ;0 1 . n ; ;| | . | ;| | . | ; ;00 10 .. n0 <- 0 } pattern to be ;01 11 .. n1 <- 1 } shifted in ;.. .. .. .. .. . } ;0n 1n .. nn <- n } (right side tile) ; ; ;How to display colours ;---------------------- ; ;There is another limitation, namely, the foreground colour must be the same ;for any two neighbouring tiles that both use this colour. If you want to use ;different foreground colours anyway, you'll have to make sure there's empty ;spaces between the tiles in question, or use multicolour mode. ; ;This program uses 8 definitions (64 transition characters), and scrolls in ;multicolour mode. It does not support multiple foreground colours. In that ;case one would have to scroll the colour screen as well, and would be limited ;to a 512-byte screen, because double buffering requires two pages in the ;colour memory, which is only 1024 bytes long. ;------------------------ CONSTANTS USED BY SCROLL ------------------------ ;screen1/2 must be multiple of 512. screen1 equ 7680;1e00 chars1 equ 7168;1c00 colourscr1 equ $9400+(screen1&512) screen2 equ 6656;1a00 chars2 equ 6144;1800 colourscr2 equ $9400+(screen2&512) scr1_9005 equ $f0 scr2_9005 equ $e0 chr1_9005 equ $0f chr2_9005 equ $0e ;----------------------- VARIABLES USED BY SCROLL ------------------------- scrollorvalue equ $ff ;temp variable ;913 newtiles equ $0342 ;shapes about to be scrolled in oldtiles equ $0342+23 ;shapes scrolled in last time jmpadr equ $03bd ;2-byte temp variable scrollphase equ $03bf ;phase 0..3 4..7 (see also scroll) shiftinpat equ $03c0 ;tile shapes to be shifted in ;----------------------------- MISC VARIABLES ----------------------------- quickrndseed equ $0340;2b ;---------------------------------- MAIN ---------------------------------- org 4095 db lo 4097,hi 4097 db 11,17,205,7,158,'4109',0,0,0 ;BASIC program entrypoint: sei ;Prevent glitches jsr quickrandomize lda #-1 sta scrollphase ;Define colours and fill screen lda #$78 ;Bord:BLK Back: YEL sta $900f lda #$a0 ;Auxi:LT RED sta $900e ldx #0 fillcolour: lda #$0a ;Fore: RED sta colourscr1,x sta colourscr1+256,x sta colourscr2,x sta colourscr2+256,x lda #0 sta screen1,x sta screen1+256,x lda #0 sta screen2,x sta screen2+256,x inx bne fillcolour ;Initialise the left side of the first domino characters ldx #19 initoldtiles: lda #0 sta oldtiles,x dex bpl initoldtiles mainloop: ;Define some random tile shapes to be scrolled in at the right ldx #3 chgrndtiles: jsr quickrnd and #15 tay jsr quickrnd and #7 sta newtiles,y jsr quickrnd and #15 clc adc #4 tay jsr quickrnd and #7 sta newtiles,y dex bpl chgrndtiles lda #0 jsr waitsync ;wait for top of screen jsr scroll jmp mainloop ;------------------------------ SCROLL ------------------------------------- ;This macro reloads the domino characters with their corresponding left ;parts. The loop is unrolled for extra speed. ;I: chardefs. ;u: P A X Y ;O: shiftinpat, chrdst scroll_reload macro chrdst ldx #0 ldy #0 scroll_load\? lda chardefs,x sta shiftinpat,x sta chrdst,y sta chrdst+8,y sta chrdst+16,y sta chrdst+24,y sta chrdst+32,y sta chrdst+40,y sta chrdst+48,y sta chrdst+56,y lda chardefs+4*8,x sta shiftinpat+4*8,x sta chrdst+256,y sta chrdst+264,y sta chrdst+272,y sta chrdst+280,y sta chrdst+288,y sta chrdst+296,y sta chrdst+304,y sta chrdst+312,y inx iny tya and #7 bne scroll_load\? tya clc adc #64-8 tay bne scroll_load\? endm ;This macro scrolls the screen one tile to the left and draws the domino ;characters that are supposed to scroll in at the right. ;I: scrsrc, oldtiles, newtiles ;u: P A X Y ;O: scrdst, oldtiles scroll_scrtile macro scrsrc,scrdst ldx #0 txa scroll_scr1b\? pha ldy #21 scroll_scr1a\? lda scrsrc+1,x sta scrdst,x lda scrsrc+1*22+1,x sta scrdst+1*22,x lda scrsrc+10*22+1,x sta scrdst+10*22,x lda scrsrc+11*22+1,x sta scrdst+11*22,x inx dey bne scroll_scr1a\? pla tay pha lda oldtiles,y asl a asl a asl a ora newtiles,y sta scrdst,x lda oldtiles+1,y asl a asl a asl a ora newtiles+1,y sta scrdst+1*22,x lda oldtiles+10,y asl a asl a asl a ora newtiles+10,y sta scrdst+10*22,x lda oldtiles+11,y asl a asl a asl a ora newtiles+11,y sta scrdst+11*22,x txa clc adc #2*22-21 tax pla clc adc #2 cmp #10 bne scroll_scr1b\? ldx #21 scroll_copytiles_lp\? lda newtiles,x sta oldtiles,x dex bpl scroll_copytiles_lp\? endm ;This macro shifts two bits (one multicolour pixel) to the left. The loop ;is unrolled for extra speed. ;I: chrsrc, shiftinpat ;u: P A X Y, scrollorvalue ;O: chrdst, shiftinpat scroll_shift macro chrsrc,chrdst ldx #63 scroll_shloop\? lda #0 asl shiftinpat,x rol a asl shiftinpat,x rol a sta scrollorvalue lda chrsrc+8*00,x asl a asl a ora scrollorvalue sta chrdst+8*00,x lda chrsrc+8*08,x asl a asl a ora scrollorvalue sta chrdst+8*08,x lda chrsrc+8*16,x asl a asl a ora scrollorvalue sta chrdst+8*16,x lda chrsrc+8*24,x asl a asl a ora scrollorvalue sta chrdst+8*24,x lda chrsrc+8*32,x asl a asl a ora scrollorvalue sta chrdst+8*32,x lda chrsrc+8*40,x asl a asl a ora scrollorvalue sta chrdst+8*40,x lda chrsrc+8*48,x asl a asl a ora scrollorvalue sta chrdst+8*48,x lda chrsrc+8*56,x asl a asl a ora scrollorvalue sta chrdst+8*56,x dex bpl scroll_shloop\? endm ;Scroll phases (In each phase, 2 pixels are scrolled) ;Ph Action Display ;-- ----------------------- --------- ;0: chr1->chr2 scr1/chr1 ;1: chr2->chr1 scr1/chr2 ;2: chr1->chr2 scr1/chr1 (same as 0) ;3: reload chr1; scr1->scr2 scr1/chr2 ;4: chr1->chr2 scr2/chr1 ;5: chr2->chr1 scr2/chr2 ;6: chr1->chr2 scr2/chr1 (same as 4) ;7: reload chr1; scr2->scr1 scr2/chr2 ;I:scrollphase ;u: P A X Y, jmpadr ;O:scrollphase, whatnot... scroll: ldx scrollphase inx txa and #7 sta scrollphase tax lda scrphase_hi_tbl,x sta jmpadr+1 lda scrphase_lo_tbl,x sta jmpadr jmp (jmpadr) scrphase_hi_tbl db hi scroll_0, hi scroll_1, hi scroll_0, hi scroll_3 db hi scroll_4, hi scroll_5, hi scroll_4, hi scroll_7 scrphase_lo_tbl db lo scroll_0, lo scroll_1, lo scroll_0, lo scroll_3 db lo scroll_4, lo scroll_5, lo scroll_4, lo scroll_7 scroll_0: lda #scr1_9005+chr1_9005 sta $9005 jmp scroll_sh1to2 scroll_1: lda #scr1_9005+chr2_9005 sta $9005 jmp scroll_sh2to1 scroll_3: lda #scr1_9005+chr2_9005 sta $9005 scroll_scrtile screen1,screen2 jmp scroll_reload1 scroll_4: lda #scr2_9005+chr1_9005 sta $9005 jmp scroll_sh1to2 scroll_5: lda #scr2_9005+chr2_9005 sta $9005 jmp scroll_sh2to1 scroll_7: lda #scr2_9005+chr2_9005 sta $9005 scroll_scrtile screen2,screen1 ; jmp scroll_reload1 scroll_reload1: scroll_reload chars1 rts scroll_sh1to2: scroll_shift chars1,chars2 rts scroll_sh2to1: scroll_shift chars2,chars1 rts ;----------------------------- MISCELLANEOUS ------------------------------- ;I:A=scan # ;u:P waitsync: waitsync_1: cmp $9004 beq waitsync_1 waitsync_2: cmp $9004 bne waitsync_2 rts ;u:P A ;O:quickrndseed quickrandomize: lda $9116 ora #1 ;Make sure seed is always != 0 sta quickrndseed lda $9117 sta quickrndseed+1 rts ;u:P quickrndseed ;O:A=RND number quickrnd: lda quickrndseed+1 asl quickrndseed rol quickrndseed+1 adc #0 and #1 ;XOR with bit that was shifted out ora quickrndseed sta quickrndseed rts ;1=BLK 2=RED 3=BROWN 0=LT PUR chardefs: db 4#1111 db 4#1111 db 4#1111 db 4#1111 db 4#1111 db 4#1111 db 4#1111 db 4#1111 db 4#1111 db 4#1211 db 4#1311 db 4#3031 db 4#1311 db 4#1211 db 4#1111 db 4#1111 db 4#1111 db 4#2222 db 4#3333 db 4#0000 db 4#0000 db 4#3333 db 4#2222 db 4#1111 db 4#1221 db 4#1331 db 4#2002 db 4#2002 db 4#2002 db 4#2002 db 4#1331 db 4#1221 db 4#3003 db 4#0330 db 4#0220 db 4#0110 db 4#0110 db 4#0220 db 4#0330 db 4#3003 db 4#3232 db 4#2323 db 4#3232 db 4#2323 db 4#3232 db 4#2323 db 4#3232 db 4#2323 db 4#1221 db 4#2332 db 4#3333 db 4#3003 db 4#3003 db 4#3333 db 4#2332 db 4#1221 db 4#2222 db 4#2222 db 4#3113 db 4#0220 db 4#0220 db 4#3113 db 4#2222 db 4#2222