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

📄 windows.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

; 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 + -