📄 windows.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
; windows.asm
; Screen windowing code
;
%define SNEeSe_ppu_windows_asm
%include "misc.inc"
%include "ppu/ppu.inc"
%include "ppu/screen.inc"
section .text
EXPORT_C windows_text_start
section .data
EXPORT_C windows_data_start
section .bss
EXPORT_C windows_bss_start
section .data
ALIGND
EXPORT ClipTableStart
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
EXPORT ClipLeftTable ;ClipLeftTable[-first_pixel_offset]
db 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
db 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
EXPORT ClipRightTable ;ClipRightTable[-pixel_count]
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
;to clip both: ClipLeftTable[-first_pixel_offset] &
; ClipRightTable[-(first_pixel_offset + pixel_count)]
section .bss
ALIGNB
EXPORT Window_Offset_First,skipl
EXPORT Window_Offset_Second,skipl
EXPORT_C WH0,skipb ; Holds window 1 left position
EXPORT_C TM ,skipb ; 000odcba o=OBJ enable,a-d=BG1-4 enable
EXPORT_C WBGLOG,skipb ; BG Window mask logic
EXPORT_C W12SEL ,skipb ; Holds plane 1/2 window mask settings
EXPORT_C WH1,skipb ; Holds window 1 right position
EXPORT_C TMW,skipb
EXPORT_C WOBJLOG,skipb ; OBJ/Colour Window mask logic
EXPORT_C W34SEL ,skipb ; Holds plane 3/4 window mask settings
EXPORT_C WH2,skipb ; Holds window 2 left position
EXPORT_C TS ,skipb ; 000odcba o=OBJ enable,a-d=BG1-4 enable
EXPORT_C CGWSEL,skipb
EXPORT_C WOBJSEL,skipb ; Holds colour/object window mask settings
EXPORT_C WH3,skipb ; Holds window 2 right position
EXPORT_C TSW,skipb
EXPORT_C CGADSUB,skipb
;Layering vars
EXPORT Layers_Low ; one of allowed TM, TS, or TM || TS
EXPORT Layers_High ; one of allowed TS, TM, or 0
EXPORT_C Layering_Mode,skipb
EXPORT SCR_TM,skipb ; TM taken from here
EXPORT SCR_TS,skipb ; TS taken from here
EXPORT SCR_TMW,skipb ; TMW taken from here
EXPORT SCR_TSW,skipb ; TSW taken from here
EXPORT_C Layer_Disable_Mask,skipb ; This is used to force planes to disable!
EXPORT TM_Allowed,skipb ; allowed layer mask & layer disable mask & TM
EXPORT TS_Allowed,skipb ; allowed layer mask & layer disable mask & TS
EXPORT Layers_In_Use,skipb ; TM_Allowed | TS_Allowed
%macro WIN_DATA 1
ALIGNB
EXPORT_C TableWin%1
EXPORT_C Win%1_Count_Out,skipb
EXPORT_C Win%1_Bands_Out,skipb 2*2
EXPORT_C Win%1_Count_In,skipb
EXPORT_C Win%1_Bands_In,skipb 2
%endmacro
WIN_DATA 1
WIN_DATA 2
ALIGNB
EXPORT TileClip1
EXPORT TileClip1Left,skipl
EXPORT TileClip1Right,skipl
EXPORT TileClip2
EXPORT TileClip2Left,skipl
EXPORT TileClip2Right,skipl
EXPORT Redo_Layering,skipb
EXPORT Redo_Windowing,skipb
;YXCS 4321
;1-4 update clip window for BG 1-4
;S update clip window for OBJ (sprites)
;C update color window
;X update window 1 area
;Y update window 2 area
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]
;al = left edge, cl = right edge + 1
ALIGNC
EXPORT_C Recalc_Window_Bands
test cl,cl ; 0 = 255 (right edge)
jz .one_inside
cmp cl,al
jbe .full_outside ; if (Right < Left) full range outside window;
.one_inside:
mov [Win_Bands_In+edx],al
test al,al
mov byte [Win_Count_In+edx],1 ; One band inside window (left,right)
mov [Win_Bands_In+edx+1],cl
jnz .not_flush_left ; if (!Left) window flush left;
test cl,cl
jnz .flush_one_side ; if (!Left && Right == 255) full range inside;
; Full range inside window
mov byte [Win_Count_Out+edx],0 ; No bands outside window
jmp .done
.not_flush_left:
; Window not flush left (1 inside, 1 or 2 outside)
test cl,cl
jz .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 [Win_Count_Out+edx],2 ; One band outside window (right+1,left-1)
mov [Win_Bands_Out+edx+1],al
mov byte [Win_Bands_Out+edx],0
mov [Win_Bands_Out+edx+2],cl
mov byte [Win_Bands_Out+edx+3],0
jmp .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 [Win_Bands_Out+edx+1],al
mov byte [Win_Count_Out+edx],1 ; One band outside window (right+1,left-1)
mov [Win_Bands_Out+edx],cl
jmp .done
.full_outside:
; Full range outside window (0 inside, 1 outside)
mov byte [Win_Count_Out+edx],1 ; One band outside window
mov dword [Win_Bands_Out+edx],0 ; Full range band
mov byte [Win_Count_In+edx],0 ; No bands inside window
.done:
ret
;%1 = Left,%2 = Right,%3 = Window table
%macro Recalc_Single_Window 3
LOAD_WIN_TABLE %3
mov al,[%1]
mov cl,[%2]
call C_LABEL(Recalc_Window_Bands)
%endmacro
%macro Recalc_Window_BG_Main 1
mov al,[SCR_TM]
LOAD_BG_TABLE %1,edi
mov cl,[SCR_TMW]
mov esi,BG_Win_Main
and al,cl
call C_LABEL(Recalc_Window_Area_BG)
%endmacro
%macro Recalc_Window_BG_Sub 1
mov al,[SCR_TS]
LOAD_BG_TABLE %1,edi
mov cl,[SCR_TSW]
mov esi,BG_Win_Sub
and al,cl
call C_LABEL(Recalc_Window_Area_BG)
%endmacro
ALIGNC
EXPORT_C Recalc_Window_Area_BG
test al,[BG_Flag+edi]
jz .no_clip
mov ax,[WSEL+edi] ;WSEL, WLOG
test al,8+2
jz .no_clip
jpe .intersect
add edi,esi
LOAD_WIN_TABLE 2
test al,2
jz .single_window_clip_2
LOAD_WIN_TABLE 1
shl al,2
.single_window_clip_2:
; we want drawn areas, not window areas, so we need the inverted results...
test al,4
jz .draw_outside
add edx,byte Win_In - Win_Out
.draw_outside:
mov al,[Win_Count+edx]
mov [edi+Win_Count],al
test al,al
jz .no_runs
.next_run:
mov cx,[edx+Win_Bands]
add edx,byte 2
mov [edi+Win_Bands],cx
add edi,byte 2
dec al
jnz .next_run
.no_runs:
ret
.no_clip:
mov byte [edi+esi+Win_Count],1
mov byte [edi+esi+Win_Bands+0],0
mov byte [edi+esi+Win_Bands+1],0
ret
; Method of generation depends on logic mode.
; OR logic uses AND on the bands outside the window area to compute
; the areas to be drawn. No seperate bands can end up adjacent to each
; other, so coalesence is unnecessary.
; AND logic uses OR on the bands outside the window area to compute
; the areas to be drawn, logic code handles coalescence of adjacent
; bands.
; XOR and XNOR logic use a sorted set of window edges, with duplicate
; edges discarded.
;logic - 00 = or; 01 = and; 10 = xor; 11 = xnor
; we want drawn areas, not window areas, so we need the inverted results...
; or = and of outside
; and = or of outside
; xor = xor of inside 1, outside 2
; xnor = xor of outside both
; edi = BG table
; esi = screen offset in BG table
.intersect:
and ah,3
cmp ah,1
je .intersect_and_setup
ja .intersect_xor_check
;each intersect setup code chains to an intersect handler
;each intersect handler expects the following register state:
; edx = address of window 1 bands
; esi = address of window 2 bands
; cl = count of window 1 bands
; ch = count of window 2 bands
; ebp = 0
; edi = address for output window area (BG_WIN_DATA)
;for OR window logic, we use AND of inverted (outside) areas
.intersect_or_setup:
add edi,esi
LOAD_WIN_TABLE 1
LOAD_WIN_TABLE 2,esi
xor ebp,ebp
; we want drawn areas, not window areas, so we need the inverted results...
test al,1
jz .or_draw_outside_1
add edx,byte Win_In - Win_Out
.or_draw_outside_1:
test al,4
jz .or_draw_outside_2
add esi,byte Win_In - Win_Out
.or_draw_outside_2:
.intersect_and_entry:
mov cl,[Win_Count+edx]
test cl,cl
jz .and_no_more_bands
mov ch,[Win_Count+esi]
test ch,ch
jz .and_no_more_bands
.and_win1_loop:
push ecx
mov ax,[edx+Win_Bands]
dec ah
push esi
.and_win2_loop:
mov bx,[esi+Win_Bands]
dec bh
cmp al,bh ;win1left, win2right
ja .and_no_intersect
cmp bl,ah ;win2left, win1right
ja .and_no_more_intersect
cmp bl,al
ja .and_max_left
mov bl,al
.and_max_left:
mov [edi+ebp*2+Win_Bands],bl
cmp bh,ah
jb .and_min_right
mov bh,ah
.and_min_right:
inc bh
mov [edi+ebp*2+Win_Bands+1],bh
inc ebp
add esi,byte 2
dec ch
jnz .and_win2_loop
.and_no_more_intersect:
pop esi
pop ecx
add edx,byte 2
dec cl
jnz .and_win1_loop
.and_no_more_bands:
mov eax,ebp
mov [edi+Win_Count],al
ret
.and_no_intersect:
add esi,byte 2
dec ch
mov [esp],esi
mov [esp+4],ecx
jnz .and_win2_loop
add esp,byte 8
jmp .and_no_more_bands
;for AND window logic, we use OR of inverted (outside) areas
.intersect_and_setup:
add edi,esi
LOAD_WIN_TABLE 1
LOAD_WIN_TABLE 2,esi
xor ebp,ebp
; we want drawn areas, not window areas, so we need the inverted results...
test al,1
jz .and_draw_outside_1
add edx,byte Win_In - Win_Out
.and_draw_outside_1:
test al,4
jz .and_draw_outside_2
add esi,byte Win_In - Win_Out
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -