From 794bc1fc09259f08764f552a700d74bbf146b752 Mon Sep 17 00:00:00 2001 From: Lucas Scharenbroich Date: Sat, 30 Jul 2022 11:04:13 -0500 Subject: [PATCH] Start adding scanline variants --- src/SpriteV1.s | 226 ----------------------------------------- src/blitter/Scanline.s | 172 +++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 226 deletions(-) delete mode 100644 src/SpriteV1.s create mode 100644 src/blitter/Scanline.s diff --git a/src/SpriteV1.s b/src/SpriteV1.s deleted file mode 100644 index 6d24dbb..0000000 --- a/src/SpriteV1.s +++ /dev/null @@ -1,226 +0,0 @@ -; Old code the was in Version 1, but is not needed. May be adapted for Verions 2. - -; Y = _Sprites array offset -_EraseSpriteY - lda _Sprites+OLD_VBUFF_ADDR,y - beq :noerase - ldx _Sprites+SPRITE_DISP,y ; get the dispatch index for this sprite (32 values) - jmp (:do_erase,x) -:noerase rts -:do_erase dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8 - dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16 - dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8 - dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16 - dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8 - dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16 - dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8 - dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16 - -; A = bank address -_EraseTileSprite8x8 - tax - phb ; Save the bank to switch to the sprite plane - - pei SpriteBanks - plb ; pop the data bank (low byte) - -]line equ 0 - lup 8 - stz: {]line*SPRITE_PLANE_SPAN}+0,x - stz: {]line*SPRITE_PLANE_SPAN}+2,x -]line equ ]line+1 - --^ - - plb ; pop the mask bank (high byte) - lda #$FFFF -]line equ 0 - lup 8 - sta: {]line*SPRITE_PLANE_SPAN}+0,x - sta: {]line*SPRITE_PLANE_SPAN}+2,x -]line equ ]line+1 - --^ - - plb - rts - -_EraseTileSprite8x16 - tax - phb ; Save the bank to switch to the sprite plane - - pei SpriteBanks - plb ; pop the data bank (low byte) - -]line equ 0 - lup 16 - stz: {]line*SPRITE_PLANE_SPAN}+0,x - stz: {]line*SPRITE_PLANE_SPAN}+2,x -]line equ ]line+1 - --^ - - plb ; pop the mask bank (high byte) - lda #$FFFF -]line equ 0 - lup 16 - sta: {]line*SPRITE_PLANE_SPAN}+0,x - sta: {]line*SPRITE_PLANE_SPAN}+2,x -]line equ ]line+1 - --^ - - plb - rts - -_EraseTileSprite16x8 - tax - phb ; Save the bank to switch to the sprite plane - - pei SpriteBanks - plb ; pop the data bank (low byte) - -]line equ 0 - lup 8 - stz: {]line*SPRITE_PLANE_SPAN}+0,x - stz: {]line*SPRITE_PLANE_SPAN}+2,x - stz: {]line*SPRITE_PLANE_SPAN}+4,x - stz: {]line*SPRITE_PLANE_SPAN}+6,x -]line equ ]line+1 - --^ - - plb ; pop the mask bank (high byte) - lda #$FFFF -]line equ 0 - lup 8 - sta: {]line*SPRITE_PLANE_SPAN}+0,x - sta: {]line*SPRITE_PLANE_SPAN}+2,x - sta: {]line*SPRITE_PLANE_SPAN}+4,x - sta: {]line*SPRITE_PLANE_SPAN}+6,x -]line equ ]line+1 - --^ - - plb - rts - -_EraseTileSprite16x16 - tax - phb ; Save the bank to switch to the sprite plane - - pei SpriteBanks - plb ; pop the data bank (low byte) - -]line equ 0 - lup 16 - stz: {]line*SPRITE_PLANE_SPAN}+0,x - stz: {]line*SPRITE_PLANE_SPAN}+2,x - stz: {]line*SPRITE_PLANE_SPAN}+4,x - stz: {]line*SPRITE_PLANE_SPAN}+6,x -]line equ ]line+1 - --^ - - plb ; pop the mask bank (high byte) - - lda #$FFFF -]line equ 0 - lup 16 - sta: {]line*SPRITE_PLANE_SPAN}+0,x - sta: {]line*SPRITE_PLANE_SPAN}+2,x - sta: {]line*SPRITE_PLANE_SPAN}+4,x - sta: {]line*SPRITE_PLANE_SPAN}+6,x -]line equ ]line+1 - --^ - - plb - rts - - -; First, if there is only one sprite, then we can skip any overhead and do a single lda/and/ora/sta to put the -; sprite data on the screen. -; -; Second, if there are 4 or less, then we "stack" the sprite data using an unrolled loop that allows each -; sprite to just be a single and/ora pair and the final result is not written to any intermediate memory buffer. -; -; Third, if there are 5 or more sprites, then we assume that the sprites are "dense" and that there will be a -; non-trivial amount of overdraw. In this case we do a series of optimized copies of the sprite data *and* -; masks into a direct page buffer in *reverse order*. Once a mask value becomes zero, then nothing else can -; show through and that value can be skipped. Once all of the mask values are zero, then the render is terminated -; and the data buffer copied to the final destination. -; -; Note that these rendering algorithms impose a priority ordering on the sprites where lower sprite IDs are drawn -; underneath higher sprite IDs. -RenderActiveSpriteTiles - cmp #0 ; Is there only one active sprite? If so optimise - bne :many - - ldx vbuff ; load the address to the (adjusted) sprite tile - lda TileStore+TS_SCREEN_ADDR,y - tay - - lda tiledata+0,y - andl spritemask,x - oral spritedata,x - sta 00,s - - lda tiledata+2,y - andl spritemask+2,x - oral spritedata+2,x - sta 02,s - - ... - tsc - adc #320 - tcs - ... - - lda tiledata+{line*4},y - andl spritemask+{line*SPAN},x - oral spritedata+{line*SPAN},x - sta 160,s - - lda tiledata+{line*4}+2,y - andl spritemask+{line*SPAN}+2,x - oral spritedata+{line*SPAN}+2,x - sta 162,s - - rts - - -:many - lda TileStore+TS_SCREEN_ADDR,y - tcs - lda TileStore+TS_TILE_ADDR,y - tay - - ldx count - jmp (:arr,x) - lda tiledata+0,y - ldx vbuff - andl spritemask,x - oral spritedata,x - ldx vbuff+2 - andl spritemask,x - oral spritedata,x - ldx vbuff+4 - andl spritemask,x - oral spritedata,x - ... - sta 00,s - - ldx count - jmp (:arr,x) - lda tiledata+0,y - ldx vbuff - andl spritemask,x - oral spritedata,x - ldx vbuff+2 - andl spritemask,x - oral spritedata,x - ldx vbuff+4 - andl spritemask,x - oral spritedata,x - ... - sta 02,s - - sta 160,s - - sta 162,s - - tsc - adc #320 \ No newline at end of file diff --git a/src/blitter/Scanline.s b/src/blitter/Scanline.s new file mode 100644 index 0000000..dc640d5 --- /dev/null +++ b/src/blitter/Scanline.s @@ -0,0 +1,172 @@ +; This support an alternate engine mode. When in scanline mode the renderer does not use the +; global StartX and StartY parameters to set up the code field. Instead, an array of scanline +; parameters must be provided to the blitter. +; +; This is a low-level mode and it is assumed that the arrays will contain valid values. This +; process is quite a bit slower that the normal setup because it must calculate code field +; entry points for each line, instead of once for the entire frame. + +_ScanlineBG0XPos + +:stk_save equ tmp0 +:virt_line_x2 equ tmp1 +:last_line_x2 equ tmp2 +:src_bank equ tmp3 +:exit_offset equ tmp4 +:entry_offset equ tmp5 +:exit_bra equ tmp6 +:exit_address equ tmp7 +:base_address equ tmp8 +:opcode equ tmp9 +:odd_entry_offset equ tmp10 + + lda StartYMod208 ; This is the base line of the virtual screen + asl + sta :virt_line_x2 ; Keep track of it + + lda ScreenHeight + asl + clc + adc :virt_line_x2 + sta :last_line_x2 + + phb + phb + pla + and #$FF00 + sta :src_bank + +:loop + ldx :virt_line_x2 + lda StartXMod164Arr,x ; Get the offset for this line + + dec ; The exit point is one byte sooner + bpl *+5 + lda #163 + + bit #$0001 ; if odd, then original number was even + beq :odd_exit ; if even, the original number was odd + + ; This is the even code path + and #$FFFE + tay + lda CodeFieldEvenBRA,y + sta :exit_bra + lda Col2CodeOffset,y + sta :exit_offset + sta LastPatchOffsetArr,x ; Cache afor later + bra :do_entry + +; This is the odd code path +:odd_exit tay + lda CodeFieldOddBRA,y + sta :exit_bra + lda Col2CodeOffset,y + sta :exit_offset + sta LastPatchOffsetArr,x + +; Handle the entry point calculations +:do_entry + lda StartXMod164Arr,x + clc + adc ScreenWidth ; move to the right edge and back up a byte + dec ; to get the index of the first on-screen byte + + cmp #164 ; Keep the value in range + bcc *+5 + sbc #164 + +; Same logic as before + + bit #$0001 + beq :odd_entry + + and #$FFFE + tay + lda Col2CodeOffset,y + sta :entry_offset + lda #$004C ; set the entry_jmp opcode to JMP + sta :opcode + stz :odd_entry_offset ; mark as an even case + bra :prep_complete + +:odd_entry + tay + lda Col2CodeOffset,y + sta :entry_offset ; Will be used to load the data + lda Col2CodeOffset-2,y + sta :odd_entry_offset ; will the the actual location to jump to + lda #$00AF ; set the entry_jmp opcode to LDAL + sta :opcode +:prep_complete + +; Not patch in the code field line + + ldy BTableLow,x ; Get the address of the first code field line + clc + adc :exit_offset ; Add some offsets to get the base address in the code field line + sta :exit_address + sty :base_address + + lda BTableHigh,x + ora src_bank + pha + plb + +; First step is to set the BRA instruction to exit the code field at the proper location. There +; are two sub-steps to do here; we need to save the 16-bit value that exists at the location and +; then overwrite it with the branch instruction. + +; SaveOpcode + ; y is already set to :base_address + ldx :exit_address ; Save from this location + lda: $0000,x + sta: OPCODE_SAVE+$0000,y + +;SetConst + txy ; ldy :exit_address -- starting at this address + ldx :exit_bra ; Copy this value into all of the lines + sta: $0000,y + +; Next, patch in the CODE_ENTRY value, which is the low byte of a JMP instruction. This is an +; 8-bit operation and, since the PEA code is bank aligned, we use the entry_offset value directly + + sep #$20 + +; SetCodeEntry + lda :entry_offset + ldy :base_address + sta: CODE_ENTRY+$0000,y + +; SetCodeEntryOpcode + + lda :opcode + sta: CODE_ENTRY_OPCODE+$0000,y + +; If this is an odd entry, also set the odd_entry low byte and save the operand high byte + + lda :odd_entry_offset + beq :not_odd + +; SetOddCodeEntry + sta: ODD_ENTRY+$0000,y +; SaveHighOperand + ldx :exit_address + lda: $0002,x + sta: OPCODE_HIGH_SAVE+$0000,y +:not_odd + rep #$21 ; clear the carry + +; Do the end of the loop -- update the virtual line counter and reduce the number +; of lines left to render + + plb ; restore the bank + + lda :virt_line_x2 + inc + inc + sta :virt_line_x2 + cmp :last_line_x2 + jne :loop + + rts \ No newline at end of file