From c533d846d7714f7de5ac7c53efabc9b86539f1c5 Mon Sep 17 00:00:00 2001 From: Lucas Scharenbroich Date: Wed, 8 Mar 2023 20:09:57 -0600 Subject: [PATCH] Be more cautious when manipulaitng the sorted list --- demos/tool/App.Main.s | 511 ++++++++++++------------------------------ src/Sprite.s | 61 +++-- 2 files changed, 193 insertions(+), 379 deletions(-) diff --git a/demos/tool/App.Main.s b/demos/tool/App.Main.s index 179db9e..f47311e 100644 --- a/demos/tool/App.Main.s +++ b/demos/tool/App.Main.s @@ -24,6 +24,8 @@ Selected equ 10 Flips equ 12 DTile equ 14 Tmp2 equ 16 +ScreenWidth equ 18 +ScreenHeight equ 20 ; Typical init phk @@ -32,32 +34,30 @@ Tmp2 equ 16 sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program _MTStartUp ; GTE requires the miscellaneous toolset to be running + lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER jsr GTEStartUp ; Load and install the GTE User Tool ; Initialize the graphics screen to a 256x160 playfield - pea #320 + pea #160 pea #200 _GTESetScreenMode ; Load a tileset + pea 0 + pea 120 pea #^TSZelda pea #TSZelda _GTELoadTileSet ; Set the palette - ldx #11*2 -:ploop - lda palette,x - stal $E19E00,x - dex - dex - bpl :ploop - bra sprt + pea $0000 + pea #^palette + pea #palette + _GTESetPalette -palette dw $0000,$08C1,$0C41,$0F93,$0777,$0FDA,$00A0,$0000,$0D20,$0FFF,$023E -sprt + jsr SetLimits ; Create stamps for the sprites we are going to use HERO_SPRITE equ SPRITE_16X16+1 @@ -68,23 +68,19 @@ HERO_SPRITE equ SPRITE_16X16+1 ; Create sprites stz Tmp0 - stz Tmp1 + stz Tmp1 ; Slot number ldx Tmp0 :sloop - pea HERO_SPRITE ; sprite id + pei Tmp1 ; Put the sprite in this slot + pea SPRITE_16X16 ; with these flags (h/v flip) + pea VBUFF_SPRITE_START lda PlayerX,x pha lda PlayerY,x pha - pei Tmp1 _GTEAddSprite - pei Tmp1 ; update the sprite in this slot - pea $0000 ; with these flags (h/v flip) - pea VBUFF_SPRITE_START ; and use this stamp - _GTEUpdateSprite - inc Tmp1 ldx Tmp0 inx @@ -95,70 +91,7 @@ HERO_SPRITE equ SPRITE_16X16+1 ; Manually fill in the 41x26 tiles of the TileStore with a test pattern of trees -; lda #TILE_DYN_BIT+TILE_PRIORITY_BIT+0 ; fill the screen the the dynamic tile slot 0 - lda #TILE_DYN_BIT+0 ; fill the screen the the dynamic tile slot 0 jsr _fillTileStore -; brl :no_trees - - ldx #0 - ldy #0 - jsr _drawTree - - ldx #3 - ldy #0 - jsr _drawTreeH - - ldx #0 - ldy #3 - jsr _drawTreeV - - ldx #3 - ldy #3 - jsr _drawTreeHV - - ldx #9 - ldy #0 - jsr _drawTree - - ldx #9 - ldy #3 - jsr _drawTree - - ldx #12 - ldy #0 - jsr _drawTree - - ldx #12 - ldy #3 - jsr _drawTree - - ldx #6 - ldy #0 - jsr _drawTreeFront - - ldx #6 - ldy #3 - jsr _drawTreeFront - - ldx #6 - ldy #6 - jsr _drawTreeFront - - ldx #3 - ldy #6 - jsr _drawTreeFront - - ldx #0 - ldy #6 - jsr _drawTreeFront -:no_trees -; Set up the dynamic tile - lda #65 - sta DTile - - pei DTile - pea $0000 - _GTECopyTileToDynamic ; Copy DTile into the first dynamic tile slot ; Initialize the frame counter @@ -166,9 +99,9 @@ HERO_SPRITE equ SPRITE_16X16+1 ; Set the screen coordinates - lda #128 + lda #0 sta ScreenX - lda #128 + lda #0 sta ScreenY stz Selected @@ -179,248 +112,58 @@ HERO_SPRITE equ SPRITE_16X16+1 pha ; space for result, with pattern _GTEReadControl pla - and #$00FF - cmp #'q' - bne :2 - brl :exit -:2 -; cmp KeyState -; beq :evt_loop -; sta KeyState -; cmp #0 -; beq :evt_loop -; cmp #' ' -; bne :evt_loop ; only advance one frame at a time -; brl :next - -:3 - cmp #'1' - bcc :3a - cmp #'9' - bcs :3a - sec - sbc #'1' - asl - sta Selected - brl :next - -:3a - cmp #'r' - bne :3b - lda Flips - clc - adc #SPRITE_HFLIP - and #SPRITE_VFLIP+SPRITE_HFLIP - sta Flips - - pei Selected ; update the sprite in this slot - pei Flips ; with these flags (h/v flip) - pea VBUFF_SPRITE_START ; and use this stamp - _GTEUpdateSprite - -:3b - cmp #'x' - bne :3d - ldx Selected - lda PlayerX,x - clc - adc PlayerU,x - sta PlayerX,x - - lda PlayerY,x - clc - adc PlayerV,x - sta PlayerY,x - brl :next -:3d - cmp #'z' - bne :3e - ldx Selected - lda PlayerX,x - sec - sbc PlayerU,x - sta PlayerX,x - - lda PlayerY,x - sec - sbc PlayerV,x - sta PlayerY,x - brl :next -:3e - cmp #'s' - bne :4 - ldx Selected - inc PlayerY,x - brl :next -:4 - cmp #'w' - bne :5 - ldx Selected - dec PlayerY,x - brl :next -:5 - cmp #'d' - bne :6 - ldx Selected - inc PlayerX,x - brl :next -:6 - cmp #'a' - bne :7 - ldx Selected - dec PlayerX,x - brl :next -:7 - cmp #$15 ; left = $08, right = $15, up = $0B, down = $0A - bne :8 - inc ScreenX - bra :next - -:8 cmp #$08 - bne :9 - dec ScreenX - brl :next - -:9 cmp #$0B - bne :10 - inc ScreenY - brl :next - -:10 cmp #$0A - bne :11 - dec ScreenY - brl :next - -:11 cmp #'y' - bne :12 - lda DTile - inc + jsr HandleKeys ; Do the generic key handlers + bcs :do_more + brl :do_render +:do_more and #$007F - sta DTile - pha - pea $0000 - _GTECopyTileToDynamic - brl :next - -:12 cmp #'f' - bne :13 - pea $0000 - _GTEFillTileStore - brl :next - -:13 cmp #'m' - bne :next - _GTERefresh - -:next -; inc ScreenX - + cmp #'a' + bne :skip_a + inc ScreenX pei ScreenX pei ScreenY _GTESetBG0Origin - -; brl no_animate - - stz Tmp0 - stz Tmp1 - - ldx Tmp0 -loopX - lda PlayerX,x - clc - adc PlayerU,x - sta PlayerX,x - bpl is_posx - cmp #-15 - bcs do_y - lda PlayerU,x - eor #$FFFF - inc - sta PlayerU,x - bra do_y -is_posx cmp #128 - bcc do_y - lda PlayerU,x - eor #$FFFF - inc - sta PlayerU,x - -do_y - lda PlayerY,x - clc - adc PlayerV,x - sta PlayerY,x - bpl is_posy - cmp #-15 - bcs do_z - lda PlayerV,x - eor #$FFFF - inc - sta PlayerV,x - bra do_z -is_posy cmp #160 - bcc do_z - lda PlayerV,x - eor #$FFFF - inc - sta PlayerV,x -do_z - inc Tmp1 - ldx Tmp0 - inx - inx - stx Tmp0 - cpx #MAX_SPRITES*2 - bcc loopX - -no_animate - stz Tmp0 - stz Tmp1 - ldx Tmp0 -loopY - pei Tmp1 - lda PlayerX,x + brl :do_render +:skip_a + cmp #'z' + bne :skip_z + inc PlayerX + pea 0 + lda PlayerX pha - lda PlayerY,x + lda PlayerY pha - _GTEMoveSprite - - inc Tmp1 - ldx Tmp0 - inx - inx - stx Tmp0 - cpx #MAX_SPRITES*2 - bcc loopY + _GTEMoveSprite +:skip_z + +:do_render + jsr _moveSprites + pea #RENDER_WITH_SHADOWING _GTERender - inc FrameCount -; Debug stuff +; Update the performance counters + + inc FrameCount pha _GTEGetSeconds pla cmp LastSecond beq :no_fps sta LastSecond - - lda FrameCount - ldx #0 - ldy #$FFFF - jsr DrawWord + +; lda FrameCount +; ldx #0 +; ldy #$FFFF +; jsr DrawWord stz FrameCount :no_fps - -; tdc -; ldx #160*32 -; jsr DrawWord - brl :evt_loop ; Shut down everything -:exit +Exit _GTEShutDown _QuitGS qtRec qtRec adrl $0000 @@ -432,56 +175,98 @@ PlayerY dw 72,24,13,56,35,72,23,8,93,123,134,87,143,14,46,65 PlayerU dw 1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4 PlayerV dw 1,1,1,1,2,2,2,4,3,3,3,3,4,4,4,4 -; Load the GTE User Tool and install it -GTEStartUp - pea $0000 - _LoaderStatus +_moveSprites + stz Tmp0 +:loop + ldx Tmp0 + + lda PlayerX,x + clc + adc PlayerU,x + sta PlayerX,x + + bpl :chk_xpos + eor #$FFFF + inc + sta PlayerX,x + bra :rev_x +:chk_xpos + cmp ScreenWidth + bcc :ok_x + sbc ScreenWidth + eor #$FFFF + inc + clc + adc ScreenWidth + sta PlayerX,x + +:rev_x + lda PlayerU,x ; reverse the velocity + eor #$FFFF + inc + sta PlayerU,x +:ok_x + + lda PlayerY,x + clc + adc PlayerV,x + sta PlayerY,x + bpl :chk_ypos + eor #$FFFF + inc + sta PlayerY,x + bra :rev_y +:chk_ypos + cmp ScreenHeight + bcc :ok_y + sbc ScreenHeight + eor #$FFFF + inc + clc + adc ScreenHeight + sta PlayerY,x + +:rev_y + lda PlayerV,x ; reverse the velocity + eor #$FFFF + inc + sta PlayerV,x + +:ok_y + txa + lsr + pha + lda PlayerX,x + pha + lda PlayerY,x + pha + _GTEMoveSprite + + lda Tmp0 + inc + inc + sta Tmp0 + cmp #2*MAX_SPRITES + bcc :loop + rts + +; Called by StartUp function callbacks when the screen size changes +SetLimits + pha ; Allocate space for x, y, width, height + pha + pha + pha + _GTEGetScreenInfo pla - - pea $0000 - pea $0000 - pea $0000 - pea $0000 - pea $0000 ; result space - - lda MyUserId - pha - - pea #^ToolPath - pea #ToolPath - pea $0001 ; do not load into special memory - _InitialLoad - bcc :ok1 - brk $01 - -:ok1 - ply - pla ; Address of the loaded tool - plx - ply - ply - - pea $8000 ; User toolset - pea $00A0 ; Set the tool set number - phx - pha ; Address of function pointer table - _SetTSPtr - bcc :ok2 - brk $02 - -:ok2 - clc ; Give GTE a page of direct page memory - tdc - adc #$0100 - pha - pea #ENGINE_MODE_DYN_TILES+ENGINE_MODE_TWO_LAYER ; Enable Dynamic Tiles and Two Layer - lda MyUserId ; Pass the userId for memory allocation - pha - _GTEStartUp - bcc :ok3 - brk $03 - -:ok3 + pla ; Discard screen corner + pla + sec + sbc #8 + sta ScreenWidth ; Pre-adjust to keep sprites on the visible playfield (for compiled sprites) + pla + sec + sbc #16 + sta ScreenHeight rts _fillTileStore @@ -490,25 +275,22 @@ _fillTileStore :oloop stz Tmp1 :iloop - pei Tmp1 - pei Tmp0 - pei Tmp2 - _GTESetTile - - lda Tmp2 - eor #TILE_PRIORITY_BIT - sta Tmp2 + ldx Tmp1 + ldy Tmp0 + jsr _drawTree lda Tmp1 inc + inc sta Tmp1 - cmp #41 + cmp #40 bcc :iloop lda Tmp0 inc + inc sta Tmp0 - cmp #26 + cmp #25 bcc :oloop rts @@ -646,9 +428,10 @@ _drawTreeHV rts MyUserId ds 2 -ToolPath str '1/Tool160' FrameCount ds 2 LastSecond dw 0 +palette dw $0000,$08C1,$0C41,$0F93,$0777,$0FDA,$00A0,$0000,$0D20,$0FFF,$023E,$0,$0,$0,$0,$0 + PUT ../kfest-2022/StartUp.s PUT App.Msg.s PUT font.s diff --git a/src/Sprite.s b/src/Sprite.s index 301b02e..478a344 100644 --- a/src/Sprite.s +++ b/src/Sprite.s @@ -411,7 +411,8 @@ _AddSprite jsr _PrecalcSpriteSize ; Cache sprite property values jsr _PrecalcSpriteBounds - jmp _InsertSprite ; Insert it into the sorted list + jsr _InsertSprite ; Insert it into the sorted list + jmp _Validate ; _SortSprite ; @@ -468,7 +469,7 @@ _SortSprite ; Into ; a <=> b and c <=> x <=> y <=> d :insert_before - jsr _OrphanNode + jsr _ReleaseNode tya sta _Sprites+SORTED_NEXT,x ; Link X to Y @@ -492,7 +493,7 @@ _SortSprite ; Into ; a <=> b and y <=> x -> nil :insert_end - jsr _OrphanNode + jsr _ReleaseNode lda #$FFFF sta _Sprites+SORTED_NEXT,x @@ -520,7 +521,7 @@ _SortSprite ; Into ; a <=> b and c <=> y <=> x <=> d :insert_after - jsr _OrphanNode + jsr _ReleaseNode tya sta _Sprites+SORTED_PREV,x ; c <=> y <-- x --- d @@ -544,7 +545,7 @@ _SortSprite ; Into ; a <=> b and head -> x <=> y :insert_front - jsr _OrphanNode + jsr _ReleaseNode stx _SortedHead txa @@ -557,16 +558,10 @@ _SortSprite :done rts -; Take the node pointed at X and remove it from the doubly-linked list. Assumes it is not -; at the beginning or end of the list -_OrphanNode +; Take the node pointed at X and remove it from the doubly-linked list. +_ReleaseNode phy - ldy _Sprites+SORTED_PREV,x ; Remove X from between A and B - lda _Sprites+SORTED_NEXT,x - sta _Sprites+SORTED_NEXT,y - tay - lda _Sprites+SORTED_PREV,x - sta _Sprites+SORTED_PREV,y + jsr _DeleteSprite ply rts @@ -663,7 +658,42 @@ _DeleteSprite sta _SortedHead rts +; Validate the integrity of the linked list +_Validate +:prev equ tmp0 +:curr equ tmp1 + ldy #$FFFF + ldx _SortedHead + bmi :done +:loop + sty :prev + stx :curr + + lda _Sprites+SORTED_PREV,x + cmp :prev + beq *+4 + brk $08 + + cpy #$FFFF + beq :skip + lda _Sprites+SORTED_NEXT,y + cmp :curr + beq *+4 + brk $06 + + lda _Sprites+SPRITE_CLIP_TOP,x + cmp _Sprites+SPRITE_CLIP_TOP,y + bcs *+4 + brk $0A +:skip + txy + lda _Sprites+SORTED_NEXT,x + tax + bpl :loop + +:done + rts ; Macro to make the unrolled loop more concise ; ; 1. Load the tile store address from a fixed offset @@ -1211,4 +1241,5 @@ _MoveSprite sta _Sprites+SPRITE_STATUS,x jsr _PrecalcSpriteBounds ; Can be specialized to only update (x,y) values - jmp _SortSprite ; Update the sprite's sorted position + jsr _SortSprite ; Update the sprite's sorted position + jmp _Validate