diff --git a/src/Defs.s b/src/Defs.s index 884fcda..e886f8a 100644 --- a/src/Defs.s +++ b/src/Defs.s @@ -228,13 +228,14 @@ TILE_CTRL_MASK equ $FE00 ; TILE_PROC_MASK equ $F800 ; Select tile proc for rendering ; Sprite constants -SPRITE_HIDE equ $2000 +SPRITE_COMPILED equ $4000 ; This is a compiled sprite (SPRITE_DISP points to a routine in the compiled cache bank) +SPRITE_HIDE equ $2000 ; Do not render the sprite SPRITE_16X16 equ $1800 ; 16 pixels wide x 16 pixels tall SPRITE_16X8 equ $1000 ; 16 pixels wide x 8 pixels tall SPRITE_8X16 equ $0800 ; 8 pixels wide x 16 pixels tall SPRITE_8X8 equ $0000 ; 8 pixels wide x 8 pixels tall -SPRITE_VFLIP equ $0400 -SPRITE_HFLIP equ $0200 +SPRITE_VFLIP equ $0400 ; Flip the sprite vertically +SPRITE_HFLIP equ $0200 ; Flip the sprite horizontally ; Stamp storage parameters VBUFF_STRIDE_BYTES equ {12*4} ; Each line has 4 slots of 16 pixels + 8 buffer pixels diff --git a/src/Render.s b/src/Render.s index fbcf56b..757517c 100644 --- a/src/Render.s +++ b/src/Render.s @@ -341,7 +341,9 @@ _RenderWithShadowing ; to create priority lists of scanline ranges. jsr _BuildShadowList ; Create the rages based on the sorted sprite y-values - jsr _ComplementList ; Create the complement to identify non-sprite scanlines +; jsr _MergeOverlay ; Add the overlay range into the shadow list (treat it as a sprite) + + jsr _ComplementList ; Create the complement to identify non-sprite / non-overlay scanlines jsr _ShadowOff ; Turn off shadowing and draw all the scanlines with sprites on them jsr _DrawShadowList @@ -484,7 +486,7 @@ _BuildShadowList ldx _SortedHead bmi :empty - bra :insert + bra :insert ; Start of loop :advance @@ -496,7 +498,7 @@ _BuildShadowList sta _ShadowListTop,y ; Set the top entry of the list to the sprite top lda _Sprites+SPRITE_CLIP_BOTTOM,x ; Optimistically set the end of the segment to the bottom of this sprite - inc + inc ; Clip values are on the scanline, so add one to make it a proper interval :replace sta _ShadowListBottom,y @@ -603,13 +605,25 @@ _DrawDirectSprites bmi :empty :loop - phx - jsr _DrawStampToScreen - plx + lda _Sprites+SPRITE_STATUS,x + bit #SPRITE_STATUS_HIDDEN + bne :next - lda _Sprites+SORTED_NEXT,x ; If there another sprite in the list? + lda _Sprites+SPRITE_ID,x ; If this is a compiled sprite, call the routine in the compilation bank + bit #SPRITE_COMPILED + bne :compiled + + phx + jsr _DrawStampToScreen + plx + bra :next + +:compiled + +:next + lda _Sprites+SORTED_NEXT,x ; If there another sprite in the list? tax - bpl :loop + bpl :loop :empty rts @@ -633,6 +647,8 @@ _DrawComplementList lda _DirectListTop,x ldy _DirectListBottom,x tax + lda #0 + jsr DebugSCBs jsr _BltRange plx @@ -646,6 +662,8 @@ _DrawComplementList phx ldy _DirectListTop,x tax + lda #1 + jsr DebugSCBs jsr _PEISlam plx bra :blt_range @@ -655,6 +673,41 @@ _DrawComplementList bcs :out ; screen, then expose that range tax ldy ScreenHeight + lda #1 + jsr DebugSCBs jsr _PEISlam :out - rts \ No newline at end of file + rts + +; Helper to set a palette index on a range of SCBs to help show whicih actions are applied to which lines +DebugSCBs + phx + phy + sep #$30 ; short m/x + + pha ; save the SCB value + + phx + tya + sec + sbc 1,s + tay ; number of scanlines + + pla + clc + adc ScreenY0 + tax ; physical line index + + pla +:loop + stal SHR_SCB,x + inx + dey + bne :loop + + rep #$30 + ply + plx + rts + + diff --git a/src/SpriteRender.s b/src/SpriteRender.s index c0a5d37..6879b15 100644 --- a/src/SpriteRender.s +++ b/src/SpriteRender.s @@ -1,7 +1,129 @@ -; Draw a sprite directly to the graphics screen. No clipping / bounds checking is performed +; Compile a stamp into a compilation cache +_CompileStamp +_lines equ tmp0 +_width0 equ tmp1 +_width equ tmp2 +baseAddr equ tmp3 +destAddr equ tmp4 +vbuffAddr equ tmp5 + + lda _Sprites+SPRITE_HEIGHT,x + sta _lines + + lda _Sprites+SPRITE_WIDTH,x ; Width in bytes (4 or 8) + lsr + sta + sta _width0 + + lda _Sprites+SPRITE_DISP,x ; Get the address of the stamp + sta vbuffAddr + tax + + ldy CompileBankTop ; First free byte in the compilation bank + + phb + pei CompileBank + plb + plb ; Set the bank to the compilation cache + + stz baseAddr + stz destAddr + +:oloop + lda _width0 + sta _width + +:iloop + ldal spritemask,x + beq :no_mask ; If Mask == $0000, then it's a solid word + cmp #$FFFF + beq :next ; If Mask == $FFFF, then it's transparent + +; Mask with the screen data + lda #LDA_ABS_X_OPCODE + sta: 0,y + lda destAddr + sta: 1,y + sta: 10,y + lda #AND_IMM_OPCODE + sta: 3,y + ldal spritemask,x + sta: 4,y + lda #ORA_IMM_OPCODE + sta: 6,y + ldal spritedata,x + sta: 7,y + lda #STA_ABS_X_OPCODE + sta: 9,y + + tya + adc #12 + tay + bra :next + +; Just store the data +:no_mask lda #LDA_IMM_OPCODE + sta: 0,y + ldal spritedata,x + sta: 1,y + + lda #STA_ABS_X_OPCODE + sta: 3,y + lda destAddr + sta: 4,y + + tya + adc #6 + tay + +:next + inx + inx + + inc destAddr ; Move to the next word + inc destAddr + + dec _width + bne :iloop + + lda vbuffAddr + adc #SPRITE_PLANE_SPAN + sta vbuffAddr + tax + + lda baseAddr ; Move to the next line + adc #160 + sta baseAddr + sta destAddr + + dec lines + bne :oloop + + lda #RTL_OPCODE ; Finish up the subroutine + sta: 0,y + iny + sty CompileBankTop + + plb + rts + +; Draw a sprite directly to the graphics screen. If sprite is clipped at all, do not draw. ; ; X = sprite record index +_DSTSOut + rts + _DrawStampToScreen + lda _Sprites+IS_OFF_SCREEN,x ; If the sprite is off-screen, don't draw it + bne _DSTSOut + + lda _Sprites+SPRITE_CLIP_WIDTH,x ; If the sprite is clipped to the playfield, don't draw it + cmp _Sprites+SPRITE_WIDTH,x + bne _DSTSOut + lda _Sprites+SPRITE_CLIP_HEIGHT,x + cmp _Sprites+SPRITE_HEIGHT,x + bne _DSTSOut + clc lda _Sprites+SPRITE_Y,x adc ScreenY0 diff --git a/src/static/TileStoreDefs.s b/src/static/TileStoreDefs.s index 6de5d4b..5dccf78 100644 --- a/src/static/TileStoreDefs.s +++ b/src/static/TileStoreDefs.s @@ -61,7 +61,7 @@ SPRITE_HEIGHT equ {MAX_SPRITES*28} SPRITE_CLIP_WIDTH equ {MAX_SPRITES*30} SPRITE_CLIP_HEIGHT equ {MAX_SPRITES*32} TS_VBUFF_BASE equ {MAX_SPRITES*34} ; Finalized VBUFF address based on the sprite position and tile offsets -SORTED_PREV equ {MAX_SPRITES*36} +SORTED_PREV equ {MAX_SPRITES*36} ; Doubly-Linked List that maintains the sprites in sorted order based on SPRITE_Y SORTED_NEXT equ {MAX_SPRITES*38} ; 52 rows by 82 columns + 2 extra rows and columns for sprite sizes