www.pudn.com > sn068s.zip > SCREEN.ASM
; screen.asm
; Screen rendering code
; -BGMODE specific handlers, including specialized handlers for:
; partial offset change in Mode 2;
; partial offset change in Mode 4;
; -Basic BG scanline renderers;
; -Line offset in tile tables.
;
%define NO_PLOTTER_PER_PRIORITY
%define WATCH_RENDER_BREAKS
;%define LAYERS_PER_LINE
;%define NO_NP_RENDER
;%define NO_OFFSET_CHANGE
;%define NO_OFFSET_CHANGE_DISABLE
;%define NO_EARLY_PRIORITY_ELIMINATION
%define OFFSET_CHANGE_ELIMINATION
%ifdef NO_NP_RENDER
%define NO_EARLY_PRIORITY_ELIMINATION
%endif
%ifndef LAYERS_PER_LINE
%define NO_EARLY_PRIORITY_ELIMINATION
%endif
%define SNEeSe_screen_asm
%include "misc.ni"
%include "clear.ni"
%include "sprites.ni"
%include "PPU.ni"
%include "tiles.ni"
%include "screen.ni"
extern SCREEN_MODE_7
extern _SNES_Screen8
extern _Offset_Change_Disable
extern _MosaicLine,_MosaicCount
section .text
EXPORT_C screen_text_start
section .data
EXPORT_C screen_data_start
section .bss
EXPORT_C screen_bss_start
section .data
ALIGND
%macro Generate_Tile_Offset_Table 1
dd 16*8*(%1)
dd 16*8*(%1)+1
dd 16*8*(%1)+2
dd 16*8*(%1)+3
dd 16*8*(%1)+4
dd 16*8*(%1)+5
dd 16*8*(%1)+6
dd 16*8*(%1)+7
%endmacro
EXPORT Tile_Offset_Table_16_8
Generate_Tile_Offset_Table 0
Generate_Tile_Offset_Table 1
EXPORT Screen_Mode
dd _SCREEN_MODE_0
dd _SCREEN_MODE_1
dd _SCREEN_MODE_2
dd _SCREEN_MODE_3
dd _SCREEN_MODE_4
dd _SCREEN_MODE_5
dd _SCREEN_MODE_6
dd SCREEN_MODE_7
palette_2bpl:
dd 0x03030303, 0x07070707, 0x0B0B0B0B, 0x0F0F0F0F
dd 0x13131313, 0x17171717, 0x1B1B1B1B, 0x1F1F1F1F
palette_4bpl:
dd 0x0F0F0F0F, 0x1F1F1F1F, 0x2F2F2F2F, 0x3F3F3F3F
dd 0x4F4F4F4F, 0x5F5F5F5F, 0x6F6F6F6F, 0x7F7F7F7F
palette_2bpl_mmx:
dd 0x03030303, 0x03030303, 0x07070707, 0x07070707
dd 0x0B0B0B0B, 0x0B0B0B0B, 0x0F0F0F0F, 0x0F0F0F0F
dd 0x13131313, 0x13131313, 0x17171717, 0x17171717
dd 0x1B1B1B1B, 0x1B1B1B1B, 0x1F1F1F1F, 0x1F1F1F1F
palette_4bpl_mmx:
dd 0x0F0F0F0F, 0x0F0F0F0F, 0x1F1F1F1F, 0x1F1F1F1F
dd 0x2F2F2F2F, 0x2F2F2F2F, 0x3F3F3F3F, 0x3F3F3F3F
dd 0x4F4F4F4F, 0x4F4F4F4F, 0x5F5F5F5F, 0x5F5F5F5F
dd 0x6F6F6F6F, 0x6F6F6F6F, 0x7F7F7F7F, 0x7F7F7F7F
section .bss
;Z-buffer for display
;#L = tiles/pixels for layer # (low priority)
;#H = tiles/pixels for layer # (high priority)
;#S = sprites (# priority) 34 24 14 04
;BA = back area 00
;modes 0-1
;layer 3H 3S 1H 2H 2S 1L 2L 1S 3H 4H 0S 3L 4L BA
;Z 38 34 32 31 24 22 21 14 12 11 04 02 01 00
;modes 2-6
;layer 3S 1H 2S 2H 1S 1L 0S 2L BA
;Z 34 32 24 22 14 12 04 02 00
;mode 7
;layer 3S 2S 1H 1S 1L 0S BA
;Z 34 24 12 14 02 04 00
ALIGNB
EXPORT DisplayZ,skipb (8+256+8)
ALIGNB
EXPORT LineAddress ,skipl ; Address of tileset, + offset to line in tile
EXPORT LineAddressY,skipl ; Same, for vertical flip
EXPORT TileMask ,skipl ; Tile address mask, for tileset wrap
; Used for offset change map addressing
EXPORT OffsetChangeMap_VOffset,skipl ; BG3VOFS + BG3SC
EXPORT OffsetChangeVMap_VOffset,skipl ; BG3VOFS + BG3SC (for split-table)
EXPORT_C Current_Line_Render,skipl
EXPORT Ready_Line_Render,skipl
EXPORT BaseDestPtr ,skipl
EXPORT Render_Select,skipl ; Base renderer
EXPORT Render_Mode ,skipl ; Mode renderer
Palette_Base:skipl
EXPORT Tile_Layers_Enabled,skipb
EXPORT Tile_priority_bit,skipb
EXPORT Tile_priority_opcode,skipb
Tile_Priority_Used:skipb
Tile_Priority_Unused:skipb
EXPORT OffsetChangeDetect1,skipb
EXPORT OffsetChangeDetect2,skipb
EXPORT OffsetChangeDetect3,skipb
section .text
;ebx = first line, edi = destination base ptr, ebp = # lines
ALIGNC
EXPORT_C Render_Layering_Option_0 ; main-on-sub
mov al,[SCR_TS] ; Get BG status for sub screens
mov ah,[SCR_TM] ; Get BG status for main screens
jmp dword [Render_Mode]
ALIGNC
EXPORT_C Render_Layering_Option_1 ; sub-on-main
mov al,[SCR_TM] ; Get BG status for main screens
mov ah,[SCR_TS] ; Get BG status for sub screens
jmp dword [Render_Mode]
ALIGNC
EXPORT_C Render_Layering_Option_2 ; main-with-sub
mov al,[SCR_TM] ; Get BG status for main/sub screens
mov ah,0
jmp dword [Render_Mode]
ALIGNC
Update_Offset_Change:
mov byte [Redo_Offset_Change],0
; Update BG3 position for offset change
mov al,[Redo_BGs]
LOAD_BG_TABLE 3
test al,4
jz .bg3_ok
and al,~4
mov [Redo_BGs],al
call Redo_8
.bg3_ok:
LOAD_BG_TABLE 3
mov ecx,[HScroll+edx]
mov esi,TLMapAddress
mov edi,TRMapAddress
and ch,1 ;8x8 tile size
jz .first_tile_in_left_screen_map
add esi,byte (TRMapAddress-TLMapAddress)
add edi,byte (TLMapAddress-TRMapAddress)
.first_tile_in_left_screen_map:
mov eax,[FirstTile+edx]
mov esi,[esi+edx]
mov edi,[edi+edx]
add esi,eax
mov [VLMapAddress+edx],esi
mov [VRMapAddress+edx],edi
%ifdef OFFSET_CHANGE_ELIMINATION
mov ebx,[OffsetChangeMap_VOffset]
mov ah,32
add esi,ebx
mov ch,[TileCount1+edx]
mov edx,[OffsetChangeVMap_VOffset]
add edi,ebx
sub ah,ch
mov al,0
mov bl,0
.detect_loop:
mov cl,[esi+1]
or al,cl
mov bh,[esi+1+edx]
add esi,byte 2
or bl,bh
dec ch
jnz .detect_loop
add ch,ah
jz .detect_end
mov ah,0
mov esi,edi
jmp short .detect_loop
.detect_end:
mov [OffsetChangeDetect1],al
or al,bl
mov [OffsetChangeDetect2],bl
mov [OffsetChangeDetect3],al
%endif
ret
%macro SORT_SCREEN_WIDTH 1
test byte [Tile_Layers_Enabled],1 << (%1 - 1)
jz %%no_recalc
mov al,[Redo_BGs]
LOAD_BG_TABLE %1
test al,1 << (%1 - 1)
jz %%no_recalc
call dword [BG_Redo+edx]
%%no_recalc:
%endmacro
%macro SORT_OFFSET_CHANGE 0
test byte [Tile_Layers_Enabled],3 ;BG1 || BG2
jz %%no_recalc
mov al,[BGMODE_Allowed_Offset_Change]
test al,al
jz %%no_recalc
mov al,[Redo_Offset_Change]
test al,al
jz %%no_recalc
call Update_Offset_Change
%%no_recalc:
%endmacro
ALIGNC
EXPORT_C Sync_Render
; edi = number of lines to recache
push eax
mov ah,[_INIDISP]
test ah,ah ; Check for screen off
js near .screen_off
push ebx
push ecx
push edx
push ebp
push esi
push edi
%ifdef WATCH_RENDER_BREAKS
extern _BreaksLast
inc dword [_BreaksLast]
%endif
extern BGMODE_Tile_Layer_Mask
mov al,[SCR_TM]
mov bl,[BGMODE_Tile_Layer_Mask]
or al,[SCR_TS]
and al,bl
mov [Tile_Layers_Enabled],al
jz near .no_tile_layers
extern Tile_Recache_Set_End,Tile_Recache_Set_Begin,Recache_Tile_Set
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
mov al,[Redo_OAM]
test al,al
jz .no_oam_recache_needed
call Recache_OAM
.no_oam_recache_needed:
SORT_SCREEN_WIDTH 1
SORT_SCREEN_WIDTH 2
SORT_SCREEN_WIDTH 3
SORT_SCREEN_WIDTH 4
SORT_OFFSET_CHANGE
mov al,[Tile_Layers_Enabled]
xor al,0xFF
and [Redo_BGs],al
.no_tile_layers:
mov ebx,[_Current_Line_Render]
mov edi,[BaseDestPtr]
inc ebx
mov ebp,[esp]
call dword [Render_Select]
pop edi
pop esi
pop ebp
pop edx
pop ecx
pop ebx
add [_Current_Line_Render],edi
mov eax,GfxBufferLinePitch
imul eax,edi
add [BaseDestPtr],eax
pop eax
ret
ALIGNC
.screen_off:
push ebx
push ecx
push edx
push ebp
push esi
push edi
mov ebp,edi
mov edi,[_SNES_Screen8] ; (256+16)*(239+1) framebuffer
; Clear the framebuffer
mov ebx,[BaseDestPtr]
xor eax,eax
add edi,ebx
mov ecx,256/4
push es
mov edx,ds
mov es,edx
cld
.clear_loop:
; Load area to clear into cache
mov bl,[edi+0]
mov bl,[edi+16*2]
mov bl,[edi+16*4]
mov bl,[edi+16*6]
mov bl,[edi+16*8]
mov bl,[edi+16*10]
mov bl,[edi+16*12]
mov bl,[edi+16*14]
mov dl,[edi+16]
mov bl,[edi+16*3]
mov dl,[edi+16*5]
mov bl,[edi+16*7]
mov dl,[edi+16*9]
mov bl,[edi+16*11]
mov dl,[edi+16*13]
mov bl,[edi+16*15]
rep stosd
add edi,byte GfxBufferLineSlack ; Point screen to next line
dec ebp
mov ecx,256/4
jnz .clear_loop
pop es
mov edi,[esp]
add [_Current_Line_Render],edi
mov eax,GfxBufferLinePitch
imul eax,edi
add [BaseDestPtr],eax
pop edi
pop esi
pop ebp
pop edx
pop ecx
pop ebx
pop eax
ret
; ~142 bytes
;%1 = Left,%2 = Right,%3 = ICount,%4 = IBands,%5 = OCount,%6 = OBands
%macro Recalc_Window_Bands 6
mov al,[%1]
mov dl,[%2]
test dl,dl ; 0 = 255 (right edge)
jz %%one_inside
cmp dl,al
jbe %%full_outside ; if (Right < Left) full range outside window;
%%one_inside:
mov [%4],al
mov [%4+1],dl
mov byte [%3],1 ; One band inside window (left,right)
test al,al
jnz %%not_flush_left ; if (!Left) window flush left;
test dl,dl
jne %%flush_one_side ; if (!Left && Right == 255) full range inside;
; Full range inside window
mov byte [%5],0 ; No bands outside window
jmp short %%done
%%not_flush_left:
; Window not flush left (1 inside, 1 or 2 outside)
test dl,dl
je %%flush_one_side ; if (Left && Right == 255) window flush right;
; Window not flush left or right (1 inside, 2 outside)
; Inside range is (left,right)
; Outside range 1 is (0,left-1)
; Outside range 2 is (right+1,255)
;dec eax ; Right outside edge 1 = Left inside edge - 1
;inc edx ; Left outside edge 2 = right inside edge + 1
mov byte [%5],2 ; One band outside window (right+1,left-1)
mov [%6+1],al
mov byte [%6],0
mov [%6+2],dl
mov byte [%6+3],0
jmp short %%done
%%flush_one_side:
; Window flush left, not flush right (1 inside, 1 outside)
; Window flush right, not flush left (1 inside, 1 outside)
; Inside range is (left,right), outside range is (right+1,left-1)
;dec eax ; Right outside edge = Left inside edge - 1
;inc edx ; Left outside edge = right inside edge + 1
mov [%6+1],al
mov byte [%5],1 ; One band outside window (right+1,left-1)
mov [%6],dl
jmp short %%done
%%full_outside:
; Full range outside window (0 inside, 1 outside)
mov byte [%5],1 ; One band outside window
mov dword [%6],0 ; Full range band
mov byte [%3],0 ; No bands inside window
%%done:
%endmacro
ALIGNC
EXPORT_C Recalc_Window_Effects
push eax
push edx
Recalc_Window_Bands _WH0, _WH1, _Win1_Count_In, _Win1_Bands_In, _Win1_Count_Out, _Win1_Bands_Out
Recalc_Window_Bands _WH2, _WH3, _Win2_Count_In, _Win2_Bands_In, _Win2_Count_Out, _Win2_Bands_Out
pop edx
pop eax
ret
; full | any == full
; full & any == any
; side-flush | same-flush == same-flush (longer)
; side-flush & same-flush == same-flush (shorter)
; side-flush ^ same-flush == 0 (if equal) or no-flush (difference)
; side-flush & other-flush == 0 (if no overlap) or no-flush (overlap)
; windows:
%if 0
TMW/TSW clipping is only done inside window areas defined by
WH0-WH1 (window 1) and WH2-WH3 (window 2), when enabled
(W12SEL/W34SEL/WOBJSEL odd bits).
Window areas can be inverted (W12SEL/W34SEL/WOBJSEL even bits).
When specified areas of windows 1/2 overlap, final window area is determined
by specified logic (WBGLOG/WOBJLOG).
Color arithmetic is done inside the area of the color window.
w2 w1
/\/\ /--+ enable
|||| |/-+ invert window area
76543210
\ /\ /
BG2 BG1 - ($2123) W12SEL
BG4 BG3 - ($2124) W34SEL
COL OBJ - ($2125) WOBJSEL
COL = Color window - related to CGWSEL ($2130)
WH0-WH1 Left and right position for window 1
WH2-WH3 Left and right position for window 2
if (left > right) no window range
/+-+ logic - 00 = or; 01 = and; 10 = xor; 11 = xnor
||
76543210
\/||||\/
BG4||||BG1 ($212A: WBGLOG)
\/\/OBJ ($212B: WOBJLOG)
BG3 BG2 ($212A: WBGLOG)
COL ($212B: WOBJLOG)
bits 4-7 are ignored in $212B: WOBJLOG
bits 5-7 are ignored in $212C-212F (TM, TS, TMW, TSW)
76543210
xxx||||\-+ BG1
|||\--+ BG2
||\---+ BG3
|\----+ BG4
\-----+ OBJ
($212C) TM specifies layers to be used as main screen
($212D) TS specifics layers to be used as sub screen, for screen arithmetic
($212E) TMW is mask to be applied with bitwise AND to TM inside window areas
($212F) TSW is mask to be applied with bitwise AND to TS inside window areas
$2130 - CGWSEL
76543210
||||xx|\-+ 1 = enable direct color mode (for BGMODEs 3,4,7)
|||| \--+ 0 = arithmetic with fixed color; 1 = arithmetic with screen
||\+-----+ sub screen normal display select \ 00 = on; 01 = on inside
\+-------+ main screen normal display select/ 10 = on outside; 11 = off
$2131 - CGADSUB
76543210
|||||||\-+ enable color arithmetic for BG1
||||||\--+ enable color arithmetic for BG2
|||||\---+ enable color arithmetic for BG3
||||\----+ enable color arithmetic for BG4
|||\-----+ enable color arithmetic for OBJ
||\------+ enable color arithmetic for back area
|\-------+ 1 = halve-result of arithmetic (except for back area)
\--------+ 0 = color addition; 1 = color subtraction
%endif
;lines, startreg, reg2, reg3
%macro Cache_Load_Lines 4
mov (%3),(%2)
%ifnid %1
%if (%1) > 1
mov ebp,(%1)
%endif
%endif
%%CL_loop:
lea (%4),[(%3)+16*8]
mov al,[(%3)+0]
mov al,[(%3)+16*2]
mov al,[(%3)+16*4]
mov al,[(%3)+16*6]
mov al,[(%4)+0]
mov al,[(%4)+16*2]
mov al,[(%4)+16*4]
mov al,[(%4)+16*6]
mov cl,[(%3)+16]
mov al,[(%3)+16*3]
mov cl,[(%3)+16*5]
mov al,[(%3)+16*7]
%ifid %1
lea (%3),[(%4)+GfxBufferLinePitch-(16*8)]
%elif (%1) > 1
lea (%3),[(%4)+GfxBufferLinePitch-(16*8)]
%endif
mov cl,[(%4)+16]
mov al,[(%4)+16*3]
mov cl,[(%4)+16*5]
mov al,[(%4)+16*7]
%ifid %1
dec (%1)
jnz %%CL_loop
%elif (%1) > 1
dec ebp
jnz %%CL_loop
%endif
%endmacro
;Variable priority loads dh from Tile_priority_bit
;All assume al == high byte of screen tile
;%1 = priority - 0 = none, 1 = low, 2 = high, 3 = variable
;%2 = branch label
%macro Check_Tile_Priority 2
%if %1 == 1
test al,0x20
jnz %2
%endif
%if %1 == 2
test al,0x20
jz %2
%endif
%if %1 == 3
mov dh,[Tile_priority_bit]
xor dh,al
and dh,0x20 ; Check tile priority
jz %2
%endif
%endmacro
; 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
%include "bg8.ni"
%include "bg16.ni"
%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
%include "bg8o.ni"
%include "bg16o.ni"
%include "bg16e.ni"
;Sets up VLMapAddress and VRMapAddress
;Uses mosaic setting, horizontal/vertical offsets, screen map size and
;current scanline
;eax = _Current_Line_Render
ALIGNC
Sort_Screen_Height_Mosaic:
Get_Current_Line
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 ecx,[FirstTile+edx]
mov ebx,[edx+esi+(BLMapAddress-TLMapAddress)]
add eax,ecx
mov [VRMapAddress+edx],ebx
mov [VLMapAddress+edx],eax
ret
ALIGNC
.line_in_top_screen_map:
mov eax,[edx+ecx]
mov ecx,[FirstTile+edx]
mov ebx,[edx+esi]
add eax,ecx
mov [VRMapAddress+edx],ebx
mov [VLMapAddress+edx],eax
ret
;%1 = planenum, 2 = priority
%macro RENDER_LINE 2
LOAD_BG_TABLE %1
%if %2 == 0
mov al,0
mov [Tile_Priority_Used],al
mov [Tile_Priority_Unused],al
%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_opcode],0x75 - (%2)
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
%macro Check_Present_OBJ 1
test byte %1,0x10
%endmacro
%macro Jump_Present_OBJ 2
Check_Present_OBJ %1
jnz (%2)
%endmacro
%macro Jump_Not_Present_OBJ 2
Check_Present_OBJ %1
jz (%2)
%endmacro
%macro Jump_BG3_Highest 1
cmp byte [_Base_BGMODE],1
jne %%not_highest
test byte [_BGMODE],8
jnz (%1)
%%not_highest:
%endmacro
%macro Jump_Not_BG3_Highest 1
cmp byte [_Base_BGMODE],1
jne (%1)
test byte [_BGMODE],8
jz (%1)
%endmacro
;requires current line in ebx, uses cl
%macro Check_Present_OBJ_Priority 1
mov cl,[OAM_Count_Priority+ebx*4-4+(%1)]
test cl,cl
%endmacro
%macro Jump_Present_OBJ_Priority 2
Check_Present_OBJ_Priority (%1)
jnz (%2)
%endmacro
%macro Jump_Not_Present_OBJ_Priority 2
Check_Present_OBJ_Priority (%1)
jz (%2)
%endmacro
%macro Render_SM01 2
Jump_Not_Present_Layer 4,[SM01_Layers+%1],%%bg4_lo_done
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
%ifndef NO_EARLY_PRIORITY_ELIMINATION
Jump_Present_Layer 3,[SM01_Layers+%1],%%bg4_lo_priority
Jump_Not_Present_OBJ [SM01_Layers+%1],%%bg4_no_priority
Jump_Present_OBJ_Priority 0,%%bg4_lo_priority
%%bg4_no_priority:
RENDER_LINE_NP 4
and byte [SM01_Layers+%1],~8
jmp %%bg3_done
%%bg4_lo_priority:
%endif
RENDER_LINE 4,0
%%bg4_lo_done:
Jump_Not_Present_Layer 3,[SM01_Layers+%1],%%bg3_lo_done
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
%ifndef NO_EARLY_PRIORITY_ELIMINATION
Jump_BG3_Highest %%bg3_lo_priority
Jump_Present_Layer 4,[SM01_Layers+%1],%%bg3_lo_priority
Jump_Not_Present_OBJ [SM01_Layers+%1],%%bg3_no_priority
Jump_Present_OBJ_Priority 0,%%bg3_lo_priority
%%bg3_no_priority:
RENDER_LINE_NP 3
and byte [SM01_Layers+%1],~4
jmp %%bg3_done
%%bg3_lo_priority:
%endif
RENDER_LINE 3,0
%%bg3_lo_done:
Jump_Not_Present_OBJ [SM01_Layers+%1],%%no_sprites_0
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
;inc ebx
mov dl,0x00
call Plot_Sprites
%%no_sprites_0:
Jump_Not_Present_Layer 4,[SM01_Layers+%1],%%bg4_hi_done
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
RENDER_LINE 4,1
%%bg4_hi_done:
Jump_Not_Present_Layer 3,[SM01_Layers+%1],%%bg3_hi_done
Jump_BG3_Highest %%bg3_hi_done
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
RENDER_LINE 3,1
%%bg3_hi_done:
%%bg3_done:
Jump_Not_Present_OBJ [SM01_Layers+%1],%%no_sprites_1
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
;inc ebx
mov dl,0x10
call Plot_Sprites
%%no_sprites_1:
Jump_Not_Present_Layer 2,[SM01_Layers+%1],%%bg2_lo_done
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
%ifndef NO_EARLY_PRIORITY_ELIMINATION
Jump_Present_Layer 1,[SM01_Layers+%1],%%bg2_lo_priority
Jump_Not_Present_OBJ [SM01_Layers+%1],%%bg2_no_priority
Jump_Present_OBJ_Priority 2,%%bg2_lo_priority
%%bg2_no_priority:
RENDER_LINE_NP 2
and byte [SM01_Layers+%1],~2
jmp %%bg1_done
%%bg2_lo_priority:
%endif
RENDER_LINE 2,0
%%bg2_lo_done:
Jump_Not_Present_Layer 1,[SM01_Layers+%1],%%bg1_lo_done
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
%ifndef NO_EARLY_PRIORITY_ELIMINATION
Jump_Present_Layer 2,[SM01_Layers+%1],%%bg1_lo_priority
Jump_Not_Present_OBJ [SM01_Layers+%1],%%bg1_no_priority
Jump_Present_OBJ_Priority 2,%%bg1_lo_priority
%%bg1_no_priority:
RENDER_LINE_NP 1
and byte [SM01_Layers+%1],~1
jmp %%bg1_done
%%bg1_lo_priority:
%endif
RENDER_LINE 1,0
%%bg1_lo_done:
Jump_Not_Present_OBJ [SM01_Layers+%1],%%no_sprites_2
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
;inc ebx
mov dl,0x20
call Plot_Sprites
%%no_sprites_2:
Jump_Not_Present_Layer 2,[SM01_Layers+%1],%%bg2_hi_done
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
RENDER_LINE 2,1
%%bg2_hi_done:
Jump_Not_Present_Layer 1,[SM01_Layers+%1],%%bg1_hi_done
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
RENDER_LINE 1,1
%%bg1_hi_done:
%%bg1_done:
Jump_Not_Present_OBJ [SM01_Layers+%1],%%no_sprites_3
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
;inc ebx
mov dl,0x30
call Plot_Sprites
%%no_sprites_3:
Jump_Not_BG3_Highest %%bg3_max_done
Jump_Not_Present_Layer 3,[SM01_Layers+%1],%%bg3_max_done
mov ebx,[SM01_Current_Line]
mov edi,[SM01_BaseDestPtr]
mov ebp,%2
RENDER_LINE 3,1
%%bg3_max_done:
%endmacro
;*
;Plot 8-16 lines of first layer (complete one tile and draw one tile)
;Plot up to 8 lines of all other layers
;*
ALIGNC
EXPORT_C SCREEN_MODE_0
EXPORT_C SCREEN_MODE_1
push eax
push ebx
push edi
push ebp
push eax
.next_line:
mov edi,[_SNES_Screen8] ; (256+16)*(239+1) framebuffer
; Clear the framebuffer
mov ebx,[SM01_BaseDestPtr]
xor eax,eax
add edi,ebx
mov ebp,1
%ifdef LAYERS_PER_LINE
mov ebp,1
%else
mov ebp,[SM01_Lines]
%endif
mov ecx,256/4
push es
mov edx,ds
mov es,edx
cld
.clear_loop:
; Load area to clear into cache
mov bl,[edi+0]
mov bl,[edi+16*2]
mov bl,[edi+16*4]
mov bl,[edi+16*6]
mov bl,[edi+16*8]
mov bl,[edi+16*10]
mov bl,[edi+16*12]
mov bl,[edi+16*14]
mov dl,[edi+16]
mov bl,[edi+16*3]
mov dl,[edi+16*5]
mov bl,[edi+16*7]
mov dl,[edi+16*9]
mov bl,[edi+16*11]
mov dl,[edi+16*13]
mov bl,[edi+16*15]
rep stosd
add edi,byte GfxBufferLineSlack ; Point screen to next line
dec ebp
mov ecx,256/4
jnz .clear_loop
pop es
%ifndef LAYERS_PER_LINE
Render_SM01 0,[SM01_Lines]
Render_SM01 1,[SM01_Lines]
%else
Render_SM01 0,1
Render_SM01 1,1
mov eax,[SM01_Layers_Copy]
mov [SM01_Layers],eax
mov edi,[SM01_BaseDestPtr]
inc dword [SM01_Current_Line]
add edi,GfxBufferLinePitch
dec dword [SM01_Lines]
mov [SM01_BaseDestPtr],edi
jnz near .next_line
%endif
add esp,byte SM01_Local_Bytes
ret
%if 0
Mode 2 - 2 background layers, 8x8 and 16x16 tile sizes
4bpl tile depth in layers 1 and 2
special: offset change data (h and v) stored in layer 3
Mode 3 - 2 background layers, 8x8 and 16x16 tile sizes
8bpl tile depth in layer 1, 4bpl tile depth in layer 2
special: direct color mode
Mode 4 - 2 background layers, 8x8 and 16x16 tile sizes
8bpl tile depth in layer 1, 2bpl tile depth in layer 2
special: direct color mode
offset change data (h or v?) stored in layer 3
Mode 5 - 2 background layers, 16x8 and 16x16 tile sizes
4bpl tile depth in layer 1, 2bpl tile depth in layer 2
special: 512 mode
Mode 6 - 1 background layer, 16x8 and 16x16 tile sizes
4bpl tile depth in layer 1
special: 512 mode
offset change data (h and v?) stored in layer 3 (?)
%endif
%define SM26_Local_Bytes 20
%define SM26_Layers_Copy esp+16
%define SM26_Current_Line esp+12
%define SM26_BaseDestPtr esp+8
%define SM26_Lines esp+4
%define SM26_Layers esp
%macro Render_SM26 2
Jump_Not_Present_Layer 2,[SM26_Layers+%1],%%bg2_lo_done
mov ebx,[SM26_Current_Line]
mov edi,[SM26_BaseDestPtr]
mov ebp,%2
%ifndef NO_EARLY_PRIORITY_ELIMINATION
Jump_Present_Layer 1,[SM26_Layers+%1],%%bg2_lo_priority
Jump_Not_Present_OBJ [SM26_Layers+%1],%%bg2_no_priority
Jump_Present_OBJ_Priority 0,%%bg2_lo_priority
Jump_Present_OBJ_Priority 1,%%bg2_lo_priority
%%bg2_no_priority:
RENDER_LINE_NP 2
and byte [SM26_Layers+%1],~2
jmp %%bg2_done
%%bg2_lo_priority:
%endif
RENDER_LINE 2,0
%%bg2_lo_done:
Jump_Not_Present_OBJ [SM26_Layers+%1],%%no_sprites_0
mov ebx,[SM26_Current_Line]
mov edi,[SM26_BaseDestPtr]
mov ebp,%2
;inc ebx
mov dl,0x00
call Plot_Sprites
%%no_sprites_0:
Jump_Not_Present_Layer 1,[SM26_Layers+%1],%%bg1_lo_done
mov ebx,[SM26_Current_Line]
mov edi,[SM26_BaseDestPtr]
mov ebp,%2
%ifndef NO_EARLY_PRIORITY_ELIMINATION
Jump_Present_Layer 2,[SM26_Layers+%1],%%bg1_lo_priority
Jump_Not_Present_OBJ [SM26_Layers+%1],%%bg1_no_priority
Jump_Present_OBJ_Priority 1,%%bg1_lo_priority
Jump_Present_OBJ_Priority 2,%%bg1_lo_priority
%%bg1_no_priority:
RENDER_LINE_NP 1
and byte [SM26_Layers+%1],~1
jmp %%bg1_done
%%bg1_lo_priority:
%endif
RENDER_LINE 1,0
%%bg1_lo_done:
Jump_Not_Present_OBJ [SM26_Layers+%1],%%no_sprites_1
mov ebx,[SM26_Current_Line]
mov edi,[SM26_BaseDestPtr]
mov ebp,%2
;inc ebx
mov dl,0x10
call Plot_Sprites
%%no_sprites_1:
Jump_Not_Present_Layer 2,[SM26_Layers+%1],%%bg2_hi_done
mov ebx,[SM26_Current_Line]
mov edi,[SM26_BaseDestPtr]
mov ebp,%2
RENDER_LINE 2,1
%%bg2_hi_done:
%%bg2_done:
Jump_Not_Present_OBJ [SM26_Layers+%1],%%no_sprites_2
mov ebx,[SM26_Current_Line]
mov edi,[SM26_BaseDestPtr]
mov ebp,%2
;inc ebx
mov dl,0x20
call Plot_Sprites
%%no_sprites_2:
Jump_Not_Present_Layer 1,[SM26_Layers+%1],%%bg1_hi_done
mov ebx,[SM26_Current_Line]
mov edi,[SM26_BaseDestPtr]
mov ebp,%2
RENDER_LINE 1,1
%%bg1_hi_done:
%%bg1_done:
Jump_Not_Present_OBJ [SM26_Layers+%1],%%no_sprites_3
mov ebx,[SM26_Current_Line]
mov edi,[SM26_BaseDestPtr]
mov ebp,%2
;inc ebx
mov dl,0x30
call Plot_Sprites
%%no_sprites_3:
%endmacro
EXPORT_C SCREEN_MODE_2
EXPORT_C SCREEN_MODE_3
EXPORT_C SCREEN_MODE_4
EXPORT_C SCREEN_MODE_5
EXPORT_C SCREEN_MODE_6
push eax
push ebx
push edi
push ebp
push eax
.next_line:
mov edi,[_SNES_Screen8] ; (256+16)*(239+1) framebuffer
; Clear the framebuffer
mov ebx,[SM26_BaseDestPtr]
xor eax,eax
add edi,ebx
mov ebp,1
%ifdef LAYERS_PER_LINE
mov ebp,1
%else
mov ebp,[SM26_Lines]
%endif
mov ecx,256/4
push es
mov edx,ds
mov es,edx
cld
.clear_loop:
; Load area to clear into cache
mov bl,[edi+0]
mov bl,[edi+16*2]
mov bl,[edi+16*4]
mov bl,[edi+16*6]
mov bl,[edi+16*8]
mov bl,[edi+16*10]
mov bl,[edi+16*12]
mov bl,[edi+16*14]
mov dl,[edi+16]
mov bl,[edi+16*3]
mov dl,[edi+16*5]
mov bl,[edi+16*7]
mov dl,[edi+16*9]
mov bl,[edi+16*11]
mov dl,[edi+16*13]
mov bl,[edi+16*15]
rep stosd
add edi,byte GfxBufferLineSlack ; Point screen to next line
dec ebp
mov ecx,256/4
jnz .clear_loop
pop es
%ifndef LAYERS_PER_LINE
Render_SM26 0,[SM26_Lines]
Render_SM26 1,[SM26_Lines]
%else
Render_SM26 0,1
Render_SM26 1,1
mov eax,[SM26_Layers_Copy]
mov [SM26_Layers],eax
mov edi,[SM26_BaseDestPtr]
inc dword [SM26_Current_Line]
add edi,GfxBufferLinePitch
dec dword [SM26_Lines]
mov [SM26_BaseDestPtr],edi
jnz near .next_line
%endif
add esp,byte SM26_Local_Bytes
ret
section .text
ALIGNC
section .data
ALIGND
section .bss
ALIGNB