📄 bg8.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_bg8_asm
%include "misc.inc"
%include "ppu/ppu.inc"
%include "ppu/tiles.inc"
%include "ppu/screen.inc"
%define R8x8_Local_Bytes_H 56
%define R8x8_Local_Bytes 52
%define R8x8_Plotter_Table_NP esp+52
%define R8x8_Plotter_Table esp+48
%define R8x8_Clipped esp+44
%define R8x8_BG_Table esp+40
%define R8x8_Current_Line esp+36
%define R8x8_BaseDestPtr esp+32
%define R8x8_Lines esp+28
%define R8x8_Runs_Left esp+24
%define R8x8_Output esp+20
%define R8x8_RunListPtr esp+16
%define R8x8R_VMapOffset esp+12
%define R8x8R_Plotter esp+8
%define R8x8R_BG_Table R8x8_BG_Table
%define R8x8R_Next_Pixel esp+4
%define R8x8R_Pixel_Count esp
%define R8x8R_Inner (4)
;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)
; 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_8x8_Run
(BGTABLE *bgtable, UINT8 *output, int vmapoffset, int nextpixel,
int numpixels,
void (*plotter)(UINT16 *screen_address, UINT8 tilecount, UINT8 *output))
)
{
UINT16 *screen_address;
output += nextpixel;
nextpixel += bgtable->hscroll & 0xFF;
if (nextpixel < 0x100)
{
screen_address = (UINT16 *) (bgtable->vlmapaddress + vmapoffset +
nextpixel / 8 * 2);
}
else
{
nextpixel -= 0x100;
screen_address = (UINT16 *) (bgtable->vrmapaddress + vmapoffset +
nextpixel / 8 * 2);
}
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(screen_address, 1, output);
if (numpixels <= 0) return;
screen_address ++;
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(screen_address, 1, output);
return;
}
}
else
{
runlength = 0x100 - nextpixel;
}
plotter(screen_address, runlength / 8, output);
numpixels -= runlength;
if (!numpixels) return;
screen_address += runlength / 8;
output += runlength;
nextpixel += runlength;
if (nextpixel < 0x100)
{
TileClip1Left &=
*(UINT32 *)(ClipRightTable - numpixels);
TileClip1Right &=
*(UINT32 *)(ClipRightTable - numpixels + 4);
plotter(screen_address, 1, output);
return;
}
}
screen_address = (UINT16 *) (bgtable->vrmapaddress + vmapoffset);
if (numpixels >= 8)
{
plotter(screen_address, numpixels / 8, output);
if (!(numpixels & 7)) return;
screen_address += numpixels / 8;
output += numpixels & ~7;
}
TileClip1Left &=
*(UINT32 *)(ClipRightTable - (numpixels & 7));
TileClip1Right &=
*(UINT32 *)(ClipRightTable - (numpixels & 7) + 4);
plotter(screen_address, 1, output);
}
%endif
ALIGNC
Render_8x8_Run:
xor ecx,ecx
mov eax,[R8x8R_Next_Pixel+R8x8R_Inner]
mov cl,[HScroll+edx]
add edi,eax ;first pixel
add ecx,eax
mov eax,[VLMapAddress+edx]
mov ebx,[R8x8R_VMapOffset+R8x8R_Inner]
cmp ecx,0x100
jb .do_before_wrap
sub ecx,0x100
mov eax,[VRMapAddress+edx]
.do_before_wrap:
mov ebp,ecx
add ebx,eax
shr ebp,3 ;(nextpixel / 8)
;hscroll + first pixel, relative to screen of first tile to be plotted
mov [R8x8R_Next_Pixel+R8x8R_Inner],ecx
and ecx,byte 7
lea ebx,[ebx+ebp*2]
jz .do_unclipped_before_wrap
sub edi,ecx
sub ecx,byte 8
sub [R8x8R_Next_Pixel+R8x8R_Inner],ecx ;nextpixel += 8 - (nextpixel & 7)
mov esi,[R8x8R_Pixel_Count+R8x8R_Inner]
add [R8x8R_Pixel_Count+R8x8R_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,esi
cmp dword [R8x8R_Pixel_Count+R8x8R_Inner],0
jl .clippedboth
jz .last_tile
mov cl,1
call [R8x8R_Plotter+R8x8R_Inner]
.do_unclipped_before_wrap:
mov eax,-1
mov ecx,0x100
mov ebp,[R8x8R_Next_Pixel+R8x8R_Inner]
mov [TileClip1Left],eax
sub ecx,ebp
mov [TileClip1Right],eax
jz .do_unclipped_after_wrap
mov eax,[R8x8R_Pixel_Count+R8x8R_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 [R8x8R_Next_Pixel+R8x8R_Inner],ecx ;nextpixel += 8 - (nextpixel & 7)
shr ecx,3
test eax,eax
jz .last_run
mov [R8x8R_Pixel_Count+R8x8R_Inner],eax
call [R8x8R_Plotter+R8x8R_Inner]
mov ebp,[R8x8R_Next_Pixel+R8x8R_Inner]
cmp ebp,0x100
jae .do_unclipped_after_wrap
.clipped_last_before_wrap:
mov ecx,[R8x8R_Pixel_Count+R8x8R_Inner]
jmp .do_clipped_last_tile
.do_unclipped_after_wrap:
mov edx,[R8x8R_BG_Table+R8x8R_Inner]
mov eax,[R8x8R_Pixel_Count+R8x8R_Inner]
mov esi,[R8x8R_VMapOffset+R8x8R_Inner]
mov ecx,eax
mov ebx,[VRMapAddress+edx]
add ebx,esi
shr eax,3
jz .do_clipped_last_tile
test ecx,7
mov ecx,eax
jz .last_run
call [R8x8R_Plotter+R8x8R_Inner]
mov ecx,[R8x8R_Pixel_Count+R8x8R_Inner]
.do_clipped_last_tile:
and ecx,byte 7
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:
jmp [R8x8R_Plotter+R8x8R_Inner]
%macro Render_8x8 1
ALIGNC
EXPORT_C Render_8x8_C%1
cmp byte [Mosaic+edx],0
jnz C_LABEL(Render_8x8M_C%1)
%if %1 == 2
mov ecx,[M0_Color+edx]
mov [Palette_Base],ecx
%endif
mov ecx,C_LABEL(Plot_Lines_V_8x8_Table_C%1)
test al,al
jnz .plotter_high
cmp byte [Tile_priority_bit],0
jnz Render_8x8_Low
.plotter_high:
push dword C_LABEL(Plot_Lines_NP_8x8_Table_C%1)
jmp Render_8x8_High
%endmacro
Render_8x8 2
Render_8x8 4
Render_8x8 8
;%1 = label, %2 = priority
%macro Render_8x8_Base 2
ALIGNC
%1:
push ecx
push esi
push edx ;BG_Table
push ebx ;Current_Line
push edi ;BaseDestPtr
push ebp ;Lines
sub esp,byte R8x8_Local_Bytes-24
mov eax,[SetAddress+edx]
mov [TilesetAddress],eax
.next_line:
mov edx,[R8x8_BG_Table]
mov eax,[R8x8_Current_Line]
%if %2 > 0
mov cl,[Priority_Unused+edx+eax*2]
test cl,cl
jz .no_plot
%endif
call Sort_Screen_Height
%if %2 == 0
xor eax,eax
mov [Tile_Priority_Used],ax
%endif
mov eax,[R8x8_Current_Line]
SORT_TILES_8_TALL
mov ebp,[R8x8_Lines] ;*
;cmp ebp,byte 1
;je .no_multi
;esi = 7 - ((VScroll + Current_Line) & 7)
cmp esi,ebp
jae .no_multi
lea ebp,[esi+1]
.no_multi:
mov edi,[R8x8_BaseDestPtr]
%if %2 > 0
mov esi,[R8x8_Current_Line]
%endif
mov eax,ebp
shl eax,8
lea ecx,[edi+ebp*GfxBufferLineSlack]
add eax,ecx
%if %2 == 0
mov ecx,[R8x8_Plotter_Table]
%else
mov cl,[Priority_Used+edx+esi*2]
cmp cl,1
mov ecx,[R8x8_Plotter_Table_NP]
jc .plotter_np
mov ecx,[R8x8_Plotter_Table]
.plotter_np:
%endif
mov [BGLineCount],ebp ;*
cmp ebp,byte 1
mov [R8x8_BaseDestPtr],eax
sbb ebp,ebp
mov eax,[C_LABEL(SNES_Screen8)]
add edi,eax
mov ecx,[ecx+ebp*4+4]
mov esi,[R8x8_Clipped]
mov al,[Win_Count+edx+esi]
test al,al
jz .done
mov [R8x8_Runs_Left],eax
lea edx,[Win_Bands+edx+esi]
mov [R8x8_Output],edi
mov [R8x8_RunListPtr],edx
mov [R8x8R_VMapOffset],ebx ;vertical screen map address
xor ebx,ebx
mov [R8x8R_Plotter],ecx ;renderer
mov bl,[edx]
xor ecx,ecx
mov cl,[edx+1]
mov edx,[R8x8_BG_Table]
sub cl,bl
setz ch
mov [R8x8R_Next_Pixel],ebx
mov [R8x8R_Pixel_Count],ecx
dec al
je .last_run
.not_last_run:
mov [R8x8_Runs_Left],al
call Render_8x8_Run
mov edx,[R8x8_RunListPtr]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -