; Lo-res cycle-counting water transparency hack ; by deater (Vince Weaver) ; Zero Page FRAMEBUFFER = $00 ; $00 - $0F YPOS = $10 YPOS_SIN = $11 CH = $24 CV = $25 GBASL = $26 GBASH = $27 BASL = $28 BASH = $29 MASK = $2E COLOR = $30 FRAME = $60 MB_VALUE = $91 BIRD_STATE = $E0 BIRD_DIR = $E1 DRAW_PAGE = $EE LASTKEY = $F1 PADDLE_STATUS = $F2 XPOS = $F3 TEMP = $FA TEMPY = $FB INL = $FC INH = $FD OUTL = $FE OUTH = $FF ; Soft Switches KEYPRESS= $C000 KEYRESET= $C010 SET_GR = $C050 ; Enable graphics FULLGR = $C052 ; Full screen, no text PAGE0 = $C054 ; Page0 PAGE1 = $C055 ; Page1 LORES = $C056 ; Enable LORES graphics PADDLE_BUTTON0 = $C061 PADDL0 = $C064 PTRIG = $C070 ; ROM routines TEXT = $FB36 ;; Set text mode HOME = $FC58 ;; Clear the text screen WAIT = $FCA8 ;; delay 1/2(26+27A+5A^2) us ; location we don't care about DUMMY = $300 waterfall_demo: ;=================== ; init screen jsr TEXT jsr HOME bit PAGE0 ;=================== ; init vars lda #0 sta BIRD_DIR sta BIRD_STATE sta FRAME lda #4 sta DRAW_PAGE sta XPOS ;=================== ; Mockingboard jsr mockingboard_init ; Enable channel A tone+noise ldx #7 ; 2 lda #$36 ; 2 sta MB_VALUE ; 3 jsr write_ay_both ; 6+65 ;============================= ; Load foreground to graphic page1 (apple page2) lda #$0c sta BASH lda #$00 sta BASL ; load image to $c00 lda #waterfall_page1 sta GBASH jsr load_rle_gr jsr gr_copy_to_current ; copy to page1 ;============================= ; Load bg to memory lda #$0c sta BASH lda #$00 sta BASL ; load image to $c00 lda #waterfall_page2 sta GBASH jsr load_rle_gr ;============================== ; setup graphics for vapor lock ;============================== ; Clear Page0 to all green lda #$0 sta DRAW_PAGE lda #$44 jsr clear_gr ; Make top half of screen blue, down to line 26 lda #$11 ldy #24 jsr clear_page_loop ;===================================================== ; attempt vapor lock ; by reading the "floating bus" we can see most recently ; written value of the display ; we look for $55 (which is the grey line) ;===================================================== ; See: ; Have an Apple Split by Bob Bishop ; Softalk, October 1982 ; Challenges: each scan line scans 40 bytes. ; The blanking happens at the *beginning* ; So 65 bytes are scanned, starting at adress of the line - 25 ; the scan takes 8 cycles, look for 4 repeats of the value ; to avoid false positive found if the horiz blanking is mirroring ; the line (max 3 repeats in that case) vapor_lock_loop: ; first make sure we have all blue lda #$11 ; 2 zxloop: ldx #$04 ; 2 wiloop: cmp $C051 ; 4 bne zxloop ; 2/3 dex ; 2 bne wiloop ; 2/3 lda #$44 ; now look for our color (4 times) ; 2 zloop: ldx #$04 ; 2 ; what cycle does CMP happen at? ; while matching match = 4+2+2+3 = 11??? ; if start at x=0, 0, 11, 22, 33 exit at 43 ; if start at x=1, 1, 12, 23, 34 exit at 44 ; if start at x=2, 2, 13, 24, 35 exit at 45 ; if start at x=3, 3, 14, 25, 36 exit at 46 ; if start at x=4, 4, 15, 26, 37 exit at 47 ; if start at x=5, 5, 16, 27, 38 exit at 48 ; if start at x=6, 6, 17, 28, 39 exit at 49 ; if start at x=7, 7, 18, 29, *40 exit at ** ; if start at x=8, 8, 19, 30, *41 exit at ** ; if not match, 2+4+3 = 9, first match = 8 qloop: cmp $C051 ; 4 bne zloop ; 2/3 dex ; 2 bne qloop ; 2/3 ; found first line of black after green, at up to line 26 on screen ; so we want roughly 22 lines * 4 = 88*65 = 5720 + 4550 = 10270 ; - 65 (for the scanline we missed) = 10205 - 12 = 10193 jsr gr_copy_to_current ; 6+ 9292 ; 10193 - 9298 = 895 ; Fudge factor (unknown) -30 = 865 ; GR part bit LORES ; 4 bit SET_GR ; 4 bit FULLGR ; 4 ; Try X=88 Y=2 cycles=893 R2 nop ; 2 ldy #2 ; 2 loopA: ldx #88 ; 2 loopB: dex ; 2 bne loopB ; 2nt/3 dey ; 2 bne loopA ; 2nt/3 jmp display_loop .align $100 ;================================================ ; Display Loop ;================================================ ; each scan line 65 cycles ; 1 cycle each byte (40cycles) + 25 for horizontal ; Total of 12480 cycles to draw screen ; Vertical blank = 4550 cycles (70 scan lines) ; Total of 17030 cycles to get back to where was ; if even, 10 + 9 + display_even + 2 (balance) = 21+display_even ; if odd 10 + 8 + display_odd + 3 (balance) = 21+display_odd ; we have 3 (the jmp) + 6 (the rts) - 1 (fallthrough) ; = 8 cycles that need to be eaten by the vblank display_loop: inc FRAME ; 5 lda FRAME ; 3 and #$10 ; 2 beq even ; 2 lda FRAME ; (nop) ; 3 jsr display_odd ; 6 jmp vblank ; 3 even: ; 3 nop ; (nop) ; 2 jsr display_even ; 6 jmp vblank ; 3 vblank: ;====================================================== ; We have 4550 cycles in the vblank, use them wisely ;====================================================== ; do_nothing should be 4550 ; -9 letfover from HBLANK code ; -49 check for keypress ; -2252 copy screen ; -2231 draw sprite ; ============= ; 9 cycles ; jsr do_nothing ; 6 ; 17 cycles inc YPOS ; 5 nop nop ; inc YPOS ; 5 ; inc YPOS ; 5 ; nop ; 2 ; nop ; 2 ;========================= ; Clear background ;========================= jsr gr_copy_row22 ; 6+ 2246 ;========= ; 2252 ;========================== ; draw bird sprite ;========================== ; 8 prefix ; bird_walk_right= 14 + 2175 2206 (need 17) ; bird_stand_right= 13 + 2190 2206 (need 3) ; bird_walk_left= 15 + 2175 2206 (need 16) ; bird_stand_left= 14 + 2190 2206 (need 2) ; call to sprite 17 postfix ;==================================================== ; 2231 lda BIRD_STATE ; 3 and #1 ; 2 ldx BIRD_DIR ; 3 bne bird_left bird_right: ; 2 cmp #1 ; 2 beq bird_walk_right ; 2 bird_stand_right: ldx #>bird_rider_stand_right ; 2 ldy #bird_rider_walk_right ; 2 ldy #bird_rider_stand_left ; 2 ldy #bird_rider_walk_left ; 2 ldy #