mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-09-27 05:54:24 +00:00
324 lines
12 KiB
ArmAsm
324 lines
12 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
|
|
_ApplyBG0YPosOld
|
|
|
|
: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
|
|
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
|
|
; CopyRTableToStkAddr :rtbl_idx_x2 ; 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
|
|
|
|
; This is an optimized version of _ApplyBG0YPos. We pre-compute the breakdown across the bank
|
|
; boundries in order to eliminate the the minimum calculation and some loop variable updates
|
|
; from the inner loop.
|
|
|
|
_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
|
|
: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]. 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))
|
|
|
|
; Pre-loop: Calculate the number of lines to copy to get the loop into a bank-aligned state
|
|
;
|
|
; lines_in_bank = 16 - (virt_line % 16)
|
|
:pre
|
|
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
|
|
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
|
|
|
|
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
|
|
|
|
jeq :done ; if there are no lines left, we're done!
|
|
cmp #33
|
|
jcc :post ; if there are 16 lines or less left, jump to post
|
|
|
|
; Now we are in the main loop. We know that the virt_line is a multiple of 16, but the number
|
|
; of remaining lines could be any number greater than 0. we test to see if the lines_left are
|
|
; less than 16. If so, we can jump straight to the post-loop update. Otherwise we caculate
|
|
; the number of 16-line iterations and but that in an auxiliary count variable and simplify
|
|
; the loop update.
|
|
|
|
tax
|
|
and #$001E ; this is the number of lines in post
|
|
sta :lines_left_x2
|
|
txa
|
|
lsr
|
|
lsr
|
|
lsr
|
|
lsr
|
|
lsr
|
|
sta :line_count ; single byte count, saves 9 cycles per loop iteration
|
|
|
|
: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
|
|
pha
|
|
|
|
lda #32 ; Do this many lines (x2)
|
|
tax
|
|
|
|
clc ; pre-advance virt_line_2 because we have the value
|
|
adc :virt_line_x2
|
|
sta :virt_line_x2
|
|
|
|
plb
|
|
CopyRTableToStkAddr :rtbl_idx_x2
|
|
|
|
txa ; carry flag is unchanged
|
|
adc #32 ; advance the index into the RTable
|
|
sta :rtbl_idx_x2
|
|
|
|
dec :line_count
|
|
jne :loop
|
|
|
|
lda :lines_left_x2
|
|
beq :done
|
|
|
|
; Draw some number of lines that are less that 16. No need to update loop variabls because we
|
|
; know we are in the last iteration
|
|
|
|
:post
|
|
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
|
|
pha
|
|
|
|
ldx :lines_left_x2 ; Do this many lines
|
|
plb
|
|
jsr _CopyRTableToStkAddr
|
|
|
|
:done
|
|
lda :stk_save
|
|
tcs
|
|
plb
|
|
rts
|
|
|
|
; Unrolled copy routine to move RTable intries into STK_ADDR position.
|
|
;
|
|
; A = index into the RTable array (x2)
|
|
; Y = starting line * $1000
|
|
; X = number of lines (x2)
|
|
CopyRTableToStkAddr mac
|
|
jmp (dispTbl,x)
|
|
dispTbl da bottom
|
|
da do01,do02,do03,do04
|
|
da do05,do06,do07,do08
|
|
da do09,do10,do11,do12
|
|
da do13,do14,do15,do16
|
|
do15 ldx ]1
|
|
bra x15
|
|
do14 ldx ]1
|
|
bra x14
|
|
do13 ldx ]1
|
|
bra x13
|
|
do12 ldx ]1
|
|
bra x12
|
|
do11 ldx ]1
|
|
bra x11
|
|
do10 ldx ]1
|
|
bra x10
|
|
do09 ldx ]1
|
|
bra x09
|
|
do08 ldx ]1
|
|
bra x08
|
|
do07 ldx ]1
|
|
bra x07
|
|
do06 ldx ]1
|
|
bra x06
|
|
do05 ldx ]1
|
|
bra x05
|
|
do04 ldx ]1
|
|
bra x04
|
|
do03 ldx ]1
|
|
bra x03
|
|
do02 ldx ]1
|
|
bra x02
|
|
do01 ldx ]1
|
|
bra x01
|
|
do16 ldx ]1
|
|
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
|
|
bottom
|
|
<<<
|
|
|
|
_CopyRTableToStkAddr
|
|
CopyRTableToStkAddr tmp0
|
|
rts |