⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sprites.asm

📁 NES game Emulator in Linux.c and asm codes.
💻 ASM
📖 第 1 页 / 共 3 页
字号:
 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 + -