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

📄 bg16.asm

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

%include "misc.inc"
%include "ppu/ppu.inc"
%include "ppu/tiles.inc"
%include "ppu/screen.inc"


%define R16x16R_VMapOffset esp+16
%define R16x16R_Plotter_Table esp+12
%define R16x16R_BG_Table esp+8
%define R16x16R_Next_Pixel esp+4
%define R16x16R_Pixel_Count esp
%define R16x16R_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_16x16_Run
(BGTABLE *bgtable, UINT8 *output, int vmapoffset, int nextpixel,
 int numpixels,
 void (**plotter_table)(UINT16 *screen_address, UINT8 tilecount,
 UINT8 *output))
)
{
 UINT16 *screen_address;

 output += nextpixel;

 nextpixel += bgtable->hscroll & 0x1FF;
 if (nextpixel < 0x200)
 {
  screen_address = (UINT16 *) (bgtable->vlmapaddress + vmapoffset +
   nextpixel / 16 * 2);
 }
 else
 {
  nextpixel -= 0x200;
  screen_address = (UINT16 *) (bgtable->vrmapaddress + vmapoffset +
   nextpixel / 16 * 2);
 }

 if (nextpixel & 15)
 {
  output -= nextpixel & 15;
  TileClip1Left = *(UINT32 *)(ClipLeftTable - (nextpixel & 15));
  TileClip1Right = *(UINT32 *)(ClipLeftTable - (nextpixel & 15) + 4);
  TileClip2Left = *(UINT32 *)(ClipLeftTable - (nextpixel & 15) + 8);
  TileClip2Right = *(UINT32 *)(ClipLeftTable - (nextpixel & 15) + 12);

  if (numpixels < 16 - (nextpixel & 15))
  {
   TileClip1Left &=
    *(UINT32 *)(ClipRightTable - ((nextpixel & 15) + numpixels));
   TileClip1Right &=
    *(UINT32 *)(ClipRightTable - ((nextpixel & 15) + numpixels) + 4);
   TileClip2Left &=
    *(UINT32 *)(ClipRightTable - ((nextpixel & 15) + numpixels) + 8);
   TileClip2Right &=
    *(UINT32 *)(ClipRightTable - ((nextpixel & 15) + numpixels) + 12);
  }

  plotter_table[(nextpixel & 8) >> 2](screen_address, 2, output);

  if (numpixels <= 0) return;

  screen_address ++;
  output += 16;
  nextpixel += 16 - (nextpixel & 15);
  numpixels -= 16 - (nextpixel & 15);
 }

 TileClip1Left = TileClip1Right = TileClip2Left = TileClip2Right = -1;

 if (nextpixel != 0x200)
 {
  UINT8 runlength;
  if (numpixels < 0x200 - nextpixel)
  {
   runlength = numpixels & ~15;
   if (!runlength)
   {
    TileClip1Left &=
     *(UINT32 *)(ClipRightTable - numpixels);
    TileClip1Right &=
     *(UINT32 *)(ClipRightTable - numpixels + 4);
    TileClip2Left &=
     *(UINT32 *)(ClipRightTable - numpixels + 8);
    TileClip2Right &=
     *(UINT32 *)(ClipRightTable - numpixels + 12);
    plotter_table(screen_address, 2, output);
    return;
   }
  }
  else
  {
   runlength = 0x200 - nextpixel;
  }

  plotter_table(screen_address, runlength / 8, output);
  numpixels -= runlength;
  if (!numpixels) return;

  screen_address += runlength / 8;
  output += runlength;
  nextpixel += runlength;

  if (nextpixel < 0x200)
  {
   TileClip1Left &=
    *(UINT32 *)(ClipRightTable - numpixels);
   TileClip1Right &=
    *(UINT32 *)(ClipRightTable - numpixels + 4);
   TileClip1Left &=
    *(UINT32 *)(ClipRightTable - numpixels + 8);
   TileClip1Right &=
    *(UINT32 *)(ClipRightTable - numpixels + 12);
   plotter_table(screen_address, 2, output);
   return;
  }
 }

 screen_address = (UINT16 *) (bgtable->vrmapaddress + vmapoffset);
 if (numpixels >= 8)
 {
  plotter_table(screen_address, numpixels / 8, output);
  if (!(numpixels & 15)) return;
  screen_address += numpixels / 8;
  output += numpixels & ~15;
 }

 TileClip1Left &=
  *(UINT32 *)(ClipRightTable - (numpixels & 15));
 TileClip1Right &=
  *(UINT32 *)(ClipRightTable - (numpixels & 15) + 4);
 TileClip2Left &=
  *(UINT32 *)(ClipRightTable - (numpixels & 15) + 8);
 TileClip2Right &=
  *(UINT32 *)(ClipRightTable - (numpixels & 15) + 12);
 plotter_table(screen_address, 2, output);
}
%endif
ALIGNC
Render_16x16_Run:
 mov ecx,[HScroll+edx]
 mov eax,[R16x16R_Next_Pixel+R16x16R_Inner]
 and ecx,0x1FF

 add edi,eax    ;first pixel
 add ecx,eax

 mov eax,[VLMapAddress+edx]
 mov ebx,[R16x16R_VMapOffset+R16x16R_Inner]
 cmp ecx,0x200
 jb .do_before_wrap
 sub ecx,0x200
 mov eax,[VRMapAddress+edx]
.do_before_wrap:

 mov ebp,ecx
 add ebx,eax

 shr ebp,4      ;(nextpixel / 16)

 ;hscroll + first pixel, relative to screen of first tile to be plotted
 mov [R16x16R_Next_Pixel+R16x16R_Inner],ecx
 and ecx,byte 15
 lea ebx,[ebx+ebp*2]
 jz .do_unclipped_before_wrap

 sub edi,ecx
 sub ecx,byte 16

 sub [R16x16R_Next_Pixel+R16x16R_Inner],ecx ;nextpixel += 16 - (nextpixel & 15)
 mov esi,[R16x16R_Pixel_Count+R16x16R_Inner]
 add [R16x16R_Pixel_Count+R16x16R_Inner],ecx    ;count -= 16 - (nextpixel & 15)
 xor ecx,byte 15

 mov eax,[ClipLeftTable+ecx+1]      ;ClipLeftTable[-(nextpixel & 15)]
 mov [TileClip1Left],eax
 mov eax,[ClipLeftTable+ecx+1+4]
 mov [TileClip1Right],eax
 mov eax,[ClipLeftTable+ecx+1+8]
 mov [TileClip2Left],eax
 mov eax,[ClipLeftTable+ecx+1+12]
 mov [TileClip2Right],eax
 lea eax,[ecx+8+1]
 sub ecx,esi
 and eax,byte 8
 mov esi,[R16x16R_Plotter_Table+R16x16R_Inner]
 add esi,eax

 cmp dword [R16x16R_Pixel_Count+R16x16R_Inner],0
 jl .clippedboth
 jz .last_tile

 mov cl,2
 call [esi]

.do_unclipped_before_wrap:
 mov eax,-1
 mov ecx,0x200
 mov ebp,[R16x16R_Next_Pixel+R16x16R_Inner]
 mov [TileClip1Left],eax
 sub ecx,ebp
 mov [TileClip1Right],eax
 mov [TileClip2Left],eax
 mov [TileClip2Right],eax
 jz .do_unclipped_after_wrap

 mov eax,[R16x16R_Pixel_Count+R16x16R_Inner]
 cmp ecx,eax
 jbe .goodcountunclippedleft

 mov ecx,eax
 and ecx,byte ~15
 jz .clipped_last_before_wrap

.goodcountunclippedleft:
 sub eax,ecx    ;count -= pixels in unclipped tiles in left run
 add [R16x16R_Next_Pixel+R16x16R_Inner],ecx ;nextpixel += 16 - (nextpixel & 15)
 mov edx,ecx
 shr ecx,3

 mov esi,[R16x16R_Plotter_Table+R16x16R_Inner]

 test eax,eax
 jz .last_run
 mov [R16x16R_Pixel_Count+R16x16R_Inner],eax
 call [esi]

 mov ebp,[R16x16R_Next_Pixel+R16x16R_Inner]
 cmp ebp,0x200
 jae .do_unclipped_after_wrap

.clipped_last_before_wrap:
 mov ecx,[R16x16R_Pixel_Count+R16x16R_Inner]
 jmp .do_clipped_last_tile

.do_unclipped_after_wrap:
 mov edx,[R16x16R_BG_Table+R16x16R_Inner]
 mov eax,[R16x16R_Pixel_Count+R16x16R_Inner]
 mov esi,[R16x16R_VMapOffset+R16x16R_Inner]
 mov ecx,eax
 mov ebx,[VRMapAddress+edx]
 add ebx,esi
 shr eax,4
 jz .do_clipped_last_tile

 add eax,eax

 test ecx,15
 mov esi,[R16x16R_Plotter_Table+R16x16R_Inner]
 mov ecx,eax
 jz .last_run

 call [esi]

 mov ecx,[R16x16R_Pixel_Count+R16x16R_Inner]

.do_clipped_last_tile:
 and ecx,byte 15
 xor ecx,byte -1

 mov esi,[R16x16R_Plotter_Table+R16x16R_Inner]

.clippedboth:
 ; ClipRightTable[-((nextpixel & 15) + pixel_count)]
 mov eax,[ClipRightTable+ecx+1]
 and [TileClip1Left],eax
 mov eax,[ClipRightTable+ecx+1+4]
 and [TileClip1Right],eax
 mov eax,[ClipRightTable+ecx+1+8]
 and [TileClip2Left],eax
 mov eax,[ClipRightTable+ecx+1+12]
 and [TileClip2Right],eax

.last_tile:
 mov cl,2
.last_run:
 jmp [esi]

%define R16x16_Local_Bytes 24
%define R16x16_Plotter_Table esp+20
%define R16x16_Clipped esp+16
%define R16x16_BG_Table esp+12
%define R16x16_Current_Line esp+8
%define R16x16_BaseDestPtr esp+4
%define R16x16_Lines esp

%macro Render_16x16 1
ALIGNC
EXPORT_C Render_16x16_C%1
 cmp byte [Mosaic+edx],0
 jnz C_LABEL(Render_16x16M_C%1)

%if %1 == 2
 mov ecx,[M0_Color+edx]
 mov [Palette_Base],ecx
%endif

%ifndef NO_NP_RENDER
 mov ecx,C_LABEL(Plot_Lines_NP_16x16_Table_C%1)
 test al,al
 jnz .have_plotter
%endif

 mov ecx,C_LABEL(Plot_Lines_V_16x16_Table_C%1)

.have_plotter:
 jmp Render_16x16_Base
%endmacro

Render_16x16 2
Render_16x16 4
Render_16x16 8

ALIGNC
Render_16x16_Base:
 push ecx
 push esi
 push edx
 push ebx
 push edi
 push ebp

 mov ecx,[SetAddress+edx]
 mov [TilesetAddress],ecx

.next_line:
 mov edx,[R16x16_BG_Table]

 mov eax,[R16x16_Current_Line]
 call Sort_Screen_Height

 mov eax,[R16x16_Current_Line]
 SORT_TILES_16_TALL
 mov ebp,[R16x16_Lines] ;*
 and esi,byte 7
;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,[R16x16_BaseDestPtr]
 mov eax,ebp
 shl eax,8
 lea ecx,[edi+ebp*GfxBufferLineSlack]
 add eax,ecx

 mov ecx,[R16x16_Plotter_Table]

 mov [BGLineCount],ebp ;*
 cmp ebp,byte 1
 mov [R16x16_BaseDestPtr],eax
 sbb ebp,ebp
 mov eax,[C_LABEL(SNES_Screen8)]
 add edi,eax
 lea ecx,[ecx+ebp*4+4]

 mov esi,[R16x16_Clipped]
 mov al,[Win_Count+edx+esi]

 test al,al
 jz .done

 push eax
 lea edx,[Win_Bands+edx+esi]

 push edi
 push edx
 push ebx       ;vertical screen map address
 xor ebx,ebx
 push ecx       ;renderer
 mov bl,[edx]

 xor ecx,ecx
 mov cl,[edx+1]
 mov edx,[R16x16_BG_Table+20]
 sub cl,bl
 setz ch

 push edx
 push ebx
 push ecx

 dec al
 je .last_run

.not_last_run:
 mov [esp+28],al
 call Render_16x16_Run

 mov edx,[esp+20]
 mov edi,[esp+24]
 xor ebx,ebx
 xor ecx,ecx
 mov bl,[edx+2]

 mov cl,[edx+3]
 add edx,byte 2
 sub cl,bl
 mov [esp+20],edx
 mov edx,[esp+8]

 mov [esp+4],ebx
 mov [esp],ecx

 mov al,[esp+28]
 dec al
 jne .not_last_run
.last_run:
 call Render_16x16_Run
 add esp,byte 32

.done:

 mov ebp,[BGLineCount] ;*
 mov eax,[R16x16_Current_Line]
 mov ecx,[R16x16_Lines]
 add eax,ebp
 sub ecx,ebp
 mov [R16x16_Current_Line],eax
 mov [R16x16_Lines],ecx

%ifndef LAYERS_PER_LINE
;cmp dword [R16x16_Lines],0
 jnz .next_line
%endif

 mov edx,[R16x16_BG_Table]
 mov al,[Tile_Priority_Used]
 mov [Priority_Used+edx],al
 mov ah,[Tile_Priority_Unused]
 mov [Priority_Unused+edx],ah

 add esp,byte R16x16_Local_Bytes
 ret

;%1 = label, %2 = priority - 0 = none, 1 = low, 2 = high, %3 = multi-line
%macro Plot_Lines_16x16_C2 2-3 1
%if %2 > 0
%%return:
 ret

ALIGNC
%1_check:
%if %2 == 1 || %2 == 3
 mov [Tile_Priority_Unused],cl
%endif
 add ebx,byte 2     ; Update screen pointer
 add edi,byte 16
 sub cl,2
 jle %%return
%else
ALIGNC
%endif

EXPORT_C %1     ; Define label, entry point
%%next_tile:
 mov al,[ebx+1]

 Check_Tile_Priority %2, %1_check

%if %3
 push ecx
 mov ecx,-1
%endif
 mov ebp,[LineAddressY]
 test al,al         ; Check Y flip
 mov si,[ebx]       ; Get tile #
 js %%flip_y
 mov ebp,[LineAddress]
%if %3
 add ecx,byte (1 * 2)
%endif

%%flip_y:
 shl esi,3
 mov edx,eax
 add esi,ebp
 and edx,byte 7*4   ; Get palette
 add ebx,byte 2     ; Update screen pointer
 mov ebp,[Palette_Base]
 mov edx,[palette_2bpl+edx]
 or ebp,edx         ; Adjust palette for mode 0
 mov edx,[TilesetAddress]
 add al,al      ; Get X flip (now in MSB)

%if %3
 push ebx
 mov ebx,[BGLineCount]
%endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -