iigs-game-engine/src/SpriteRender.s

601 lines
14 KiB
ArmAsm

; 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
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_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
; 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