📄 sprites.asm
字号:
cmp ebp,256*8
mov edi,[C_LABEL(OBNAME)]
jae .name
mov edi,[C_LABEL(OBBASE)]
.name:
and eax,0x3FFFF
add ebp,edi
shl ebp,18
or eax,ebp
pop ebp
;eax = prepared tile descriptor
mov [edx],eax
sub al,byte 8
sub ebp,byte 8
add edx,byte 4
dec ch
jnz .next_tile
sub edx,34*4
add ch,cl
mov cl,0
jnz .next_tile
ret
ALIGNC
;ebp -= (count - 1) * 8; al += (count - 1) * 8;
EXPORT_C Add_Sprite_X_Positive_Flip_X
xor ebx,ebx
mov bl,ch
add bl,cl
dec bl
shl ebx,3
add al,bl
;sub ebp,ebx
.next_tile:
; compute tile line #'s and store line descriptors
push ebp
and ebp,511*8+7
cmp ebp,256*8
mov edi,[C_LABEL(OBNAME)]
jae .name
mov edi,[C_LABEL(OBBASE)]
.name:
and eax,0x3FFFF
add ebp,edi
shl ebp,18
or eax,ebp
pop ebp
;eax = prepared tile descriptor
mov [edx],eax
sub al,byte 8
add ebp,byte 8
add edx,byte 4
dec ch
jnz .next_tile
sub edx,34*4
add ch,cl
mov cl,0
jnz .next_tile
ret
ALIGNC
;ebp += (count - 1) * 8; al += (count - 1) * 8;
;if al < ((count - 1) * 8) ah ^= 1;
EXPORT_C Add_Sprite_X_Negative_Flip_None
.next_tile:
; compute tile line #'s and store line descriptors
push ebp
and ebp,511*8+7
cmp ebp,256*8
mov edi,[C_LABEL(OBNAME)]
jae .name
mov edi,[C_LABEL(OBBASE)]
.name:
and eax,0x3FFFF
add ebp,edi
shl ebp,18
or eax,ebp
pop ebp
;eax = prepared tile descriptor
mov [edx],eax
sub al,byte 8
jnc .no_carry
xor ah,1
.no_carry:
sub ebp,byte 8
add edx,byte 4
dec ch
jnz .next_tile
sub edx,34*4
add ch,cl
mov cl,0
jnz .next_tile
ret
ALIGNC
;ebp -= (count - 1) * 8; al += (count - 1) * 8;
;if al < ((count - 1) * 8) ah ^= 1;
EXPORT_C Add_Sprite_X_Negative_Flip_X
.next_tile:
; compute tile line #'s and store line descriptors
push ebp
and ebp,511*8+7
cmp ebp,256*8
mov edi,[C_LABEL(OBNAME)]
jae .name
mov edi,[C_LABEL(OBBASE)]
.name:
and eax,0x3FFFF
add ebp,edi
shl ebp,18
or eax,ebp
pop ebp
;eax = prepared tile descriptor
mov [edx],eax
sub al,byte 8
jnc .no_carry
xor ah,1
.no_carry:
add ebp,byte 8
add edx,byte 4
dec ch
jnz .next_tile
sub edx,34*4
add ch,cl
mov cl,0
jnz .next_tile
ret
ALIGNC
EXPORT_C Check_OAM_Recache
;if priority rotation is off, treat OAM address as 0
xor eax,eax
mov al,[SPRLatch]
mov ebx,[C_LABEL(OAMAddress)]
sar al,7
and ebx,eax
;convert address to OBJ #
shr ebx,byte 1
cmp [C_LABEL(HiSprite)],bl
jne .priority_update
mov al,[Redo_OAM]
test al,al
jnz C_LABEL(Recache_OAM)
ret
.priority_update:
mov [C_LABEL(HiSprite)],bl
shl ebx,2
;sub ebx,byte 4
;and ebx,0x1FC
mov [C_LABEL(HiSpriteAddr)],ebx
shr ebx,4
add ebx,0x200
mov [C_LABEL(HiSpriteBits)],ebx
mov bl,[C_LABEL(HiSprite)]
mov bh,128
mov [C_LABEL(HiSpriteCnt2)+1],bl ;
sub bh,bl
mov [C_LABEL(HiSpriteCnt1)+1],bh ;
mov bh,7
add bl,bl
sub bh,bl
and bh,7
mov [C_LABEL(HiSpriteCnt1)],bh ;
mov ebx,C_LABEL(OAM)
add [C_LABEL(HiSpriteAddr)],ebx
add [C_LABEL(HiSpriteBits)],ebx
jmp C_LABEL(Recache_OAM)
ALIGNC
EXPORT_C Recache_OAM
%ifdef Profile_Recache_OAM
inc dword [C_LABEL(Calls_Recache_OAM)]
%endif
; Clear count tables
mov edi,C_LABEL(OAM_Count_Priority)
xor eax,eax
mov ecx,240*4/32
call Do_Clear
mov edi,C_LABEL(OAM_Count)
mov ecx,240*2/32
call Do_Clear
mov edi,OAM_Tail
mov ecx,224/32
call Do_Clear
mov bl,[edi]
mov [edi],eax
mov [edi+4],eax
mov [edi+8],eax
mov [edi+12],eax
mov edi,C_LABEL(OAM_TimeRange)
mov ecx,224/32
call Do_Clear
mov bl,[edi]
mov [edi],eax
mov [edi+4],eax
mov [edi+8],eax
mov [edi+12],eax
mov edi,C_LABEL(OAM_Low_Before_High)
mov ecx,224/32
call Do_Clear
mov bl,[edi]
mov [edi],eax
mov [edi+4],eax
mov [edi+8],eax
mov [edi+12],eax
mov edi,C_LABEL(OAM_Lowest_Priority)
mov ecx,224/32
dec eax
call Do_Clear
mov bl,[edi]
mov [edi],eax
mov [edi+4],eax
mov [edi+8],eax
mov [edi+12],eax
;mov al,[C_LABEL(OBSEL)]
;cmp al,0xC0 ; If invalid size selected, no sprites to plot
;jnb .done
mov ecx,[C_LABEL(HiSpriteCnt1)] ; Size of first set and bit offset
mov eax,[C_LABEL(HiSpriteCnt2)]
mov esi,[C_LABEL(HiSpriteAddr)]
test ah,ah
mov edi,[C_LABEL(HiSpriteBits)]
jz .is_zero
push byte 0
.is_zero:
push eax
jmp .next_sprite
; Tile attribute word: YXPP CCCT TTTT TTTT
; Where:
; Y, X are vertical/horizontal flip
; P is priority
; C is color palette selector
; T is tile number
;
; AAAA AAAA AAAA AAAA YXPP CCCX XXXX XXXX
; A - OAM sprite line-in-tile address
; YXPP CCC - bits 1-7 of OAM attribute word
; X - X position
ALIGNC
.next_sprite:
;esi = OAM 512 byte subtable address OAM+(0-511)
;edi = OAM 32 byte subtable address OAM+(512-543)
;cl = variable shift count for OAM subtable (1, 3, 5, 7)
;ch = count left in current decode pass (1-128)
;Perform clipping & determine visible range
;Get size
mov ah,[edi]
mov edx,[Sprite_Size_Current_X]
mov ebx,[Sprite_Size_Current_Y]
;Shift size bit into carry
shl ah,cl
jnc .do_small
;dl = sprite size in tiles
;dh = lower limit for negative X position
shr edx,16 ;X
shr ebx,16 ;Y
.do_small:
cmp dl,bl ;rectangular OBJ?
jne .rect_obj
mov al,0
.have_vflip_fixup:
mov [OBJ_vflip_fixup],al
;dl = sprite size in tiles
;dh = lower limit for negative X position
mov al,[esi] ; ax = X
;Get X sign bit
shr ah,8
jnc .do_positive
;Determine if sprite is entirely offscreen
cmp al,dh
jb .off_screen
.do_negative:
;# tiles -= 32 - ((X + 7) & FF) / 8 for -X
add eax,byte 7
mov dh,dl
shr eax,3
xor al,0xFF
add al,33
sub dh,al
;visible width count in dh, total count in dl
;esi = OAM 512 byte subtable address
;edi = OAM 32 byte subtable address
;ecx, esi, edi must be preserved!
call C_LABEL(Add_Sprite_X_Negative)
jmp .off_screen
.do_positive:
;# tiles <= 32 - (X & 0xFF) / 8 for +X
shr al,3
mov dh,dl
xor al,0xFF
add al,33
;max visible count in al
;dl = min(max count(al), total count(dl))
push ebx
sub al,dl
sbb bl,bl
and bl,al
add dh,bl
pop ebx
;visible width count in dh, total count in dl
;esi = OAM 512 byte subtable address
;edi = OAM 32 byte subtable address
;ecx, esi, edi must be preserved!
call C_LABEL(Add_Sprite_X_Positive)
jmp .off_screen
.rect_obj:
mov al,dl
shl al,3
jmp .have_vflip_fixup
ALIGNC
.off_screen:
sub cl,2 ; Adjust variable shift count
jnc .bits_left
and cl,7
inc edi ; Goto next sprite X-MSB/size byte
.bits_left:
add esi,byte 4 ; Goto next sprite XYAA dword
dec ch ; Check sprite list count
jnz .next_sprite
mov ch,[1+esp] ; Get next list count
sub esi,0x200 ; Adjust pointers to sprite 127 (if we're at end)
sub edi,byte 0x20
add esp,byte 4
test ch,ch ; Continue if valid list
jnz .next_sprite
.done:
mov byte [Redo_OAM],0
ret
ALIGNC
EXPORT_C Reset_Sprites
pusha
; Set eax to 0, as we're setting most everything to 0...
xor eax,eax
; Reset sprite renderer vars
mov byte [C_LABEL(HiSprite)],0
mov dword [C_LABEL(HiSpriteAddr)],C_LABEL(OAM)+0x000
mov dword [C_LABEL(HiSpriteBits)],C_LABEL(OAM)+0x200
mov dword [C_LABEL(HiSpriteCnt1)],0x8007
mov dword [C_LABEL(HiSpriteCnt2)],0x0007
mov byte [Redo_OAM],-1
mov ecx,[Sprite_Size_Table]
mov edx,[Sprite_Size_Table+4]
mov [Sprite_Size_Current_X],ecx
mov [Sprite_Size_Current_Y],edx
mov byte [Pixel_Allocation_Tag],1
mov [C_LABEL(OBBASE)],eax
mov [C_LABEL(OBNAME)],eax
; Reset sprite port vars
mov [C_LABEL(OAMAddress)],eax
mov [C_LABEL(OAMAddress_VBL)],eax
mov [OAMHigh],al
mov [OAM_Write_Low],al
mov [SPRLatch],al
mov [C_LABEL(OBSEL)],al
; Clear pixel allocation tag table
mov edi,DisplayZ+8
xor eax,eax
mov ecx,256/32
call Do_Clear
popa
ret
ALIGNC
EXPORT SNES_R2138 ; OAMDATAREAD
mov edx,[C_LABEL(OAMAddress)]
mov al,[OAMHigh]
cmp edx,0x100 ; if address >= 0x100...
jb .no_mirror
and edx,0x10F ; ignore disconnected lines
.no_mirror:
xor al,1
mov [OAMHigh],al
jnz .read_low
mov al,[C_LABEL(OAM)+edx*2+1]
mov edx,[C_LABEL(OAMAddress)]
inc edx
and edx,0x1FF ; address is 9 bits
mov [C_LABEL(OAMAddress)],edx
ret
ALIGNC
.read_low:
mov al,[C_LABEL(OAM)+edx*2]
ret
ALIGNC
EXPORT SNES_W2101 ; OBSEL
cmp [C_LABEL(OBSEL)],al
je .no_change
UpdateDisplay ;*
push ebx
mov [C_LABEL(OBSEL)],al ; Get our copy of this
mov ebx,eax
shr eax,5
and eax,byte 7
mov edx,[Sprite_Size_Table+eax*8]
mov eax,[Sprite_Size_Table+eax*8+4]
mov [Sprite_Size_Current_X],edx
mov [Sprite_Size_Current_Y],eax
mov eax,ebx
mov edx,eax
and ebx,byte 3<<3 ; Name address 0000 0000 000n n000
and edx,byte 3 ; Base address 0000 0000 0000 0xbb
;shl ebx,10 ; Name is either 0x0000,0x1000,0x2000,0x3000 words
;shl edx,14 ; Base is either 0x0000,0x2000,0x4000,0x6000 words
shl ebx,8 ; Name is either 0x0000,0x0800,0x1000,0x1800 lines
shl edx,12 ; Base is either 0x0000,0x1000,0x2000,0x3000 lines
add ebx,edx
;and edx,0xFFFF
;and ebx,0xFFFF
and edx,0x3FFF
and ebx,0x3FFF
;add edx,edx ; Convert to offsets into tile cache
;add ebx,ebx
;add edx,C_LABEL(TileCache4)
;add ebx,C_LABEL(TileCache4)
mov [C_LABEL(OBBASE)],edx
mov [C_LABEL(OBNAME)],ebx
pop ebx
mov byte [Redo_OAM],-1
.no_change:
ret
ALIGNC
EXPORT SNES_W2102 ; OAMADDL
UpdateDisplay ;*
push ebx
xor ebx,ebx
mov [OAMHigh],bh
mov [C_LABEL(OAMAddress)],al
mov [C_LABEL(OAMAddress_VBL)],al
pop ebx
ret
ALIGNC
EXPORT SNES_W2103 ; OAMADDH
UpdateDisplay ;*
push ebx
mov ebx,[C_LABEL(OAMAddress_VBL)]
xor edx,edx
mov bh,1
mov [OAMHigh],dl
and bh,al ; Only want MSB of address
mov dl,0x80
mov [C_LABEL(OAMAddress_VBL)+1],bh
and dl,al ; Is priority rotation bit set?
mov [C_LABEL(OAMAddress)],ebx
mov [SPRLatch],dl
pop ebx
ret
ALIGNC
EXPORT SNES_W2104 ; OAMDATA
push ebx
cmp byte [HVBJOY], 0
js .in_vblank
cmp byte [C_LABEL(INIDISP)], 0
jns .no_increment ;.no_change
.in_vblank:
xor ebx,ebx
mov edx,[C_LABEL(OAMAddress)]
mov bl,[OAMHigh]
cmp edx,0x100 ; if address >= 0x100, byte access
jnb .byte_access
xor ebx,byte 1
mov [OAMHigh],bl
jnz .write_low
mov bl,[OAM_Write_Low]
mov bh,al
cmp [C_LABEL(OAM)+edx*2],bx
je .no_change
UpdateDisplay ;*
mov edx,[C_LABEL(OAMAddress)]
mov byte [Redo_OAM],-1
mov [C_LABEL(OAM)+edx*2],bx
.no_change:
mov edx,[C_LABEL(OAMAddress)]
inc edx
and edx,0x1FF ; address is 9 bits
mov [C_LABEL(OAMAddress)],edx
.no_increment:
.ignore_write:
pop ebx
ret
ALIGNC
.write_low:
mov [OAM_Write_Low],al
pop ebx
ret
ALIGNC
.byte_access:
and edx,0x10F ; ignore disconnected lines
cmp [C_LABEL(OAM)+edx*2+ebx],al
je .ba_no_change
push edx
UpdateDisplay ;*
pop edx
mov byte [Redo_OAM],-1
mov [C_LABEL(OAM)+edx*2+ebx],al
.ba_no_change:
xor ebx,byte 1
mov [OAMHigh],bl
jnz .no_increment
mov edx,[C_LABEL(OAMAddress)]
inc edx
and edx,0x1FF ; address is 9 bits
mov [C_LABEL(OAMAddress)],edx
pop ebx
ret
section .text
ALIGNC
section .data
ALIGND
section .bss
ALIGNB
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -