📄 bg8o.asm
字号:
%if 0
SNEeSe, an Open Source Super NES emulator.
Copyright (c) 1998-2004 Charles Bilyue'.
Portions Copyright (c) 2003-2004 Daniel Horchner.
This is free software. See 'LICENSE' for details.
You must read and accept the license prior to use.
%endif
%define SNEeSe_ppu_bg8o_asm
%include "misc.inc"
%include "ppu/ppu.inc"
%include "ppu/tiles.inc"
%include "ppu/screen.inc"
%define RO8x8_Local_Bytes 56+24
%define RO8x8_Plotter_Table esp+52+24
%define RO8x8_Clipped esp+48+24
%define RO8x8_BG_Table esp+44+24
%define RO8x8_Current_Line esp+40+24
%define RO8x8_BaseDestPtr esp+36+24
%define RO8x8_Lines esp+32+24
; contains bit for determining planes to affect
%define RO8x8_OC_Flag esp+28+24
; Same as LineAddress(Y), additional vars for offset change code
%define RO8x8_LineAddressOffset esp+24+24
%define RO8x8_LineAddressOffsetY esp+20+24
%define RO8x8_FirstTile esp+16+24
; Scroll-adjusted tile map address for offset
; change code when tile offset not changed
%define RO8x8_MapAddress_Current esp+12+24
%define RO8x8_TMapAddress esp+8+24
%define RO8x8_BMapAddress esp+4+24
%define RO8x8_RMapDifference esp+24
%define RO8x8_Runs_Left esp+20
%define RO8x8_Output esp+16
%define RO8x8_RunListPtr esp+12
%define RO8x8R_VMapOffset esp+8
;VMapOffset can be eliminated by merging its value with VL/VRMapAddress?
%define RO8x8R_Plotter_Table RO8x8_Plotter_Table
%define RO8x8R_BG_Table RO8x8_BG_Table
%define RO8x8R_Next_Pixel esp+4
%define RO8x8R_Pixel_Count esp
%define RO8x8R_Inner (4)
%define RO8x8_Inner (8)
;VMapOffset = bg_line_offset (vscroll + current line) / bg tile size *
; 32 words (per line)
;Plotter = background plotting handler, passed:
; ebx = VRAM screen address of first tile
; cl = tile count to plot
; edi = pointer to destination surface, leftmost pixel of first tile
; (even if clipped)
; ebx = tile address offset from first tile on line
; (nextpixel + (hscroll & 7)) / 8 * 2
; esi = offset screen map address of first offset-change capable tile
; to be drawn
; VLMapAddressBG3 + OffsetChangeMap_VOffset +
; HScroll_3 / 8 * 2 - (ebx ? 2 : 0)
; cl = # tiles
; ch = offset-change enable bit
; uses qword TileClip1 (dword TileClip1Left, dword TileClip1Right)
;BG_Table = pointer to background structure
;Next_Pixel = first pixel in run to be plotted
; (local) hscroll-adjusted pixel to be plotted next (not always updated)
;Pixel_Count = count of pixels in run to be plotted
;edx = pointer to background structure (same as passed on stack)
;edi = native pointer to destination surface, start of first line
; to be drawn in output
%if 0
C-pseudo code
void Render_Offset_8x8_Run
(BGTABLE *bgtable, UINT8 *output, int vmapoffset, int nextpixel,
int numpixels,
void (**plotter_table)(UINT16 *offset_screen_address, int tile_offset,
UINT8 tilecount, UINT8 *output))
)
{
UINT16 *offset_screen_address;
int tile_offset = (nextpixel + (bgtable->hscroll & 7)) / 8;
output += nextpixel;
nextpixel += (bgtable->hscroll & 7) + bg3table.hscroll & 0xF8;
if (nextpixel < 0x108)
{
offset_screen_address = (UINT16 *) (bg3table.vlmapaddress + vmapoffset +
nextpixel / 8 * 2 - (tile_offset ? 2 : 0));
}
else
{
nextpixel -= 0x100;
offset_screen_address = (UINT16 *) (bg3table.vrmapaddress + vmapoffset +
nextpixel / 8 * 2 - (tile_offset ? 2 : 0));
}
nextpixel -= 8;
if (nextpixel & 7)
{
output -= nextpixel & 7;
TileClip1Left = *(UINT32 *)(ClipLeftTable - (nextpixel & 7));
TileClip1Right = *(UINT32 *)(ClipLeftTable - (nextpixel & 7) + 4);
if (numpixels < 8 - (nextpixel & 7))
{
TileClip1Left &=
*(UINT32 *)(ClipRightTable - ((nextpixel & 7) + numpixels));
TileClip1Right &=
*(UINT32 *)(ClipRightTable - ((nextpixel & 7) + numpixels) + 4);
}
plotter_table[(tile_offset ? 1 : 0](offset_screen_address, tile_offset,
1, output);
if (numpixels <= 0) return;
if (tile_offset) offset_screen_address ++;
tile_offset ++;
output += 8;
nextpixel += 8 - (nextpixel & 7);
numpixels -= 8 - (nextpixel & 7);
}
TileClip1Left = TileClip1Right = -1;
if (nextpixel != 0x100)
{
UINT8 runlength;
if (numpixels < 0x100 - nextpixel)
{
runlength = numpixels & ~7;
if (!runlength)
{
TileClip1Left &=
*(UINT32 *)(ClipRightTable - numpixels);
TileClip1Right &=
*(UINT32 *)(ClipRightTable - numpixels + 4);
plotter_table[(tile_offset ? 1 : 0](offset_screen_address, tile_offset,
1, output);
return;
}
}
else
{
runlength = 0x100 - nextpixel;
}
plotter_table[(tile_offset ? 1 : 0](offset_screen_address, tile_offset,
runlength / 8, output);
numpixels -= runlength;
if (!numpixels) return;
offset_screen_address += runlength / 8;
tile_offset += runlength / 8;
output += runlength;
nextpixel += runlength;
if (nextpixel < 0x100)
{
TileClip1Left &=
*(UINT32 *)(ClipRightTable - numpixels);
TileClip1Right &=
*(UINT32 *)(ClipRightTable - numpixels + 4);
plotter_table[1](offset_screen_address, tile_offset,
1, output);
return;
}
}
screen_address = (UINT16 *) (bgtable->vrmapaddress + vmapoffset);
if (numpixels >= 8)
{
plotter_table[1](offset_screen_address, tile_offset,
numpixels / 8, output);
if (!(numpixels & 7)) return;
screen_address += numpixels / 8;
tile_offset += numpixels / 8;
output += numpixels & ~7;
}
TileClip1Left &=
*(UINT32 *)(ClipRightTable - (numpixels & 7));
TileClip1Right &=
*(UINT32 *)(ClipRightTable - (numpixels & 7) + 4);
plotter_table[1](offset_screen_address, tile_offset,
1, output);
}
%endif
ALIGNC
Render_Offset_8x8_Run:
mov ecx,[HScroll_3]
mov eax,[RO8x8R_Next_Pixel+RO8x8R_Inner]
mov ebx,[HScroll+edx]
and ecx,0xF8
and ebx,byte 7
add edi,eax ;first pixel
add ebx,eax
add ecx,ebx
mov eax,[VLMapAddressBG3]
mov edx,[RO8x8R_VMapOffset+RO8x8R_Inner]
cmp ecx,0x108
jb .do_before_wrap
sub ecx,0x100
mov eax,[VRMapAddressBG3]
.do_before_wrap:
shr ebx,3
mov ebp,ecx
add eax,edx
shr ebp,3 ;(nextpixel / 8)
add ebx,byte -1
;hscroll + first pixel, relative to screen of first tile to be plotted
sbb edx,edx
sub ecx,byte 8
inc ebx
mov [RO8x8R_Next_Pixel+RO8x8R_Inner],ecx
add ebx,ebx
and edx,byte 2
lea esi,[eax+ebp*2]
sub esi,edx
add edx,edx
and ecx,byte 7
jz .do_unclipped_before_wrap
sub edi,ecx
sub ecx,byte 8
sub [RO8x8R_Next_Pixel+RO8x8R_Inner],ecx ;nextpixel += 8 - (nextpixel & 7)
add [RO8x8R_Pixel_Count+RO8x8R_Inner],ecx ;count -= 8 - (nextpixel & 7)
xor ecx,byte 7
mov eax,[ClipLeftTable+ecx+1] ;ClipLeftTable[-(nextpixel & 7)]
mov [TileClip1Left],eax
mov eax,[ClipLeftTable+ecx+1+4]
mov [TileClip1Right],eax
sub ecx,[RO8x8R_Pixel_Count+RO8x8R_Inner]
cmp dword [RO8x8R_Pixel_Count+RO8x8R_Inner],0
jl .clippedboth
jz .last_tile
mov cl,1
mov eax,[RO8x8R_Plotter_Table+RO8x8R_Inner]
; ch contains bit for determining planes to affect
mov ch,[RO8x8_OC_Flag+RO8x8R_Inner]
call [eax+edx]
mov edx,4
.do_unclipped_before_wrap:
mov eax,-1
mov ecx,0x100
mov ebp,[RO8x8R_Next_Pixel+RO8x8R_Inner]
mov [TileClip1Left],eax
sub ecx,ebp
mov [TileClip1Right],eax
jz .do_unclipped_after_wrap
mov eax,[RO8x8R_Pixel_Count+RO8x8R_Inner]
cmp ecx,eax
jbe .goodcountunclippedleft
mov ecx,eax
and ecx,byte ~7
jz .clipped_last_before_wrap
.goodcountunclippedleft:
sub eax,ecx ;count -= pixels in unclipped tiles in left run
add [RO8x8R_Next_Pixel+RO8x8R_Inner],ecx ;nextpixel += 8 - (nextpixel & 7)
shr ecx,3
test eax,eax
jz .last_run
mov [RO8x8R_Pixel_Count+RO8x8R_Inner],eax
mov eax,[RO8x8R_Plotter_Table+RO8x8R_Inner]
; ch contains bit for determining planes to affect
mov ch,[RO8x8_OC_Flag+RO8x8R_Inner]
call [eax+edx]
mov ebp,[RO8x8R_Next_Pixel+RO8x8R_Inner]
cmp ebp,0x100
jae .do_unclipped_after_wrap
.clipped_last_before_wrap:
mov ecx,[RO8x8R_Pixel_Count+RO8x8R_Inner]
jmp .do_clipped_last_tile
.do_unclipped_after_wrap:
mov eax,[RO8x8R_Pixel_Count+RO8x8R_Inner]
mov esi,[RO8x8R_VMapOffset+RO8x8R_Inner]
mov ecx,eax
mov ebp,[VRMapAddressBG3]
add esi,ebp
shr eax,3
jz .do_clipped_last_tile
mov edx,4
test ecx,7
mov ecx,eax
jz .last_run
mov eax,[RO8x8R_Plotter_Table+RO8x8R_Inner]
; ch contains bit for determining planes to affect
mov ch,[RO8x8_OC_Flag+RO8x8R_Inner]
call [eax+edx]
mov ecx,[RO8x8R_Pixel_Count+RO8x8R_Inner]
.do_clipped_last_tile:
and ecx,byte 7
mov edx,4
xor ecx,byte -1
.clippedboth:
; ClipRightTable[-((nextpixel & 7) + pixel_count)]
mov eax,[ClipRightTable+ecx+1]
and [TileClip1Left],eax
mov eax,[ClipRightTable+ecx+1+4]
and [TileClip1Right],eax
.last_tile:
mov cl,1
.last_run:
mov eax,[RO8x8R_Plotter_Table+RO8x8R_Inner]
; ch contains bit for determining planes to affect
mov ch,[RO8x8_OC_Flag+RO8x8R_Inner]
call [eax+edx]
ret
; -Tile on left edge of screen not affected by V-offset change
; -Offset change map is scrollable - always 8x8
%macro Render_Offset_8x8 1
ALIGNC
EXPORT_C Render_Offset_8x8_C%1
%ifndef NO_OFFSET_CHANGE
%ifndef NO_OFFSET_CHANGE_DISABLE
cmp byte [C_LABEL(Offset_Change_Disable)],0 ; Hack to disable offset change
jnz C_LABEL(Render_8x8_C%1)
%endif ; !NO_OFFSET_CHANGE_DISABLE
%else ; NO_OFFSET_CHANGE
jmp C_LABEL(Render_8x8_C%1)
%endif ; NO_OFFSET_CHANGE
%ifdef OFFSET_CHANGE_ELIMINATION
%if %1 == 4 ;mode 2: 4-plane tiles, split offset table
mov cl,[OffsetChangeDetect3]
test cl,[OC_Flag+edx]
jz C_LABEL(Render_8x8_C%1)
%else ;mode 4: 2- and 8-plane tiles, unified offset table
mov cl,[OffsetChangeDetect1]
test cl,[OC_Flag+edx]
jz C_LABEL(Render_8x8_C%1)
%endif
%endif
cmp byte [Mosaic+edx],0
jnz C_LABEL(Render_Offset_8x8M_C%1)
%ifndef NO_NP_RENDER
mov ecx,C_LABEL(Plot_Lines_NP_Offset_8x8_Table_C%1)
test al,al
jnz .have_plotter
%endif
mov ecx,C_LABEL(Plot_Lines_V_Offset_8x8_Table_C%1)
.have_plotter:
jmp Render_Offset_8x8_Base
%endmacro
Render_Offset_8x8 2
Render_Offset_8x8 4
Render_Offset_8x8 8
ALIGNC
Render_Offset_8x8_Base:
push ecx
push esi
push edx ;BG_Table
push ebx ;Current_Line
push edi ;BaseDestPtr
push ebp ;Lines
sub esp,byte RO8x8_Local_Bytes-24
; ch contains bit for determining planes to affect
mov ch,[OC_Flag+edx]
mov eax,[SetAddress+edx]
mov [RO8x8_OC_Flag],ch
mov [TilesetAddress],eax
.next_line:
mov edx,[RO8x8_BG_Table]
mov eax,[RO8x8_Current_Line]
call Sort_Screen_Height
mov eax,[RO8x8_Current_Line]
SORT_TILES_8_TALL [RO8x8_MapAddress_Current]
; Corrupts eax,ecx,ebp
mov eax,[TLMapAddress+edx]
mov ecx,[RO8x8_Current_Line]
mov edi,[BLMapAddress+edx]
mov ebp,[VScroll+edx]
mov [RO8x8_TMapAddress],eax
add ecx,ebp
mov [RO8x8_BMapAddress],edi
mov ebp,[RO8x8_MapAddress_Current]
and ch,1
;global Tile_Height
;Tile_Height equ $-1 ; 1 = 8x8, 16x8, 2 = 16x16
jz .current_line_in_screen_map_top
mov eax,edi
.current_line_in_screen_map_top:
add eax,ebp
mov ebp,[HScroll+edx]
mov [RO8x8_MapAddress_Current],eax
shr ebp,3
mov eax,[TRMapAddress+edx]
add ebp,ebp
mov ecx,[TLMapAddress+edx]
mov [RO8x8_FirstTile],ebp ;FirstTile = (HScroll / 8) * 2
sub eax,ecx
mov [RO8x8_RMapDifference],eax
mov eax,[C_LABEL(SNES_Screen8)]
mov edi,[RO8x8_BaseDestPtr]
add edi,eax
mov esi,[RO8x8_Clipped]
mov al,[Win_Count+edx+esi]
test al,al
jz .done
mov ebx,[OffsetChangeMap_VOffset]
mov [RO8x8_Runs_Left],eax
lea edx,[Win_Bands+edx+esi]
mov [RO8x8_Output],edi
mov [RO8x8_RunListPtr],edx
mov [RO8x8R_VMapOffset],ebx ;vertical screen map address
xor ebx,ebx
;mov [RO8x8R_Plotter_Table],ecx ;renderer
mov bl,[edx]
xor ecx,ecx
mov cl,[edx+1]
mov edx,[RO8x8_BG_Table]
sub cl,bl
setz ch
mov [RO8x8R_Next_Pixel],ebx
mov [RO8x8R_Pixel_Count],ecx
dec al
je .last_run
.not_last_run:
mov [RO8x8_Runs_Left],al
call Render_Offset_8x8_Run
mov edx,[RO8x8_RunListPtr]
mov edi,[RO8x8_Output]
xor ebx,ebx
xor ecx,ecx
mov bl,[edx+2]
mov cl,[edx+3]
add edx,byte 2
sub cl,bl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -