📄 sprites.asm
字号:
mov [ebx + 4],ch
.no_pixel_bp_4:
mov al,[esi + 1]
and al,dh
jz .no_pixel_bp_1
mov ch,[ebx + 1]
or ch,ah
mov [ebx + 1],ch
.no_pixel_bp_1:
mov al,[esi + 5]
and al,dh
jz .no_pixel_bp_5
mov ch,[ebx + 5]
or ch,ah
mov [ebx + 5],ch
.no_pixel_bp_5:
mov al,[esi + 2]
and al,dh
jz .no_pixel_bp_2
mov ch,[ebx + 2]
or ch,ah
mov [ebx + 2],ch
.no_pixel_bp_2:
mov al,[esi + 6]
and al,dh
jz .no_pixel_bp_6
mov ch,[ebx + 6]
or ch,ah
mov [ebx + 6],ch
.no_pixel_bp_6:
mov al,[esi + 3]
and al,dh
jz .no_pixel_bp_3
mov ch,[ebx + 3]
or ch,ah
mov [ebx + 3],ch
.no_pixel_bp_3:
mov al,[esi + 7]
and al,dh
jz .no_pixel_bp_7
mov ch,[ebx + 7]
or ch,ah
mov [ebx + 7],ch
.no_pixel_bp_7:
pop ecx
pop ebx
dec cl
jnz .next_tile
jmp .check_tag
ALIGNC
.bad_priority_flip_x:
mov al,[esi + 7]
and al,dh
jz .no_pixel_bp_0_x
mov ch,[ebx]
or ch,ah
mov [ebx],ch
.no_pixel_bp_0_x:
mov al,[esi + 3]
and al,dh
jz .no_pixel_bp_4_x
mov ch,[ebx + 4]
or ch,ah
mov [ebx + 4],ch
.no_pixel_bp_4_x:
mov al,[esi + 6]
and al,dh
jz .no_pixel_bp_1_x
mov ch,[ebx + 1]
or ch,ah
mov [ebx + 1],ch
.no_pixel_bp_1_x:
mov al,[esi + 2]
and al,dh
jz .no_pixel_bp_5_x
mov ch,[ebx + 5]
or ch,ah
mov [ebx + 5],ch
.no_pixel_bp_5_x:
mov al,[esi + 5]
and al,dh
jz .no_pixel_bp_2_x
mov ch,[ebx + 2]
or ch,ah
mov [ebx + 2],ch
.no_pixel_bp_2_x:
mov al,[esi + 1]
and al,dh
jz .no_pixel_bp_6_x
mov ch,[ebx + 6]
or ch,ah
mov [ebx + 6],ch
.no_pixel_bp_6_x:
mov al,[esi + 4]
and al,dh
jz .no_pixel_bp_3_x
mov ch,[ebx + 3]
or ch,ah
mov [ebx + 3],ch
.no_pixel_bp_3_x:
mov al,[esi]
and al,dh
jz .no_pixel_bp_7_x
mov ch,[ebx + 7]
or ch,ah
mov [ebx + 7],ch
.no_pixel_bp_7_x:
pop ecx
pop ebx
dec cl
jnz .next_tile
jmp .check_tag
; In the precalculator...
; eax = (internal)
; edx = (internal)
; ebx = current sprite (internal)
; cl = sprite flags bit count (internal)
; ebp = (internal)
; esi = sprite tables (internal)
; edi = sprite flags (internal)
;
%macro Add_Sprite_Y_Check 0
; Check if sprite entirely offscreen
mov cl,[esi+1]
lea eax,[edx*8]
cmp cl,239
jb %%on_screen_y
add al,cl
dec al
jns %%on_screen_y
%%off_screen:
pop ecx
ret
%%on_screen_y:
%endmacro
%define ASXP_Lines_Left esp
;%define ASXP_X_Position esp+1 ;planned but not yet used
%define ASXP_Total_Size esp+4
%define ASXP_Visible_Width esp+5
%define ASXP_Total_Lines esp+6
%define OAM_TIME_OVER (1 << 7)
%define OAM_RANGE_OVER (1 << 6)
;tiles are added to ring buffers in right-to-left order
;ring buffers handle time-overflow by spilling excess tiles
;starts with first+max-count or last (first+count-1) tile
ALIGNC
EXPORT_C Add_Sprite_X_Positive
;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!
push ecx
Add_Sprite_Y_Check
lea ecx,[ebx*8] ; Convert tiles to lines
; Save visible width and total size, these won't be changing
push edi
push edx
mov [ASXP_Total_Lines-4],cl
; Get base tile #
mov ebp,[esi]
xor ebx,ebx
shr ebp,16
mov al,[esi+3]
and eax,byte 0x40
jnz .flip_x
; If tile is X-flipped, set to last tile # instead of first
mov dl,dh
dec ebp
jmp .adjust_x_done
.flip_x:
; Set to first tile #
sub dl,dh
.adjust_x_done:
and edx,byte 0x7F ; Size will always be less than this
add ebp,edx
mov bl,[esi+1] ; Get first line
shl ebp,3
push ecx
;ebx = current line
;cl = lines left
;dl = ASXP_Total_Lines
;ebp = tile # (leftmost as shown)
.next_line:
;If line never displayed, ignore line
cmp bl,239
jnb .check_count
; Check OBJ count for line (if 32, set range over and ignore OBJ)
mov al,[C_LABEL(OAM_Count)+ebx*2]
cmp al,32
jb .range_okay
or byte [C_LABEL(OAM_TimeRange)+ebx],OAM_RANGE_OVER
jmp .check_count
.range_okay:
; else increment OBJ count
inc al
mov ch,[ASXP_Visible_Width]
mov [C_LABEL(OAM_Count)+ebx*2],al
mov dl,[ASXP_Total_Lines]
mov dh,[esi+3]
;shl dl,3
push ebp
add dh,dh
jc .flip_y
; line in sprite = line size - lines left
sub dl,[ASXP_Lines_Left+4]
jnz .adjust_y
jmp .adjust_y_done
.flip_y:
; line in sprite = lines left - 1
mov dl,[ASXP_Lines_Left+4]
dec dl
xor dl,[OBJ_vflip_fixup] ;*
jz .adjust_y_done
.adjust_y:
; convert tile # in ebp to tile line #
mov edi,edx
and edx,byte 0x38 ; tile offset
shl edx,3+1 ; (lines / 8) * 16 tiles * 8 lines
and edi,byte 7 ; line in tile
add ebp,edx
add ebp,edi
.adjust_y_done:
; setup pointer to line descriptors to be used, update line count
; edx = C_LABEL(OAM_Lines)+(ebx*34+((byte) [C_LABEL(OAM_Count)+ebx*2+1]))*4
mov edx,ebx
push ebx
shl edx,5
add edx,ebx
xor eax,eax
add edx,ebx
; Check tile count for line (if 34, set time over and ignore tiles)
; If will be over 34, set time over and adjust width
mov al,[C_LABEL(OAM_Count)+ebx*2+1]
mov cl,0
cmp al,34
je .time_over
add edx,eax
add al,ch
cmp al,34
ja .time_first_over
mov [C_LABEL(OAM_Count)+ebx*2+1],al
jmp .time_okay
.time_first_over:
mov byte [C_LABEL(OAM_Count)+ebx*2+1],34
sub al,34
jmp .list_wrap
.time_over:
mov al,[OAM_Tail+ebx]
add edx,eax
add al,ch
mov [OAM_Tail+ebx],al
sub al,34
jb .time_over_detect
je .fixup_head
.list_wrap:
mov cl,al
.fixup_head:
mov [OAM_Tail+ebx],al
sub ch,al
.time_over_detect:
or byte [C_LABEL(OAM_TimeRange)+ebx],OAM_TIME_OVER
.time_okay:
mov al,[C_LABEL(OAM_Count)+ebx*2+1]
lea edx,[C_LABEL(OAM_Lines)+edx*4]
push eax
; Determine if sprite sequence on line contains higher priorities
; after lower priorities, set new last-tile-for-priority
mov ah,[C_LABEL(OAM_Lowest_Priority)+ebx]
mov al,[esi+3]
and al,0x30
cmp ah,al
jb .low_before_high
mov [C_LABEL(OAM_Lowest_Priority)+ebx],al
jmp .priority_done
.low_before_high:
mov byte [C_LABEL(OAM_Low_Before_High)+ebx],0xFF
.priority_done:
; setup flags & X position of tiles in line descriptor
and eax,0x30
shr eax,4
lea ebx,[C_LABEL(OAM_Count_Priority)+eax+ebx*4]
pop eax
mov [ebx],al
mov ah,0xFE
mov bh,[esi+3]
and ah,bh
and bh,0x40
mov al,[esi]
jz .Flip_None
;cl = lines left (including current)
;ch = tile count for line, dl = OBJ size in pixel width/height
;ebp = tile # (not Y adjusted)
;esi = OAM pointer
;sprite line = cl - 1 (Y flip), dl - cl (no Y flip)
call C_LABEL(Add_Sprite_X_Positive_Flip_X)
pop ebx
pop ebp
jmp .check_count
.Flip_None:
call C_LABEL(Add_Sprite_X_Positive_Flip_None)
pop ebx
.check_count_time_over:
pop ebp
.check_count:
inc bl
dec byte [ASXP_Lines_Left]
jnz .next_line
pop eax
pop edx
pop edi
pop ecx
ret
;starts with first or last (first+max-1) tile
ALIGNC
EXPORT_C Add_Sprite_X_Negative
;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!
push ecx
Add_Sprite_Y_Check
lea ecx,[ebx*8] ; Convert tiles to lines
; Save visible width and total size, these won't be changing
push edi
push edx
mov [ASXP_Total_Lines-4],cl
; Get base tile #
mov ebp,[esi]
xor ebx,ebx
shr ebp,16
mov al,[esi+3]
and eax,byte 0x40
jnz .flip_x
; If tile is X-flipped, set to last tile # instead of first
and edx,byte 0x7F ; Size will always be less than this
dec ebp
add ebp,edx
.flip_x:
mov bl,[esi+1] ; Get first line
shl ebp,3 ; tile # * 8 lines
push ecx
;ebx = current line
;cl = lines left
;dl = ASXP_Total_Lines
;ebp = tile # (leftmost as shown)
.next_line:
;If line never displayed, ignore line
cmp bl,239
jnb .check_count
; Check OBJ count for line (if 32, set range over and ignore OBJ)
mov al,[C_LABEL(OAM_Count)+ebx*2]
cmp al,32
jb .range_okay
or byte [C_LABEL(OAM_TimeRange)+ebx],OAM_RANGE_OVER
jmp .check_count
.range_okay:
; increment OBJ count
inc al
mov ch,[ASXP_Visible_Width]
mov [C_LABEL(OAM_Count)+ebx*2],al
mov dl,[ASXP_Total_Lines]
mov dh,[esi+3]
;shl dl,3
push ebp
add dh,dh
jc .flip_y
; line in sprite = line size - lines left
sub dl,[ASXP_Lines_Left+4]
jnz .adjust_y
jmp .adjust_y_done
.flip_y:
; line in sprite = lines left - 1
mov dl,[ASXP_Lines_Left+4]
dec dl
xor dl,[OBJ_vflip_fixup] ;*
jz .adjust_y_done
.adjust_y:
; convert tile # in ebp to tile line #
mov edi,edx
and edx,byte 0x38 ; tile offset
shl edx,3+1 ; (lines / 8) * 16 tiles * 8 lines
and edi,byte 7 ; line in tile
add ebp,edx
add ebp,edi
.adjust_y_done:
; setup pointer to line descriptors to be used, update line count
; edx = C_LABEL(OAM_Lines)+(ebx*34+((byte) [C_LABEL(OAM_Count)+ebx*2+1]))*4
mov edx,ebx
push ebx
shl edx,5
add edx,ebx
xor eax,eax
add edx,ebx
; Check tile count for line (if 34, set time over and ignore tiles)
; If will be over 34, set time over and adjust width
mov al,[C_LABEL(OAM_Count)+ebx*2+1]
mov cl,0
cmp al,34
je .time_over
add edx,eax
add al,ch
cmp al,34
ja .time_first_over
mov [C_LABEL(OAM_Count)+ebx*2+1],al
jmp .time_okay
.time_first_over:
mov byte [C_LABEL(OAM_Count)+ebx*2+1],34
sub al,34
jmp .list_wrap
.time_over:
mov al,[OAM_Tail+ebx]
add edx,eax
add al,ch
mov [OAM_Tail+ebx],al
sub al,34
jb .time_over_detect
je .fixup_head
.list_wrap:
mov cl,al
.fixup_head:
mov [OAM_Tail+ebx],al
sub ch,al
.time_over_detect:
or byte [C_LABEL(OAM_TimeRange)+ebx],OAM_TIME_OVER
.time_okay:
mov al,[C_LABEL(OAM_Count)+ebx*2+1]
lea edx,[C_LABEL(OAM_Lines)+edx*4]
push eax
; Determine if sprite sequence on line contains higher priorities
; after lower priorities, set new last-tile-for-priority
mov ah,[C_LABEL(OAM_Lowest_Priority)+ebx]
mov al,[esi+3]
and al,0x30
cmp ah,al
jb .low_before_high
mov [C_LABEL(OAM_Lowest_Priority)+ebx],al
jmp .priority_done
.low_before_high:
mov byte [C_LABEL(OAM_Low_Before_High)+ebx],0xFF
.priority_done:
; setup flags & X position of tiles in line descriptor
and eax,0x30
shr eax,4
lea ebx,[C_LABEL(OAM_Count_Priority)+eax+ebx*4]
pop eax
mov [ebx],al
mov ah,[ASXP_Total_Size+8]
mov bh,[esi+3]
dec ah
or bh,1
mov al,[esi]
shl ah,3
add al,ah
mov ah,bh
jnc .no_carry
xor ah,1
.no_carry:
and bh,0x40
jz .Flip_None
;cl = lines left (including current)
;ch = tile count for line, dl = OBJ size in pixel width/height
;ebp = tile # (not Y adjusted)
;esi = OAM pointer
;sprite line = cl - 1 (Y flip), dl - cl (no Y flip)
call C_LABEL(Add_Sprite_X_Negative_Flip_X)
pop ebx
pop ebp
jmp .check_count
.Flip_None:
call C_LABEL(Add_Sprite_X_Negative_Flip_None)
pop ebx
.check_count_time_over:
pop ebp
.check_count:
inc bl
dec byte [ASXP_Lines_Left]
jnz .next_line
pop eax
pop edx
pop edi
pop ecx
ret
ALIGNC
;ebp += (count - 1) * 8; al += (count - 1) * 8;
EXPORT_C Add_Sprite_X_Positive_Flip_None
xor ebx,ebx
mov bl,ch
add bl,cl
dec bl
shl ebx,3
add al,bl
;add ebp,ebx
.next_tile:
; compute tile line #'s and store line descriptors
push ebp
and ebp,511*8+7
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -