mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-06-08 03:29:32 +00:00
Add per-scanline offset rendering.
This commit is contained in:
parent
899c6c9770
commit
e3409f92fa
|
@ -104,6 +104,8 @@ extern pascal void GTEClearBG1Buffer(Word value) inline(0x29A0, tool_dispatcher)
|
||||||
/* GTE Misc. Functions */
|
/* GTE Misc. Functions */
|
||||||
extern pascal Word GTEReadControl(void) inline(0x09A0, tool_dispatcher);
|
extern pascal Word GTEReadControl(void) inline(0x09A0, tool_dispatcher);
|
||||||
extern pascal Word GTEGetSeconds(void) inline(0x14A0, tool_dispatcher);
|
extern pascal Word GTEGetSeconds(void) inline(0x14A0, tool_dispatcher);
|
||||||
|
extern pascal Pointer GTEGetAddress(Word tableId) inline(0x2CA0, tool_dispatcher);
|
||||||
|
extern pascal void GTESetAddress(Word tableId, Pointer pointer) inline(0x2EA0, tool_dispatcher);
|
||||||
|
|
||||||
|
|
||||||
/* GTE Timer Functions */
|
/* GTE Timer Functions */
|
||||||
|
|
|
@ -35,6 +35,7 @@ MaxGlobalX equ 16
|
||||||
MaxGlobalY equ 18
|
MaxGlobalY equ 18
|
||||||
MaxBG0X equ 20
|
MaxBG0X equ 20
|
||||||
MaxBG0Y equ 22
|
MaxBG0Y equ 22
|
||||||
|
frameCount equ 24
|
||||||
OldOneSecondCounter equ 26
|
OldOneSecondCounter equ 26
|
||||||
appTmp0 equ 28
|
appTmp0 equ 28
|
||||||
|
|
||||||
|
@ -74,6 +75,10 @@ appTmp0 equ 28
|
||||||
jsr BG0SetUp
|
jsr BG0SetUp
|
||||||
jsr SetLimits
|
jsr SetLimits
|
||||||
|
|
||||||
|
pea #80
|
||||||
|
pei MaxBG0Y
|
||||||
|
_GTESetBG0Origin
|
||||||
|
|
||||||
lda #193 ; Tile ID of '0'
|
lda #193 ; Tile ID of '0'
|
||||||
jsr InitOverlay ; Initialize the status bar
|
jsr InitOverlay ; Initialize the status bar
|
||||||
pha
|
pha
|
||||||
|
@ -82,6 +87,18 @@ appTmp0 equ 28
|
||||||
sta OldOneSecondCounter
|
sta OldOneSecondCounter
|
||||||
jsr UdtOverlay
|
jsr UdtOverlay
|
||||||
|
|
||||||
|
; Set up the per-scanline rendering
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
jsr InitOffsets
|
||||||
|
pea #scanlineHorzOffset
|
||||||
|
pea #^BG0Offsets
|
||||||
|
pea #BG0Offsets
|
||||||
|
_GTESetAddress
|
||||||
|
|
||||||
|
pea $0000 ; one regular render to fill the screen with the tilemap
|
||||||
|
_GTERender
|
||||||
|
|
||||||
; Set up a very specific test. First, we draw a sprite into the sprite plane, and then
|
; Set up a very specific test. First, we draw a sprite into the sprite plane, and then
|
||||||
; leave it alone. We are just testing the ability to merge sprite plane data into
|
; leave it alone. We are just testing the ability to merge sprite plane data into
|
||||||
; the play field tiles.
|
; the play field tiles.
|
||||||
|
@ -102,9 +119,11 @@ EvtLoop
|
||||||
bcc *+5
|
bcc *+5
|
||||||
brl :do_render
|
brl :do_render
|
||||||
inc StartX
|
inc StartX
|
||||||
pei StartX
|
lda StartX
|
||||||
pei StartY
|
jsr SetOffsets
|
||||||
_GTESetBG0Origin
|
; pei StartX
|
||||||
|
; pei StartY
|
||||||
|
; _GTESetBG0Origin
|
||||||
brl :do_render
|
brl :do_render
|
||||||
:not_d
|
:not_d
|
||||||
|
|
||||||
|
@ -114,9 +133,11 @@ EvtLoop
|
||||||
bne *+5
|
bne *+5
|
||||||
brl :do_render
|
brl :do_render
|
||||||
dec StartX
|
dec StartX
|
||||||
pei StartX
|
lda StartX
|
||||||
pei StartY
|
jsr SetOffsets
|
||||||
_GTESetBG0Origin
|
; pei StartX
|
||||||
|
; pei StartY
|
||||||
|
; _GTESetBG0Origin
|
||||||
brl :do_render
|
brl :do_render
|
||||||
:not_a
|
:not_a
|
||||||
|
|
||||||
|
@ -144,7 +165,7 @@ EvtLoop
|
||||||
:not_w
|
:not_w
|
||||||
|
|
||||||
:do_render
|
:do_render
|
||||||
pea $0000
|
pea #RENDER_PER_SCANLINE
|
||||||
_GTERender
|
_GTERender
|
||||||
|
|
||||||
; Update the performance counters
|
; Update the performance counters
|
||||||
|
@ -234,7 +255,85 @@ SetLimits
|
||||||
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
frameCount equ 24
|
SetOffsets
|
||||||
|
and #$00FF
|
||||||
|
brl _SetOffsets
|
||||||
|
|
||||||
|
InitOffsets
|
||||||
|
and #$00FF
|
||||||
|
sta appTmp0
|
||||||
|
|
||||||
|
ldx #0
|
||||||
|
ldy #80
|
||||||
|
jsr _InitRange
|
||||||
|
ldx #80
|
||||||
|
ldy #80
|
||||||
|
jsr _InitRange
|
||||||
|
ldx #160
|
||||||
|
ldy #48
|
||||||
|
jsr _InitRange
|
||||||
|
|
||||||
|
lda appTmp0
|
||||||
|
_SetOffsets
|
||||||
|
ldx #160
|
||||||
|
ldy #48
|
||||||
|
jsr _SetRange
|
||||||
|
lsr
|
||||||
|
ldx #80
|
||||||
|
ldy #80
|
||||||
|
jsr _SetRange
|
||||||
|
lsr
|
||||||
|
ldx #0
|
||||||
|
ldy #80
|
||||||
|
jsr _SetRange
|
||||||
|
rts
|
||||||
|
|
||||||
|
_SetRange
|
||||||
|
pha
|
||||||
|
|
||||||
|
txa
|
||||||
|
asl
|
||||||
|
tax
|
||||||
|
|
||||||
|
:loop2 lda BG0Offsets,x
|
||||||
|
and #$FF00
|
||||||
|
ora 1,s
|
||||||
|
sta BG0Offsets,x
|
||||||
|
|
||||||
|
dey
|
||||||
|
beq :done
|
||||||
|
|
||||||
|
inx
|
||||||
|
inx
|
||||||
|
cpx #416
|
||||||
|
bcc :loop2
|
||||||
|
:done
|
||||||
|
pla
|
||||||
|
rts
|
||||||
|
|
||||||
|
_InitRange
|
||||||
|
txa
|
||||||
|
asl
|
||||||
|
tax
|
||||||
|
|
||||||
|
tya
|
||||||
|
dec
|
||||||
|
and #$00FF
|
||||||
|
xba
|
||||||
|
|
||||||
|
:loop1 sta BG0Offsets,x
|
||||||
|
sec
|
||||||
|
sbc #$0100
|
||||||
|
dey
|
||||||
|
beq :done
|
||||||
|
inx
|
||||||
|
inx
|
||||||
|
cpx #416
|
||||||
|
bcc :loop1
|
||||||
|
:done
|
||||||
|
rts
|
||||||
|
|
||||||
|
BG0Offsets ds 416
|
||||||
|
|
||||||
PUT ../StartUp.s
|
PUT ../StartUp.s
|
||||||
PUT ../../shell/Overlay.s
|
PUT ../../shell/Overlay.s
|
||||||
|
|
|
@ -132,6 +132,9 @@ _GTEGetAddress MAC
|
||||||
_GTECompileSpriteStamp MAC
|
_GTECompileSpriteStamp MAC
|
||||||
UserTool $2D00+GTEToolNum
|
UserTool $2D00+GTEToolNum
|
||||||
<<<
|
<<<
|
||||||
|
_GTESetAddress MAC
|
||||||
|
UserTool $2E00+GTEToolNum
|
||||||
|
<<<
|
||||||
|
|
||||||
; EngineMode definitions
|
; EngineMode definitions
|
||||||
; Script definition
|
; Script definition
|
||||||
|
|
|
@ -251,13 +251,13 @@ EngineReset
|
||||||
bne :loop
|
bne :loop
|
||||||
|
|
||||||
; Set the scanline tables to reasonable default values
|
; Set the scanline tables to reasonable default values
|
||||||
ldx #{416*2}-2
|
; ldx #{416*2}-2
|
||||||
lda #0
|
; lda #0
|
||||||
:sxm_loop
|
;:sxm_loop
|
||||||
sta StartXMod164Arr,x
|
; sta StartXMod164Arr,x
|
||||||
dex
|
; dex
|
||||||
dex
|
; dex
|
||||||
bpl :sxm_loop
|
; bpl :sxm_loop
|
||||||
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,9 @@ RenderFlags equ 124 ; Flags passed to the Render() function
|
||||||
BG1Scaling equ 126
|
BG1Scaling equ 126
|
||||||
|
|
||||||
activeSpriteList equ 128 ; 32 bytes for the active sprite list (can persist across frames)
|
activeSpriteList equ 128 ; 32 bytes for the active sprite list (can persist across frames)
|
||||||
; tiletmp equ 178 ; 16 bytes of temp storage for the tile renderers
|
|
||||||
|
; Free space from 160 to 192
|
||||||
|
|
||||||
blttmp equ 192 ; 32 bytes of local cache/scratch space for blitter
|
blttmp equ 192 ; 32 bytes of local cache/scratch space for blitter
|
||||||
|
|
||||||
tmp8 equ 224 ; another 16 bytes of temporary space to be used as scratch
|
tmp8 equ 224 ; another 16 bytes of temporary space to be used as scratch
|
||||||
|
@ -282,8 +284,8 @@ VBuffHorzTableSelect EXT
|
||||||
BG1YCache EXT
|
BG1YCache EXT
|
||||||
ScalingTables EXT
|
ScalingTables EXT
|
||||||
|
|
||||||
StartXMod164Arr EXT
|
;StartXMod164Arr EXT
|
||||||
LastPatchOffsetArr EXT
|
;LastPatchOffsetArr EXT
|
||||||
|
|
||||||
_SortedHead EXT
|
_SortedHead EXT
|
||||||
_ShadowListCount EXT
|
_ShadowListCount EXT
|
||||||
|
@ -294,6 +296,7 @@ _DirectListTop EXT
|
||||||
_DirectListBottom EXT
|
_DirectListBottom EXT
|
||||||
|
|
||||||
StartXMod164Tbl EXT
|
StartXMod164Tbl EXT
|
||||||
|
LastOffsetTbl EXT
|
||||||
|
|
||||||
; Tool error codes
|
; Tool error codes
|
||||||
NO_TIMERS_AVAILABLE equ 10
|
NO_TIMERS_AVAILABLE equ 10
|
||||||
|
|
22
src/Render.s
22
src/Render.s
|
@ -169,7 +169,17 @@ _RenderScanlines
|
||||||
|
|
||||||
; jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
; jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||||
|
|
||||||
jsr _ScanlineBG0XPos ; Patch the code field instructions with exit BRA opcode
|
jsr _ApplyScanlineBG0XPos ; Patch the code field instructions with exit BRA opcode
|
||||||
|
|
||||||
|
jsr _BuildShadowList ; Create the rages based on the sorted sprite y-values
|
||||||
|
|
||||||
|
jsr _ShadowOff ; Turn off shadowing and draw all the scanlines with sprites on them
|
||||||
|
jsr _DrawShadowList
|
||||||
|
jsr _DrawDirectSprites ; Draw the sprites directly to the Bank $01 graphics buffer (skipping the render-to-tile step)
|
||||||
|
|
||||||
|
jsr _ShadowOn ; Turn shadowing back on
|
||||||
|
; jsr _DrawComplementList ; Alternate drawing scanlines and PEI slam to expose the full fram
|
||||||
|
jsr _DrawFinalPass
|
||||||
|
|
||||||
; jsr _ApplyBG1XPos ; Update the direct page value based on the horizontal position
|
; jsr _ApplyBG1XPos ; Update the direct page value based on the horizontal position
|
||||||
|
|
||||||
|
@ -209,11 +219,11 @@ _RenderScanlines
|
||||||
; jsr _BltRange
|
; jsr _BltRange
|
||||||
; bra :done
|
; bra :done
|
||||||
|
|
||||||
:no_ovrly
|
;:no_ovrly
|
||||||
ldx #0 ; Blit the full virtual buffer to the screen
|
; ldx #0 ; Blit the full virtual buffer to the screen
|
||||||
ldy ScreenHeight
|
; ldy ScreenHeight
|
||||||
jsr _BltRange
|
; jsr _BltRange
|
||||||
:done
|
;:done
|
||||||
|
|
||||||
; ldx #0
|
; ldx #0
|
||||||
; ldy ScreenHeight
|
; ldy ScreenHeight
|
||||||
|
|
37
src/Tool.s
37
src/Tool.s
|
@ -99,6 +99,7 @@ _CallTable
|
||||||
adrl _TSGetAddress-1
|
adrl _TSGetAddress-1
|
||||||
|
|
||||||
adrl _TSCompileSpriteStamp-1
|
adrl _TSCompileSpriteStamp-1
|
||||||
|
adrl _TSSetAddress-1
|
||||||
|
|
||||||
_CTEnd
|
_CTEnd
|
||||||
_GTEAddSprite MAC
|
_GTEAddSprite MAC
|
||||||
|
@ -302,6 +303,12 @@ _TSRender
|
||||||
bra :done
|
bra :done
|
||||||
|
|
||||||
:no_shadowing
|
:no_shadowing
|
||||||
|
bit #RENDER_PER_SCANLINE
|
||||||
|
beq :no_scanline
|
||||||
|
jsr _RenderScanlines
|
||||||
|
bra :done
|
||||||
|
|
||||||
|
:no_scanline
|
||||||
jsr _Render
|
jsr _Render
|
||||||
|
|
||||||
:done
|
:done
|
||||||
|
@ -865,27 +872,45 @@ _TSSetBG1Scale
|
||||||
sta BG1Scaling
|
sta BG1Scaling
|
||||||
_TSExit #0;#2
|
_TSExit #0;#2
|
||||||
|
|
||||||
|
; Pointer GetAddress(tblId)
|
||||||
_TSGetAddress
|
_TSGetAddress
|
||||||
:output equ FirstParam+0
|
:tblId equ FirstParam+0
|
||||||
:tblId equ FirstParam+4
|
:output equ FirstParam+2
|
||||||
|
|
||||||
_TSEntry
|
_TSEntry
|
||||||
lda #0
|
lda #0
|
||||||
sta :output,s
|
sta :output,s
|
||||||
sta :output+2,s
|
sta :output+2,s
|
||||||
|
|
||||||
lda :value,s
|
lda :tblId,s
|
||||||
cmp #scanlineHorzOffset
|
cmp #scanlineHorzOffset
|
||||||
bne :out
|
bne :out
|
||||||
|
|
||||||
lda #StartXMod164Arr
|
lda StartXMod164Tbl
|
||||||
sta :output,s
|
sta :output,s
|
||||||
lda #^StartXMod164Arr
|
lda StartXMod164Tbl+2
|
||||||
sta :output+2,s
|
sta :output+2,s
|
||||||
|
|
||||||
:out
|
:out
|
||||||
_TSExit #0;#2
|
_TSExit #0;#2
|
||||||
|
|
||||||
|
; SetAddress(tblId, Pointer)
|
||||||
|
_TSSetAddress
|
||||||
|
:ptr equ FirstParam+0
|
||||||
|
:tblId equ FirstParam+4
|
||||||
|
|
||||||
|
_TSEntry
|
||||||
|
lda :tblId,s
|
||||||
|
cmp #scanlineHorzOffset
|
||||||
|
bne :out
|
||||||
|
|
||||||
|
lda :ptr,s
|
||||||
|
sta StartXMod164Tbl
|
||||||
|
lda :ptr+2,s
|
||||||
|
sta StartXMod164Tbl+2
|
||||||
|
:out
|
||||||
|
_TSExit #0;#6
|
||||||
|
|
||||||
; CompileSpriteStamp(spriteId, vbuffAddr)
|
; CompileSpriteStamp(spriteId, vbuffAddr)
|
||||||
_TSCompileSpriteStamp
|
_TSCompileSpriteStamp
|
||||||
:vbuff equ FirstParam
|
:vbuff equ FirstParam
|
||||||
|
@ -916,7 +941,7 @@ _TSCompileSpriteStamp
|
||||||
put Sprite2.s
|
put Sprite2.s
|
||||||
put SpriteRender.s
|
put SpriteRender.s
|
||||||
put Render.s
|
put Render.s
|
||||||
put blitter/Scanline.s
|
; put blitter/Scanline.s
|
||||||
put render/Render.s
|
put render/Render.s
|
||||||
put render/Fast.s
|
put render/Fast.s
|
||||||
put render/Slow.s
|
put render/Slow.s
|
||||||
|
|
|
@ -50,11 +50,7 @@ _RestoreBG0Opcodes
|
||||||
|
|
||||||
:virt_line_x2 equ tmp1
|
:virt_line_x2 equ tmp1
|
||||||
:lines_left_x2 equ tmp2
|
:lines_left_x2 equ tmp2
|
||||||
:draw_count_x2 equ tmp3
|
|
||||||
:exit_offset equ tmp4
|
:exit_offset equ tmp4
|
||||||
:stk_save equ tmp5
|
|
||||||
|
|
||||||
phb ; Save data bank
|
|
||||||
|
|
||||||
asl
|
asl
|
||||||
sta :virt_line_x2 ; Keep track of it
|
sta :virt_line_x2 ; Keep track of it
|
||||||
|
@ -66,6 +62,14 @@ _RestoreBG0Opcodes
|
||||||
lda LastPatchOffset ; If zero, there are no saved opcodes
|
lda LastPatchOffset ; If zero, there are no saved opcodes
|
||||||
sta :exit_offset
|
sta :exit_offset
|
||||||
|
|
||||||
|
_RestoreBG0OpcodesAlt
|
||||||
|
:virt_line_x2 equ tmp1
|
||||||
|
:lines_left_x2 equ tmp2
|
||||||
|
:draw_count_x2 equ tmp3
|
||||||
|
:exit_offset equ tmp4
|
||||||
|
:stk_save equ tmp5
|
||||||
|
|
||||||
|
phb ; Save data bank
|
||||||
tsc
|
tsc
|
||||||
sta :stk_save
|
sta :stk_save
|
||||||
|
|
||||||
|
@ -144,18 +148,8 @@ _ApplyBG0XPosPre
|
||||||
rts
|
rts
|
||||||
|
|
||||||
_ApplyBG0XPos
|
_ApplyBG0XPos
|
||||||
|
|
||||||
:stk_save equ tmp0
|
|
||||||
:virt_line_x2 equ tmp1
|
:virt_line_x2 equ tmp1
|
||||||
:lines_left_x2 equ tmp2
|
:lines_left_x2 equ tmp2
|
||||||
:draw_count_x2 equ tmp3
|
|
||||||
:exit_offset equ tmp4
|
|
||||||
:entry_offset equ tmp5
|
|
||||||
:exit_bra equ tmp6
|
|
||||||
:exit_address equ tmp7
|
|
||||||
:base_address equ tmp8
|
|
||||||
:opcode equ tmp9
|
|
||||||
:odd_entry_offset equ tmp10
|
|
||||||
|
|
||||||
; If there are saved opcodes that have not been restored, do not run this routine
|
; If there are saved opcodes that have not been restored, do not run this routine
|
||||||
lda LastPatchOffset
|
lda LastPatchOffset
|
||||||
|
@ -232,6 +226,21 @@ _ApplyBG0XPos
|
||||||
; +-----------+
|
; +-----------+
|
||||||
|
|
||||||
lda StartXMod164
|
lda StartXMod164
|
||||||
|
|
||||||
|
; Alternate entry point if the virt_line_x2 and lines_left_x2 and XMod164 values are passed in externally
|
||||||
|
_ApplyBG0XPosAlt
|
||||||
|
:stk_save equ tmp0
|
||||||
|
:virt_line_x2 equ tmp1
|
||||||
|
:lines_left_x2 equ tmp2
|
||||||
|
:draw_count_x2 equ tmp3
|
||||||
|
:exit_offset equ tmp4
|
||||||
|
:entry_offset equ tmp5
|
||||||
|
:exit_bra equ tmp6
|
||||||
|
:exit_address equ tmp7
|
||||||
|
:base_address equ tmp8
|
||||||
|
:opcode equ tmp9
|
||||||
|
:odd_entry_offset equ tmp10
|
||||||
|
|
||||||
bit #$0001
|
bit #$0001
|
||||||
jne :odd_case ; Specialized routines for even/odd cases
|
jne :odd_case ; Specialized routines for even/odd cases
|
||||||
|
|
||||||
|
@ -368,7 +377,7 @@ _ApplyBG0XPos
|
||||||
sbc #164
|
sbc #164
|
||||||
|
|
||||||
tax
|
tax
|
||||||
lda Col2CodeOffset-1,x
|
lda Col2CodeOffset-1,x ; Odd offset to get the value in the high byte
|
||||||
and #$FF00
|
and #$FF00
|
||||||
ora #$00AF
|
ora #$00AF
|
||||||
sta :opcode
|
sta :opcode
|
||||||
|
@ -445,361 +454,148 @@ _ApplyBG0XPos
|
||||||
plb
|
plb
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
_RestoreScanlineBG0Opcodes
|
||||||
|
:virt_line_x2 equ tmp1
|
||||||
|
:lines_left_x2 equ tmp2
|
||||||
|
:exit_offset equ tmp4
|
||||||
|
|
||||||
|
; Avoid local var collisions
|
||||||
|
:virt_line_pos_x2 equ tmp11
|
||||||
|
:total_left_x2 equ tmp12
|
||||||
|
:current_count_x2 equ tmp13
|
||||||
|
:ptr equ tmp14
|
||||||
|
|
||||||
|
asl
|
||||||
|
sta :virt_line_pos_x2
|
||||||
|
tay
|
||||||
|
|
||||||
|
txa
|
||||||
|
asl
|
||||||
|
sta :total_left_x2
|
||||||
|
|
||||||
|
lda StartXMod164Tbl
|
||||||
|
sta :ptr
|
||||||
|
lda StartXMod164Tbl+2
|
||||||
|
sta :ptr+2
|
||||||
|
|
||||||
|
; Patch our the ranges from the StartXMod164Tbl array starting at the first virtual line
|
||||||
|
:loop
|
||||||
|
lda [:ptr],y
|
||||||
|
and #$FF00 ; Determine how many sequential lines to restore
|
||||||
|
xba
|
||||||
|
inc
|
||||||
|
asl
|
||||||
|
min :total_left_x2 ; Don't draw more than the number of lines that are left to process
|
||||||
|
sta :current_count_x2 ; Save a copy for later
|
||||||
|
|
||||||
|
sta :lines_left_x2 ; Set the parameter
|
||||||
|
sty :virt_line_x2 ; Set the parameter
|
||||||
|
lda LastOffsetTbl,y
|
||||||
|
sta :exit_offset
|
||||||
|
jsr _RestoreBG0OpcodesAlt
|
||||||
|
|
||||||
|
clc
|
||||||
|
lda :virt_line_pos_x2
|
||||||
|
adc :current_count_x2
|
||||||
|
cmp #208*2 ; Do the modulo check in this loop
|
||||||
|
bcc *+5
|
||||||
|
sbc #208*2
|
||||||
|
sta :virt_line_pos_x2
|
||||||
|
tay
|
||||||
|
|
||||||
|
lda :total_left_x2
|
||||||
|
sec
|
||||||
|
sbc :current_count_x2
|
||||||
|
sta :total_left_x2
|
||||||
|
bne :loop
|
||||||
|
|
||||||
|
rts
|
||||||
|
|
||||||
; This is a variant of the above routine that allows each x-position to be set independently from a table of value. This is
|
; This is a variant of the above routine that allows each x-position to be set independently from a table of value. This is
|
||||||
; quite a bit slower than the other routine since we cannot store constant values for each line.
|
; quite a bit slower than the other routine since we cannot store constant values for each line.
|
||||||
;
|
;
|
||||||
; We still want to perform operation in blocks of 16 to avoid repeatedly setting the data bank register for each line. In
|
; This routine operates at a higher level and does not try to be super optimized for the case where every line has a different
|
||||||
; order to accomplish this, the even/odd cases are split into separate code blocks and the unrolled loop will patch up
|
; set of parameters. Instead, we optimize for the case where there are a few large ranges of the screen moving at different
|
||||||
; all of the memory locations on each line, rather than doing each patch one at a time. This may actually be more efficient
|
; rates, e.g. a fixed status bar area on top, a slow-scrolling area in the middle and a fast are in the foreground.
|
||||||
; since it eliminates several jmp (abs,x) / tax instructions and removed some register reloading.
|
|
||||||
;
|
;
|
||||||
; The two unrolled loop elements are:
|
; The table that drives this is dense and has the following format for each word
|
||||||
;
|
;
|
||||||
; Even:
|
; Bits 0 - 7: X mod 164 value
|
||||||
; lda: $0000,x ; Load from X = BTableLow + exit_offset
|
; Bits 8 - 15: Number of scanline to persist this mod value
|
||||||
; sta: OPCODE_SAVE,y ; Save the two byte in another area of the line code
|
|
||||||
; lda :exit_bra[n]
|
|
||||||
; sta $0000,x ; Replace the two bytes with a BRA instruction to exit the blitter
|
|
||||||
; lda :opcode[n]
|
|
||||||
; sta: CODE_ENTRY_OPCODE,y ; CODE_ENTRY_OPCODE and CODE_ENTRY are adjacent -- could make this a single 16-bit store
|
|
||||||
;
|
;
|
||||||
; Odd:
|
; So, if the first 10 entries has a mod value of 5, they would look like: $0905, $0805, $0705, ... $0105, $0005
|
||||||
; Same as above, plus...
|
;
|
||||||
; lda :odd_entry_offset[n] ; [8-bit] Get back into the code after fixing up the odd edge
|
; This allows the code to start an an arbitrary location and immeditely sync up with the modulo list. It also allows
|
||||||
; sta: ODD_ENTRY,y
|
; the code to easily skip ranges of constant values using the existing _ApplyBG0XPos function as a subroutine.
|
||||||
; lda: $0001,x ; Save the high word in case the last instruction is PEA and we need to load the top byte
|
_ApplyScanlineBG0XPos
|
||||||
; sta: OPCODE_HIGH_SAVE,y
|
|
||||||
;
|
; Copies of the local variables in _ApplyBG0XPos
|
||||||
_ApplyBG0XPosPerScanline
|
|
||||||
:stk_save equ tmp0
|
|
||||||
:virt_line_x2 equ tmp1
|
:virt_line_x2 equ tmp1
|
||||||
:lines_left_x2 equ tmp2
|
:lines_left_x2 equ tmp2
|
||||||
:draw_count_x2 equ tmp3
|
|
||||||
:exit_offset equ tmp4
|
:exit_offset equ tmp4
|
||||||
:entry_offset equ tmp5
|
|
||||||
:exit_bra equ tmp6
|
|
||||||
:exit_address equ tmp7
|
|
||||||
:base_address equ tmp8
|
|
||||||
:opcode equ tmp9
|
|
||||||
:odd_entry_offset equ tmp10
|
|
||||||
|
|
||||||
; If there are saved opcodes that have not been restored, do not run this routine
|
; Avoid local var collision with _ApplyBG0XPos
|
||||||
lda LastPatchOffset
|
:virt_line_pos_x2 equ tmp11
|
||||||
beq :ok
|
:total_left_x2 equ tmp12
|
||||||
|
:current_count_x2 equ tmp13
|
||||||
|
:ptr equ tmp14
|
||||||
|
|
||||||
|
lda StartXMod164Tbl
|
||||||
|
sta :ptr
|
||||||
|
lda StartXMod164Tbl+2
|
||||||
|
sta :ptr+2
|
||||||
|
ora :ptr
|
||||||
|
bne *+3 ; null pointer check
|
||||||
rts
|
rts
|
||||||
|
|
||||||
; In this routine, basically every horizontal parameter is based off of the :virt_line_x2 index
|
|
||||||
:ok
|
|
||||||
lda StartYMod208 ; This is the base line of the virtual screen
|
lda StartYMod208 ; This is the base line of the virtual screen
|
||||||
asl
|
asl
|
||||||
sta :virt_line_x2 ; Keep track of it
|
sta :virt_line_pos_x2
|
||||||
|
tay
|
||||||
|
|
||||||
lda ScreenHeight
|
lda ScreenHeight
|
||||||
asl
|
asl
|
||||||
sta :lines_left_x2
|
sta :total_left_x2
|
||||||
|
|
||||||
; Sketch out the core structural elements of the loop + bank management
|
|
||||||
|
|
||||||
phb ; Save the existing bank
|
|
||||||
tsc
|
|
||||||
sta :stk_save
|
|
||||||
|
|
||||||
|
; Patch our the ranges from the StartXMod164Tbl array starting at the first virtual line
|
||||||
:loop
|
:loop
|
||||||
ldx :virt_line_x2
|
lda [:ptr],y
|
||||||
|
|
||||||
txa
|
|
||||||
and #$001E
|
|
||||||
eor #$FFFF
|
|
||||||
sec
|
|
||||||
adc #2*16 ; 2 * (16 - virt_line % 16). This get us aligned to 16-line boundaries
|
|
||||||
min :lines_left_x2 ; Make sure we handle cases where lines_left < aligned remainder
|
|
||||||
sta :draw_count_x2 ; We are drawing this many lines on this iteration starting at _virt_line_x2
|
|
||||||
|
|
||||||
ldal BTableHigh,x ; Set the bank
|
|
||||||
pha
|
|
||||||
plb
|
|
||||||
|
|
||||||
jsr :DoScanlineRange ; Patch in the code field for this range (Bank is set)
|
|
||||||
|
|
||||||
lda :draw_count_x2
|
|
||||||
clc ; advance to the virtual line after the segment we just
|
|
||||||
adc :virt_line_x2 ; filled in
|
|
||||||
sta :virt_line_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
|
|
||||||
|
|
||||||
; Run through and build an array of scanline data and place it in temporary zero page space. Need a total of 48 bytes.
|
|
||||||
:BuildScanlineData
|
|
||||||
|
|
||||||
; First step, run though and create the tables for the copy routine
|
|
||||||
lda StartXMod164Tbl,x
|
|
||||||
bit #$0001
|
|
||||||
; bne :bsd_odd
|
|
||||||
|
|
||||||
tay
|
|
||||||
lda CodeFieldEvenBRA-2,y ; The exit point comes after the left edge (reverse order due to stack)
|
|
||||||
sta :exit_bra,x
|
|
||||||
lda Col2CodeOffset-2,y
|
|
||||||
sta :exit_offset,x
|
|
||||||
|
|
||||||
|
|
||||||
:DoScanlineRange
|
|
||||||
ldx :virt_line_x2
|
|
||||||
|
|
||||||
; First, calculate the exit point
|
|
||||||
|
|
||||||
ldal StartXMod164Tbl,x ; Get the origin for this line
|
|
||||||
bit #$0001
|
|
||||||
bne :is_odd ; Quickly switch to specialized even/odd routines
|
|
||||||
|
|
||||||
; For even offsets, the index is x - 2
|
|
||||||
; For odd offsets, the index is x - 1
|
|
||||||
;
|
|
||||||
; So, for both we can do (x - 1) & $FFFE = dec / and #$FFFE = lsr / asl + clears the carry
|
|
||||||
|
|
||||||
; This is an even-aligned line
|
|
||||||
|
|
||||||
; dec ; Move to the previous address for entry (a - 1) % 164
|
|
||||||
; dec ; Optimization: Coule eliminate this with a double-width tbale for CodeFieldEvenBRA
|
|
||||||
; bpl *+5
|
|
||||||
; lda #162
|
|
||||||
|
|
||||||
tay
|
|
||||||
lda CodeFieldEvenBRA-2,y
|
|
||||||
sta :exit_bra ; Store are exit_offset +
|
|
||||||
lda Col2CodeOffset-2,y
|
|
||||||
sta :exit_offset
|
|
||||||
|
|
||||||
; tya
|
|
||||||
; adc ScreenWidth
|
|
||||||
; cmp #164 ; Keep the value in range
|
|
||||||
; bcc *+5
|
|
||||||
; sbc #164
|
|
||||||
; tay
|
|
||||||
|
|
||||||
lda Col2CodeOffset-2-1,y ; -2 for even case , -1 to load value into high byte
|
|
||||||
and #$FF00
|
|
||||||
; sta :entry_offset
|
|
||||||
ora #$004C ; set the entry_jmp opcode to JMP
|
|
||||||
sta :opcode
|
|
||||||
; stz :odd_entry_offset ; mark as an even case
|
|
||||||
|
|
||||||
ldal BTableLow,x ; Get the address of the code field line
|
|
||||||
tay ; Save it to use as the base address
|
|
||||||
clc
|
|
||||||
adc :exit_offset ; Add some offsets to get the base address in the code field line
|
|
||||||
tax
|
tax
|
||||||
|
|
||||||
clc
|
and #$FF00 ; Determine how many sequential lines have this mod value
|
||||||
; This is the core even patch loop. The y-register tracks the base address of the starting line. Set the x-register
|
xba
|
||||||
; based on the per-line exit_offset and eveything else references other data
|
inc
|
||||||
|
asl
|
||||||
|
min :total_left_x2 ; Don't draw more than the number of lines that are left to process
|
||||||
|
sta :current_count_x2 ; Save a copy for later
|
||||||
|
|
||||||
; tya
|
sta :lines_left_x2 ; Set the parameter
|
||||||
; adc :exit_offset+{]line*2}
|
sty :virt_line_x2 ; Set the parameter
|
||||||
; tax
|
txa ; Put the X mod 164 value in the accumulator
|
||||||
; lda: {]line*$1000},x
|
and #$00FF
|
||||||
; sta: OPCODE_SAVE+{]line*$1000},y
|
jsr _ApplyBG0XPosAlt
|
||||||
; lda :exit_bra+{]line*2} ; Copy this value into all of the lines
|
|
||||||
; sta: {]line*$1000},x
|
|
||||||
; lda :entry_offset+{]line*2} ; Pre-merged with the appropriate opcode + offset
|
|
||||||
; sta: CODE_ENTRY_OPCODE+{]line*$1000},y
|
|
||||||
|
|
||||||
bra :prep_complete
|
lda :exit_offset ; Get the direct address in the code field that was overwritten
|
||||||
|
ldy :virt_line_pos_x2
|
||||||
; This is an odd-aligned line
|
sta LastOffsetTbl,y ; Stash it for use by the per-scanline resotre function
|
||||||
:is_odd
|
|
||||||
dec ; Remove the least-significant byte (must stay positive)
|
|
||||||
tay
|
|
||||||
lda CodeFieldOddBRA,y
|
|
||||||
sta :exit_bra
|
|
||||||
lda Col2CodeOffset,y
|
|
||||||
sta :exit_offset
|
|
||||||
|
|
||||||
tya
|
tya
|
||||||
adc ScreenWidth
|
|
||||||
cmp #164 ; Keep the value in range
|
|
||||||
bcc *+5
|
|
||||||
sbc #164
|
|
||||||
tay
|
|
||||||
lda Col2CodeOffset,y
|
|
||||||
sta :entry_offset ; Will be used to load the data
|
|
||||||
lda Col2CodeOffset-2,y
|
|
||||||
sta :odd_entry_offset ; will be the actual location to jump to
|
|
||||||
lda #$00AF ; set the entry_jmp opcode to LDAL
|
|
||||||
sta :opcode
|
|
||||||
|
|
||||||
:prep_complete
|
|
||||||
ldal BTableLow,x ; Get the address of the code field line
|
|
||||||
tay ; Save it to use as the base address
|
|
||||||
clc
|
clc
|
||||||
adc :exit_offset ; Add some offsets to get the base address in the code field line
|
adc :current_count_x2
|
||||||
|
cmp #208*2 ; Do the modulo check in this loop
|
||||||
|
bcc *+5
|
||||||
|
sbc #208*2
|
||||||
|
sta :virt_line_pos_x2
|
||||||
|
tay
|
||||||
|
|
||||||
; sta :exit_address
|
lda :total_left_x2
|
||||||
; sty :base_address
|
|
||||||
|
|
||||||
|
|
||||||
; ldy :base_address
|
|
||||||
; ldx :exit_address ; Save from this location (not needed in fast mode)
|
|
||||||
; SaveOpcode ; X = :exit_address on return
|
|
||||||
tax
|
|
||||||
lda: $0000,x
|
|
||||||
sta: OPCODE_SAVE+$0000,y
|
|
||||||
|
|
||||||
|
|
||||||
; txy ; ldy :exit_address -- starting at this address
|
|
||||||
; ldx :draw_count_x2 ; Do this many lines
|
|
||||||
lda :exit_bra ; Copy this value into all of the lines
|
|
||||||
; SetConst ; All registers are preserved
|
|
||||||
sta: $0000,x
|
|
||||||
|
|
||||||
; Next, patch in the CODE_ENTRY value, which is the low byte of a JMP instruction. This is an
|
|
||||||
; 8-bit operation and, since the PEA code is bank aligned, we use the entry_offset value directly
|
|
||||||
|
|
||||||
sep #$20
|
|
||||||
|
|
||||||
lda :entry_offset
|
|
||||||
; ldy :base_address
|
|
||||||
; SetCodeEntry ; All registers are preserved
|
|
||||||
sta: CODE_ENTRY+$0000,y
|
|
||||||
|
|
||||||
; Now, patch in the opcode
|
|
||||||
|
|
||||||
lda :opcode
|
|
||||||
; SetCodeEntryOpcode ; All registers are preserved
|
|
||||||
sta: CODE_ENTRY_OPCODE+$0000,y
|
|
||||||
|
|
||||||
; If this is an odd entry, also set the odd_entry low byte and save the operand high byte
|
|
||||||
|
|
||||||
lda :odd_entry_offset
|
|
||||||
jeq :not_odd
|
|
||||||
|
|
||||||
; SetOddCodeEntry ; All registers are preserved
|
|
||||||
sta: ODD_ENTRY+$0000,y
|
|
||||||
; SaveHighOperand :exit_address ; Only used once, so "inline" it
|
|
||||||
ldx :exit_address
|
|
||||||
lda: $0002,x
|
|
||||||
sta: OPCODE_HIGH_SAVE+$0000,y
|
|
||||||
|
|
||||||
:not_odd
|
|
||||||
rep #$21 ; clear the carry
|
|
||||||
|
|
||||||
lda :virt_line_x2 ; advance to the virtual line after
|
|
||||||
adc :draw_count_x2 ; filled in
|
|
||||||
sta :virt_line_x2
|
|
||||||
|
|
||||||
lda :lines_left_x2 ; subtract the number of lines we just completed
|
|
||||||
sec
|
sec
|
||||||
sbc :draw_count_x2
|
sbc :current_count_x2
|
||||||
sta :lines_left_x2
|
sta :total_left_x2
|
||||||
|
bne :loop
|
||||||
jne :loop
|
|
||||||
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
|
||||||
; DoEvenRange
|
|
||||||
;
|
|
||||||
; Does all the core operations for an even range (16-bit accumulator and registers)
|
|
||||||
;
|
|
||||||
; X = number of lines * 2, 0 to 32
|
|
||||||
; Y = starting line * $1000
|
|
||||||
; A = code field location * $1000
|
|
||||||
DoEvenRange mac
|
|
||||||
asl ; mult the offset by 2 and clear the carry at the same time
|
|
||||||
adc #dispTbl
|
|
||||||
stal patch+1
|
|
||||||
patch jmp $0000
|
|
||||||
dispTbl jmp bottom
|
|
||||||
db 1
|
|
||||||
jmp x01
|
|
||||||
db 1
|
|
||||||
jmp x02
|
|
||||||
db 1
|
|
||||||
jmp x03
|
|
||||||
db 1
|
|
||||||
jmp x04
|
|
||||||
db 1
|
|
||||||
jmp x05
|
|
||||||
db 1
|
|
||||||
jmp x06
|
|
||||||
db 1
|
|
||||||
jmp x07
|
|
||||||
db 1
|
|
||||||
jmp x08
|
|
||||||
db 1
|
|
||||||
jmp x09
|
|
||||||
db 1
|
|
||||||
jmp x10
|
|
||||||
db 1
|
|
||||||
jmp x11
|
|
||||||
db 1
|
|
||||||
jmp x12
|
|
||||||
db 1
|
|
||||||
jmp x13
|
|
||||||
db 1
|
|
||||||
jmp x14
|
|
||||||
db 1
|
|
||||||
jmp x15
|
|
||||||
db 1
|
|
||||||
x16 tya
|
|
||||||
adc :exit_offset+$1E
|
|
||||||
tax
|
|
||||||
lda: $F000,x
|
|
||||||
sta: OPCODE_SAVE+$F000,y
|
|
||||||
lda :exit_bra+$1E
|
|
||||||
sta: $F000,x
|
|
||||||
lda :entry_offset+$1E ; Pre-merged with the appropriate opcode + offset
|
|
||||||
sta: CODE_ENTRY_OPCODE+$F000,y
|
|
||||||
|
|
||||||
x15 tya
|
|
||||||
adc :exit_offset+$1E
|
|
||||||
tax
|
|
||||||
lda: $E000,x
|
|
||||||
sta: OPCODE_SAVE+$E000,y
|
|
||||||
lda :exit_bra+$1C
|
|
||||||
sta: $E000,x
|
|
||||||
lda :entry_offset+$1C
|
|
||||||
sta: CODE_ENTRY_OPCODE+$E000,y
|
|
||||||
|
|
||||||
x14 lda $D002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$D000,y
|
|
||||||
x13 lda $C002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$C000,y
|
|
||||||
x12 lda $B002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$B000,y
|
|
||||||
x11 lda $A002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$A000,y
|
|
||||||
x10 lda $9002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$9000,y
|
|
||||||
x09 lda $8002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$8000,y
|
|
||||||
x08 lda $7002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$7000,y
|
|
||||||
x07 lda $6002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$6000,y
|
|
||||||
x06 lda $5002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$5000,y
|
|
||||||
x05 lda $4002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$4000,y
|
|
||||||
x04 lda $3002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$3000,y
|
|
||||||
x03 lda $2002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$2000,y
|
|
||||||
x02 lda $1002,x
|
|
||||||
sta OPCODE_HIGH_SAVE+$1000,y
|
|
||||||
x01 lda: $0002,x
|
|
||||||
sta: OPCODE_HIGH_SAVE+$0000,y
|
|
||||||
bottom <<<
|
|
||||||
|
|
||||||
; SaveHighOperand
|
; SaveHighOperand
|
||||||
;
|
;
|
||||||
; Save the high byte of the 3-byte code field instruction into the odd handler at the end
|
; Save the high byte of the 3-byte code field instruction into the odd handler at the end
|
||||||
|
|
|
@ -108,6 +108,10 @@ TileStoreLookup ENT
|
||||||
Col2CodeOffset ENT
|
Col2CodeOffset ENT
|
||||||
lup 82
|
lup 82
|
||||||
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
|
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
|
||||||
|
]step equ ]step+1
|
||||||
|
--^
|
||||||
|
lup 82 ; Make is a double-length table so we can add the ScreenWidth without testing for wrap-around
|
||||||
|
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
|
||||||
]step equ ]step+1
|
]step equ ]step+1
|
||||||
--^
|
--^
|
||||||
dw CODE_TOP+{81*PER_TILE_SIZE}
|
dw CODE_TOP+{81*PER_TILE_SIZE}
|
||||||
|
@ -386,6 +390,10 @@ BG1YOffsetTable ENT
|
||||||
|
|
||||||
; Per-scanline offsets for BG0
|
; Per-scanline offsets for BG0
|
||||||
StartXMod164Tbl ENT
|
StartXMod164Tbl ENT
|
||||||
|
dw 0,0
|
||||||
|
|
||||||
|
LastOffsetTbl ENT
|
||||||
|
ds 416
|
||||||
|
|
||||||
; Other Toolset variables
|
; Other Toolset variables
|
||||||
OneSecondCounter ENT
|
OneSecondCounter ENT
|
||||||
|
@ -566,7 +574,7 @@ Scale15 dw $003C,$003C,$003C,$003E,$003E,$003E,$003E,$0040,$0040,$0040,$0040,$
|
||||||
blt_return
|
blt_return
|
||||||
stk_save
|
stk_save
|
||||||
|
|
||||||
StartXMod164Arr ENT
|
;StartXMod164Arr ENT
|
||||||
ds 416*2
|
; ds 416*2
|
||||||
LastPatchOffsetArr ENT
|
;LastPatchOffsetArr ENT
|
||||||
ds 416*2
|
; ds 416*2
|
||||||
|
|
Loading…
Reference in New Issue
Block a user