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

📄 bg16o.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_bg16o_asm

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


%define RO16x16_Local_Bytes 56+24
%define RO16x16_Plotter_Table esp+52+24
%define RO16x16_Clipped esp+48+24
%define RO16x16_BG_Table esp+44+24
%define RO16x16_Current_Line esp+40+24
%define RO16x16_BaseDestPtr esp+36+24
%define RO16x16_Lines esp+32+24

; contains bit for determining planes to affect
%define RO16x16_OC_Flag esp+28+24

; Same as LineAddress(Y), additional vars for offset change code
%define RO16x16_LineAddressOffset  esp+24+24
%define RO16x16_LineAddressOffsetY esp+20+24

%define RO16x16_FirstTile esp+16+24

; Scroll-adjusted tile map address for offset
;  change code when tile offset not changed
%define RO16x16_MapAddress_Current esp+12+24

%define RO16x16_TMapAddress esp+8+24
%define RO16x16_BMapAddress esp+4+24
%define RO16x16_RMapDifference esp+24

%define RO16x16_Runs_Left esp+20
%define RO16x16_Output esp+16
%define RO16x16_RunListPtr esp+12
%define RO16x16R_VMapOffset esp+8
;VMapOffset can be eliminated by merging its value with VL/VRMapAddress?

%define RO16x16R_Plotter_Table RO16x16_Plotter_Table
%define RO16x16R_BG_Table RO16x16_BG_Table
%define RO16x16R_Next_Pixel esp+4
%define RO16x16R_Pixel_Count esp
%define RO16x16R_Inner (4)
%define RO16x16_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_16x16_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_16x16_Run:
 mov ecx,[HScroll_3]

 mov eax,[RO16x16R_Next_Pixel+RO16x16R_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,[RO16x16R_VMapOffset+RO16x16R_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 [RO16x16R_Next_Pixel+RO16x16R_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 [RO16x16R_Next_Pixel+RO16x16R_Inner],ecx   ;nextpixel += 8 - (nextpixel & 7)
 add [RO16x16R_Pixel_Count+RO16x16R_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,[RO16x16R_Pixel_Count+RO16x16R_Inner]

 cmp dword [RO16x16R_Pixel_Count+RO16x16R_Inner],0
 jl .clippedboth
 jz .last_tile

 mov cl,1
 mov eax,[RO16x16R_Plotter_Table+RO16x16R_Inner]
 ; ch contains bit for determining planes to affect
 mov ch,[RO16x16_OC_Flag+RO16x16R_Inner]
 call [eax+edx]

 mov edx,4

.do_unclipped_before_wrap:
 mov eax,-1
 mov ecx,0x100
 mov ebp,[RO16x16R_Next_Pixel+RO16x16R_Inner]
 mov [TileClip1Left],eax
 sub ecx,ebp
 mov [TileClip1Right],eax
 jz .do_unclipped_after_wrap

 mov eax,[RO16x16R_Pixel_Count+RO16x16R_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 [RO16x16R_Next_Pixel+RO16x16R_Inner],ecx   ;nextpixel += 8 - (nextpixel & 7)
 shr ecx,3

 test eax,eax
 jz .last_run
 mov [RO16x16R_Pixel_Count+RO16x16R_Inner],eax

 mov eax,[RO16x16R_Plotter_Table+RO16x16R_Inner]
 ; ch contains bit for determining planes to affect
 mov ch,[RO16x16_OC_Flag+RO16x16R_Inner]
 call [eax+edx]

 mov ebp,[RO16x16R_Next_Pixel+RO16x16R_Inner]
 cmp ebp,0x100
 jae .do_unclipped_after_wrap

.clipped_last_before_wrap:
 mov ecx,[RO16x16R_Pixel_Count+RO16x16R_Inner]
 jmp .do_clipped_last_tile

.do_unclipped_after_wrap:
 mov eax,[RO16x16R_Pixel_Count+RO16x16R_Inner]
 mov esi,[RO16x16R_VMapOffset+RO16x16R_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,[RO16x16R_Plotter_Table+RO16x16R_Inner]
 ; ch contains bit for determining planes to affect
 mov ch,[RO16x16_OC_Flag+RO16x16R_Inner]
 call [eax+edx]

 mov ecx,[RO16x16R_Pixel_Count+RO16x16R_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,[RO16x16R_Plotter_Table+RO16x16R_Inner]
 ; ch contains bit for determining planes to affect
 mov ch,[RO16x16_OC_Flag+RO16x16R_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_16x16 1
ALIGNC
EXPORT_C Render_Offset_16x16_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_16x16_C%1)
%endif  ; !NO_OFFSET_CHANGE_DISABLE
%else   ; NO_OFFSET_CHANGE
 jmp C_LABEL(Render_16x16_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_16x16_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_16x16_C%1)
%endif
%endif

 cmp byte [Mosaic+edx],0
 jnz C_LABEL(Render_Offset_16x16M_C%1)

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

 mov ecx,C_LABEL(Plot_Lines_V_Offset_16x16_Table_C%1)
.have_plotter:

 jmp Render_Offset_16x16_Base
%endmacro

Render_Offset_16x16 2
Render_Offset_16x16 4
Render_Offset_16x16 8

ALIGNC
Render_Offset_16x16_Base:
 push ecx
 push esi
 push edx ;BG_Table
 push ebx ;Current_Line
 push edi ;BaseDestPtr
 push ebp ;Lines
 sub esp,byte RO16x16_Local_Bytes-24

 ; ch contains bit for determining planes to affect
 mov ch,[OC_Flag+edx]
 mov eax,[SetAddress+edx]
 mov [RO16x16_OC_Flag],ch
 mov [TilesetAddress],eax

.next_line:
 mov edx,[RO16x16_BG_Table]

 mov eax,[RO16x16_Current_Line]
 call Sort_Screen_Height

 mov eax,[RO16x16_Current_Line]
 SORT_TILES_16_TALL [RO16x16_MapAddress_Current]

 ; Corrupts eax,ecx,ebp
 mov eax,[TLMapAddress+edx]
 mov ecx,[RO16x16_Current_Line]
 mov edi,[BLMapAddress+edx]
 mov ebp,[VScroll+edx]
 mov [RO16x16_TMapAddress],eax
 add ecx,ebp
 mov [RO16x16_BMapAddress],edi
 mov ebp,[RO16x16_MapAddress_Current]

 and ch,2
;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 [RO16x16_MapAddress_Current],eax
 shr ebp,3
 mov eax,[TRMapAddress+edx]
 mov ecx,[TLMapAddress+edx]
 mov [RO16x16_FirstTile],ebp   ;FirstTile = (HScroll / 8) * 2

 sub eax,ecx
 mov [RO16x16_RMapDifference],eax

 mov eax,[C_LABEL(SNES_Screen8)]
 mov edi,[RO16x16_BaseDestPtr]
 add edi,eax

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

 test al,al
 jz .done

 mov ebx,[OffsetChangeMap_VOffset]
 mov [RO16x16_Runs_Left],eax
 lea edx,[Win_Bands+edx+esi]

 mov [RO16x16_Output],edi
 mov [RO16x16_RunListPtr],edx
 mov [RO16x16R_VMapOffset],ebx    ;vertical screen map address
 xor ebx,ebx
;mov [RO16x16R_Plotter_Table],ecx ;renderer
 mov bl,[edx]

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

 mov [RO16x16R_Next_Pixel],ebx
 mov [RO16x16R_Pixel_Count],ecx

 dec al
 je .last_run

.not_last_run:
 mov [RO16x16_Runs_Left],al
 call Render_Offset_16x16_Run

 mov edx,[RO16x16_RunListPtr]
 mov edi,[RO16x16_Output]
 xor ebx,ebx
 xor ecx,ecx
 mov bl,[edx+2]

 mov cl,[edx+3]
 add edx,byte 2
 sub cl,bl
 mov [RO16x16_RunListPtr],edx
 mov edx,[RO16x16_BG_Table]

 mov [RO16x16R_Next_Pixel],ebx
 mov [RO16x16R_Pixel_Count],ecx

 mov al,[RO16x16_Runs_Left]
 dec al
 jne .not_last_run
.last_run:
 call Render_Offset_16x16_Run

.done:

%ifndef LAYERS_PER_LINE
 mov edi,[RO16x16_BaseDestPtr]
 inc dword [RO16x16_Current_Line]
 add edi,GfxBufferLinePitch
 dec dword [RO16x16_Lines]

⌨️ 快捷键说明

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