;license:MIT ;(c) 2020 by 4am & qkumba ; ; The screen is separated into 48 boxes. ; Boxes are laid out in a grid, left-to-right, top-down: ; ; 0 1 2 3 4 5 6 7 ; 8 9 10 11 12 13 14 15 ; 16 17 18 19 20 21 22 23 ; 24 25 26 27 28 29 30 31 ; 32 33 34 35 36 37 38 39 ; 40 41 42 43 44 45 46 47 ; ; Each box is 70x32 pixels, so each row of each box is 5 consecutive ; bytes in main memory and another 5 in auxiliary memory, all of which ; are easy to find once you calculate the base address for that row. ; ; |BoxInitialStages| defines the initial grid of stages for each box. ; Each stage is used an index into the |StagesHi| array ; to find the drawing routine for that stage (if any). ; Each box's stage is incremented after each iteration through the main loop. ; When the main loop iterates through all 48 boxes without drawing anything, ; the program exits. ; ; There are 16 clear routines that set certain bits to 0 (black), ; labeled clear00..clear0F. clear00 clears the inner-most box, and ; clear0F clears the outermost box (see diagram). ; There are 16 copy routines that copy certain bits from the source ; image on page 2 to the destination image on page 1, labeled copy00..copy0F. ; ; row| pixels ; ---+--------------------------------------- ; 00 |FFFFFFF|FFFFFFF|FFFFFFF|FFFFFFF|FFFFFFF ; 01 |FEEEEEE|EEEEEEE|EEEEEEE|EEEEEEE|EEEEEEF ; 02 |FEDDDDD|DDDDDDD|DDDDDDD|DDDDDDD|DDDDDEF ; 03 |FEDCCCC|CCCCCCC|CCCCCCC|CCCCCCC|CCCCDEF ; 04 |FEDCBBB|BBBBBBB|BBBBBBB|BBBBBBB|BBBCDEF ; 05 |FEDCBAA|AAAAAAA|AAAAAAA|AAAAAAA|AABCDEF ; 06 |FEDCBA9|9999999|9999999|9999999|9ABCDEF ; 07 |FEDCBA9|8888888|8888888|8888888|9ABCDEF ; ---+-------+-------+-------+-------+------- ; 08 |FEDCBA9|8777777|7777777|7777778|9ABCDEF ; 09 |FEDCBA9|8766666|6666666|6666678|9ABCDEF ; 0A |FEDCBA9|8765555|5555555|5555678|9ABCDEF ; 0B |FEDCBA9|8765444|4444444|4445678|9ABCDEF ; 0C |FEDCBA9|8765433|3333333|3345678|9ABCDEF ; 0D |FEDCBA9|8765432|2222222|2345678|9ABCDEF ; 0E |FEDCBA9|8765432|1111111|2345678|9ABCDEF ; 0F |FEDCBA9|8765432|1000001|2345678|9ABCDEF ; ---+-------+-------+-------+-------+------- ; 10 |FEDCBA9|8765432|1000001|2345678|9ABCDEF ; 11 |FEDCBA9|8765432|1111111|2345678|9ABCDEF ; 12 |FEDCBA9|8765432|2222222|2345678|9ABCDEF ; 13 |FEDCBA9|8765433|3333333|3345678|9ABCDEF ; 14 |FEDCBA9|8765444|4444444|4445678|9ABCDEF ; 15 |FEDCBA9|8765555|5555555|5555678|9ABCDEF ; 16 |FEDCBA9|8766666|6666666|6666678|9ABCDEF ; 17 |FEDCBA9|8777777|7777777|7777778|9ABCDEF ; ---+-------+-------+-------+-------+------- ; 18 |FEDCBA9|8888888|8888888|8888888|9ABCDEF ; 19 |FEDCBA9|9999999|9999999|9999999|9ABCDEF ; 1A |FEDCBAA|AAAAAAA|AAAAAAA|AAAAAAA|AABCDEF ; 1B |FEDCBBB|BBBBBBB|BBBBBBB|BBBBBBB|BBBCDEF ; 1C |FEDCCCC|CCCCCCC|CCCCCCC|CCCCCCC|CCCCDEF ; 1D |FEDDDDD|DDDDDDD|DDDDDDD|DDDDDDD|DDDDDEF ; 1E |FEEEEEE|EEEEEEE|EEEEEEE|EEEEEEE|EEEEEEF ; 1F |FFFFFFF|FFFFFFF|FFFFFFF|FFFFFFF|FFFFFFF ; !ifndef USES_CLEAR { ; if an effect doesn't use any clear stages, you can reduce code size ; by setting USES_CLEAR=0 before including this file USES_CLEAR = 1 } src = $00 ; [word][must be at $00] used by drawing routines dst = $02 ; [word] used by drawing routines rowcount = $04 ; [byte] used by drawing routines tmpy = $05 ; [byte] used by drawing routines box = $0E ; [byte] counter in main loop any = $0F ; [byte][must be at $0F] counter in main loop BoxStages = $10 ; [$30 bytes] current stage for each box auxsrc_hgrhi = $BC00 ; [$C0 bytes] HGR base addresses (hi) starting at $9000 hgrhi = $BD00 ; [$C0 bytes] HGR base addresses (hi) starting at $2000 hgrlo = $BE00 ; [$C0 bytes] HGR base addresses (lo) starting at $2000 BoxesX = $BDC0 ; [$30 bytes] starting row for each box BoxesY = $BEC0 ; [$30 bytes] starting byte offset for each box ; High bytes of drawing routines for each stage (actual routines will be page-aligned). ; To minimize code size, we build drawing routines in this order: ; - copy01 (STAGE1 template) ; - copy00 (STAGE0 template) ; - copy0F..copy09 (OUTER_STAGE template) ; - copy08..copy02 (MIDDLE_STAGE template) ; - change some opcodes to turn the 'copy' routines into 'clear' routines ; - clear0F..clear08 (OUTER_STAGE) ; - clear07..clear02 (MIDDLE_STAGE) ; - clear01 (STAGE1) ; - clear00 (STAGE0) clear00 = $70 clear01 = $71 clear02 = $72 clear03 = $73 clear04 = $74 clear05 = $75 clear06 = $76 clear07 = $77 clear08 = $78 clear09 = $79 clear0A = $7A clear0B = $7B clear0C = $7C clear0D = $7D clear0E = $7E clear0F = $7F copy02 = $80 copy03 = $81 copy04 = $82 copy05 = $83 copy06 = $84 copy07 = $85 copy08 = $86 copy09 = $87 copy0A = $88 copy0B = $89 copy0C = $8A copy0D = $8B copy0E = $8C copy0F = $8D copy00 = $8E copy01 = $8F ; tokens for code generation ; used as indexes into |codegen_pieces| and |codegen_piece_lengths|, ; so keep all three in sync k_rts = 0 ; must be 0 k_edge_left_mask_main = 1 ; must be 1 k_edge_right_mask_main = 2 ; must be 2 k_left_mask_main = 3 ; must be 3 k_right_mask_main = 4 ; must be 4 k_edge_left_mask_aux = 5 ; must be 5 k_edge_right_mask_aux = 6 ; must be 6 k_left_mask_aux = 7 ; must be 7 k_right_mask_aux = 8 ; must be 8 k_current_page = 9 k_switch_to_main = 10 k_switch_to_aux = 11 k_switch_to_aux_and_byte_copy = 12 k_inx_and_recalc = 13 k_recalc = 14 k_set_row_count = 15 k_set_first_row = 16 k_iny2 = 17 k_iny = 18 k_dey = 19 k_save_y = 20 k_restore_y = 21 k_middle_jsr = 22 k_outer_jsr = 23 k_middle_branch = 24 k_outer_branch = 25 k_mask_copy_pre = 26 k_mask_copy_post = 27 k_byte_copy = 28 k_byte_copy_and_iny = 29 k_bitcopy = 30 ; must be last token !source "src/fx/macros.a" ; generate |BoxesX| and |BoxesY| arrays ldx #48 ldy #$A0 lda #$23 pha - tya sta BoxesX-1, x pla sta BoxesY-1, x sec sbc #5 bcs + lda #$23 + pha dex txa and #7 bne - tya sec sbc #$20 tay txa bne - pla ; construct drawing routines for each stage jsr BuildDrawingRoutines ; A=0 here ; set up zero page for drawing phase tax - ldy BoxInitialStages-BoxStages, x sty $00, x sta EndStagesHi, x inx bne - ; X=0 here +BUILD_HGR_LOOKUP_TABLES_X_IS_ALREADY_0 hgrlo, hgrhi ; X=$C0 here - lda hgrhi-1, x clc adc #$70 sta auxsrc_hgrhi-1, x dex bne - sta $C001 ; 80STORE mode so we can bank $2000/aux in & out with STA $C055 & $C054 MainLoop ldx #48 BoxLoop stx box ldy BoxStages-1, x ; for each box, get its current stage inc BoxStages-1, x ; increment every box's stage every time through the loop lda StagesHi, y beq NextBox ; if stage's drawing routine is 0, nothing to do sta j+2 lda BoxesX-1, x ldy BoxesY-1, x ; Y = starting byte offset for this box tax ; X = starting HGR row for this box inc any ; was initialized by the BoxStages copy loop clc j jsr $FD00 ; [SMC] call drawing routine for this stage ldx box NextBox dex bne BoxLoop lda any beq + ; if we didn't draw anything in any box, we're done stx any ; X=0 here bit $C000 ; check for key bpl MainLoop + sta $C000 ; 80STORE off ; execution falls through here ; These are all the pieces of code we need to construct the drawing routines. ; There are 32 drawing routines (16 if USES_CLEAR=0), which we construct from ; four templates (below). Templates use tokens to refer to these code pieces. ; Note that several pieces overlap in order to minimize code size. ; Everything from CODEGEN_COPY_START and onward is copied to zero page for ; the code generation phase on program startup. EDGE_LEFT_MASK_MAIN = $01 ; address $01 to match token EDGE_RIGHT_MASK_MAIN = $02 ; address $02 to match token LEFT_MASK_MAIN = $03 ; address $03 to match token RIGHT_MASK_MAIN = $04 ; address $04 to match token EDGE_LEFT_MASK_AUX = $05 ; address $05 to match token EDGE_RIGHT_MASK_AUX = $06 ; address $06 to match token LEFT_MASK_AUX = $07 ; address $07 to match token RIGHT_MASK_AUX = $08 ; address $08 to match token CODEGEN_COPY_START !pseudopc 9 { RTS0 SWITCH_TO_MAIN sta $C054 SWITCH_TO_MAIN_E rts ; also terminates MainLoop RTS0_E ; SWITCH_TO_AUX_AND_BYTE_COPY SWITCH_TO_AUX sta $C055 lda auxsrc_hgrhi, x sta src+1 SWITCH_TO_AUX_E BYTECOPY_AND_INY BYTECOPY lda (src), y sta (dst), y BYTECOPY_E SWITCH_TO_AUX_AND_BYTE_COPY_E INY2 INY1 iny INY1_E BYTECOPY_AND_INY_E iny INY2_E ; DEY1 dey DEY1_E ; SAVE_Y sty tmpy SAVE_Y_E ; RESTORE_Y ldy tmpy RESTORE_Y_E ; INX_AND_RECALC inx RECALC lda hgrlo, x sta src sta dst lda hgrhi, x sta dst+1 eor #$60 sta src+1 RECALC_E INX_AND_RECALC_E ; SET_ROW_COUNT ROW_COUNT=*+1 lda #$1D ; SMC sta rowcount SET_ROW_COUNT_E ; SET_FIRST_ROW txa FIRST_ROW=*+1 adc #$0E ; SMC tax SET_FIRST_ROW_E ; MASKCOPY_PRE lda (dst), y BIT_FOR_CLEAR eor (src), y !byte $29 ; (AND #$44 opcode) MASKCOPY_PRE_E ; codegen_pieces ; address of each of the pieces (on zero page, so 1 byte) !byte do special bitcopy logic during codegen BuildDrawingRoutineFrom sta nothing to generate bmi + ; copymask>=$80 -> assume full byte lda #k_mask_copy_pre jsr ProcessToken lda #1 sta =$80 sta * != >STAGE0 { !error "Templates are not all on same page" } ; Note: the final k_rts is later copied to zero page $0F and used in MainLoop, ; so don't put any more code before BoxInitialStages. BoxInitialStages