mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2025-01-29 15:33:52 +00:00
Fix off-by-one error in overlay
This commit is contained in:
parent
b449d983ee
commit
e013ff03fd
@ -47,6 +47,7 @@ PlayerX equ 40
|
||||
PlayerY equ 42
|
||||
PlayerXVel equ 44
|
||||
PlayerYVel equ 46
|
||||
OverlayTop equ 48
|
||||
|
||||
phk
|
||||
plb
|
||||
@ -107,6 +108,7 @@ PlayerYVel equ 46
|
||||
sta StartY
|
||||
stz frameCount
|
||||
stz frameCountTotal
|
||||
stz OverlayTop
|
||||
|
||||
pei StartX
|
||||
pei StartY
|
||||
@ -222,7 +224,21 @@ EvtLoop
|
||||
_GTESetBG0Origin
|
||||
bra :do_render
|
||||
:not_w
|
||||
cmp #' '
|
||||
bne :not_space
|
||||
lda OverlayTop
|
||||
inc
|
||||
and #$3F
|
||||
sta OverlayTop
|
||||
pha
|
||||
clc
|
||||
adc #8
|
||||
pha
|
||||
pea #^StatusBar
|
||||
pea #StatusBar
|
||||
_GTEUpdateOverlay
|
||||
|
||||
:not_space
|
||||
:do_render
|
||||
jsr SetBG1Animation ; Update the per-scanline BG1 offsets
|
||||
|
||||
|
@ -275,6 +275,17 @@ r_ovrly
|
||||
--^
|
||||
jmp r_ovrly_rtn ; In R1W1, so can't use the stack
|
||||
|
||||
r_ovrly2
|
||||
]idx equ 0
|
||||
lup R_CHAR_COUNT
|
||||
lda r_line+]idx,x
|
||||
sta ]idx
|
||||
lda r_line+]idx+2,x
|
||||
sta ]idx+2
|
||||
]idx equ ]idx+4
|
||||
--^
|
||||
jmp r_ovrly_rtn ; In R1W1, so can't use the stack
|
||||
|
||||
l_ovrly
|
||||
]idx equ 0
|
||||
lup L_CHAR_COUNT
|
||||
@ -289,11 +300,23 @@ l_ovrly
|
||||
]idx equ ]idx+4
|
||||
--^
|
||||
jmp l_ovrly_rtn
|
||||
|
||||
|
||||
l_ovrly2
|
||||
]idx equ 0
|
||||
lup L_CHAR_COUNT
|
||||
lda l_line+]idx,x
|
||||
sta ]idx
|
||||
lda l_line+]idx+2,x
|
||||
sta ]idx+2
|
||||
]idx equ ]idx+4
|
||||
--^
|
||||
jmp l_ovrly_rtn
|
||||
|
||||
; Single TSB slam
|
||||
m_line
|
||||
]idx equ $9E
|
||||
lup 80 ; 80 words max for a full-width screen
|
||||
; sta ]idx
|
||||
tsb ]idx
|
||||
]idx equ ]idx-2
|
||||
--^
|
||||
|
328
src/Render.s
328
src/Render.s
@ -135,6 +135,7 @@ _Render
|
||||
:no_removal
|
||||
rts
|
||||
|
||||
; Small helper function to draw a single overlay
|
||||
_DoOverlay
|
||||
lda Overlays+OVERLAY_PROC
|
||||
stal :disp+1
|
||||
@ -162,12 +163,9 @@ _RenderScanlines
|
||||
jsr _ResetBG1YTable
|
||||
:ytbl_ok
|
||||
|
||||
jsr _ApplyBG0YPos ; Set stack addresses for the virtual lines to the physical screen
|
||||
jsr _ApplyBG0YPos ; Set stack addresses for the virtual lines to the physical screen
|
||||
jsr _ApplyScanlineBG1YPos ; Set the y-register values of the blitter
|
||||
|
||||
; _ApplyBG0Xpos need to be split because we have to set the offsets, then draw in any updated tiles, and
|
||||
; finally patch out the code field. Right now, the BRA operand is getting overwritten by tile data.
|
||||
|
||||
jsr _ApplyBG0XPosPre
|
||||
jsr _ApplyBG1XPosPre
|
||||
|
||||
@ -233,7 +231,7 @@ _RenderScanlines
|
||||
; i. Draw the overlay
|
||||
; ii. Change the sprite segment to start after the overlay
|
||||
; iii. Go to [1]
|
||||
_DrawFinalPass2
|
||||
_DrawFinalPass
|
||||
:cursor equ tmp8
|
||||
:bottom equ tmp9
|
||||
|
||||
@ -306,9 +304,10 @@ _DrawFinalPass2
|
||||
|
||||
:_somerge
|
||||
phxy
|
||||
ldx :cursor
|
||||
ldy _Sprites+SPRITE_CLIP_TOP,x ; PEI Slam to the top of the overlay (:bottom is greater than this value)
|
||||
ldx :cursor
|
||||
sty :cursor
|
||||
; brk $44
|
||||
jsr _PEISlam
|
||||
lda 3,s ; Retrieve the sprite index
|
||||
tax
|
||||
@ -371,112 +370,6 @@ _DrawFinalPass2
|
||||
sta :cursor
|
||||
brl :_so_loop
|
||||
|
||||
_DrawFinalPass
|
||||
:cursor equ tmp8
|
||||
|
||||
stz :cursor ; Current mark in the sweep down the screen
|
||||
|
||||
ldy ObjectListHead ; If there are no items, just _BltRange the rest of the screen and return
|
||||
jmi :finish
|
||||
|
||||
:loop
|
||||
ldx :cursor
|
||||
lda ObjectList+OL_SPRITE_TOP,y
|
||||
sta :cursor
|
||||
jsr :_BltRange3 ; Expose from the cursor to the top and update the cursor
|
||||
|
||||
lda ObjectList+OL_SPRITE_ID,y ; See if we are processing an overlay or a sprite region
|
||||
bit #SPRITE_OVERLAY
|
||||
jne :obj_is_overlay
|
||||
|
||||
:obj_is_sprite
|
||||
ldx ObjectList+OL_NEXT,y
|
||||
jmi :sprite_complete
|
||||
|
||||
; Look at the next item, if it's below the current sprite range, do a slam and move on to the next item
|
||||
|
||||
lda ObjectList+OL_CLIP_BOTTOM,y
|
||||
cmp ObjectList+OL_CLIP_TOP,x
|
||||
bcs :sprite_overlap
|
||||
|
||||
txy ; Move to the next sprite
|
||||
ldx :cursor
|
||||
sta :cursor ; A = bottom, x = :cursor
|
||||
jsr _PEISlam
|
||||
bra :loop ; Loop back and do the BltRange up to the top of the next sprite
|
||||
|
||||
; Now we know that the next item must be an overlay (because sprite ranges are already combined), so go ahead
|
||||
; and PEI slam up to the top of the overlay
|
||||
:sprite_overlap
|
||||
lda ObjectList+OL_CLIP_TOP,x
|
||||
ldx :cursor
|
||||
sta :cursor
|
||||
jsr _PEISlam
|
||||
|
||||
lda ObjectList+OL_CLIP_BOTTOM,x ; If the overlay is fully within the sprite, do extra work.
|
||||
cmp ObjectList+OL_CLIP_BOTTOM,y ; Otherwise continue knowing we are currently handling an overlay
|
||||
bcc :split
|
||||
|
||||
txy
|
||||
bra :overlay_next
|
||||
|
||||
:split
|
||||
jsr split
|
||||
bra :obj_is_sprite
|
||||
|
||||
; Do a similar process for the overlays
|
||||
:obj_is_overlay
|
||||
ldx ObjectList+OL_NEXT,y
|
||||
bmi :ovrly_complete
|
||||
|
||||
; Look at the next item, if it's below the current overlay range, draw the overlay and move on to the next item
|
||||
|
||||
lda ObjectList+OL_CLIP_BOTTOM,y
|
||||
cmp ObjectList+OL_CLIP_TOP,x
|
||||
bcs :ovrly_overlap
|
||||
|
||||
jsr DrawOverlayY
|
||||
txy ; Move to the next item
|
||||
bra :loop ; Loop back and do the BltRange up to the top of the next sprite
|
||||
|
||||
; Now we know that the next item must be a sprite. Skip any sprite that are completely covered by the overlay. If
|
||||
; a sprite is split by the overlay, then reduce the top value
|
||||
:ovrly_overlap
|
||||
lda ObjectList+OL_CLIP_TOP,x
|
||||
ldx :cursor
|
||||
sta :cursor
|
||||
jsr PEISlam
|
||||
|
||||
lda ObjectList+OL_CLIP_BOTTOM,x ; If the next
|
||||
cmp ObjectList+OL_CLIP_BOTTOM,y ; Otherwise continue knowing we are currently handling an overlay
|
||||
bcc :split
|
||||
|
||||
txy
|
||||
bra :overlay_next
|
||||
|
||||
|
||||
; When a sprite is the last item before the end of the screen, jump here
|
||||
:sprite_complete
|
||||
ldx :cursor
|
||||
lda ObjectList+OL_CLIP_BOTTOM,y
|
||||
sta :cursor
|
||||
tay
|
||||
jsr PEISlam
|
||||
|
||||
; Jump here when there are no items left to process.
|
||||
:finish
|
||||
ldx :cursor
|
||||
ldy ScreenHeight
|
||||
jmp _BltRange
|
||||
|
||||
|
||||
lda ObjectList+OL_CLIP_BOTTOM,x ; If the overlay is fully within the sprite, do extra work.
|
||||
cmp ObjectList+OL_CLIP_BOTTOM,y ; Otherwise continue knowing we are currently handling an overlay
|
||||
bcc :split
|
||||
|
||||
txy
|
||||
bra :overlay_next
|
||||
|
||||
; Run through all of the tiles on the DirtyTile list and render them
|
||||
_ApplyTiles
|
||||
ldx DirtyTileCount
|
||||
@ -575,97 +468,14 @@ _RenderWithShadowing
|
||||
; At this point, everything in the background has been rendered into the code field. Next, we need
|
||||
; to create priority lists of scanline ranges.
|
||||
|
||||
; jsr _BuildShadowList ; Create the ranges based on the sorted sprite y-values
|
||||
|
||||
jsr _ShadowOff ; Turn off shadowing and draw all the scanlines with sprites on them
|
||||
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 _DrawDirectSprites ; Draw the sprites directly to the Bank $01 graphics buffer (skipping the render-to-tile step)
|
||||
|
||||
jsr _ShadowOn ; Turn shadowing back on
|
||||
jsr _ShadowOn ; Turn shadowing back on
|
||||
jsr _DrawFinalPass
|
||||
|
||||
;
|
||||
; The objects that need to be reasoned about are
|
||||
;
|
||||
; 1. Sprites
|
||||
; 2. Overlays
|
||||
; a. Solid High Priority
|
||||
; b. Solid Low Priority
|
||||
; c. Masked High Priority
|
||||
; d. Masked Low Priority
|
||||
; 3. Background
|
||||
;
|
||||
; Notes:
|
||||
;
|
||||
; A High Priority overlay is rendered above the sprites
|
||||
; A Low Priority overlay is rendered below the sprites
|
||||
; A Solid High Priority overlay obscured everything and if the only thing drawn on the scanline
|
||||
;
|
||||
; The order of draw oprations is:
|
||||
;
|
||||
; 1. Turn off shadowing
|
||||
; 2. Draw the background for scanlines with (Sprites OR a Masked Low Priority overlay) AND NOT a Solid Low Priority overlay
|
||||
; 3. Draw the Solid Low Priority overlays
|
||||
; 4. Draw the Sprites
|
||||
; 5. Draw the Masked Low Priority overlays
|
||||
; 6. Turn on shadowing
|
||||
; 7. Draw, in top-to-bottom order
|
||||
; a. Background lines not drawn yet
|
||||
; b. PEI Slam lines with (Sprites OR a Masked Low Priority Overlay) AND NOT a High Priority overlay
|
||||
; c. High Priority overlays
|
||||
;
|
||||
; The work of this routine is to quickly build a sorted list of scanline ranges that can call the appropriate
|
||||
; sub-renderer
|
||||
|
||||
; jsr BuildShadowSegments
|
||||
;
|
||||
; The trick is to create a bit-field mapping for the different actions to define
|
||||
|
||||
; lda Overlays
|
||||
; beq :no_ovrly
|
||||
;
|
||||
; jsr _ShadowOff
|
||||
|
||||
; Shadowing is turned off. Render all of the scan lines that need a second pass. One
|
||||
; optimization that can be done here is that the lines can be rendered in any order
|
||||
; since it is not shown on-screen yet.
|
||||
|
||||
; ldx Overlays+OVERLAY_TOP ; Blit the full virtual buffer to the screen
|
||||
; ldy Overlays+OVERLAY_BOTTOM
|
||||
; jsr _BltRange
|
||||
|
||||
; Turn shadowing back on
|
||||
|
||||
; jsr _ShadowOn
|
||||
|
||||
; Now render all of the remaining lines in top-to-bottom (or bottom-to-top) order
|
||||
|
||||
; ldx #0
|
||||
; ldy Overlays+OVERLAY_TOP
|
||||
; beq :skip
|
||||
; jsr _BltRange
|
||||
;:skip
|
||||
; jsr _DoOverlay
|
||||
|
||||
; ldx Overlays+OVERLAY_BOTTOM
|
||||
; cpx ScreenHeight
|
||||
; beq :done
|
||||
; ldy ScreenHeight
|
||||
; jsr _BltRange
|
||||
; bra :done
|
||||
|
||||
;:no_ovrly
|
||||
|
||||
; ldx #0 ; Blit the full virtual buffer to the screen
|
||||
; ldy ScreenHeight
|
||||
; jsr _BltRange
|
||||
|
||||
;:done
|
||||
|
||||
; ldx #0
|
||||
; ldy ScreenHeight
|
||||
; jsr _BltSCB
|
||||
|
||||
lda StartYMod208 ; Restore the fields back to their original state
|
||||
ldx ScreenHeight
|
||||
jsr _RestoreBG0Opcodes
|
||||
@ -690,95 +500,6 @@ _RenderWithShadowing
|
||||
:no_removal
|
||||
rts
|
||||
|
||||
; Look at the overlay list and the sprite list and figure out which scanline ranges need to be
|
||||
; blitted in what order. We try to build all of the scan line segments lists because that
|
||||
; saves the work of re-scanning the lists.
|
||||
;
|
||||
; The semgent list definitions are:
|
||||
;
|
||||
; BLIT_W_SHADOW_OF
|
||||
BuildShadowSegments
|
||||
; ldx _SortedHead
|
||||
; bmi :no_sprite
|
||||
;:loop
|
||||
; lda _Sprites+CLIP_TOP,x
|
||||
; lda _Sprites+SORTED_NEXT,x
|
||||
; tax
|
||||
; bpl :loop
|
||||
;
|
||||
; lda #0 ; Start at the top of the
|
||||
|
||||
rts
|
||||
|
||||
; Function go through the object list and draw the background for areas that will need to draw
|
||||
; additional items on top
|
||||
_DrawShadowBkgnd
|
||||
ldx _SortedHead
|
||||
bmi :empty ; If there is nothing, do nothing
|
||||
|
||||
lda _Sprites+SPRITE_ID,x
|
||||
|
||||
|
||||
:empty
|
||||
rts
|
||||
|
||||
; Function to iterate through the object list and build a merged scanline list of areas of the screen that
|
||||
; need to be drawn with shadowing off.
|
||||
_BuildShadowList
|
||||
|
||||
ldy #0 ; This is the index into the list of shadow segments
|
||||
|
||||
ldx _SortedHead
|
||||
|
||||
:preloop
|
||||
bmi :empty ; If the list is empty / skipped, do nothing
|
||||
lda _Sprites+SPRITE_ID,x
|
||||
bit #SPRITE_HIDE ; Make sure we don't do extra work for hidden objects
|
||||
beq :insert
|
||||
lda _Sprites+SORTED_NEXT,x
|
||||
tax
|
||||
bra :preloop
|
||||
|
||||
; Start of loop
|
||||
:advance
|
||||
iny
|
||||
iny
|
||||
|
||||
:insert
|
||||
lda _Sprites+SPRITE_CLIP_TOP,x ; Load the sprite's top line
|
||||
sta _ShadowListTop,y ; Set the top entry of the list to the sprite top
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_BOTTOM,x ; Optimistically set the end of the segment to the bottom of this sprite
|
||||
inc ; Clip values are on the scanline, so add one to make it a proper interval
|
||||
|
||||
:replace
|
||||
sta _ShadowListBottom,y
|
||||
:skip
|
||||
lda _Sprites+SORTED_NEXT,x ; If there another sprite in the list?
|
||||
bmi :no_more_sprites ; If not, we can finish up
|
||||
|
||||
tax
|
||||
lda _Sprites+SPRITE_ID,x
|
||||
bit #SPRITE_HIDE
|
||||
bne :skip
|
||||
|
||||
lda _ShadowListBottom,y ; If the bottom of the current sprite is _less than_ the top of the next
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,x ; sprite, then there is a gap and we create a new entry
|
||||
bcc :advance
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_BOTTOM,x ; Get the bottom value of the next sprite.
|
||||
inc
|
||||
cmp _ShadowListBottom,y ; If it extends the segment then replace the value, otherwise skip
|
||||
bcc :skip
|
||||
bra :replace
|
||||
|
||||
:no_more_sprites
|
||||
iny ; Set the list count to N * 2
|
||||
iny
|
||||
:empty
|
||||
sty _ShadowListCount
|
||||
rts
|
||||
|
||||
; Iterate through the shadow list and call _BltRange on each
|
||||
_DrawShadowList
|
||||
ldx #0
|
||||
@ -882,12 +603,6 @@ _DrawDirectSprites
|
||||
;
|
||||
; We can't alter that actual sorted list of items, so we create a reduced list which allows items to be filtered and
|
||||
; to keep a simple, single-linked list
|
||||
isNotHidden mac
|
||||
bit #SPRITE_OVERLAY
|
||||
bne ]1
|
||||
bit #SPRITE_HIDE
|
||||
beq ]1
|
||||
|
||||
EOL equ $FFFF
|
||||
|
||||
|
||||
@ -1009,9 +724,6 @@ _DrawObjShadow
|
||||
;:empty
|
||||
; rts
|
||||
|
||||
; Walk the object list and call _BltRange for the sprite
|
||||
_DrawShadowRanges
|
||||
|
||||
|
||||
; Split
|
||||
;
|
||||
@ -1023,21 +735,21 @@ _DrawShadowRanges
|
||||
split
|
||||
:prev equ tmp15
|
||||
|
||||
lda ObjectList+OL_CLIP_BOTTOM,x ; If the next item is fully within the current one, split
|
||||
cmp ObjectList+OL_CLIP_BOTTOM,y
|
||||
lda ObjectList+OL_SPRITE_BOTTOM,x ; If the next item is fully within the current one, split
|
||||
cmp ObjectList+OL_SPRITE_BOTTOM,y
|
||||
bcc :do_split
|
||||
rts
|
||||
|
||||
:do_split
|
||||
sta ObjectList+OL_CLIP_TOP,y ; Set the top of the current item past the bottom of the next item
|
||||
sta ObjectList+OL_SPRITE_TOP,y ; Set the top of the current item past the bottom of the next item
|
||||
|
||||
:split_lp
|
||||
lda ObjectList+OL_NEXT,x ; search to find the spot in the linked list that we should
|
||||
bmi :insert_after ; move the fragment forward to
|
||||
stx :prev
|
||||
tax
|
||||
lda ObjectList+OL_CLIP_TOP,y
|
||||
cmp ObjectList+OL_CLIP_TOP,x
|
||||
lda ObjectList+OL_SPRITE_TOP,y
|
||||
cmp ObjectList+OL_SPRITE_TOP,x
|
||||
bcc :insert_before ; If the modified node's top value is <= the node we are inspecting,
|
||||
beq :insert_before ; then it can be inserted here
|
||||
bra :split_lp
|
||||
@ -1067,12 +779,6 @@ split
|
||||
plx
|
||||
rts
|
||||
|
||||
_BltRange2
|
||||
phx
|
||||
jsr _BltRange
|
||||
plx
|
||||
rts
|
||||
|
||||
_GetNextItem
|
||||
cpx #EOL ; early out if we're at the end of the list
|
||||
bne *+3
|
||||
@ -1107,14 +813,6 @@ DrawOverlayY
|
||||
plx
|
||||
rts
|
||||
|
||||
DrawOverlayX
|
||||
phx
|
||||
phy
|
||||
jsr _DrawOverlay
|
||||
ply
|
||||
plx
|
||||
rts
|
||||
|
||||
; A = top line
|
||||
; X = sprite record
|
||||
; Y = bottom line
|
||||
|
@ -729,11 +729,11 @@ _TSSetOverlay
|
||||
lda :top,s
|
||||
sta Overlays+OVERLAY_TOP,x
|
||||
lda :bottom,s
|
||||
dec
|
||||
; dec
|
||||
sta Overlays+OVERLAY_BOTTOM,x
|
||||
sec
|
||||
sbc :top,s
|
||||
inc
|
||||
; inc
|
||||
sta Overlays+OVERLAY_HEIGHT,x
|
||||
|
||||
lda :proc,s
|
||||
@ -759,11 +759,11 @@ _TSUpdateOverlay
|
||||
lda :top,s
|
||||
sta Overlays+OVERLAY_TOP
|
||||
lda :bottom,s
|
||||
dec
|
||||
; dec
|
||||
sta Overlays+OVERLAY_BOTTOM
|
||||
sec
|
||||
sbc :top,s
|
||||
inc
|
||||
; inc
|
||||
sta Overlays+OVERLAY_HEIGHT,x
|
||||
|
||||
lda :proc,s
|
||||
|
Loading…
x
Reference in New Issue
Block a user