mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-06-04 21:29:27 +00:00
Compare commits
2 Commits
b2ead87d25
...
9cc5b2e3af
Author | SHA1 | Date | |
---|---|---|---|
|
9cc5b2e3af | ||
|
f6371f914e |
159
demos/smb/Main.s
159
demos/smb/Main.s
|
@ -18,7 +18,7 @@ DOWN_ARROW equ $0A
|
||||||
; Nametable queue
|
; Nametable queue
|
||||||
NT_QUEUE_LEN equ $1000
|
NT_QUEUE_LEN equ $1000
|
||||||
NT_QUEUE_SIZE equ {2*NT_QUEUE_LEN}
|
NT_QUEUE_SIZE equ {2*NT_QUEUE_LEN}
|
||||||
NT_QUEUE_MOD equ {NT_QUEUE_SIZE-1}
|
NT_QUEUE_MOD equ {NT_QUEUE_SIZE-1}
|
||||||
|
|
||||||
mx %00
|
mx %00
|
||||||
|
|
||||||
|
@ -38,8 +38,26 @@ CurrNTQueueEnd equ 40
|
||||||
BGToggle equ 44
|
BGToggle equ 44
|
||||||
LastEnable equ 46
|
LastEnable equ 46
|
||||||
ShowFPS equ 48
|
ShowFPS equ 48
|
||||||
|
HideStatusBar equ 50
|
||||||
|
;ROMPlayerY equ 52
|
||||||
|
YOrigin equ 54
|
||||||
|
|
||||||
OldOneSec equ 100
|
OldOneSec equ 100
|
||||||
|
RenderFlags equ 102
|
||||||
|
NesTop equ 104 ; Clip any sprite that has a NES OAM y-coordinate above this line
|
||||||
|
NesBottom equ 106 ; Clip any sprite that has a NES OAM y-coordinate below this line
|
||||||
|
ScreenBase equ 108 ; SHR address of the top-left edge of the play field
|
||||||
|
ScreenRows equ 110 ; Number of 8-line block we are showing on-screen
|
||||||
|
ScreenHeight equ 112
|
||||||
|
ScreenTop equ 114 ; SCB line of the top of the play field
|
||||||
|
|
||||||
|
MinYScroll equ 116 ; Smallest YOrigin value: 0 when showing stratus bar, 16 when hiding status bar
|
||||||
|
MaxYScroll equ 118 ; Largest YOrigin value for GTESetBG0Origin
|
||||||
|
|
||||||
|
;VirtTop equ 104 ; The top virtual line that is the top of the active play field (excludes status bar)
|
||||||
|
;VirtBottom equ 106 ; The bottom virtual line that is bottom of the active play field
|
||||||
|
;MaxNesY equ 108 ; This is the largest NES y coordinate that will display in the active play field
|
||||||
|
;MinNesY equ 110 ; This is the smallest NES y coordinate that will display in the active play field
|
||||||
|
|
||||||
Tmp0 equ 240
|
Tmp0 equ 240
|
||||||
Tmp1 equ 242
|
Tmp1 equ 242
|
||||||
|
@ -66,6 +84,8 @@ FTblTmp equ 228
|
||||||
stz OldROMScrollEdge
|
stz OldROMScrollEdge
|
||||||
stz LastAreaType
|
stz LastAreaType
|
||||||
stz ShowFPS
|
stz ShowFPS
|
||||||
|
stz HideStatusBar
|
||||||
|
stz YOrigin
|
||||||
|
|
||||||
lda #1
|
lda #1
|
||||||
sta BGToggle
|
sta BGToggle
|
||||||
|
@ -73,6 +93,39 @@ FTblTmp equ 228
|
||||||
lda #$0008
|
lda #$0008
|
||||||
sta LastEnable
|
sta LastEnable
|
||||||
|
|
||||||
|
lda #16
|
||||||
|
; lda #32
|
||||||
|
sta NesTop
|
||||||
|
|
||||||
|
lda #16
|
||||||
|
sta MinYScroll
|
||||||
|
|
||||||
|
lda #1
|
||||||
|
sta HideStatusBar
|
||||||
|
|
||||||
|
lda #128
|
||||||
|
sta ScreenHeight
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
sta ScreenRows
|
||||||
|
|
||||||
|
lda #200
|
||||||
|
sec
|
||||||
|
sbc ScreenHeight
|
||||||
|
sta MaxYScroll
|
||||||
|
|
||||||
|
lda NesTop
|
||||||
|
clc
|
||||||
|
adc ScreenHeight
|
||||||
|
sec
|
||||||
|
sbc #8
|
||||||
|
inc
|
||||||
|
sta NesBottom
|
||||||
|
|
||||||
|
; lda #0
|
||||||
|
; sta ScreenTop
|
||||||
|
|
||||||
; The next two direct pages will be used by GTE, so get another 2 pages beyond that for the ROM. We get
|
; The next two direct pages will be used by GTE, so get another 2 pages beyond that for the ROM. We get
|
||||||
; 4K of DP/Stack space by default, so there is plenty to share
|
; 4K of DP/Stack space by default, so there is plenty to share
|
||||||
|
|
||||||
|
@ -143,12 +196,36 @@ FTblTmp equ 228
|
||||||
; pea #184
|
; pea #184
|
||||||
|
|
||||||
pea #128
|
pea #128
|
||||||
pea #200
|
pei ScreenHeight
|
||||||
|
|
||||||
; pea #80
|
; pea #80
|
||||||
; pea #144
|
; pea #144
|
||||||
_GTESetScreenMode
|
_GTESetScreenMode
|
||||||
|
|
||||||
|
pha ; Allocate space for x, y, width, height
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
pha
|
||||||
|
_GTEGetScreenInfo
|
||||||
|
pla ; Discard x
|
||||||
|
pla
|
||||||
|
sta ScreenTop
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
sta ScreenBase
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
clc
|
||||||
|
adc ScreenBase
|
||||||
|
clc
|
||||||
|
adc #$2000+x_offset
|
||||||
|
sta ScreenBase
|
||||||
|
pla ; Discard width and height
|
||||||
|
pla
|
||||||
|
|
||||||
ldx #Area1Palette
|
ldx #Area1Palette
|
||||||
lda #TmpPalette
|
lda #TmpPalette
|
||||||
jsr NESColorToIIgs
|
jsr NESColorToIIgs
|
||||||
|
@ -391,6 +468,13 @@ EvtLoop
|
||||||
brl EvtLoop
|
brl EvtLoop
|
||||||
:not_t
|
:not_t
|
||||||
|
|
||||||
|
cmp #'x' ; break
|
||||||
|
bne :not_x
|
||||||
|
lda #1
|
||||||
|
sta user_break
|
||||||
|
brl EvtLoop
|
||||||
|
:not_x
|
||||||
|
|
||||||
cmp #'q'
|
cmp #'q'
|
||||||
beq Exit
|
beq Exit
|
||||||
brl EvtLoop
|
brl EvtLoop
|
||||||
|
@ -416,6 +500,7 @@ DPSave dw 0
|
||||||
LastAreaType dw 0
|
LastAreaType dw 0
|
||||||
frameCount dw 0
|
frameCount dw 0
|
||||||
show_vbl_cpu dw 0
|
show_vbl_cpu dw 0
|
||||||
|
user_break dw 0
|
||||||
|
|
||||||
; Toggle an APU control bit
|
; Toggle an APU control bit
|
||||||
ToggleAPUChannel
|
ToggleAPUChannel
|
||||||
|
@ -497,16 +582,42 @@ RenderFrame
|
||||||
pha
|
pha
|
||||||
|
|
||||||
; Get the player's Y coordinate and determine of we need to adjust the camera based on the physical play field size
|
; Get the player's Y coordinate and determine of we need to adjust the camera based on the physical play field size
|
||||||
; sep #$20
|
ldx ROMZeroPg
|
||||||
; ldal ROMBase+$b5 ; Player_Y_HighPos
|
ldal $0000b5,x ; Player_Y_Page ; 0 = above screen, 1 = on screen, 2 = below
|
||||||
; xba
|
and #$00FF
|
||||||
; ldal ROMBase+$ce ; Player_Y_Position
|
beq :max_clamp
|
||||||
; rep #$20
|
cmp #2
|
||||||
;
|
beq :min_clamp
|
||||||
; sec
|
|
||||||
; sbc TopClip ; If we're hiding the
|
|
||||||
|
|
||||||
pea $0000
|
ldal $0000ce,x ; Player_Y_Position
|
||||||
|
and #$00FF
|
||||||
|
; sta ROMPlayerY
|
||||||
|
|
||||||
|
; The "full screen" size is 200 lines that cover NES rows 16 through 216. If the
|
||||||
|
; size of the playfield is less, then we adjust the origin a bit.
|
||||||
|
;
|
||||||
|
; Y_Origin = min(200 - ScreenHeight, max(0, ROMPlayerY - 16 - ScreenHeight/2))
|
||||||
|
|
||||||
|
sec
|
||||||
|
sbc NesTop
|
||||||
|
asl
|
||||||
|
sec
|
||||||
|
sbc ScreenHeight
|
||||||
|
bmi :max_neg
|
||||||
|
lsr
|
||||||
|
cmp MinYScroll
|
||||||
|
bcc :max_clamp
|
||||||
|
|
||||||
|
cmp MaxYScroll
|
||||||
|
bcc :set_y
|
||||||
|
:min_clamp lda MaxYScroll
|
||||||
|
bra :set_y
|
||||||
|
:max_neg
|
||||||
|
:max_clamp
|
||||||
|
lda MinYScroll
|
||||||
|
:set_y
|
||||||
|
sta YOrigin
|
||||||
|
pha
|
||||||
_GTESetBG0Origin
|
_GTESetBG0Origin
|
||||||
|
|
||||||
lda ppumask
|
lda ppumask
|
||||||
|
@ -518,11 +629,21 @@ RenderFrame
|
||||||
_GTEEnableBackground
|
_GTEEnableBackground
|
||||||
:bghop
|
:bghop
|
||||||
|
|
||||||
pea $FFFF ; NES mode
|
; pea $FFFF ; NES mode
|
||||||
|
lda HideStatusBar
|
||||||
|
beq :full_screen
|
||||||
|
|
||||||
|
pea $FFFD
|
||||||
_GTERender
|
_GTERender
|
||||||
|
bra :render_done
|
||||||
|
|
||||||
|
:full_screen
|
||||||
|
pea $FFFF
|
||||||
|
_GTERender
|
||||||
|
:render_done
|
||||||
|
|
||||||
; Check the AreaType and see if the palette needs to be changed. We do this after the screen is blitted
|
; Check the AreaType and see if the palette needs to be changed. We do this after the screen is blitted
|
||||||
; so the palette does not get changed too eary while old pixels are still on the screen.
|
; so the palette does not get changed too early while old pixels are still on the screen.
|
||||||
|
|
||||||
ldal ROMBase+$074E
|
ldal ROMBase+$074E
|
||||||
and #$00FF
|
and #$00FF
|
||||||
|
@ -845,7 +966,8 @@ DrainNTQueue
|
||||||
; issues because many frames can pass before Render gets control again. We need to expose a
|
; issues because many frames can pass before Render gets control again. We need to expose a
|
||||||
; _SetTileImmediate function in the list of function callbacks....
|
; _SetTileImmediate function in the list of function callbacks....
|
||||||
|
|
||||||
_GTESetTile
|
_GTESetTileImmediate
|
||||||
|
; _GTESetTile
|
||||||
; inc :Count
|
; inc :Count
|
||||||
brl :skip
|
brl :skip
|
||||||
|
|
||||||
|
@ -1106,7 +1228,9 @@ CopyStatus
|
||||||
inx
|
inx
|
||||||
stx Tmp2
|
stx Tmp2
|
||||||
|
|
||||||
_GTESetTile
|
; _GTESetTile
|
||||||
|
_GTESetTileImmediate
|
||||||
|
|
||||||
|
|
||||||
ply
|
ply
|
||||||
plx
|
plx
|
||||||
|
@ -1193,7 +1317,8 @@ CopyNametable
|
||||||
stx Tmp2
|
stx Tmp2
|
||||||
:x_hop
|
:x_hop
|
||||||
|
|
||||||
_GTESetTile
|
; _GTESetTile
|
||||||
|
_GTESetTileImmediate
|
||||||
|
|
||||||
ply
|
ply
|
||||||
plx
|
plx
|
||||||
|
|
168
demos/smb/apu.s
168
demos/smb/apu.s
|
@ -287,16 +287,24 @@ setup_doc_registers
|
||||||
|
|
||||||
jsr access_doc_registers
|
jsr access_doc_registers
|
||||||
|
|
||||||
ldx #pulse1_sound_settings
|
ldx #pulse1_sound_settings_l
|
||||||
|
jsr copy_register_config
|
||||||
|
ldx #pulse1_sound_settings_r
|
||||||
jsr copy_register_config
|
jsr copy_register_config
|
||||||
|
|
||||||
ldx #pulse2_sound_settings
|
ldx #pulse2_sound_settings_l
|
||||||
|
jsr copy_register_config
|
||||||
|
ldx #pulse2_sound_settings_r
|
||||||
jsr copy_register_config
|
jsr copy_register_config
|
||||||
|
|
||||||
ldx #triangle_sound_settings
|
ldx #triangle_sound_settings_l
|
||||||
|
jsr copy_register_config
|
||||||
|
ldx #triangle_sound_settings_r
|
||||||
jsr copy_register_config
|
jsr copy_register_config
|
||||||
|
|
||||||
ldx #noise_sound_settings
|
ldx #noise_sound_settings_l
|
||||||
|
jsr copy_register_config
|
||||||
|
ldx #noise_sound_settings_r
|
||||||
jsr copy_register_config
|
jsr copy_register_config
|
||||||
|
|
||||||
rep #$20
|
rep #$20
|
||||||
|
@ -388,7 +396,7 @@ pulse2_oscillator = 2
|
||||||
triangle_oscillator = 4
|
triangle_oscillator = 4
|
||||||
noise_oscillator = 6
|
noise_oscillator = 6
|
||||||
default_freq = 800
|
default_freq = 800
|
||||||
pulse1_sound_settings = *
|
pulse1_sound_settings_l = *
|
||||||
dfb $00+pulse1_oscillator,default_freq ; frequency low register
|
dfb $00+pulse1_oscillator,default_freq ; frequency low register
|
||||||
dfb $20+pulse1_oscillator,default_freq/256 ; frequency high register
|
dfb $20+pulse1_oscillator,default_freq/256 ; frequency high register
|
||||||
dfb $40+pulse1_oscillator,0 ; volume register, volume = 0
|
dfb $40+pulse1_oscillator,0 ; volume register, volume = 0
|
||||||
|
@ -396,7 +404,15 @@ pulse1_sound_settings = *
|
||||||
dfb $c0+pulse1_oscillator,0 ; wavetable size register, 256 byte length
|
dfb $c0+pulse1_oscillator,0 ; wavetable size register, 256 byte length
|
||||||
dfb $a0+pulse1_oscillator,0 ; mode register, set to free run
|
dfb $a0+pulse1_oscillator,0 ; mode register, set to free run
|
||||||
|
|
||||||
pulse2_sound_settings = *
|
pulse1_sound_settings_r = *
|
||||||
|
dfb $01+pulse1_oscillator,default_freq ; frequency low register
|
||||||
|
dfb $21+pulse1_oscillator,default_freq/256 ; frequency high register
|
||||||
|
dfb $41+pulse1_oscillator,0 ; volume register, volume = 0
|
||||||
|
dfb $81+pulse1_oscillator,3 ; wavetable pointer register, point to $0300 by default (50% duty cycle)
|
||||||
|
dfb $c1+pulse1_oscillator,0 ; wavetable size register, 256 byte length
|
||||||
|
dfb $a1+pulse1_oscillator,$10 ; mode register, set to free run
|
||||||
|
|
||||||
|
pulse2_sound_settings_l = *
|
||||||
dfb $00+pulse2_oscillator,default_freq ; frequency low register
|
dfb $00+pulse2_oscillator,default_freq ; frequency low register
|
||||||
dfb $20+pulse2_oscillator,default_freq/256 ; frequency high register
|
dfb $20+pulse2_oscillator,default_freq/256 ; frequency high register
|
||||||
dfb $40+pulse2_oscillator,0 ; volume register, volume = 0
|
dfb $40+pulse2_oscillator,0 ; volume register, volume = 0
|
||||||
|
@ -404,7 +420,15 @@ pulse2_sound_settings = *
|
||||||
dfb $c0+pulse2_oscillator,0 ; wavetable size register, 256 byte length
|
dfb $c0+pulse2_oscillator,0 ; wavetable size register, 256 byte length
|
||||||
dfb $a0+pulse2_oscillator,0 ; mode register, set to free run
|
dfb $a0+pulse2_oscillator,0 ; mode register, set to free run
|
||||||
|
|
||||||
triangle_sound_settings = *
|
pulse2_sound_settings_r = *
|
||||||
|
dfb $01+pulse2_oscillator,default_freq ; frequency low register
|
||||||
|
dfb $21+pulse2_oscillator,default_freq/256 ; frequency high register
|
||||||
|
dfb $41+pulse2_oscillator,0 ; volume register, volume = 0
|
||||||
|
dfb $81+pulse2_oscillator,3 ; wavetable pointer register, point to $0300 by default (50% duty cycle)
|
||||||
|
dfb $c1+pulse2_oscillator,0 ; wavetable size register, 256 byte length
|
||||||
|
dfb $a1+pulse2_oscillator,$10 ; mode register, set to free run
|
||||||
|
|
||||||
|
triangle_sound_settings_l = *
|
||||||
dfb $00+triangle_oscillator,default_freq ; frequency low register
|
dfb $00+triangle_oscillator,default_freq ; frequency low register
|
||||||
dfb $20+triangle_oscillator,default_freq/256 ; frequency high register
|
dfb $20+triangle_oscillator,default_freq/256 ; frequency high register
|
||||||
dfb $40+triangle_oscillator,0 ; volume register, volume = 0
|
dfb $40+triangle_oscillator,0 ; volume register, volume = 0
|
||||||
|
@ -412,7 +436,15 @@ triangle_sound_settings = *
|
||||||
dfb $c0+triangle_oscillator,0 ; wavetable size register, 256 byte length
|
dfb $c0+triangle_oscillator,0 ; wavetable size register, 256 byte length
|
||||||
dfb $a0+triangle_oscillator,0 ; mode register, set to free run
|
dfb $a0+triangle_oscillator,0 ; mode register, set to free run
|
||||||
|
|
||||||
noise_sound_settings = *
|
triangle_sound_settings_r = *
|
||||||
|
dfb $01+triangle_oscillator,default_freq ; frequency low register
|
||||||
|
dfb $21+triangle_oscillator,default_freq/256 ; frequency high register
|
||||||
|
dfb $41+triangle_oscillator,0 ; volume register, volume = 0
|
||||||
|
dfb $81+triangle_oscillator,5 ; wavetable pointer register, point to $0500
|
||||||
|
dfb $c1+triangle_oscillator,0 ; wavetable size register, 256 byte length
|
||||||
|
dfb $a1+triangle_oscillator,$10 ; mode register, set to free run
|
||||||
|
|
||||||
|
noise_sound_settings_l = *
|
||||||
dfb $00+noise_oscillator,default_freq ; frequency low register
|
dfb $00+noise_oscillator,default_freq ; frequency low register
|
||||||
dfb $20+noise_oscillator,default_freq/256 ; frequency high register
|
dfb $20+noise_oscillator,default_freq/256 ; frequency high register
|
||||||
dfb $40+noise_oscillator,128 ; volume register, volume = 0
|
dfb $40+noise_oscillator,128 ; volume register, volume = 0
|
||||||
|
@ -420,6 +452,15 @@ noise_sound_settings = *
|
||||||
dfb $c0+noise_oscillator,0 ; wavetable size register, 256 byte length
|
dfb $c0+noise_oscillator,0 ; wavetable size register, 256 byte length
|
||||||
dfb $a0+noise_oscillator,0 ; mode register, set to free run
|
dfb $a0+noise_oscillator,0 ; mode register, set to free run
|
||||||
|
|
||||||
|
noise_sound_settings_r = *
|
||||||
|
dfb $01+noise_oscillator,default_freq ; frequency low register
|
||||||
|
dfb $21+noise_oscillator,default_freq/256 ; frequency high register
|
||||||
|
dfb $41+noise_oscillator,128 ; volume register, volume = 0
|
||||||
|
dfb $81+noise_oscillator,6 ; wavetable pointer register, point to $0600
|
||||||
|
dfb $c1+noise_oscillator,0 ; wavetable size register, 256 byte length
|
||||||
|
dfb $a1+noise_oscillator,$10 ; mode register, set to free run
|
||||||
|
|
||||||
|
|
||||||
backup_interrupt_ptr ds 4
|
backup_interrupt_ptr ds 4
|
||||||
apu_mode ds 2
|
apu_mode ds 2
|
||||||
|
|
||||||
|
@ -703,22 +744,25 @@ update_doc_registers
|
||||||
sta _apu_pulse1_last_period
|
sta _apu_pulse1_last_period
|
||||||
jsr get_pulse_freq ; return freq in 16-bit accumulator
|
jsr get_pulse_freq ; return freq in 16-bit accumulator
|
||||||
sep #$30
|
sep #$30
|
||||||
|
|
||||||
ldx #$00+pulse1_oscillator
|
ldx #$00+pulse1_oscillator
|
||||||
stx sound_address
|
jsr set_osc_register_pair
|
||||||
sta sound_data
|
; stx sound_address
|
||||||
|
; sta sound_data
|
||||||
ldx #$20+pulse1_oscillator
|
ldx #$20+pulse1_oscillator
|
||||||
stx sound_address
|
; stx sound_address
|
||||||
xba
|
xba
|
||||||
sta sound_data
|
jsr set_osc_register_pair
|
||||||
|
; sta sound_data
|
||||||
:freq_end_pulse1 sep #$30 ; redundent, but avoids extra branches
|
:freq_end_pulse1 sep #$30 ; redundent, but avoids extra branches
|
||||||
|
|
||||||
lda #$80+pulse1_oscillator
|
ldx #$80+pulse1_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda APU_PULSE1_REG1 ; Get the cycle duty bits
|
lda APU_PULSE1_REG1 ; Get the cycle duty bits
|
||||||
jsr set_pulse_duty_cycle
|
jsr set_pulse_duty_cycle
|
||||||
|
|
||||||
lda #$40+pulse1_oscillator
|
ldx #$40+pulse1_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda APU_PULSE1_REG1
|
lda APU_PULSE1_REG1
|
||||||
bit #PULSE_CONST_VOL_FLAG ; Check the constant volume bit
|
bit #PULSE_CONST_VOL_FLAG ; Check the constant volume bit
|
||||||
bne :set_volume_pulse1
|
bne :set_volume_pulse1
|
||||||
|
@ -727,11 +771,12 @@ update_doc_registers
|
||||||
|
|
||||||
:mute_pulse1
|
:mute_pulse1
|
||||||
sep #$30
|
sep #$30
|
||||||
lda #$40+pulse1_oscillator
|
ldx #$40+pulse1_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda #0
|
lda #0
|
||||||
:set_volume_pulse1 jsr set_pulse_volume
|
:set_volume_pulse1 jsr set_pulse_volume
|
||||||
|
|
||||||
|
|
||||||
; Now do the second square wave
|
; Now do the second square wave
|
||||||
lda APU_PULSE2_MUTE ; If the sweep muted the channel, no output
|
lda APU_PULSE2_MUTE ; If the sweep muted the channel, no output
|
||||||
bne :mute_pulse2
|
bne :mute_pulse2
|
||||||
|
@ -748,21 +793,23 @@ update_doc_registers
|
||||||
jsr get_pulse_freq ; return freq in 16-bic accumulator
|
jsr get_pulse_freq ; return freq in 16-bic accumulator
|
||||||
sep #$30
|
sep #$30
|
||||||
ldx #$00+pulse2_oscillator
|
ldx #$00+pulse2_oscillator
|
||||||
stx sound_address
|
; stx sound_address
|
||||||
sta sound_data
|
; sta sound_data
|
||||||
|
jsr set_osc_register_pair
|
||||||
ldx #$20+pulse2_oscillator
|
ldx #$20+pulse2_oscillator
|
||||||
stx sound_address
|
; stx sound_address
|
||||||
xba
|
xba
|
||||||
sta sound_data
|
; sta sound_data
|
||||||
|
jsr set_osc_register_pair
|
||||||
:freq_end_pulse2 sep #$30
|
:freq_end_pulse2 sep #$30
|
||||||
|
|
||||||
lda #$80+pulse2_oscillator
|
ldx #$80+pulse2_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda APU_PULSE2_REG1 ; Get the cycle duty bits
|
lda APU_PULSE2_REG1 ; Get the cycle duty bits
|
||||||
jsr set_pulse_duty_cycle
|
jsr set_pulse_duty_cycle
|
||||||
|
|
||||||
lda #$40+pulse2_oscillator
|
ldx #$40+pulse2_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda APU_PULSE2_REG1
|
lda APU_PULSE2_REG1
|
||||||
bit #PULSE_CONST_VOL_FLAG ; Check the constant volume bit
|
bit #PULSE_CONST_VOL_FLAG ; Check the constant volume bit
|
||||||
bne :set_volume_pulse2
|
bne :set_volume_pulse2
|
||||||
|
@ -770,8 +817,8 @@ update_doc_registers
|
||||||
bra :set_volume_pulse2
|
bra :set_volume_pulse2
|
||||||
:mute_pulse2
|
:mute_pulse2
|
||||||
sep #$30
|
sep #$30
|
||||||
lda #$40+pulse2_oscillator
|
ldx #$40+pulse2_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda #0
|
lda #0
|
||||||
:set_volume_pulse2 jsr set_pulse_volume
|
:set_volume_pulse2 jsr set_pulse_volume
|
||||||
|
|
||||||
|
@ -802,23 +849,25 @@ update_doc_registers
|
||||||
lsr
|
lsr
|
||||||
sep #$30
|
sep #$30
|
||||||
ldx #$00+triangle_oscillator
|
ldx #$00+triangle_oscillator
|
||||||
stx sound_address
|
; stx sound_address
|
||||||
sta sound_data
|
; sta sound_data
|
||||||
|
jsr set_osc_register_pair
|
||||||
ldx #$20+triangle_oscillator
|
ldx #$20+triangle_oscillator
|
||||||
stx sound_address
|
; stx sound_address
|
||||||
xba
|
xba
|
||||||
sta sound_data
|
; sta sound_data
|
||||||
|
jsr set_osc_register_pair
|
||||||
:freq_end_triangle sep #$30
|
:freq_end_triangle sep #$30
|
||||||
|
|
||||||
lda #$40+triangle_oscillator
|
ldx #$40+triangle_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda #12 ; Triangle is a bit softer than pulse channels
|
lda #12 ; Triangle is a bit softer than pulse channels
|
||||||
bra :set_volume_triangle
|
bra :set_volume_triangle
|
||||||
|
|
||||||
:mute_triangle
|
:mute_triangle
|
||||||
sep #$30
|
sep #$30
|
||||||
lda #$40+triangle_oscillator
|
ldx #$40+triangle_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda #0
|
lda #0
|
||||||
:set_volume_triangle jsr set_pulse_volume
|
:set_volume_triangle jsr set_pulse_volume
|
||||||
|
|
||||||
|
@ -828,24 +877,26 @@ update_doc_registers
|
||||||
beq :mute_noise
|
beq :mute_noise
|
||||||
|
|
||||||
ldx #$00+noise_oscillator
|
ldx #$00+noise_oscillator
|
||||||
stx sound_address
|
; stx sound_address
|
||||||
lda APU_NOISE_CURRENT_PERIOD
|
lda APU_NOISE_CURRENT_PERIOD
|
||||||
sta sound_data
|
; sta sound_data
|
||||||
|
jsr set_osc_register_pair
|
||||||
ldx #$20+noise_oscillator
|
ldx #$20+noise_oscillator
|
||||||
stx sound_address
|
; stx sound_address
|
||||||
lda APU_NOISE_CURRENT_PERIOD+1
|
lda APU_NOISE_CURRENT_PERIOD+1
|
||||||
sta sound_data
|
; sta sound_data
|
||||||
|
jsr set_osc_register_pair
|
||||||
|
|
||||||
lda #$40+noise_oscillator
|
ldx #$40+noise_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda APU_NOISE_REG1
|
lda APU_NOISE_REG1
|
||||||
bit #NOISE_CONST_VOL_FLAG ; Check the constant volume bit
|
bit #NOISE_CONST_VOL_FLAG ; Check the constant volume bit
|
||||||
bne :set_volume_noise
|
bne :set_volume_noise
|
||||||
lda APU_NOISE_ENVELOPE
|
lda APU_NOISE_ENVELOPE
|
||||||
bra :set_volume_noise
|
bra :set_volume_noise
|
||||||
:mute_noise
|
:mute_noise
|
||||||
lda #$40+noise_oscillator
|
ldx #$40+noise_oscillator
|
||||||
sta sound_address
|
; sta sound_address
|
||||||
lda #0
|
lda #0
|
||||||
:set_volume_noise
|
:set_volume_noise
|
||||||
and #$0F
|
and #$0F
|
||||||
|
@ -860,7 +911,8 @@ update_doc_registers
|
||||||
asl
|
asl
|
||||||
pha
|
pha
|
||||||
:high_pitch pla
|
:high_pitch pla
|
||||||
sta sound_data
|
; sta sound_data
|
||||||
|
jsr set_osc_register_pair
|
||||||
|
|
||||||
:not_timer
|
:not_timer
|
||||||
no_frame
|
no_frame
|
||||||
|
@ -875,17 +927,30 @@ no_frame
|
||||||
clc
|
clc
|
||||||
rtl
|
rtl
|
||||||
|
|
||||||
|
; X = addr
|
||||||
|
; A = data
|
||||||
|
set_osc_register_pair
|
||||||
|
mx %11
|
||||||
|
stx sound_address
|
||||||
|
sta sound_data
|
||||||
|
inc sound_address
|
||||||
|
sta sound_data
|
||||||
|
rts
|
||||||
|
|
||||||
|
; X = addr
|
||||||
|
; A = duty cycle select
|
||||||
set_pulse_duty_cycle
|
set_pulse_duty_cycle
|
||||||
mx %11
|
mx %11
|
||||||
rol
|
rol
|
||||||
rol
|
rol
|
||||||
rol
|
rol
|
||||||
and #$03
|
and #$03
|
||||||
tax
|
tay
|
||||||
|
|
||||||
lda duty_cycle_page,x
|
lda duty_cycle_page,y
|
||||||
sta sound_data
|
jmp set_osc_register_pair
|
||||||
rts
|
; sta sound_data
|
||||||
|
; rts
|
||||||
|
|
||||||
set_pulse_volume
|
set_pulse_volume
|
||||||
and #$0F
|
and #$0F
|
||||||
|
@ -893,8 +958,9 @@ set_pulse_volume
|
||||||
asl
|
asl
|
||||||
asl
|
asl
|
||||||
asl
|
asl
|
||||||
sta sound_data
|
jmp set_osc_register_pair
|
||||||
rts
|
; sta sound_data
|
||||||
|
; rts
|
||||||
|
|
||||||
; This is a bit different because we actually calculate a scan rate directly to match the
|
; This is a bit different because we actually calculate a scan rate directly to match the
|
||||||
; rate at which new samples are read form DOC RAM to the period of the noise channel
|
; rate at which new samples are read form DOC RAM to the period of the noise channel
|
||||||
|
|
130
demos/smb/ppu.s
130
demos/smb/ppu.s
|
@ -110,6 +110,7 @@ PPUMASK_WRITE ENT
|
||||||
|
|
||||||
; $2002 - PPUSTATUS For "ldx ppustatus"
|
; $2002 - PPUSTATUS For "ldx ppustatus"
|
||||||
PPUSTATUS_READ_X ENT
|
PPUSTATUS_READ_X ENT
|
||||||
|
pha ; spacefor result
|
||||||
php
|
php
|
||||||
pha
|
pha
|
||||||
|
|
||||||
|
@ -117,31 +118,29 @@ PPUSTATUS_READ_X ENT
|
||||||
stal w_bit ; Reset the address latch used by PPUSCROLL and PPUADDR
|
stal w_bit ; Reset the address latch used by PPUSCROLL and PPUADDR
|
||||||
|
|
||||||
ldal ppustatus
|
ldal ppustatus
|
||||||
tax
|
sta 3,s
|
||||||
and #$7F ; Clear the VBL flag
|
and #$7F ; Clear the VBL flag
|
||||||
stal ppustatus
|
stal ppustatus
|
||||||
|
|
||||||
pla ; Restore the accumulator (return value in X)
|
pla ; Restore the accumulator (return value in X)
|
||||||
plp
|
plp
|
||||||
phx ; re-read x to set any relevant flags
|
|
||||||
plx
|
plx
|
||||||
|
|
||||||
rtl
|
rtl
|
||||||
|
|
||||||
PPUSTATUS_READ ENT
|
PPUSTATUS_READ ENT
|
||||||
|
pha ; space for return value
|
||||||
php
|
php
|
||||||
|
|
||||||
lda #1
|
lda #1
|
||||||
stal w_bit ; Reset the address latch used by PPUSCROLL and PPUADDR
|
stal w_bit ; Reset the address latch used by PPUSCROLL and PPUADDR
|
||||||
|
|
||||||
ldal ppustatus
|
ldal ppustatus
|
||||||
pha
|
sta 2,s
|
||||||
and #$7F ; Clear the VBL flag
|
and #$7F ; Clear the VBL flag
|
||||||
stal ppustatus
|
stal ppustatus
|
||||||
|
|
||||||
pla ; pop the return value
|
|
||||||
plp
|
plp
|
||||||
pha ; re-read accumulator to set any relevant flags
|
|
||||||
pla
|
pla
|
||||||
rtl
|
rtl
|
||||||
|
|
||||||
|
@ -334,8 +333,8 @@ PPUDATA_WRITE ENT
|
||||||
sta nt_queue,y
|
sta nt_queue,y
|
||||||
|
|
||||||
:full
|
:full
|
||||||
; lda #1
|
lda #1
|
||||||
; jsr setborder
|
jsr setborder
|
||||||
rts
|
rts
|
||||||
|
|
||||||
:attrtbl
|
:attrtbl
|
||||||
|
@ -421,6 +420,30 @@ PPUDATA_WRITE ENT
|
||||||
dex
|
dex
|
||||||
jmp :enqueue
|
jmp :enqueue
|
||||||
|
|
||||||
|
incborder
|
||||||
|
php
|
||||||
|
sep #$20
|
||||||
|
ldal $E0C034
|
||||||
|
inc
|
||||||
|
eorl $E0C034
|
||||||
|
and #$0F
|
||||||
|
eorl $E0C034
|
||||||
|
stal $E0C034
|
||||||
|
plp
|
||||||
|
rts
|
||||||
|
|
||||||
|
decborder
|
||||||
|
php
|
||||||
|
sep #$20
|
||||||
|
ldal $E0C034
|
||||||
|
dec
|
||||||
|
eorl $E0C034
|
||||||
|
and #$0F
|
||||||
|
eorl $E0C034
|
||||||
|
stal $E0C034
|
||||||
|
plp
|
||||||
|
rts
|
||||||
|
|
||||||
setborder
|
setborder
|
||||||
php
|
php
|
||||||
sep #$20
|
sep #$20
|
||||||
|
@ -588,25 +611,47 @@ PPUDMA_WRITE ENT
|
||||||
plp
|
plp
|
||||||
rtl
|
rtl
|
||||||
|
|
||||||
y_offset_rows equ 2
|
;y_offset_rows equ 2
|
||||||
y_height_rows equ 25
|
;y_height_rows equ 25
|
||||||
y_offset equ {y_offset_rows*8}
|
;y_offset equ {y_offset_rows*8}
|
||||||
y_height equ {y_height_rows*8}
|
;y_height equ {y_height_rows*8}
|
||||||
max_nes_y equ {y_height+y_offset-8}
|
;max_nes_y equ {y_height+y_offset-8}
|
||||||
|
|
||||||
x_offset equ 16
|
x_offset equ 16
|
||||||
|
|
||||||
; Scan the OAM memory and copy the values of the sprites that need to be drawn. There are two reasons to do this
|
; Scan the OAM memory and copy the values of the sprites that need to be drawn. There are two reasons to do this
|
||||||
;
|
;
|
||||||
; 1. Freeze the OAM memory at this instanct so that the NES ISR can keep running without changing values
|
; This code has an optimization that it directly scans the NES RAM that would be DMA copied into the PPU
|
||||||
; 2. We have to scan this list twice -- once to build up the shadow list and once to actually render the sprites
|
; OAM space. This is ok, because
|
||||||
|
;
|
||||||
|
; 1. The OAM DMA occurs in the NES ROM before running any game logic
|
||||||
|
; 2. This code is running after the prior ISR, so it is loically happening at the beginning of the next NMI
|
||||||
|
;
|
||||||
|
; When scanning the OAM values, sprites that are not visible for any number of reasons are skipped and the
|
||||||
|
; sprite's y-position is adjusted based on the GTE camera view. This allow all of the shadowBitmap and
|
||||||
|
; shadow lits work to assume an index value of zero is the top of the active play field.
|
||||||
OAM_COPY ds 256
|
OAM_COPY ds 256
|
||||||
spriteCount ds 0
|
spriteCount ds 0
|
||||||
db 0 ; Pad in case we can to access using 16-bit instructions
|
db 0 ; Pad in case we can to access using 16-bit instructions
|
||||||
|
|
||||||
mx %00
|
mx %00
|
||||||
scanOAMSprites
|
scanOAMSprites
|
||||||
stz Tmp5
|
:top_line equ Tmp5
|
||||||
|
:bot_line equ Tmp6
|
||||||
|
|
||||||
|
; In order for the shadow bitmap to be zeroed based on the active playfield, we need to adjust the NES
|
||||||
|
; sprite y-coordinates by the designated top row of the NES graphics screen, and then add an additional
|
||||||
|
; adjustment for the position of the GTE rendering window within that vertical space
|
||||||
|
|
||||||
|
lda NesTop
|
||||||
|
clc
|
||||||
|
adc YOrigin
|
||||||
|
sta :top_line
|
||||||
|
|
||||||
|
lda NesBottom
|
||||||
|
clc
|
||||||
|
adc YOrigin
|
||||||
|
sta :bot_line
|
||||||
|
|
||||||
sep #$30
|
sep #$30
|
||||||
|
|
||||||
|
@ -616,15 +661,23 @@ scanOAMSprites
|
||||||
:loop
|
:loop
|
||||||
; lda PPU_OAM,x ; Y-coordinate
|
; lda PPU_OAM,x ; Y-coordinate
|
||||||
ldal ROMBase+$200,x
|
ldal ROMBase+$200,x
|
||||||
cmp #max_nes_y+1 ; Skip anything that is beyond this line
|
cmp :bot_line
|
||||||
bcs :skip
|
bcs :skip
|
||||||
cmp #y_offset
|
cmp :top_line
|
||||||
bcc :skip
|
bcc :skip
|
||||||
|
sbc :top_line
|
||||||
|
sta OAM_COPY,y ; Keep the adjusted coordinate
|
||||||
|
|
||||||
|
; cmp #max_nes_y+1 ; Skip sprites that are
|
||||||
|
; bcs :skip
|
||||||
|
; cmp #y_offset
|
||||||
|
; bcc :skip
|
||||||
|
|
||||||
; lda PPU_OAM+1,x ; $FC is an empty tile, don't draw it
|
; lda PPU_OAM+1,x ; $FC is an empty tile, don't draw it
|
||||||
ldal ROMBase+$201,x
|
ldal ROMBase+$201,x
|
||||||
cmp #$FC
|
cmp #$FC
|
||||||
beq :skip
|
beq :skip
|
||||||
|
sta OAM_COPY+1,y
|
||||||
|
|
||||||
; lda PPU_OAM+3,x ; If X-coordinate is off the edge skip it, too.
|
; lda PPU_OAM+3,x ; If X-coordinate is off the edge skip it, too.
|
||||||
ldal ROMBase+$203,x
|
ldal ROMBase+$203,x
|
||||||
|
@ -633,8 +686,8 @@ scanOAMSprites
|
||||||
|
|
||||||
rep #$20
|
rep #$20
|
||||||
; lda PPU_OAM,x
|
; lda PPU_OAM,x
|
||||||
ldal ROMBase+$200,x
|
; ldal ROMBase+$200,x
|
||||||
sta OAM_COPY,y
|
; sta OAM_COPY,y
|
||||||
; lda PPU_OAM+2,x
|
; lda PPU_OAM+2,x
|
||||||
ldal ROMBase+$202,x
|
ldal ROMBase+$202,x
|
||||||
sta OAM_COPY+2,y
|
sta OAM_COPY+2,y
|
||||||
|
@ -834,19 +887,18 @@ buildShadowBitmap
|
||||||
rts
|
rts
|
||||||
|
|
||||||
; Set the SCB values equal to the bitmap to visually debug
|
; Set the SCB values equal to the bitmap to visually debug
|
||||||
ldx #0
|
ldx ScreenTop
|
||||||
ldy #0
|
ldy #0
|
||||||
:vloop
|
:vloop
|
||||||
lda #8
|
lda #8
|
||||||
sta Tmp6
|
sta Tmp6
|
||||||
lda shadowBitmap+2,y
|
lda shadowBitmap,y
|
||||||
:iloop
|
:iloop
|
||||||
asl
|
asl
|
||||||
pha
|
pha
|
||||||
|
|
||||||
lda #0
|
lda #0
|
||||||
bcc :zero
|
rol
|
||||||
inc
|
|
||||||
:zero stal $E19D00,x
|
:zero stal $E19D00,x
|
||||||
pla
|
pla
|
||||||
|
|
||||||
|
@ -855,7 +907,7 @@ buildShadowBitmap
|
||||||
bne :iloop
|
bne :iloop
|
||||||
|
|
||||||
iny
|
iny
|
||||||
cpy #25
|
cpy ScreenRows
|
||||||
bcc :vloop
|
bcc :vloop
|
||||||
|
|
||||||
rep #$30
|
rep #$30
|
||||||
|
@ -1016,7 +1068,7 @@ exposeShadowList
|
||||||
|
|
||||||
:exit
|
:exit
|
||||||
ldx :last ; Expose the final part
|
ldx :last ; Expose the final part
|
||||||
ldy #y_height
|
ldy ScreenHeight
|
||||||
lda #0
|
lda #0
|
||||||
jsl LngJmp
|
jsl LngJmp
|
||||||
rts
|
rts
|
||||||
|
@ -1030,16 +1082,15 @@ shadowBitmapToList
|
||||||
|
|
||||||
sep #$30
|
sep #$30
|
||||||
|
|
||||||
ldx #y_offset_rows ; Start at the third row (y_offset = 16) walk the bitmap for 25 bytes (200 lines of height)
|
ldx #0 ; List is zero-based to the active play field
|
||||||
lda #0
|
stz shadowListCount ; zero out the shadow list count
|
||||||
sta shadowListCount ; zero out the shadow list count
|
|
||||||
|
|
||||||
; This loop is called when we are not tracking a sprite range
|
; This loop is called when we are not tracking a sprite range
|
||||||
:zero_loop
|
:zero_loop
|
||||||
ldy shadowBitmap,x
|
ldy shadowBitmap,x
|
||||||
beq :zero_next
|
beq :zero_next
|
||||||
|
|
||||||
lda {mul8-y_offset_rows},x ; This is the scanline we're on (offset by the starting byte)
|
lda mul8,x ; This is the scanline we're on (offset by the starting byte)
|
||||||
clc
|
clc
|
||||||
adc offset,y ; This is the first line defined by the bit pattern
|
adc offset,y ; This is the first line defined by the bit pattern
|
||||||
sta :top
|
sta :top
|
||||||
|
@ -1047,7 +1098,7 @@ shadowBitmapToList
|
||||||
|
|
||||||
:zero_next
|
:zero_next
|
||||||
inx
|
inx
|
||||||
cpx #y_height_rows+y_offset_rows ; +1 ; End at byte 27
|
cpx ScreenRows
|
||||||
bcc :zero_loop
|
bcc :zero_loop
|
||||||
bra :exit ; ended while not tracking a sprite, so exit the function
|
bra :exit ; ended while not tracking a sprite, so exit the function
|
||||||
|
|
||||||
|
@ -1063,7 +1114,8 @@ shadowBitmapToList
|
||||||
and offsetMask,y
|
and offsetMask,y
|
||||||
sta shadowBitmap,x
|
sta shadowBitmap,x
|
||||||
|
|
||||||
lda {mul8-y_offset_rows},x
|
; lda {mul8-y_offset_rows},x
|
||||||
|
lda mul8,x
|
||||||
clc
|
clc
|
||||||
adc invOffset,y
|
adc invOffset,y
|
||||||
|
|
||||||
|
@ -1081,7 +1133,8 @@ shadowBitmapToList
|
||||||
|
|
||||||
:one_next
|
:one_next
|
||||||
inx
|
inx
|
||||||
cpx #y_height_rows+y_offset_rows+1
|
cpx ScreenRows
|
||||||
|
|
||||||
bcc :one_loop
|
bcc :one_loop
|
||||||
|
|
||||||
; If we end while tracking a sprite, add to the list as the last item
|
; If we end while tracking a sprite, add to the list as the last item
|
||||||
|
@ -1089,7 +1142,7 @@ shadowBitmapToList
|
||||||
ldx shadowListCount
|
ldx shadowListCount
|
||||||
lda :top
|
lda :top
|
||||||
sta shadowListTop,x
|
sta shadowListTop,x
|
||||||
lda #y_height
|
lda ScreenHeight
|
||||||
sta shadowListBot,x
|
sta shadowListBot,x
|
||||||
inx
|
inx
|
||||||
stx shadowListCount
|
stx shadowListCount
|
||||||
|
@ -1130,6 +1183,8 @@ drawOAMSprites
|
||||||
plb
|
plb
|
||||||
|
|
||||||
pha ; Save the phase indicator
|
pha ; Save the phase indicator
|
||||||
|
pei 124 ; RenderFlags
|
||||||
|
|
||||||
tdc ; Keep a copy of the second page of GTE direct page space
|
tdc ; Keep a copy of the second page of GTE direct page space
|
||||||
clc
|
clc
|
||||||
adc #$0100
|
adc #$0100
|
||||||
|
@ -1144,6 +1199,8 @@ drawOAMSprites
|
||||||
stx FTblPtr+2
|
stx FTblPtr+2
|
||||||
|
|
||||||
pla
|
pla
|
||||||
|
sta RenderFlags
|
||||||
|
pla
|
||||||
|
|
||||||
; Check what phase we're in
|
; Check what phase we're in
|
||||||
;
|
;
|
||||||
|
@ -1160,10 +1217,7 @@ drawOAMSprites
|
||||||
; We need to "freeze" the OAM values, otherwise they can change between when we build the rendering pipeline
|
; We need to "freeze" the OAM values, otherwise they can change between when we build the rendering pipeline
|
||||||
|
|
||||||
sei
|
sei
|
||||||
ldal nmiCount
|
|
||||||
pha
|
|
||||||
jsr scanOAMSprites ; Filter out any sprites that don't need to be drawn
|
jsr scanOAMSprites ; Filter out any sprites that don't need to be drawn
|
||||||
pla
|
|
||||||
cli
|
cli
|
||||||
|
|
||||||
jsr buildShadowBitmap ; Run though and quickly create a bitmap of lines with sprites
|
jsr buildShadowBitmap ; Run though and quickly create a bitmap of lines with sprites
|
||||||
|
@ -1202,7 +1256,7 @@ drawSprites
|
||||||
oam_loop
|
oam_loop
|
||||||
phx ; Save x
|
phx ; Save x
|
||||||
|
|
||||||
lda OAM_COPY,x ; Y-coordinate
|
lda OAM_COPY,x ; Y-coordinate (zero based to screen)
|
||||||
; inc ; Compensate for PPU delayed scanline
|
; inc ; Compensate for PPU delayed scanline
|
||||||
|
|
||||||
rep #$30
|
rep #$30
|
||||||
|
@ -1218,7 +1272,7 @@ oam_loop
|
||||||
clc
|
clc
|
||||||
adc :tmp
|
adc :tmp
|
||||||
clc
|
clc
|
||||||
adc #$2000-{y_offset*160}+x_offset
|
adc ScreenBase
|
||||||
sta :tmp
|
sta :tmp
|
||||||
|
|
||||||
lda OAM_COPY+3,x
|
lda OAM_COPY+3,x
|
||||||
|
|
|
@ -144,6 +144,12 @@ _GTEEnableSprites MAC
|
||||||
_GTEEnableBackground MAC
|
_GTEEnableBackground MAC
|
||||||
UserTool $3100+GTEToolNum
|
UserTool $3100+GTEToolNum
|
||||||
<<<
|
<<<
|
||||||
|
_GTEDrawTileToScreen MAC
|
||||||
|
UserTool $3200+GTEToolNum
|
||||||
|
<<<
|
||||||
|
_GTESetTileImmediate MAC
|
||||||
|
UserTool $3300+GTEToolNum
|
||||||
|
<<<
|
||||||
|
|
||||||
; EngineMode definitions
|
; EngineMode definitions
|
||||||
; Script definition
|
; Script definition
|
||||||
|
@ -189,8 +195,9 @@ vblCallback equ $0004
|
||||||
extSpriteRenderer equ $0005
|
extSpriteRenderer equ $0005
|
||||||
rawDrawTile equ $0006
|
rawDrawTile equ $0006
|
||||||
extBG0TileUpdate equ $0007
|
extBG0TileUpdate equ $0007
|
||||||
userTileCallback equ $0008
|
userTileCallback equ $0008 ; Callback for rendering custom tiles into the code field
|
||||||
liteBlitter equ $0009
|
liteBlitter equ $0009
|
||||||
|
userTileDirectCallback equ $000A ; Callback for drawing custom tiles directly to the screen buffer
|
||||||
|
|
||||||
; CopyPicToBG1 flags
|
; CopyPicToBG1 flags
|
||||||
COPY_PIC_NORMAL equ $0000 ; Copy into BG1 buffer in "normal mode"
|
COPY_PIC_NORMAL equ $0000 ; Copy into BG1 buffer in "normal mode"
|
||||||
|
|
|
@ -208,8 +208,9 @@ vblCallback equ $0004 ; User routine to be called by VBL int
|
||||||
extSpriteRenderer equ $0005
|
extSpriteRenderer equ $0005
|
||||||
rawDrawTile equ $0006
|
rawDrawTile equ $0006
|
||||||
extBG0TileUpdate equ $0007
|
extBG0TileUpdate equ $0007
|
||||||
userTileCallback equ $0008
|
userTileCallback equ $0008 ; Callback for rendering custom tiles into the code field
|
||||||
liteBlitter equ $0009
|
liteBlitter equ $0009
|
||||||
|
userTileDirectCallback equ $000A ; Callback for drawing custom tiles directly to the screen buffer
|
||||||
|
|
||||||
; CopyPicToBG1 flags
|
; CopyPicToBG1 flags
|
||||||
COPY_PIC_NORMAL equ $0000 ; Copy into BG1 buffer in "normal mode" treating the buffer as a 164x208 pixmap with stride of 256
|
COPY_PIC_NORMAL equ $0000 ; Copy into BG1 buffer in "normal mode" treating the buffer as a 164x208 pixmap with stride of 256
|
||||||
|
|
145
src/Render.s
145
src/Render.s
|
@ -160,13 +160,96 @@ ExtFuncBlock
|
||||||
|
|
||||||
; Special NES renderer that externalizes the sprite rendering in order to exceed the internal limit of 16 sprites
|
; Special NES renderer that externalizes the sprite rendering in order to exceed the internal limit of 16 sprites
|
||||||
_RenderNES
|
_RenderNES
|
||||||
; jsr _ApplyBG0YPos
|
sta RenderFlags
|
||||||
; jsr _ApplyBG0XPosPre
|
bit #$0002 ; If this bit is off, don't render the top. If the top *is* rendered, assume full-screen
|
||||||
|
bne *+5
|
||||||
|
jmp _RenderNES2
|
||||||
|
|
||||||
|
jsr _ApplyBG0YPosPreLite
|
||||||
jsr _ApplyBG0YPosLite
|
jsr _ApplyBG0YPosLite
|
||||||
jsr _ApplyBG0XPosPre
|
jsr _ApplyBG0XPosPre
|
||||||
|
|
||||||
; Callback to update the tilestore with any new tiles
|
jsr _RenderNESTileCallback
|
||||||
|
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||||
|
|
||||||
|
; Render the status bar area, which is fixed
|
||||||
|
|
||||||
|
stz tmp1 ; virt_line_x2
|
||||||
|
lda #16*2
|
||||||
|
sta tmp2 ; lines_left_x2
|
||||||
|
lda #0 ; Xmod164
|
||||||
|
jsr _ApplyBG0XPosAltLite
|
||||||
|
lda tmp4 ; :exit_offset
|
||||||
|
stal nesTopOffset
|
||||||
|
|
||||||
|
; Next render the remaining lines, which should have their screen locations adjusted for the
|
||||||
|
; vertical offset
|
||||||
|
|
||||||
|
lda #16*2
|
||||||
|
clc
|
||||||
|
adc StartYMod208
|
||||||
|
sta tmp1 ; virt_line_x2
|
||||||
|
lda ScreenHeight
|
||||||
|
sec
|
||||||
|
sbc #16
|
||||||
|
asl
|
||||||
|
sta tmp2 ; lines_left_x2
|
||||||
|
lda StartXMod164 ; Xmod164
|
||||||
|
jsr _ApplyBG0XPosAltLite
|
||||||
|
lda tmp4
|
||||||
|
stal nesBottomOffset
|
||||||
|
|
||||||
|
jsr _RenderNESSpritesCallback
|
||||||
|
|
||||||
|
stz tmp1 ; :virt_line_x2
|
||||||
|
lda #16*2
|
||||||
|
sta tmp2 ; :lines_left_x2
|
||||||
|
ldal nesTopOffset
|
||||||
|
sta tmp4 ; :exit_offset
|
||||||
|
jsr _RestoreBG0OpcodesAltLite
|
||||||
|
|
||||||
|
lda #16*2
|
||||||
|
sta tmp1 ; :virt_line_x2
|
||||||
|
lda ScreenHeight
|
||||||
|
sec
|
||||||
|
sbc #16
|
||||||
|
asl
|
||||||
|
sta tmp2 ; lines_left_x2
|
||||||
|
ldal nesBottomOffset
|
||||||
|
sta tmp4 ; :exit_offset
|
||||||
|
jsr _RestoreBG0OpcodesAltLite
|
||||||
|
bra :final_step
|
||||||
|
|
||||||
|
:no_status_restore
|
||||||
|
stz tmp1
|
||||||
|
lda ScreenHeight
|
||||||
|
sta tmp2
|
||||||
|
ldal nesBottomOffset
|
||||||
|
sta tmp4 ; :exit_offset
|
||||||
|
jsr _RestoreBG0OpcodesAltLite
|
||||||
|
|
||||||
|
:final_step
|
||||||
|
jmp _RenderNESExit
|
||||||
|
|
||||||
|
_RenderNES2
|
||||||
|
jsr _ApplyBG0YPosPreLite
|
||||||
|
jsr _ApplyBG0YPosLite
|
||||||
|
jsr _ApplyBG0XPosPre
|
||||||
|
|
||||||
|
jsr _RenderNESTileCallback
|
||||||
|
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||||
|
|
||||||
|
jsr _ApplyBG0XPosLite ; Do the full screen
|
||||||
|
jsr _RenderNESSpritesCallback
|
||||||
|
|
||||||
|
lda StartYMod208 ; Restore the fields back to their original state
|
||||||
|
ldx ScreenHeight
|
||||||
|
jsr _RestoreBG0OpcodesLite
|
||||||
|
|
||||||
|
jmp _RenderNESExit
|
||||||
|
|
||||||
|
; Callback to update the tilestore with any new tiles
|
||||||
|
_RenderNESTileCallback
|
||||||
lda ExtUpdateBG0Tiles
|
lda ExtUpdateBG0Tiles
|
||||||
ora ExtUpdateBG0Tiles+2
|
ora ExtUpdateBG0Tiles+2
|
||||||
beq :no_tile
|
beq :no_tile
|
||||||
|
@ -176,31 +259,7 @@ _RenderNES
|
||||||
lda ExtUpdateBG0Tiles+1
|
lda ExtUpdateBG0Tiles+1
|
||||||
stal :patch0+2
|
stal :patch0+2
|
||||||
:patch0 jsl $000000
|
:patch0 jsl $000000
|
||||||
:no_tile
|
:no_tile rts
|
||||||
|
|
||||||
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
|
||||||
|
|
||||||
stz tmp1 ; virt_line_x2
|
|
||||||
lda #16*2
|
|
||||||
sta tmp2 ; lines_left_x2
|
|
||||||
lda #0 ; Xmod164
|
|
||||||
; jsr _ApplyBG0XPosAlt
|
|
||||||
jsr _ApplyBG0XPosAltLite
|
|
||||||
lda tmp4 ; :exit_offset
|
|
||||||
stal nesTopOffset
|
|
||||||
|
|
||||||
lda #16*2
|
|
||||||
sta tmp1 ; virt_line_x2
|
|
||||||
lda ScreenHeight
|
|
||||||
sec
|
|
||||||
sbc #16
|
|
||||||
asl
|
|
||||||
sta tmp2 ; lines_left_x2
|
|
||||||
lda StartXMod164 ; Xmod164
|
|
||||||
; jsr _ApplyBG0XPosAlt
|
|
||||||
jsr _ApplyBG0XPosAltLite
|
|
||||||
lda tmp4
|
|
||||||
stal nesBottomOffset
|
|
||||||
|
|
||||||
; This is a tricky part. The NES does not keep sprites sorted, so we need an alternative way to figure out
|
; This is a tricky part. The NES does not keep sprites sorted, so we need an alternative way to figure out
|
||||||
; which lines to shadow and which ones not to. Our compromise is to build a bitmap of lines that the sprite
|
; which lines to shadow and which ones not to. Our compromise is to build a bitmap of lines that the sprite
|
||||||
|
@ -208,7 +267,7 @@ _RenderNES
|
||||||
;
|
;
|
||||||
; This is handled by the callback in two phases. We pass pointers to the internal function the callback needs
|
; This is handled by the callback in two phases. We pass pointers to the internal function the callback needs
|
||||||
; access to. If there is no function defined, do nothing
|
; access to. If there is no function defined, do nothing
|
||||||
|
_RenderNESSpritesCallback
|
||||||
lda GTEControlBits
|
lda GTEControlBits
|
||||||
bit #CTRL_SPRITE_DISABLE
|
bit #CTRL_SPRITE_DISABLE
|
||||||
bne :no_render
|
bne :no_render
|
||||||
|
@ -243,32 +302,9 @@ _RenderNES
|
||||||
ldx #^ExtFuncBlock
|
ldx #^ExtFuncBlock
|
||||||
ldy #ExtFuncBlock
|
ldy #ExtFuncBlock
|
||||||
:patch2 jsl $000000
|
:patch2 jsl $000000
|
||||||
|
:no_render rts
|
||||||
|
|
||||||
:no_render
|
_RenderNESExit
|
||||||
stz tmp1 ; :virt_line_x2
|
|
||||||
lda #16*2
|
|
||||||
sta tmp2 ; :lines_left_x2
|
|
||||||
ldal nesTopOffset
|
|
||||||
sta tmp4 ; :exit_offset
|
|
||||||
; jsr _RestoreBG0OpcodesAlt
|
|
||||||
jsr _RestoreBG0OpcodesAltLite
|
|
||||||
|
|
||||||
lda #16*2
|
|
||||||
sta tmp1 ; :virt_line_x2
|
|
||||||
lda ScreenHeight
|
|
||||||
sec
|
|
||||||
sbc #16
|
|
||||||
asl
|
|
||||||
sta tmp2 ; lines_left_x2
|
|
||||||
ldal nesBottomOffset
|
|
||||||
sta tmp4 ; :exit_offset
|
|
||||||
; jsr _RestoreBG0OpcodesAlt
|
|
||||||
jsr _RestoreBG0OpcodesAltLite
|
|
||||||
|
|
||||||
; lda StartYMod208 ; Restore the fields back to their original state
|
|
||||||
; ldx ScreenHeight
|
|
||||||
; jsr _RestoreBG0Opcodes
|
|
||||||
|
|
||||||
lda StartY
|
lda StartY
|
||||||
sta OldStartY
|
sta OldStartY
|
||||||
lda StartX
|
lda StartX
|
||||||
|
@ -637,6 +673,7 @@ _RenderLite
|
||||||
sta RenderFlags
|
sta RenderFlags
|
||||||
jsr _DoTimers ; Run any pending timer tasks
|
jsr _DoTimers ; Run any pending timer tasks
|
||||||
|
|
||||||
|
jsr _ApplyBG0YPosPreLite
|
||||||
jsr _ApplyBG0YPosLite ; Set stack addresses for the virtual lines to the physical screen
|
jsr _ApplyBG0YPosLite ; Set stack addresses for the virtual lines to the physical screen
|
||||||
jsr _ApplyBG0XPosPre ; Lock in certain rendering variables (not lite/non-lite specific)
|
jsr _ApplyBG0XPosPre ; Lock in certain rendering variables (not lite/non-lite specific)
|
||||||
|
|
||||||
|
|
90
src/Tiles.s
90
src/Tiles.s
|
@ -352,6 +352,75 @@ _CalcTileProcIndex
|
||||||
:no_flip_d lda #0
|
:no_flip_d lda #0
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
; Set a tile value in the backing store and immediately render into the code field
|
||||||
|
;
|
||||||
|
; A = tile id
|
||||||
|
; X = tile column [0, 40] (41 columns)
|
||||||
|
; Y = tile row [0, 25] (26 rows)
|
||||||
|
;
|
||||||
|
; Registers are not preserved
|
||||||
|
_SetTileImmediate
|
||||||
|
sta newTileId
|
||||||
|
jsr _GetTileStoreOffset0 ; Get the address of the X,Y tile position
|
||||||
|
tax
|
||||||
|
|
||||||
|
lda TileStore+TS_TILE_ID,x
|
||||||
|
cmp newTileId
|
||||||
|
bne :changed
|
||||||
|
rts
|
||||||
|
|
||||||
|
:changed sta oldTileId
|
||||||
|
lda newTileId
|
||||||
|
sta TileStore+TS_TILE_ID,x ; Value is different, store it.
|
||||||
|
|
||||||
|
; If the user bit is set, then skip most of the setup and just fill in the TileProcs with the user callback
|
||||||
|
; target
|
||||||
|
bit #TILE_USER_BIT
|
||||||
|
bne :set_user_tile
|
||||||
|
|
||||||
|
jsr _GetTileAddr
|
||||||
|
sta TileStore+TS_TILE_ADDR,x ; Committed to drawing this tile, so get the address of the tile in the tiledata bank for later
|
||||||
|
|
||||||
|
; Set the renderer procs for this tile.
|
||||||
|
;
|
||||||
|
; NOTE: Later on, optimize this to just take the Tile ID & TILE_CTRL_MASK and lookup the right proc
|
||||||
|
; table address from a lookup table....
|
||||||
|
;
|
||||||
|
; 1. The dirty render proc is always set the same.
|
||||||
|
; 2. If BG1 and DYN_TILES are disabled, then the TS_BASE_TILE_DISP is selected from the Fast Renderers, otherwise
|
||||||
|
; it is selected from the full tile rendering functions.
|
||||||
|
; 3. The copy process is selected based on the flip bits
|
||||||
|
;
|
||||||
|
; When a tile overlaps the sprite, it is the responsibility of the Render function to compose the appropriate
|
||||||
|
; functionality. Sometimes it is simple, but in cases of the sprites overlapping Dynamic Tiles and other cases
|
||||||
|
; it can be more involved.
|
||||||
|
|
||||||
|
; Calculate the base tile proc selector from the tile Id (need X-register set to tile store index)
|
||||||
|
|
||||||
|
lda newTileId
|
||||||
|
jsr _SetNormalTileProcs
|
||||||
|
bra :render_tile
|
||||||
|
|
||||||
|
:set_user_tile
|
||||||
|
and #$01FF
|
||||||
|
jsr _GetTileAddr ; The user tile callback needs access to this info, too, but
|
||||||
|
sta TileStore+TS_TILE_ADDR,x ; we just give the base tile address (hflip bit is ignored)
|
||||||
|
|
||||||
|
lda #UserTileDispatch
|
||||||
|
stal K_TS_BASE_TILE_DISP,x
|
||||||
|
stal K_TS_SPRITE_TILE_DISP,x
|
||||||
|
stal K_TS_ONE_SPRITE,x
|
||||||
|
|
||||||
|
:render_tile
|
||||||
|
phd ; save the current direct page
|
||||||
|
tdc
|
||||||
|
clc
|
||||||
|
adc #$100 ; move to the next page
|
||||||
|
tcd
|
||||||
|
jsr _RenderTile
|
||||||
|
pld
|
||||||
|
rts
|
||||||
|
|
||||||
; Set a tile value in the tile backing store. Mark dirty if the value changes
|
; Set a tile value in the tile backing store. Mark dirty if the value changes
|
||||||
;
|
;
|
||||||
; A = tile id
|
; A = tile id
|
||||||
|
@ -447,6 +516,27 @@ _UTDPatch jsl UserHook1 ; Call the users code
|
||||||
:done
|
:done
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
; Provides a direct callback without using the TileStore information
|
||||||
|
; A = user data
|
||||||
|
; Y = screen address
|
||||||
|
; X = tile address
|
||||||
|
;
|
||||||
|
; Bank will be set to the tiledata bank, so lda $0000,x will load the first word of the tile's data
|
||||||
|
UserTileDirectDispatch
|
||||||
|
phd
|
||||||
|
pha
|
||||||
|
tdc
|
||||||
|
clc
|
||||||
|
adc #$100
|
||||||
|
tcd
|
||||||
|
pla
|
||||||
|
pei DP2_TILEDATA_AND_TILESTORE_BANKS ; set the bank to the tiledata bank
|
||||||
|
plb
|
||||||
|
_UTD2Patch jsl UserHook1 ; Call the user's code
|
||||||
|
plb ; Restore the curent bank
|
||||||
|
pld
|
||||||
|
rts
|
||||||
|
|
||||||
; Stub to have a valid address for initialization / reset
|
; Stub to have a valid address for initialization / reset
|
||||||
UserHook1 rtl
|
UserHook1 rtl
|
||||||
|
|
||||||
|
|
85
src/Tool.s
85
src/Tool.s
|
@ -105,6 +105,9 @@ _CallTable
|
||||||
adrl _TSEnableSprites-1
|
adrl _TSEnableSprites-1
|
||||||
adrl _TSEnableBackground-1
|
adrl _TSEnableBackground-1
|
||||||
|
|
||||||
|
adrl _TSDrawTileToScreen-1
|
||||||
|
adrl _TSSetTileImmediate-1
|
||||||
|
|
||||||
_CTEnd
|
_CTEnd
|
||||||
_GTEAddSprite MAC
|
_GTEAddSprite MAC
|
||||||
UserTool $1000+GTEToolNum
|
UserTool $1000+GTEToolNum
|
||||||
|
@ -271,19 +274,36 @@ _TSReadControl
|
||||||
|
|
||||||
_TSExit #0;#0
|
_TSExit #0;#0
|
||||||
|
|
||||||
; SetTile(xTile, yTile, tileId)
|
; SetTileImmediate(xTile, yTile, tileId)
|
||||||
_TSSetTile
|
_TSSetTileImmediate
|
||||||
tileId equ FirstParam
|
:tileId equ FirstParam
|
||||||
yTile equ FirstParam+2
|
:yTile equ FirstParam+2
|
||||||
xTile equ FirstParam+4
|
:xTile equ FirstParam+4
|
||||||
|
|
||||||
_TSEntry
|
_TSEntry
|
||||||
|
|
||||||
lda xTile,s ; Valid range [0, 40] (41 columns)
|
lda :xTile,s ; Valid range [0, 40] (41 columns)
|
||||||
tax
|
tax
|
||||||
lda yTile,s ; Valid range [0, 25] (26 rows)
|
lda :yTile,s ; Valid range [0, 25] (26 rows)
|
||||||
tay
|
tay
|
||||||
lda tileId,s
|
lda :tileId,s
|
||||||
|
jsr _SetTileImmediate
|
||||||
|
|
||||||
|
_TSExit #0;#6
|
||||||
|
|
||||||
|
; SetTile(xTile, yTile, tileId)
|
||||||
|
_TSSetTile
|
||||||
|
:tileId equ FirstParam
|
||||||
|
:yTile equ FirstParam+2
|
||||||
|
:xTile equ FirstParam+4
|
||||||
|
|
||||||
|
_TSEntry
|
||||||
|
|
||||||
|
lda :xTile,s ; Valid range [0, 40] (41 columns)
|
||||||
|
tax
|
||||||
|
lda :yTile,s ; Valid range [0, 25] (26 rows)
|
||||||
|
tay
|
||||||
|
lda :tileId,s
|
||||||
jsr _SetTile
|
jsr _SetTile
|
||||||
|
|
||||||
_TSExit #0;#6
|
_TSExit #0;#6
|
||||||
|
@ -312,6 +332,8 @@ _TSRender
|
||||||
beq :nes
|
beq :nes
|
||||||
cmp #$FFFE ; Experimental gte-lite mode
|
cmp #$FFFE ; Experimental gte-lite mode
|
||||||
beq :lite
|
beq :lite
|
||||||
|
cmp #$FFFD
|
||||||
|
beq :nes
|
||||||
|
|
||||||
bit #RENDER_WITH_SHADOWING
|
bit #RENDER_WITH_SHADOWING
|
||||||
beq :no_shadowing
|
beq :no_shadowing
|
||||||
|
@ -1054,7 +1076,26 @@ _TSSetAddress
|
||||||
stal _UTDPatch+2
|
stal _UTDPatch+2
|
||||||
brl :out
|
brl :out
|
||||||
|
|
||||||
:next_6
|
:next_6 cmp #userTileDirectCallback
|
||||||
|
bne :next_7
|
||||||
|
lda :ptr,s
|
||||||
|
ora :ptr+2,s
|
||||||
|
beq :utd2_restore
|
||||||
|
|
||||||
|
lda :ptr,s
|
||||||
|
stal _UTD2Patch+1 ; long addressing because we're patching code in the K bank
|
||||||
|
lda :ptr+1,s
|
||||||
|
stal _UTD2Patch+2
|
||||||
|
brl :out
|
||||||
|
|
||||||
|
:utd2_restore
|
||||||
|
lda #UserHook1
|
||||||
|
stal _UTD2Patch+1
|
||||||
|
lda #>UserHook1
|
||||||
|
stal _UTD2Patch+2
|
||||||
|
brl :out
|
||||||
|
|
||||||
|
:next_7
|
||||||
:out
|
:out
|
||||||
_TSExit #0;#6
|
_TSExit #0;#6
|
||||||
|
|
||||||
|
@ -1110,6 +1151,32 @@ _TSEnableBackground
|
||||||
:done
|
:done
|
||||||
_TSExit #0;#2
|
_TSExit #0;#2
|
||||||
|
|
||||||
|
; Draw a tile directly to the graphics screen. Provides an convenient way to immediately draw
|
||||||
|
; tile content on the the graphics buffer without having to go through a Render function.
|
||||||
|
;
|
||||||
|
; DrawTileToScreen(screenAddr, tileId, tileFlags)
|
||||||
|
_TSDrawTileToScreen
|
||||||
|
:tileId equ FirstParam+4 ; fetches the address of the internal tile data buffer
|
||||||
|
:screenAddr equ FirstParam+2 ; screen address on the SHR
|
||||||
|
:userData equ FirstParam ; used in place of :tileId for user callback function
|
||||||
|
|
||||||
|
_TSEntry
|
||||||
|
|
||||||
|
lda :tileId,s
|
||||||
|
bit #TILE_USER_BIT
|
||||||
|
bne :doUserTile
|
||||||
|
|
||||||
|
bra :done
|
||||||
|
:doUserTile
|
||||||
|
jsr _GetTileAddr
|
||||||
|
tax
|
||||||
|
lda :screenAddr,s
|
||||||
|
tay
|
||||||
|
lda :userData,s
|
||||||
|
jsr UserTileDirectDispatch
|
||||||
|
:done
|
||||||
|
_TSExit #0;#6
|
||||||
|
|
||||||
; Insert the GTE code
|
; Insert the GTE code
|
||||||
|
|
||||||
put Math.s
|
put Math.s
|
||||||
|
|
|
@ -1,38 +1,39 @@
|
||||||
; Subroutines that deal with the vertical scrolling and rendering. The primary function
|
; Subroutines that deal with the vertical scrolling and rendering. The primary function
|
||||||
; of these routines are to adjust tables and patch in new values into the code field
|
; of these routines are to adjust tables and patch in new values into the code field
|
||||||
; when the virtual Y-position of the play field changes.
|
; when the virtual Y-position of the play field changes.
|
||||||
|
_ApplyBG0YPosPreLite
|
||||||
_ApplyBG0YPosLite
|
|
||||||
|
|
||||||
:rtbl_idx_x2 equ tmp0
|
|
||||||
:virt_line_x2 equ tmp1
|
|
||||||
:lines_left_x2 equ tmp2
|
|
||||||
:draw_count_x2 equ tmp3
|
|
||||||
:stk_save equ tmp4
|
|
||||||
:line_count equ tmp5
|
|
||||||
|
|
||||||
; First task is to fill in the STK_ADDR values by copying them from the RTable array. We
|
|
||||||
; copy from RTable[i] into BlitField[StartY+i].
|
|
||||||
|
|
||||||
stz :rtbl_idx_x2 ; Start copying from the first entry in the table
|
|
||||||
|
|
||||||
lda StartY ; This is the base line of the virtual screen
|
lda StartY ; This is the base line of the virtual screen
|
||||||
jsr Mod208
|
jsr Mod208
|
||||||
sta StartYMod208
|
sta StartYMod208
|
||||||
|
rts
|
||||||
|
|
||||||
asl
|
_ApplyBG0YPosLite
|
||||||
sta :virt_line_x2 ; Keep track of it
|
|
||||||
|
|
||||||
; copy a range of address from the table into the destination bank. If we restrict ourselves to
|
:virt_line_x2 equ tmp1
|
||||||
; rectangular playfields, this can be optimized to just subtracting a constant value. See the
|
:lines_left_x2 equ tmp2
|
||||||
; Templates::SetScreenAddrs subroutine.
|
|
||||||
|
; First task is to fill in the STK_ADDR values by copying them from the RTable array. We
|
||||||
|
; copy from RTable[i] into BlitField[StartY+i].
|
||||||
|
|
||||||
lda ScreenHeight
|
lda ScreenHeight
|
||||||
asl
|
asl
|
||||||
sta :lines_left_x2
|
sta :lines_left_x2
|
||||||
|
|
||||||
|
lda StartYMod208
|
||||||
|
asl
|
||||||
|
sta :virt_line_x2 ; Keep track of it
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
|
||||||
|
_ApplyBG0YPosAltLite
|
||||||
|
:rtbl_idx_x2 equ tmp0
|
||||||
|
:virt_line_x2 equ tmp1
|
||||||
|
:lines_left_x2 equ tmp2
|
||||||
|
:draw_count_x2 equ tmp3
|
||||||
|
|
||||||
; Check to see if we need to split the update into two parts, e.g. do we wrap around the end
|
; Check to see if we need to split the update into two parts, e.g. do we wrap around the end
|
||||||
; of the code field?
|
; of the code field?
|
||||||
|
sta :rtbl_idx_x2
|
||||||
|
|
||||||
ldx :lines_left_x2
|
ldx :lines_left_x2
|
||||||
lda #208*2
|
lda #208*2
|
||||||
|
@ -46,6 +47,11 @@ _ApplyBG0YPosLite
|
||||||
|
|
||||||
stz :virt_line_x2 ; virtual line is at the top (by construction)
|
stz :virt_line_x2 ; virtual line is at the top (by construction)
|
||||||
|
|
||||||
|
lda :rtbl_idx_x2
|
||||||
|
clc
|
||||||
|
adc :draw_count_x2
|
||||||
|
sta :rtbl_idx_x2
|
||||||
|
|
||||||
lda :lines_left_x2
|
lda :lines_left_x2
|
||||||
sec
|
sec
|
||||||
sbc :draw_count_x2 ; this many left to draw. Fall through to finish up
|
sbc :draw_count_x2 ; this many left to draw. Fall through to finish up
|
||||||
|
@ -62,6 +68,8 @@ _ApplyBG0YPosLite
|
||||||
tay
|
tay
|
||||||
iny ; Fill in the first byte (_ENTRY_1 = 0)
|
iny ; Fill in the first byte (_ENTRY_1 = 0)
|
||||||
|
|
||||||
|
ldx :rtbl_idx_x2 ; Load the stack address from here
|
||||||
|
|
||||||
sep #$20 ; Set the data bank to the code field
|
sep #$20 ; Set the data bank to the code field
|
||||||
lda BTableHigh
|
lda BTableHigh
|
||||||
pha
|
pha
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
; External entrypoint to render a tile directly into the code field
|
||||||
|
RenderTile
|
||||||
|
|
||||||
; If there are no sprites, then we copy the tile data into the code field as fast as possible.
|
; If there are no sprites, then we copy the tile data into the code field as fast as possible.
|
||||||
; If there are sprites, then additional work is required
|
; If there are sprites, then additional work is required
|
||||||
_RenderTile
|
_RenderTile
|
||||||
|
|
Loading…
Reference in New Issue
Block a user