📄 bg16oe.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_bg16oe_asm
%include "misc.inc"
%include "ppu/ppu.inc"
%include "ppu/tiles.inc"
%include "ppu/screen.inc"
%define RO16E_Local_Bytes 56+24
%define RO16E_Plotter_Table esp+52+24
%define RO16E_Clipped esp+48+24
%define RO16E_BG_Table esp+44+24
%define RO16E_Current_Line esp+40+24
%define RO16E_BaseDestPtr esp+36+24
%define RO16E_Lines esp+32+24
; contains bit for determining planes to affect
%define RO16E_OC_Flag esp+28+24
; Same as LineAddress(Y), additional vars for offset change code
%define RO16E_LineAddressOffset esp+24+24
%define RO16E_LineAddressOffsetY esp+20+24
%define RO16E_FirstTile esp+16+24
; Scroll-adjusted tile map address for offset
; change code when tile offset not changed
%define RO16E_MapAddress_Current esp+12+24
%define RO16E_TMapAddress esp+8+24
%define RO16E_BMapAddress esp+4+24
%define RO16E_RMapDifference esp+24
%define RO16E_Runs_Left esp+20
%define RO16E_Output esp+16
%define RO16E_RunListPtr esp+12
%define RO16ER_VMapOffset esp+8
;VMapOffset can be eliminated by merging its value with VL/VRMapAddress?
%define RO16ER_Plotter_Table RO16E_Plotter_Table
%define RO16ER_BG_Table RO16E_BG_Table
%define RO16ER_Next_Pixel esp+4
%define RO16ER_Pixel_Count esp
%define RO16ER_Inner (4)
%define RO16E_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_16_Even_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_16_Even_Run:
mov ecx,[HScroll_3]
mov eax,[RO16ER_Next_Pixel+RO16ER_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,[RO16ER_VMapOffset+RO16ER_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 [RO16ER_Next_Pixel+RO16ER_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 [RO16ER_Next_Pixel+RO16ER_Inner],ecx ;nextpixel += 8 - (nextpixel & 7)
add [RO16ER_Pixel_Count+RO16ER_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,[RO16ER_Pixel_Count+RO16ER_Inner]
cmp dword [RO16ER_Pixel_Count+RO16ER_Inner],0
jl .clippedboth
jz .last_tile
mov cl,1
mov eax,[RO16ER_Plotter_Table+RO16ER_Inner]
; ch contains bit for determining planes to affect
mov ch,[RO16E_OC_Flag+RO16ER_Inner]
call [eax+edx]
mov edx,4
.do_unclipped_before_wrap:
mov eax,-1
mov ecx,0x100
mov ebp,[RO16ER_Next_Pixel+RO16ER_Inner]
mov [TileClip1Left],eax
sub ecx,ebp
mov [TileClip1Right],eax
jz .do_unclipped_after_wrap
mov eax,[RO16ER_Pixel_Count+RO16ER_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 [RO16ER_Next_Pixel+RO16ER_Inner],ecx ;nextpixel += 8 - (nextpixel & 7)
shr ecx,3
test eax,eax
jz .last_run
mov [RO16ER_Pixel_Count+RO16ER_Inner],eax
mov eax,[RO16ER_Plotter_Table+RO16ER_Inner]
; ch contains bit for determining planes to affect
mov ch,[RO16E_OC_Flag+RO16ER_Inner]
call [eax+edx]
mov ebp,[RO16ER_Next_Pixel+RO16ER_Inner]
cmp ebp,0x100
jae .do_unclipped_after_wrap
.clipped_last_before_wrap:
mov ecx,[RO16ER_Pixel_Count+RO16ER_Inner]
jmp .do_clipped_last_tile
.do_unclipped_after_wrap:
mov eax,[RO16ER_Pixel_Count+RO16ER_Inner]
mov esi,[RO16ER_VMapOffset+RO16ER_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,[RO16ER_Plotter_Table+RO16ER_Inner]
; ch contains bit for determining planes to affect
mov ch,[RO16E_OC_Flag+RO16ER_Inner]
call [eax+edx]
mov ecx,[RO16ER_Pixel_Count+RO16ER_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,[RO16ER_Plotter_Table+RO16ER_Inner]
; ch contains bit for determining planes to affect
mov ch,[RO16E_OC_Flag+RO16ER_Inner]
call [eax+edx]
ret
; -Tile on left edge of screen not affected by V-offset change
; -Offset change map is scrollable - always 8x8
;depth, tile height
%macro Render_Offset_16_Even 2
ALIGNC
EXPORT_C Render_Offset_16x%2_Even_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_16x%2_Even_C%1)
%endif ; !NO_OFFSET_CHANGE_DISABLE
%else ; NO_OFFSET_CHANGE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -