; Compile a stamp into a compilation cache ; ; A = vbuff address ; X = width (in bytes) ; Y = height (in scanlines) _CompileStamp :lines equ tmp0 :sprwidth equ tmp1 :cntwidth equ tmp2 :baseAddr equ tmp3 :destAddr equ tmp4 :vbuffAddr equ tmp5 :rtnval equ tmp6 LDA_IMM_OPCODE equ $A9 LDA_ABS_X_OPCODE equ $BD AND_IMM_OPCODE equ $29 ORA_IMM_OPCODE equ $09 STA_ABS_X_OPCODE equ $9D STZ_ABS_X_OPCODE equ $9E RTL_OPCODE equ $6B sta :vbuffAddr sty :lines txa lsr sta :sprwidth ; Get ready to build the sprite ldy CompileBankTop ; First free byte in the compilation bank sty :rtnval ; Save it as the return value phb pei CompileBank plb ; Set the bank to the compilation cache stz :baseAddr stz :destAddr :oloop lda :sprwidth sta :cntwidth ldx :vbuffAddr :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 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 lda :destAddr sta: 10,y tya clc adc #12 tay bra :next ; Just store the data :no_mask lda #LDA_IMM_OPCODE sta: 0,y ldal spritedata,x beq :zero sta: 1,y lda #STA_ABS_X_OPCODE sta: 3,y lda :destAddr sta: 4,y tya clc adc #6 tay bra :next :zero lda #STZ_ABS_X_OPCODE sta: 0,y lda :destAddr sta: 1,y iny iny iny :next inx inx inc :destAddr ; Move to the next word inc :destAddr dec :cntwidth bne :iloop lda :vbuffAddr clc adc #SPRITE_PLANE_SPAN sta :vbuffAddr lda :baseAddr ; Move to the next line clc adc #160 sta :baseAddr sta :destAddr dec :lines beq :out brl :oloop :out lda #RTL_OPCODE ; Finish up the subroutine sta: 0,y iny sty CompileBankTop plb plb lda :rtnval ; Address in the compile memory 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_ID,x ; If the sprite is hidden or an overlay, don't draw it bit #SPRITE_OVERLAY+SPRITE_HIDE 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 asl asl asl asl asl sta tmp0 asl asl clc adc tmp0 clc adc #$2000 clc adc ScreenX0 adc _Sprites+SPRITE_X,x ; Move to the horizontal address tay ; This is the on-screen address lda _Sprites+SPRITE_ID,x ; If this is a compiled sprite, call the routine in the compilation bank bit #SPRITE_COMPILED beq *+5 brl :compiled lda _Sprites+SPRITE_HEIGHT,x sta tmp0 ; Sprite is either 8 or 16 pixels wide, so select the entry point lda _Sprites+SPRITE_WIDTH,x cmp #4 beq :skinny lda _Sprites+SPRITE_DISP,x ; This is the VBUFF address with the correct sprite frame tax phb pea $0101 plb plb bra :entry16 :loop16 clc txa adc #SPRITE_PLANE_SPAN tax tya adc #SHR_LINE_WIDTH tay :entry16 lda: 6,y andl spritemask+6,x oral spritedata+6,x sta: 6,y lda: 4,y andl spritemask+4,x oral spritedata+4,x sta: 4,y lda: 2,y andl spritemask+2,x oral spritedata+2,x sta: 2,y lda: 0,y andl spritemask+0,x oral spritedata+0,x sta: 0,y dec tmp0 bne :loop16 plb rts :skinny lda _Sprites+SPRITE_DISP,x ; This is the VBUFF address with the correct sprite frame tax phb pea $0101 plb plb bra :entry8 :loop8 clc txa adc #SPRITE_PLANE_SPAN tax tya adc #SHR_LINE_WIDTH tay :entry8 lda: 2,y andl spritemask+2,x oral spritedata+2,x sta: 2,y lda: 0,y andl spritemask+0,x oral spritedata+0,x sta: 0,y dec tmp0 bne :loop8 plb rts :compiled lda CompileBank-1 ; Load the bank into the high byte stal :patch+2 ; Put it into the 3rd address bytes (2nd byte is garbage) lda _Sprites+SPRITE_DISP,x ; Address in the compile bank stal :patch+1 ; Set 1st and 2nd address bytes tyx ; Put on-screen address in X-register phb ; Compiled sprites assume bank register is $01 pea $0101 plb plb :patch jsl $000000 ; Dispatch plb rts ; Alternate entry point that takes arguments in registers instead of using a _Sprite ; record ; ; Y = VBUFF address ; X = Tile Data address ; A = Sprite Flags DISP_VFLIP equ $0004 ; hard code these because they are internal values DISP_HFLIP equ $0002 DISP_MASK equ $0018 ; Preserve the size bits _DrawSpriteStamp sty tmp1 stx tmp2 xba and #DISP_MASK ; dispatch to all of the different orientations sta tmp3 phb pea #^tiledata ; Set the bank to the tile data plb ; X = sprite ID ; Y = Tile Data ; A = VBUFF address ldx tmp3 ldy tmp2 lda tmp1 jsr _DrawSprite lda tmp3 ora #DISP_HFLIP tax ldy tmp2 lda tmp1 clc adc #3*4 jsr _DrawSprite lda tmp3 ora #DISP_VFLIP tax ldy tmp2 lda tmp1 clc adc #6*4 jsr _DrawSprite lda tmp3 ora #DISP_HFLIP+DISP_VFLIP tax ldy tmp2 lda tmp1 clc adc #9*4 jsr _DrawSprite ; Restore bank plb ; pop extra byte plb rts ; ; X = _Sprites array offset _DrawSprite jmp (draw_sprite,x) draw_sprite dw draw_8x8,draw_8x8h,draw_8x8v,draw_8x8hv ; 8 wide x 8 tall dw draw_8x16,draw_8x16h,draw_8x16v,draw_8x16hv ; 8 wide x 16 tall dw draw_16x8,draw_16x8h,draw_16x8v,draw_16x8hv ; 16 wide by 8 tall dw draw_16x16,draw_16x16h,draw_16x16v,draw_16x16hv ; 16 wide by 16 tall dw :rtn,:rtn,:rtn,:rtn ; hidden bit is set dw :rtn,:rtn,:rtn,:rtn dw :rtn,:rtn,:rtn,:rtn dw :rtn,:rtn,:rtn,:rtn :rtn rts draw_8x8 tax jmp _DrawTile8x8 draw_8x8h tax clc tya adc #64 tay jmp _DrawTile8x8 draw_8x8v tax jmp _DrawTile8x8V draw_8x8hv tax clc tya adc #64 tay jmp _DrawTile8x8V draw_8x16 tax jsr _DrawTile8x8 clc txa adc #{8*SPRITE_PLANE_SPAN} tax tya adc #{128*32} ; 32 tiles to the next vertical one, each tile is 128 bytes tay jmp _DrawTile8x8 draw_8x16h tax clc tya adc #64 tay jsr _DrawTile8x8 clc txa adc #{8*SPRITE_PLANE_SPAN} tax tya adc #{128*32} ; 32 tiles to the next vertical one, each tile is 128 bytes tay jmp _DrawTile8x8 draw_8x16v clc tax tya pha adc #{128*32} tay jsr _DrawTile8x8V clc txa adc #{8*SPRITE_PLANE_SPAN} tax ply jmp _DrawTile8x8V draw_8x16hv clc tax tya adc #64 pha adc #{128*32} tay jsr _DrawTile8x8V clc txa adc #{8*SPRITE_PLANE_SPAN} tax ply jmp _DrawTile8x8V draw_16x8 tax jsr _DrawTile8x8 clc txa adc #4 tax tya adc #128 ; Next tile is 128 bytes away tay jmp _DrawTile8x8 draw_16x8h clc tax tya adc #64 pha adc #128 tay jsr _DrawTile8x8 txa adc #4 tax ply jmp _DrawTile8x8 draw_16x8v tax jsr _DrawTile8x8V clc txa adc #4 tax tya adc #128 tay jmp _DrawTile8x8V draw_16x8hv clc tax tya adc #64 pha adc #128 tay jsr _DrawTile8x8V txa adc #4 tax ply jmp _DrawTile8x8V ; X = sprite ID ; Y = Tile Data ; A = VBUFF address draw_16x16 clc tax jsr _DrawTile8x8 txa adc #4 tax tya adc #128 tay jsr _DrawTile8x8 txa adc #{8*SPRITE_PLANE_SPAN}-4 tax tya adc #{128*{32-1}} tay jsr _DrawTile8x8 txa adc #4 tax tya adc #128 tay jmp _DrawTile8x8 draw_16x16h clc tax tya adc #64 pha adc #128 tay jsr _DrawTile8x8 txa adc #4 tax ply jsr _DrawTile8x8 txa adc #{8*SPRITE_PLANE_SPAN}-4 tax tya adc #{128*32} pha adc #128 tay jsr _DrawTile8x8 txa adc #4 tax ply jmp _DrawTile8x8 draw_16x16v clc tax tya pha ; store some copies phx pha adc #{128*32} tay jsr _DrawTile8x8V txa adc #{8*SPRITE_PLANE_SPAN} tax ply jsr _DrawTile8x8V pla adc #4 tax lda 1,s adc #{128*{32+1}} tay jsr _DrawTile8x8V txa adc #{8*SPRITE_PLANE_SPAN} tax pla adc #128 tay jmp _DrawTile8x8V draw_16x16hv clc tax tya pha adc #{128*{32+1}}+64 ; Bottom-right source to top-left tay jsr _DrawTile8x8V txa adc #4 tax lda 1,s adc #{128*32}+64 tay jsr _DrawTile8x8V txa adc #{8*SPRITE_PLANE_SPAN}-4 tax lda 1,s adc #128+64 tay jsr _DrawTile8x8V txa adc #4 tax pla adc #64 tay jmp _DrawTile8x8V ; X = sprite vbuff address ; Y = tile data pointer _DrawTile8x8 _CopyTile8x8 ]line equ 0 lup 8 lda: tiledata+32+{]line*4},y stal spritemask+{]line*SPRITE_PLANE_SPAN},x lda: tiledata+{]line*4},y stal spritedata+{]line*SPRITE_PLANE_SPAN},x lda: tiledata+32+{]line*4}+2,y stal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x lda: tiledata+{]line*4}+2,y stal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x ]line equ ]line+1 --^ rts _DrawTile8x8V _CopyTile8x8V ]line equ 0 lup 8 lda: tiledata+32+{{7-]line}*4},y stal spritemask+{]line*SPRITE_PLANE_SPAN},x lda: tiledata+{{7-]line}*4},y stal spritedata+{]line*SPRITE_PLANE_SPAN},x lda: tiledata+32+{{7-]line}*4}+2,y stal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x lda: tiledata+{{7-]line}*4}+2,y stal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x ]line equ ]line+1 --^ rts