iigs-game-engine/src/blitter/Vert.s

166 lines
6.4 KiB
ArmAsm

; 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
; when the virtual Y-position of the play field changes.
; Based on the current value of StartY in the direct page. Set up the dispatch
; information so that the BltRange driver will render the correct code field
; lines in the correct order
_ApplyBG0YPos
:rtbl_idx_x2 equ tmp0
:virt_line_x2 equ tmp1
:lines_left_x2 equ tmp2
:draw_count_x2 equ tmp3
:stk_save equ tmp4
; 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]. As with all of this code, the difficult part
; is decomposing the update across banks
stz :rtbl_idx_x2 ; Start copying from the first entry in the table
lda StartY ; This is the base line of the virtual screen
jsr Mod208
sta StartYMod208
asl
sta :virt_line_x2 ; Keep track of it
phb ; Save the current bank
tsc ; we intentionally leak one byte of stack in each loop
sta :stk_save ; iteration, so save the stack to repair at the end
; copy a range of address from the table into the destination bank. If we restrict ourselves to
; rectangular playfields, this can be optimized to just subtracting a constant value. See the
; Templates::SetScreenAddrs subroutine.
lda ScreenHeight
asl
sta :lines_left_x2
; This is the verbose part -- figure out how many lines to draw. We don't want to artificially limit
; the height of the visible screen (for example, doing an animated wipe while scrolling), so the screen
; height could be anything from 1 to 200.
;
; For larger values, we want to break things up on 16-line boundaries based on the virt_line value. So,
;
; draw_count = min(lines_left, (16 - (virt_line % 16))
:loop
ldx :virt_line_x2
ldal BTableLow,x ; Get the address of the first code field line
tay
ldal BTableHigh,x ; Target bank in low byte, current bank in high
pha
txa
and #$001E
eor #$FFFF
sec
adc #32
min :lines_left_x2
sta :draw_count_x2 ; Do this many lines
tax
clc ; pre-advance virt_line_2 because we have the value
adc :virt_line_x2
sta :virt_line_x2
plb
jsr (:CopyRTableToStkAddr,x) ; X = rtbl_idx_x2 on return
txa ; carry flag is unchanged
adc :draw_count_x2 ; advance the index into the RTable
sta :rtbl_idx_x2
lda :lines_left_x2 ; subtract the number of lines we just completed
sec
sbc :draw_count_x2
sta :lines_left_x2
jne :loop
lda :stk_save
tcs
plb
rts
; Unrolled copy routine to move RTable intries into STK_ADDR position.
;
; A = intect into the RTable array (x2)
; Y = starting line * $1000
; X = number of lines (x2)
:CopyRTableToStkAddr
da :none
da :do01,:do02,:do03,:do04
da :do05,:do06,:do07,:do08
da :do09,:do10,:do11,:do12
da :do13,:do14,:do15,:do16
:do15 ldx :rtbl_idx_x2
bra :x15
:do14 ldx :rtbl_idx_x2
bra :x14
:do13 ldx :rtbl_idx_x2
bra :x13
:do12 ldx :rtbl_idx_x2
bra :x12
:do11 ldx :rtbl_idx_x2
bra :x11
:do10 ldx :rtbl_idx_x2
bra :x10
:do09 ldx :rtbl_idx_x2
bra :x09
:do08 ldx :rtbl_idx_x2
bra :x08
:do07 ldx :rtbl_idx_x2
bra :x07
:do06 ldx :rtbl_idx_x2
bra :x06
:do05 ldx :rtbl_idx_x2
bra :x05
:do04 ldx :rtbl_idx_x2
bra :x04
:do03 ldx :rtbl_idx_x2
bra :x03
:do02 ldx :rtbl_idx_x2
bra :x02
:do01 ldx :rtbl_idx_x2
bra :x01
:do16 ldx :rtbl_idx_x2
ldal RTable+30,x
sta STK_ADDR+$F000,y
:x15 ldal RTable+28,x
sta STK_ADDR+$E000,y
:x14 ldal RTable+26,x
sta STK_ADDR+$D000,y
:x13 ldal RTable+24,x
sta STK_ADDR+$C000,y
:x12 ldal RTable+22,x
sta STK_ADDR+$B000,y
:x11 ldal RTable+20,x
sta STK_ADDR+$A000,y
:x10 ldal RTable+18,x
sta STK_ADDR+$9000,y
:x09 ldal RTable+16,x
sta STK_ADDR+$8000,y
:x08 ldal RTable+14,x
sta STK_ADDR+$7000,y
:x07 ldal RTable+12,x
sta STK_ADDR+$6000,y
:x06 ldal RTable+10,x
sta STK_ADDR+$5000,y
:x05 ldal RTable+08,x
sta STK_ADDR+$4000,y
:x04 ldal RTable+06,x
sta STK_ADDR+$3000,y
:x03 ldal RTable+04,x
sta STK_ADDR+$2000,y
:x02 ldal RTable+02,x
sta STK_ADDR+$1000,y
:x01 ldal RTable+00,x
sta: STK_ADDR+$0000,y
:none rts