📄 screen.asm
字号:
mov ecx,256/16
jnz .clear_mmx_loop
emms
ret
ALIGNC
EXPORT_C Update_Display
; edx = number of lines to recache
mov edx,[Ready_Line_Render]
push eax
sub edx,[C_LABEL(Current_Line_Render)]
mov byte [Display_Needs_Update],0
push ebx
push ecx
push edi
push ebp
push esi
push edx
;handle mosaic - setup linecounters for first line drawn
%if 0
LineCounter_BG[no mosaic] = current_line
if (!MosaicCountdown)
{
LineCounter_BG[mosaic] = current_line
}
%endif
mov cl,[MosaicCountdown]
mov al,[MOSAIC]
mov ebx,[C_LABEL(Current_Line_Render)]
add cl,255
sbb cl,cl
inc ebx
and al,cl
test al,1
jnz .no_update_linecounter_bg1
mov [LineCounter_BG1],ebx
.no_update_linecounter_bg1:
test al,2
jnz .no_update_linecounter_bg2
mov [LineCounter_BG2],ebx
.no_update_linecounter_bg2:
test al,4
jnz .no_update_linecounter_bg3
mov [LineCounter_BG3],ebx
.no_update_linecounter_bg3:
test al,8
jnz .no_update_linecounter_bg4
mov [LineCounter_BG4],ebx
.no_update_linecounter_bg4:
mov ah,[C_LABEL(INIDISP)]
test ah,ah ; Check for screen off
js .screen_off
cmp byte [Redo_Layering],0
jz .no_layering_recalc_needed
call C_LABEL(Update_Layering)
.no_layering_recalc_needed:
xor eax,eax
mov [Priority_Used_BG1],ax
mov [Priority_Used_BG2],ax
mov [Priority_Used_BG3],ax
mov [Priority_Used_BG4],ax
%ifdef WATCH_RENDER_BREAKS
EXTERN_C BreaksLast
inc dword [C_LABEL(BreaksLast)]
%endif
mov al,[SCR_TM]
mov bl,[BGMODE_Tile_Layer_Mask]
or al,[SCR_TS]
and al,bl
mov [Tile_Layers_Enabled],al
jz .no_tile_layers
mov edi,[Tile_Recache_Set_End]
inc edi
js .no_tile_recache_needed ; No set to recache?
sub edi,[Tile_Recache_Set_Begin]
mov byte [Redo_Offset_Change],0xFF
call Recache_Tile_Set
mov edi,-2
mov [Tile_Recache_Set_Begin],edi
mov [Tile_Recache_Set_End],edi
.no_tile_recache_needed:
test byte [Tile_Layers_Enabled],0x10
jz .no_oam_recache_needed
call C_LABEL(Check_OAM_Recache)
.no_oam_recache_needed:
SORT_OFFSET_CHANGE
.no_tile_layers:
cmp byte [Redo_Windowing],0
jz .no_window_recalc_needed
call C_LABEL(Recalc_Window_Effects)
.no_window_recalc_needed:
mov ebx,[C_LABEL(Current_Line_Render)]
mov edi,[BaseDestPtr]
inc ebx
mov ebp,[esp]
call dword [Render_Select]
pop edx
mov ebx,[C_LABEL(Current_Line_Render)]
add ebx,edx
mov [C_LABEL(Current_Line_Render)],ebx
mov al,[MOSAIC]
test al,1
jnz .mosaic_bg1
mov [LineCounter_BG1],ebx
.mosaic_bg1:
test al,2
jnz .mosaic_bg2
mov [LineCounter_BG2],ebx
.mosaic_bg2:
test al,4
jnz .mosaic_bg3
mov [LineCounter_BG3],ebx
.mosaic_bg3:
test al,8
jnz .mosaic_bg4
mov [LineCounter_BG4],ebx
.mosaic_bg4:
;if (countdown >= linecount) countdown -= linecount;
;else
;{
; line += countdown + MosaicLine[linecount - countdown - 1];
; countdown = MosaicCount[linecount - countdown];
; if (countdown == size) countdown = 0;
;}
mov eax,[MosaicCountdown]
mov ebp,eax
sub eax,edx
jge .mosaic_fixup_done
mov esi,[Mosaic_Size_Select]
xor eax,-1
xor ecx,ecx
xor ebx,ebx
mov cl,[C_LABEL(MosaicCount)+esi+eax+1] ;1
mov bl,[C_LABEL(MosaicLine)+esi+eax+1-1] ;6c
mov eax,[Mosaic_Size] ;1
add ebx,ebp ;6c
cmp ecx,eax ;
sbb eax,eax
and eax,ecx
.mosaic_fixup_done:
mov [MosaicCountdown],eax
mov al,[MOSAIC]
mov ebx,[LineCounter_BG1]
mov ecx,[LineCounter_BG2]
mov esi,[LineCounter_BG3]
mov edi,[LineCounter_BG4]
test al,1
jz .no_mosaic_bg1
add [LineCounter_BG1],ebp
.no_mosaic_bg1:
test al,2
jz .no_mosaic_bg2
add [LineCounter_BG2],ebp
.no_mosaic_bg2:
test al,4
jz .no_mosaic_bg3
add [LineCounter_BG3],ebp
.no_mosaic_bg3:
test al,8
jz .no_mosaic_bg4
add [LineCounter_BG4],ebp
.no_mosaic_bg4:
pop esi
pop ebp
pop edi
pop ecx
pop ebx
mov eax,GfxBufferLinePitch
imul eax,edx
add [BaseDestPtr],eax
pop eax
.return:
ret
ALIGNC
.screen_off:
mov ebp,edx
mov edi,[C_LABEL(SNES_Screen8)] ; (256+16)*(239+1) framebuffer
mov ebx,[BaseDestPtr]
add edi,ebx
; Clear the framebuffer
call C_LABEL(Clear_Scanlines)
pop edx
mov ebx,[C_LABEL(Current_Line_Render)]
add ebx,edx
mov [C_LABEL(Current_Line_Render)],ebx
mov al,[MOSAIC]
test al,1
jnz .so_mosaic_bg1
mov [LineCounter_BG1],ebx
.so_mosaic_bg1:
test al,2
jnz .so_mosaic_bg2
mov [LineCounter_BG2],ebx
.so_mosaic_bg2:
test al,4
jnz .so_mosaic_bg3
mov [LineCounter_BG3],ebx
.so_mosaic_bg3:
test al,8
jnz .so_mosaic_bg4
mov [LineCounter_BG4],ebx
.so_mosaic_bg4:
;if (countdown >= linecount) countdown -= linecount;
;else
;{
; line += countdown + MosaicLine[linecount - countdown - 1];
; countdown = MosaicCount[linecount - countdown];
; if (countdown == size) countdown = 0;
;}
mov eax,[MosaicCountdown]
mov ebp,eax
sub eax,edx
jge .so_mosaic_fixup_done
mov esi,[Mosaic_Size_Select]
xor eax,-1
xor ecx,ecx
xor ebx,ebx
mov ecx,[C_LABEL(MosaicCount)+esi+eax+1]
mov ebx,[C_LABEL(MosaicLine)+esi+eax+1-1]
mov eax,[Mosaic_Size]
add ebx,ebp
cmp ecx,eax
sbb eax,eax
and ecx,eax
mov [MosaicCountdown],cl
mov al,[MOSAIC]
mov ebx,[LineCounter_BG1]
mov ecx,[LineCounter_BG2]
mov esi,[LineCounter_BG3]
mov edi,[LineCounter_BG4]
test al,1
jz .so_no_mosaic_bg1
add [LineCounter_BG1],ebp
.so_no_mosaic_bg1:
test al,2
jz .so_no_mosaic_bg2
add [LineCounter_BG2],ebp
.so_no_mosaic_bg2:
test al,4
jz .so_no_mosaic_bg3
add [LineCounter_BG3],ebp
.so_no_mosaic_bg3:
test al,8
jz .so_no_mosaic_bg4
add [LineCounter_BG4],ebp
.so_no_mosaic_bg4:
.so_mosaic_fixup_done:
mov [MosaicCountdown],eax
pop esi
pop ebp
pop edi
pop ecx
pop ebx
mov eax,GfxBufferLinePitch
imul eax,edx
add [BaseDestPtr],eax
pop eax
ret
; esi is screen address, works cos we only plot until wraparound!
; ch contains the X counter
; cl contains the screen addition for palette offsetting (2bpl only)
; edi is the address to draw to..
; LineAddress contains the location for the SNES tile data
; LineAddress(Y) must be offset to the correct line for that row
; LineAddressY is used for Y-flip
%if 0
Mode 2 is a special snes mode - It is known as offset change mode,
basically the snes has the ability to change the horizontal and/or
vertical offset of each column on the screen, a pig to emulate but
here is the information:
BG1 & BG2 are 16 colour planes (this much was simple to find out)
BG3 - This does not exist but its address in VRAM is very important!
What happens is the horizontal and verticle information is written to
BG2 address's BG2+0 - BG2+63, this gives 128 bytes (since VRAM is a
word addressed system). BG2+0 - BG2+31 is the address for changing
the horizontal value BG2+32 - BG2+63 is the address for changing the
vertical value
There are 32 values per BG mode since there are 32 tiles horizontally across the screen! My
best guess is this value is immune to scrolling (otherwise it would make more sense to
give a 64 tile range in case of extra width modes).
Ok, the only other thing you need to know is what do the values at address BG2+x do.
Well its the same for horiz as vertical the values are encoded as :
00 | 01 | 02 | 03 |.......| 62 | 63
col 0 offset | col 0 flags | col 1 offset | col 1 flags |.......| col 31 offset | col 31 flags
The flags as far as I can tell are :
bit 7 6 5 4 3 2 1 0
? y x ? ? ? ? ? where y = affect bg1
x = affect bg0
The above information came from me Savoury SnaX
Addendum by TRAC (0.33 -> 0.34)
BG modes 2/4/6 have offset change support.
Offset change info is always stored at address set via BG3SC ($2109)?
Offset change info is stored one word per (width 8) tile, which appears
to have the format of:
FEDCBA9786543210
421xxxoooooooooo
4 = reserved in modes 2/6 - vertical select in mode 4
o = offset
1 = enable for first layer
2 = enable for second layer
The (width 8) tile on the left edge of a layer cannot have its offset
changed. It will always use standard H/V scroll.
The offset change map is used for the remaining width of the screen.
The maximum number of displayed tiles is 33, and the leftmost tile is
excluded, hence there is data in the table for 32 tiles.
There are one or two sets of data for the scanline. Each set is 32 words
(one word per tile). In BG modes 2 and 6 there are two: one for
horizontal, followed by one for vertical. In BG mode 4, there is one,
shared between horizontal and vertical.
Mode 4 stores only one word of offset change data per tile - bit 15
of a word entry determines if it is used for changing horizontal or
vertical offset (set for vertical).
When offset change is enabled for a tile, it replaces the standard offset
(BG#HOFS, BG#VOFS) value for that tile (horizontal offset replaces
BG#HOFS, vertical offset + 1 replaces BG#VOFS).
The BG3 scroll registers move the offset change map. The scrolling is
limited to increments of 8.
; word offset in offset change map of first offset change entry
OffsetChangeMap_X = BG3HOFS >> 3;
; word offset in row in offset change map to use
OffsetChangeMap_Y = (BG3VOFS >> 3) << 5;
Note that the offset change map does wrap rows back to themselves like
any other layer.
%endif
;Sets up VLMapAddress and VRMapAddress
;Uses mosaic setting, horizontal/vertical offsets, screen map size and
;current scanline
;eax = C_LABEL(Current_Line_Render)
ALIGNC
EXPORT Sort_Screen_Height_Mosaic
Get_Current_Line
EXPORT Sort_Screen_Height
; Corrupts eax,ebx,ecx,esi
mov bl,[HScroll+1+edx]
mov ecx,TLMapAddress
mov bh,[TileWidth+edx] ; 1 = 8x8, 2 = 16x8, 16x16
mov esi,TRMapAddress
test bl,bh
jz .first_tile_in_left_screen_map
add ecx,byte (TRMapAddress-TLMapAddress)
add esi,byte (TLMapAddress-TRMapAddress)
.first_tile_in_left_screen_map:
mov bl,[TileHeight+edx] ; 1 = 8x8, 16x8, 2 = 16x16
add eax,[VScroll+edx]
test ah,bl
jz .line_in_top_screen_map
mov eax,[edx+ecx+(BLMapAddress-TLMapAddress)]
mov ebx,[edx+esi+(BLMapAddress-TLMapAddress)]
mov [VRMapAddress+edx],ebx
mov [VLMapAddress+edx],eax
ret
ALIGNC
.line_in_top_screen_map:
mov eax,[edx+ecx]
mov ebx,[edx+esi]
mov [VRMapAddress+edx],ebx
mov [VLMapAddress+edx],eax
ret
;%1 = planenum, 2 = priority
%macro RENDER_LINE 2
LOAD_BG_TABLE %1
%if %2 == 0
xor eax,eax
mov [Tile_Priority_Used],ax
%else
mov al,[Priority_Unused+edx]
test al,al
jz %%no_plot
mov al,[Priority_Used+edx]
cmp al,1
sbb al,al
%endif
; set up depth
mov byte [Tile_priority_bit],(1 - (%2)) << (13 - 8)
; tile size and depth selected in BGMODE write handler
call dword [LineRender+edx]
%%no_plot:
%endmacro
;%1 = planenum
%macro RENDER_LINE_NP 1
LOAD_BG_TABLE %1
mov al,1
; tile size and depth selected in BGMODE write handler
call dword [LineRender+edx]
%endmacro
%if 0
Mode 0 - 4 background layers, 8x8 and 16x16 tile sizes
2bpl tile depth in all layers
special: each background layer has its own set of palettes
Mode 1 - 3 background layers, 8x8 and 16x16 tile sizes
4bpl tile depth in layers 1 and 2, 2bpl tile depth in layer 3
special: BG3 high priority selection
%endif
%define SM01_Local_Bytes 20
%define SM01_Layers_Copy esp+16
%define SM01_Current_Line esp+12
%define SM01_BaseDestPtr esp+8
%define SM01_Lines esp+4
%define SM01_Layers esp
%macro Check_Present_Layer 2
test byte %2,1 << ((%1)-1)
%endmacro
%macro Jump_Present_Layer 3
Check_Present_Layer (%1),%2
jnz (%3)
%endmacro
%macro Jump_Not_Present_Layer 3
Check_Present_Layer (%1),%2
jz (%3)
%endmacro
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -