From e3cb742626d51d7904e535c12e65507c08d4d3c2 Mon Sep 17 00:00:00 2001 From: Lucas Scharenbroich Date: Tue, 10 Aug 2021 07:59:14 -0500 Subject: [PATCH] Fix tile rendering This is not quite correct yet. IT appears that two rows or columns are drawn on the edges when only a single solumn or row is necessary. Also, this code is based on the old GTE codebase, so the initial rectangle for rendering tiles is width+1, height+1. This can be improved. --- src/Actions.s | 37 +++-- src/App.Main.s | 345 +++++++++++++++++++-------------------- src/App.Msg.s | 5 +- src/Render.s | 19 +++ src/TileMap.s | 237 +++++++++++++++++---------- src/blitter/DirectPage.s | 127 +++++++------- src/blitter/Tiles.s | 7 + src/font.s | 2 + 8 files changed, 435 insertions(+), 344 deletions(-) diff --git a/src/Actions.s b/src/Actions.s index 0927da3..bed6f11 100644 --- a/src/Actions.s +++ b/src/Actions.s @@ -3,11 +3,11 @@ MoveLeft adc StartX ; Increment the virtual X-position jsr SetBG0XPos - lda StartX - lsr - jsr SetBG1XPos +; lda StartX +; lsr +; jsr SetBG1XPos - jsr DoFrame + jsr Render rts MoveRight @@ -19,11 +19,11 @@ MoveRight lda #0 jsr SetBG0XPos - lda StartX - lsr - jsr SetBG1XPos +; lda StartX +; lsr +; jsr SetBG1XPos - jsr DoFrame + jsr Render pla rts @@ -46,7 +46,7 @@ MoveUp ; lsr ; jsr SetBG1YPos - jsr DoFrame + jsr Render rts MoveDown @@ -58,11 +58,11 @@ MoveDown lda #0 jsr SetBG0YPos - lda StartY - lsr - jsr SetBG1YPos +; lda StartY +; lsr +; jsr SetBG1YPos - jsr DoFrame + jsr Render pla rts @@ -108,7 +108,7 @@ Demo ; jsr MoveLeft jsr UpdateBG1Rotation ; jsr DoColorCycle - jsr DoFrame + jsr Render inc frameCount @@ -190,7 +190,7 @@ AngleUp sbc #64 sta angle jsr _ApplyAngle - jsr DoFrame + jsr Render rts AngleDown @@ -201,7 +201,7 @@ AngleDown adc #64 sta angle jsr _ApplyAngle - jsr DoFrame + jsr Render rts angle dw 0 @@ -289,3 +289,8 @@ _DoTimers + + + + + diff --git a/src/App.Main.s b/src/App.Main.s index bb3f24e..e4ef4b2 100644 --- a/src/App.Main.s +++ b/src/App.Main.s @@ -26,7 +26,7 @@ SHADOW_REG equ $E0C035 STATE_REG equ $E0C068 NEW_VIDEO_REG equ $E0C029 -BORDER_REG equ $E0C034 ; 0-3 = border, 4-7 Text color +BORDER_REG equ $E0C034 ; 0-3 = border, 4-7 Text color VBL_VERT_REG equ $E0C02E VBL_HORZ_REG equ $E0C02F @@ -46,8 +46,8 @@ SHR_PALETTES equ $E19E00 tiledata ext ; Feature flags -NO_INTERRUPTS equ 1 ; turn off for crossrunner debugging -NO_MUSIC equ 1 ; turn music + tool loading off +NO_INTERRUPTS equ 1 ; turn off for crossrunner debugging +NO_MUSIC equ 1 ; turn music + tool loading off ; Typical init @@ -56,14 +56,14 @@ NO_MUSIC equ 1 ; turn music + tool loading ; Tool startup - _TLStartUp ; normal tool initialization + _TLStartUp ; normal tool initialization pha _MMStartUp - _Err ; should never happen + _Err ; should never happen pla - sta MasterId ; our master handle references the memory allocated to us - ora #$0100 ; set auxID = $01 (valid values $01-0f) - sta UserId ; any memory we request must use our own id + sta MasterId ; our master handle references the memory allocated to us + ora #$0100 ; set auxID = $01 (valid values $01-0f) + sta UserId ; any memory we request must use our own id _MTStartUp @@ -85,7 +85,7 @@ NO_MUSIC equ 1 ; turn music + tool loading pea #MusicFile _NTPLoadOneMusic - pea $0001 ; loop + pea $0001 ; loop _NTPPlayMusic :no_music @@ -97,37 +97,31 @@ NO_MUSIC equ 1 ; turn music + tool loading lda #NO_INTERRUPTS bne :no_interrupts PushLong #0 - pea $0015 ; Get the existing 1-second interrupt handler and save + pea $0015 ; Get the existing 1-second interrupt handler and save _GetVector PullLong OldOneSecVec - pea $0015 ; Set the new handler and enable interrupts + pea $0015 ; Set the new handler and enable interrupts PushLong #OneSecHandler _SetVector pea $0006 _IntSource - PushLong #VBLTASK ; Also register a Heart Beat Task + PushLong #VBLTASK ; Also register a Heart Beat Task _SetHeartBeat :no_interrupts ; Start up the graphics engine... - jsr MemInit ; Allocate memory - jsr BlitInit ; Initialize the memory - jsr GrafInit ; Initialize the graphics screen + jsr MemInit ; Allocate memory + jsr BlitInit ; Initialize the memory + jsr GrafInit ; Initialize the graphics screen - ldx #0 ; Gameboy Advance size + ldx #0 ; jsr SetScreenMode - lda #0 ; Set the virtual Y-position - jsr SetBG0YPos - - lda #0 ; Set the virtual X-position - jsr SetBG0XPos - - jsr _InitBG1 ; Initialize the second background + jsr _InitBG1 ; Initialize the second background lda #0 jsr _ClearBG1Buffer @@ -137,20 +131,20 @@ NO_MUSIC equ 1 ; turn music + tool loading ; Allocate room to load data - jsr AllocOneBank2 ; Alloc 64KB for Load/Unpack - sta BankLoad ; Store "Bank Pointer" + jsr AllocOneBank2 ; Alloc 64KB for Load/Unpack + sta BankLoad ; Store "Bank Pointer" - jsr MovePlayerToOrigin ; Put the player at the beginning of the map - lda #$FFFF ; Force a redraw of all the tiles - jsr _UpdateBG0TileMap + jsr MovePlayerToOrigin ; Put the player at the beginning of the map + lda #DIRTY_BIT_BG0_REFRESH ; Redraw all of the tiles on the next Render + tsb DirtyBits ; jsr DoTiles ; jsr DoLoadBG1 ; jsr Demo EvtLoop jsr ReadControl - and #$007F ; Ignore the buttons for now + and #$007F ; Ignore the buttons for now cmp #'q' bne :1 @@ -171,17 +165,17 @@ EvtLoop jsr DumpBanks bra EvtLoop -:3 cmp #'f' ; render a 'f'rame +:3 cmp #'f' ; render a 'f'rame bne :4 - jsr DoFrame + jsr Render bra EvtLoop -:4 cmp #'h' ; Show the 'h'eads up display +:4 cmp #'h' ; Show the 'h'eads up display bne :5 jsr DoHUP bra EvtLoop -:5 cmp #'1' ; User selects a new screen size +:5 cmp #'1' ; User selects a new screen size bcc :6 cmp #'9'+1 bcs :6 @@ -197,7 +191,7 @@ EvtLoop jsr DoTiles brl EvtLoop -:7 cmp #$15 ; left = $08, right = $15, up = $0B, down = $0A +:7 cmp #$15 ; left = $08, right = $15, up = $0B, down = $0A bne :8 lda #1 jsr MoveRight @@ -244,14 +238,14 @@ Exit lda #NO_INTERRUPTS bne :no_interrupts - pea $0007 ; disable 1-second interrupts + pea $0007 ; disable 1-second interrupts _IntSource - PushLong #VBLTASK ; Remove our heartbeat task + PushLong #VBLTASK ; Remove our heartbeat task _DelHeartBeat pea $0015 - PushLong OldOneSecVec ; Reset the interrupt vector + PushLong OldOneSecVec ; Reset the interrupt vector _SetVector :no_interrupts @@ -260,7 +254,7 @@ Exit _NTPShutDown :no_music - PushWord UserId ; Deallocate all of our memory + PushWord UserId ; Deallocate all of our memory _DisposeAll _QuitGS qtRec @@ -270,8 +264,9 @@ Fatal brk $00 ; Position the screen with the botom-left corner of the tilemap visible MovePlayerToOrigin - lda #0 ; Set the player's position + lda #0 ; Set the player's position jsr SetBG0XPos + lda TileMapHeight asl asl @@ -279,6 +274,7 @@ MovePlayerToOrigin sec sbc ScreenHeight jsr SetBG0YPos + rts ClearBankLoad @@ -321,7 +317,7 @@ SetScreenMode cpx #9 asl tax - lda #320 ; Calculate the screen offset + lda #320 ; Calculate the screen offset sec sbc: ]ScreenModeWidth,x lsr @@ -354,8 +350,8 @@ DoHUP ldx #{160-12*4} ldy #$7777 jsr DrawString - lda OneSecondCounter ; Number of elapsed seconds - ldx #{160-4*4} ; Render the word 4 charaters from right edge + lda OneSecondCounter ; Number of elapsed seconds + ldx #{160-4*4} ; Render the word 4 charaters from right edge jsr DrawWord lda #TicksStr @@ -376,7 +372,7 @@ DoTiles :column equ 3 :tile equ 5 - pea $0000 ; Allocate local variable space + pea $0000 ; Allocate local variable space pea $0000 pea $0000 @@ -410,18 +406,11 @@ DoTiles cmp #26 bcc :rowloop - pla ; restore the stack + pla ; restore the stack pla pla rts -; Set up the code field and render it -DoFrame - lda #$FFFF - sta DirtyBits - jsr Render ; Render the play field - rts - ; Load a binary file in the BG1 buffer DoLoadBG1 lda BankLoad @@ -450,7 +439,7 @@ DoLoadFG ldx #FGName jsr LoadFile - ldx BankLoad ; Copy it into the code field + ldx BankLoad ; Copy it into the code field lda #0 jsr CopyBinToField rts @@ -458,10 +447,10 @@ DoLoadFG ; Load a simple picture format onto the SHR screen DoLoadPic lda BankLoad - ldx #ImageName ; Load+Unpack Boot Picture - jsr LoadPicture ; X=Name, A=Bank to use for loading + ldx #ImageName ; Load+Unpack Boot Picture + jsr LoadPicture ; X=Name, A=Bank to use for loading - ldx BankLoad ; Copy it into the code field + ldx BankLoad ; Copy it into the code field lda #0 jsr CopyPicToField rts @@ -507,7 +496,7 @@ CopyBinToField stz :line_cnt :rloop - lda :line_cnt ; get the pointer to the code field line + lda :line_cnt ; get the pointer to the code field line asl tax @@ -516,78 +505,78 @@ CopyBinToField lda BTableHigh,x sta :dstptr+2 - ldx #162 ; move backwards in the code field - ldy #0 ; move forward in the image data + ldx #162 ; move backwards in the code field + ldy #0 ; move forward in the image data - lda #82 ; keep a running column count + lda #82 ; keep a running column count sta :col_cnt :cloop phy - lda [:srcptr],y ; load the picture data + lda [:srcptr],y ; load the picture data cmp :mask_color - beq :transparent ; a value of $0000 is transparent + beq :transparent ; a value of $0000 is transparent - jsr :toMask ; Infer a mask value for this. If it's $0000, then + jsr :toMask ; Infer a mask value for this. If it's $0000, then cmp #$0000 - bne :mixed ; the data is solid, otherwise mixed + bne :mixed ; the data is solid, otherwise mixed ; This is a solid word :solid lda [:srcptr],y - ldy Col2CodeOffset,x ; Get the offset to the code from the line start + ldy Col2CodeOffset,x ; Get the offset to the code from the line start - pha ; Save the data - lda #$00F4 ; PEA instruction + pha ; Save the data + lda #$00F4 ; PEA instruction sta [:dstptr],y iny pla - sta [:dstptr],y ; PEA operand + sta [:dstptr],y ; PEA operand bra :next :transparent - lda :mask_color ; Make sure we actually have to mask + lda :mask_color ; Make sure we actually have to mask cmp #$A5A5 beq :solid - ldy Col2CodeOffset,x ; Get the offset to the code from the line start - lda #$B1 ; LDA (dp),y + ldy Col2CodeOffset,x ; Get the offset to the code from the line start + lda #$B1 ; LDA (dp),y sta [:dstptr],y iny - lda 1,s ; load the saved Y-index - ora #$4800 ; put a PHA after the offset + lda 1,s ; load the saved Y-index + ora #$4800 ; put a PHA after the offset sta [:dstptr],y bra :next :mixed - sta :mask ; Save the mask - lda [:srcptr],y ; Refetch the screen data + sta :mask ; Save the mask + lda [:srcptr],y ; Refetch the screen data sta :data - ldy Col2CodeOffset,x ; Get the offset into the code field - lda #$4C ; JMP exception + ldy Col2CodeOffset,x ; Get the offset into the code field + lda #$4C ; JMP exception sta [:dstptr],y iny - lda JTableOffset,x ; Get the address offset and add to the base address + lda JTableOffset,x ; Get the address offset and add to the base address clc adc :dstptr sta [:dstptr],y - ldy JTableOffset,x ; This points to the code fragment - lda 1,s ; load the offset + ldy JTableOffset,x ; This points to the code fragment + lda 1,s ; load the offset xba ora #$00B1 - sta [:dstptr],y ; write the LDA (--),y instruction + sta [:dstptr],y ; write the LDA (--),y instruction iny iny - iny ; advance to the AND #imm operand + iny ; advance to the AND #imm operand lda :mask sta [:dstptr],y iny iny - iny ; advance to the ORA #imm operand + iny ; advance to the ORA #imm operand lda :mask - eor #$FFFF ; invert the mask to clear up the data + eor #$FFFF ; invert the mask to clear up the data and :data sta [:dstptr],y @@ -616,10 +605,10 @@ CopyBinToField :exit rts -:toMask pha ; save original +:toMask pha ; save original lda 1,s - eor :mask_color ; only identical bits produce zero + eor :mask_color ; only identical bits produce zero and #$F000 beq *+7 pea #$0000 @@ -661,7 +650,7 @@ CopyBinToField sta 1,s pla - sta 1,s ; pop the saved word + sta 1,s ; pop the saved word pla rts @@ -686,7 +675,7 @@ CopyPicToField stz :line_cnt :rloop - lda :line_cnt ; get the pointer to the code field line + lda :line_cnt ; get the pointer to the code field line asl tax @@ -695,70 +684,70 @@ CopyPicToField lda BTableHigh,x sta :dstptr+2 - ldx #162 ; move backwards in the code field - ldy #0 ; move forward in the image data + ldx #162 ; move backwards in the code field + ldy #0 ; move forward in the image data - lda #80 ; keep a running column count + lda #80 ; keep a running column count ; lda #82 ; keep a running column count sta :col_cnt :cloop phy - lda [:srcptr],y ; load the picture data - beq :transparent ; a value of $0000 is transparent + lda [:srcptr],y ; load the picture data + beq :transparent ; a value of $0000 is transparent - jsr :toMask ; Infer a mask value for this. If it's $0000, then - bne :mixed ; the data is solid, otherwise mixed + jsr :toMask ; Infer a mask value for this. If it's $0000, then + bne :mixed ; the data is solid, otherwise mixed ; This is a solid word lda [:srcptr],y - ldy Col2CodeOffset,x ; Get the offset to the code from the line start + ldy Col2CodeOffset,x ; Get the offset to the code from the line start - pha ; Save the data - lda #$00F4 ; PEA instruction + pha ; Save the data + lda #$00F4 ; PEA instruction sta [:dstptr],y iny pla - sta [:dstptr],y ; PEA operand + sta [:dstptr],y ; PEA operand bra :next :transparent - ldy Col2CodeOffset,x ; Get the offset to the code from the line start - lda #$B1 ; LDA (dp),y + ldy Col2CodeOffset,x ; Get the offset to the code from the line start + lda #$B1 ; LDA (dp),y sta [:dstptr],y iny - lda 1,s ; load the saved Y-index - ora #$4800 ; put a PHA after the offset + lda 1,s ; load the saved Y-index + ora #$4800 ; put a PHA after the offset sta [:dstptr],y bra :next :mixed - sta :mask ; Save the mask - lda [:srcptr],y ; Refetch the screen data + sta :mask ; Save the mask + lda [:srcptr],y ; Refetch the screen data sta :data - ldy Col2CodeOffset,x ; Get the offset into the code field - lda #$4C ; JMP exception + ldy Col2CodeOffset,x ; Get the offset into the code field + lda #$4C ; JMP exception sta [:dstptr],y iny - lda JTableOffset,x ; Get the address offset and add to the base address + lda JTableOffset,x ; Get the address offset and add to the base address clc adc :dstptr sta [:dstptr],y - ldy JTableOffset,x ; This points to the code fragment - lda 1,s ; load the offset + ldy JTableOffset,x ; This points to the code fragment + lda 1,s ; load the offset xba ora #$00B1 - sta [:dstptr],y ; write the LDA (--),y instruction + sta [:dstptr],y ; write the LDA (--),y instruction iny iny - iny ; advance to the AND #imm operand + iny ; advance to the AND #imm operand lda :mask sta [:dstptr],y iny iny - iny ; advance to the ORA #imm operand + iny ; advance to the ORA #imm operand lda :data sta [:dstptr],y @@ -828,9 +817,9 @@ CopyBinToBG1 sta :srcptr stx :srcptr+2 - sty :dstptr+2 ; Everything goes into this bank + sty :dstptr+2 ; Everything goes into this bank - ; Advance over the header + ; Advance over the header lda :srcptr clc adc #8 @@ -838,14 +827,14 @@ CopyBinToBG1 stz :line_cnt :rloop - lda :line_cnt ; get the pointer to the code field line + lda :line_cnt ; get the pointer to the code field line asl tax lda BG1YTable,x sta :dstptr - ldy #0 ; move forward in the image data and image data + ldy #0 ; move forward in the image data and image data :cloop lda [:srcptr],y sta [:dstptr],y @@ -856,17 +845,17 @@ CopyBinToBG1 cpy #164 bcc :cloop - lda [:srcptr] ; Duplicate the last byte in the extra space at the end of the line + lda [:srcptr] ; Duplicate the last byte in the extra space at the end of the line sta [:dstptr],y lda :srcptr clc - adc #164 ; Each line is 328 pixels + adc #164 ; Each line is 328 pixels sta :srcptr inc :line_cnt lda :line_cnt - cmp #208 ; A total of 208 lines + cmp #208 ; A total of 208 lines bcc :rloop rts @@ -898,7 +887,7 @@ OneSecHandler mx %11 sep #$20 ldal $E0C032 - and #%10111111 ;clear IRQ source + and #%10111111 ;clear IRQ source stal $E0C032 pla @@ -924,9 +913,13 @@ BlitInit stz ScreenTileHeight stz ScreenTileWidth stz StartX + stz OldStartX stz StartXMod164 + stz StartY + stz OldStartY stz StartYMod208 + stz EngineMode stz DirtyBits stz LastPatchOffset @@ -1017,26 +1010,26 @@ GetBorderColor lda #0000 rts ; Set the border color to the accumulator value. -SetBorderColor sep #$20 ; ACC = $X_Y, REG = $W_Z - eorl BORDER_REG ; ACC = $(X^Y)_(Y^Z) - and #$0F ; ACC = $0_(Y^Z) - eorl BORDER_REG ; ACC = $W_(Y^Z^Z) = $W_Y +SetBorderColor sep #$20 ; ACC = $X_Y, REG = $W_Z + eorl BORDER_REG ; ACC = $(X^Y)_(Y^Z) + and #$0F ; ACC = $0_(Y^Z) + eorl BORDER_REG ; ACC = $W_(Y^Z^Z) = $W_Y stal BORDER_REG rep #$20 rts ; Clear to SHR screen to a specific color -ClearToColor ldx #$7D00 ;start at top of pixel data! ($2000-9D00) +ClearToColor ldx #$7D00 ;start at top of pixel data! ($2000-9D00) :clearloop dex dex - stal SHR_SCREEN,x ;screen location - bne :clearloop ;loop until we've worked our way down to 0 + stal SHR_SCREEN,x ;screen location + bne :clearloop ;loop until we've worked our way down to 0 rts ; Set a palette values ; A = palette number, X = palette address SetPalette - and #$000F ; palette values are 0 - 15 and each palette is 32 bytes + and #$000F ; palette values are 0 - 15 and each palette is 32 bytes asl asl asl @@ -1054,7 +1047,7 @@ SetPalette rts ; Initialize the SCB -SetSCBs ldx #$0100 ;set all $100 scbs to A +SetSCBs ldx #$0100 ;set all $100 scbs to A :scbloop dex dex stal SHR_SCB,x @@ -1093,21 +1086,21 @@ GetVBL sep #$20 ldal VBL_HORZ_REG asl ldal VBL_VERT_REG - rol ; put V5 into carry bit, if needed. See TN #39 for details. + rol ; put V5 into carry bit, if needed. See TN #39 for details. rep #$20 and #$00FF rts WaitForVBL sep #$20 -:wait1 ldal VBL_STATE_REG ; If we are already in VBL, then wait +:wait1 ldal VBL_STATE_REG ; If we are already in VBL, then wait bmi :wait1 :wait2 ldal VBL_STATE_REG - bpl :wait2 ; spin until transition into VBL + bpl :wait2 ; spin until transition into VBL rep #$20 rts WaitForKey sep #$20 - stal KBD_STROBE_REG ; clear the strobe + stal KBD_STROBE_REG ; clear the strobe :WFK ldal KBD_REG bpl :WFK rep #$20 @@ -1120,9 +1113,9 @@ ClearKeyboardStrobe sep #$20 rts ReadControl - pea $0000 ; low byte = key code, high byte = %------AB + pea $0000 ; low byte = key code, high byte = %------AB - ldal OPTION_KEY_REG ; 'B' button + ldal OPTION_KEY_REG ; 'B' button and #$0080 beq :BNotDown @@ -1140,9 +1133,9 @@ ReadControl sta 1,s :ANotDown - ldal KBD_STROBE_REG ; read the keyboard + ldal KBD_STROBE_REG ; read the keyboard bit #$0080 - beq :KbdNotDwn ; check the key-down status + beq :KbdNotDwn ; check the key-down status and #$007f ora 1,s sta 1,s @@ -1154,43 +1147,43 @@ ReadControl ; Graphics helpers LoadPicture - jsr LoadFile ; X=Nom Image, A=Banc de chargement XX/00 + jsr LoadFile ; X=Nom Image, A=Banc de chargement XX/00 bcc :loadOK rts :loadOK - jsr UnpackPicture ; A=Packed Size + jsr UnpackPicture ; A=Packed Size rts -UnpackPicture sta UP_PackedSize ; Size of Packed Data - lda #$8000 ; Size of output Data Buffer +UnpackPicture sta UP_PackedSize ; Size of Packed Data + lda #$8000 ; Size of output Data Buffer sta UP_UnPackedSize - lda BankLoad ; Banc de chargement / Decompression - sta UP_Packed+1 ; Packed Data + lda BankLoad ; Banc de chargement / Decompression + sta UP_Packed+1 ; Packed Data clc adc #$0080 - stz UP_UnPacked ; On remet a zero car modifie par l'appel + stz UP_UnPacked ; On remet a zero car modifie par l'appel stz UP_UnPacked+2 - sta UP_UnPacked+1 ; Unpacked Data buffer + sta UP_UnPacked+1 ; Unpacked Data buffer - PushWord #0 ; Space for Result : Number of bytes unpacked - PushLong UP_Packed ; Pointer to buffer containing the packed data - PushWord UP_PackedSize ; Size of the Packed Data - PushLong #UP_UnPacked ; Pointer to Pointer to unpacked buffer - PushLong #UP_UnPackedSize ; Pointer to a Word containing size of unpacked data + PushWord #0 ; Space for Result : Number of bytes unpacked + PushLong UP_Packed ; Pointer to buffer containing the packed data + PushWord UP_PackedSize ; Size of the Packed Data + PushLong #UP_UnPacked ; Pointer to Pointer to unpacked buffer + PushLong #UP_UnPackedSize ; Pointer to a Word containing size of unpacked data _UnPackBytes - pla ; Number of byte unpacked + pla ; Number of byte unpacked rts -UP_Packed hex 00000000 ; Address of Packed Data -UP_PackedSize hex 0000 ; Size of Packed Data -UP_UnPacked hex 00000000 ; Address of Unpacked Data Buffer (modified) -UP_UnPackedSize hex 0000 ; Size of Unpacked Data Buffer (modified) +UP_Packed hex 00000000 ; Address of Packed Data +UP_PackedSize hex 0000 ; Size of Packed Data +UP_UnPacked hex 00000000 ; Address of Unpacked Data Buffer (modified) +UP_UnPackedSize hex 0000 ; Size of Unpacked Data Buffer (modified) ; Basic I/O function to load files LoadFile - stx openRec+4 ; X=File, A=Bank (high word) assumed zero for low + stx openRec+4 ; X=File, A=Bank (high word) assumed zero for low stz readRec+4 sta readRec+6 jsr ClearBankLoad @@ -1212,7 +1205,7 @@ LoadFile :closeFile _CloseGS closeRec clc - lda eofRec+4 ; File Size + lda eofRec+4 ; File Size rts :openReadErr jsr :closeFile @@ -1247,22 +1240,22 @@ FGName strl '1/fg1.bin' MasterId ds 2 UserId ds 2 -openRec dw 2 ; pCount - ds 2 ; refNum - adrl FGName ; pathname +openRec dw 2 ; pCount + ds 2 ; refNum + adrl FGName ; pathname -eofRec dw 2 ; pCount - ds 2 ; refNum - ds 4 ; eof +eofRec dw 2 ; pCount + ds 2 ; refNum + ds 4 ; eof -readRec dw 4 ; pCount - ds 2 ; refNum - ds 4 ; dataBuffer - ds 4 ; requestCount - ds 4 ; transferCount +readRec dw 4 ; pCount + ds 2 ; refNum + ds 4 ; dataBuffer + ds 4 ; requestCount + ds 4 ; transferCount -closeRec dw 1 ; pCount - ds 2 ; refNum +closeRec dw 1 ; pCount + ds 2 ; refNum qtRec adrl $0000 da $00 @@ -1272,6 +1265,7 @@ qtRec adrl $0000 put Actions.s put font.s put Render.s + put Overlay.s put blitter/Blitter.s put blitter/Horz.s put blitter/PEISlammer.s @@ -1291,17 +1285,6 @@ qtRec adrl $0000 - - - - - - - - - - - diff --git a/src/App.Msg.s b/src/App.Msg.s index 86d4f86..cd06771 100644 --- a/src/App.Msg.s +++ b/src/App.Msg.s @@ -43,11 +43,12 @@ Addr2ToString xba ; A=Value ; X=Screen offset DrawWord phx ; Save register value + phy ldy #WordBuff+1 jsr WordToString + ply plx lda #WordBuff - ldy #$7777 jsr DrawString rts @@ -145,6 +146,8 @@ Addr3Buff str '000000' ; str adds leading length byte + + diff --git a/src/Render.s b/src/Render.s index 4cec3a3..7eed5d5 100644 --- a/src/Render.s +++ b/src/Render.s @@ -93,6 +93,12 @@ Render ; ldy #8 ; jsr _PEISlam +; ldx #0 ; Blit the full virtual buffer to the screen +; ldy #16 +; jsr _BltRange + +; jsr Overlay + ldx #0 ; Blit the full virtual buffer to the screen ldy ScreenHeight jsr _BltRange @@ -101,6 +107,12 @@ Render ldx ScreenHeight jsr _RestoreBG0Opcodes + lda StartY + sta OldStartY + lda StartX + sta OldStartX + + stz DirtyBits rts @@ -112,3 +124,10 @@ Render + + + + + + + diff --git a/src/TileMap.s b/src/TileMap.s index 9af0425..e188dce 100644 --- a/src/TileMap.s +++ b/src/TileMap.s @@ -10,6 +10,17 @@ ; in actual games since the primary background is often large empty areas, or runs ; of repeating tiles. +; Debug locations +LastTop ds 2 +LastBottom ds 2 +LastLeft ds 2 +LastRight ds 2 + +; The ranges are [:Left, :Right] and [:Top, :Bottom], so :Right can be, at most, 40 +; if we are drawing all 41 tiles (Index 0 through 40). The :Bottom value can be +; at most 25. +MAX_TILE_X equ 40 +MAX_TILE_Y equ 25 ; _UpdateBG0TileMap ; @@ -23,13 +34,13 @@ _UpdateBG0TileMap :Top equ tmp2 :Bottom equ tmp3 -:Width equ tmp4 ; Used in DrawRectBG0 +:Width equ tmp4 ; Used in DrawRectBG0 :Height equ tmp5 -:MulA equ tmp6 ; Scratch space for multiplication +:MulA equ tmp6 ; Scratch space for multiplication :MulB equ tmp7 -:Offset equ tmp8 ; Address offset into the tilemap +:Offset equ tmp8 ; Address offset into the tilemap :Span equ tmp9 :GlobalTileIdxX equ tmp10 @@ -38,35 +49,24 @@ _UpdateBG0TileMap :BlkX equ tmp12 :BlkY equ tmp13 -:Refresh equ tmp14 - - cmp #$FFFF - lda #0 - rol - sta :Refresh ; 1 if A = $FFFF, 0 otherwise - - lda StartY ; calculate the tile index of the current location - and #$FFF8 + lda StartY ; calculate the tile index of the current location lsr lsr lsr sta BG0TileOriginY lda OldStartY - and #$FFF8 lsr lsr lsr sta OldBG0TileOriginY lda StartX - and #$FFFC lsr lsr sta BG0TileOriginX lda OldStartX - and #$FFFC lsr lsr sta OldBG0TileOriginX @@ -91,48 +91,48 @@ _UpdateBG0TileMap ; | | ; +--- Left Right --+ - stz :Left ; prepare to do the entire screen - lda ScreenTileWidth ; and then whack off the parts - sta :Right ; that are not needed - lda StartX - and #$0003 ; If not tile-aligned, then we need to draw one extra column - beq *+2 - inc :Right + stz :Left ; prepare to do the entire screen + lda ScreenTileWidth ; and then whack off the parts + sta :Right ; that are not needed - stz :Top - lda ScreenTileHeight - sta :Bottom - and #$0007 - beq *+2 - inc :Bottom + stz :Top ; since the ranges are inclusive, we are + lda ScreenTileHeight ; always going to be drawing width+1 tiles + sta :Bottom ; which takes care of edge tiles. ; If we are supposed to refresh the whole field, just do that and return - lda :Refresh + + lda #DIRTY_BIT_BG0_REFRESH + bit DirtyBits beq :NoRefresh - jmp :DrawRectBG0 ; Let the DrawRectBG0 RTS take care of the return for us + trb DirtyBits ; Clear the dirty bit +:FullScreen jmp :DrawRectBG0 ; Let the DrawRectBG0 RTS take care of the return for us :NoRefresh lda BG0TileOriginY cmp OldBG0TileOriginY - beq :NoYUpdate ; if equal, don't change Y + beq :NoYUpdate ; if equal, don't change Y sec - sbc OldBG0TileOriginY ; find the difference; D = Y_new - Y_old - bpl :DoBottom ; if we scrolled up, fill in the bottom row(s) + sbc OldBG0TileOriginY ; find the difference; D = Y_new - Y_old + bpl :DoBottom ; if we scrolled up, fill in the bottom row(s) - eor #$FFFF ; if we scrolled down, Y_new < Y_old and we need - sta :Bottom ; to fill in the top row(s) from 0 to Y_new - Y_old - 1 + eor #$FFFF ; if we scrolled down, Y_new < Y_old and we need + cmp :Bottom ; to fill in the top row(s) from 0 to Y_new - Y_old - 1 + bcs :FullScreen ; If the displacement was very large, just fill in the whole screen + + sta :Bottom bra :DoYUpdate :DoBottom - eor #$FFFF ; same explanation as above, except we are filling in from - inc a ; Bottom - (Y_new - Y_old) to Bottom + eor #$FFFF ; same explanation as above, except we are filling in from + inc ; Bottom - (Y_new - Y_old) to Bottom clc adc ScreenTileHeight + bmi :FullScreen sta :Top :DoYUpdate - jsr :DrawRectBG0 ; Fill in the rectangle. + jsr :DrawRectBG0 ; Fill in the rectangle. ; We performed an update in the Y-direction, so now change the bounds so ; an update in the X-direction will not draw too many rows @@ -155,14 +155,14 @@ _UpdateBG0TileMap lda :Top beq :drewTop - dec a ; already did Y to HEIGHT, so only need to draw from - sta :Bottom ; 0 to (Y-1) for any horizontal updates + dec ; already did Y to HEIGHT, so only need to draw from + sta :Bottom ; 0 to (Y-1) for any horizontal updates stz :Top bra :NoYUpdate :drewTop - lda :Bottom ; opposite, did 0 to Y - inc a ; so do Y+1 to HEIGHT + lda :Bottom ; opposite, did 0 to Y + inc ; so do Y+1 to HEIGHT sta :Top lda ScreenTileHeight sta :Bottom @@ -186,17 +186,19 @@ _UpdateBG0TileMap ; The Top an Bottom are set the the correct values to draw in whatever potential range of tiles ; need to be draws if there was any horizontal displacement :NoYUpdate - lda BG0TileOriginX ; Did the first column of the tile map change from before? - cmp OldBG0TileOriginX ; Did it change from before? - beq :NoXUpdate ; no, so we can ignore this + lda BG0TileOriginX ; Did the first column of the tile map change from before? + cmp OldBG0TileOriginX ; Did it change from before? + beq :NoXUpdate ; no, so we can ignore this sec - sbc OldBG0TileOriginX ; find the difference - bpl :DoRightSide ; did we move in a pos or neg? + sbc OldBG0TileOriginX ; find the difference + bpl :DoRightSide ; did we move in a pos or neg? ; Handle the two sides in an analagous way as the vertical code eor #$FFFF + cmp :Right + bcs :FullScreen sta :Right bra :DoXUpdate @@ -205,33 +207,41 @@ _UpdateBG0TileMap inc clc adc ScreenTileWidth + bmi :FullScreen sta :Left :DoXUpdate - jsr :DrawRectBG0 ; Fill in the rectangle. + jsr :DrawRectBG0 ; Fill in the rectangle. :NoXUpdate rts +;:Debug +; lda :Top ; Debugging +; sta LastTop +; lda :Bottom +; sta LastBottom +; lda :Left +; sta LastLeft +; lda :Right +; sta LastRight +; rts + ; This is a private subroutine that draws in tiles into the code fields using the ; data from the tilemap and the local :Top, :Left, :Bottom and :Right parameters. -; -; The ranges are [:Left, :Right) and [:Top, :Bottom), so :Right can be, at most, 41 -; if we are drawing all 41 tiles (Index 0 through 40). The :Bottom value can be -; at most 26. -MAX_TILE_X equ 40 -MAX_TILE_Y equ 25 :DrawRectBG0 lda :Bottom sec sbc :Top - sta :Height ; Maximum value of 25 + inc + sta :Height ; Maximum value of 26 (top = 0, bottom = 25) lda :Right sec sbc :Left - sta :Width ; Maximum value of 40 + inc + sta :Width ; Maximum value of 41 (left = 0, right = 40) ; Compute the offset into the tile array of the top-left corner @@ -242,57 +252,63 @@ MAX_TILE_Y equ 25 lda :Top clc - adc BG0TileOriginY ; This is the global verical index + adc BG0TileOriginY ; This is the global verical index sta :GlobalTileIdxY ldx TileMapWidth jsr :MulAX clc adc :GlobalTileIdxX - asl ; Double for word sizes - sta :Offset ; Stash the pointer offset in Y + asl ; Double for word sizes + sta :Offset ; Stash the pointer offset in Y +; Draw the tiles lda TileMapWidth sec sbc :Width - asl ; This is the number of bytes to move the Offset to advance from the end of - sta :Span ; one line to the beginning of the next + asl ; This is the number of bytes to move the Offset to advance from the end of + sta :Span ; one line to the beginning of the next ; Now we need to figure out the code field tile coordinate of corner of ; play field. That is, becuase the screen is scrolling, the location of ; tile (0, 0) could be anywhere within the code field - lda StartYMod208 ; This is the code field line that is at the top of the screen - and #$FFF8 ; Clamp to the nearest block + lda StartYMod208 ; This is the code field line that is at the top of the screen + and #$FFF8 ; Clamp to the nearest block lsr lsr - lsr ; Could optimize because the Tile code shifts back.... + lsr ; Could optimize because the Tile code shifts back.... clc adc :Top - sta :BlkY ; This is the Y-block we start drawing from + cmp #MAX_TILE_Y+1 ; Top can be less than or equal to 25 + bcc *+5 + sbc #MAX_TILE_Y+1 + sta :BlkY ; This is the Y-block we start drawing from - lda StartXMod164 ; Dx the same thing for X, except only need to clamp by 4 + lda StartXMod164 ; Dx the same thing for X, except only need to clamp by 4 and #$FFFC lsr lsr clc adc :Left + cmp #MAX_TILE_X+1 ; Left can be less than or equal to 40 + bcc *+5 + sbc #MAX_TILE_X+1 sta :BlkX - ; Call the copy tile routine to blit the tile data into the playfield ; ; A = Tile ID (0 - 1023) ; X = Tile column (0 - 40) ; Y = Tile row (0 - 25) - pei :BlkX ; cache the starting X-block index to restore later - pei :Width ; cache the Width value to restore later + pei :BlkX ; cache the starting X-block index to restore later + pei :Width ; cache the Width value to restore later :yloop :xloop - ldy :Offset ; Set up the arguments and call the tile blitter + ldy :Offset ; Set up the arguments and call the tile blitter lda [TileMapPtr],y - iny ; pre-increment the address. A bit faster than two "INC DP" instructions + iny ; pre-increment the address. A bit faster than two "INC DP" instructions iny sty :Offset @@ -302,46 +318,45 @@ MAX_TILE_Y equ 25 lda :BlkX inc - cmp #MAX_TILE_X+1 ; If we go past the physical block index, wrap around + cmp #MAX_TILE_X+1 ; If we go past the maximum block index, wrap around bcc *+5 lda #0 sta :BlkX - dec :Width ; Decrement out count + dec :Width ; Decrement out count bne :xloop - lda :Offset ; Move to the next line of the Tile Map + lda :Offset ; Move to the next line of the Tile Map clc adc :Span sta :Offset - lda 3,s ; Reset the BlkX + lda 3,s ; Reset the BlkX sta :BlkX - lda 1,s ; Reset the width + lda 1,s ; Reset the width sta :Width - lda :BlkY ; The y lookup has a double0length array, may not need the bounds check + lda :BlkY ; The y lookup has a double-length array, may not need the bounds check inc cmp #MAX_TILE_Y+1 bcc *+5 lda #0 sta :BlkY - dec :Height ; Have we done all of the rows? + dec :Height ; Have we done all of the rows? bne :yloop - pla ; Pop off cached values + pla ; Pop off cached values pla rts - ; Quick multiplication of the accumulator and x-register ; A = A * X :MulAX stx :MulA - cmp :MulA ; Put the smaller value in MulA (less shifts on average) + cmp :MulA ; Put the smaller value in MulA (less shifts on average) bcc :swap sta :MulB bra :entry @@ -357,13 +372,13 @@ MAX_TILE_Y equ 25 ; branch on the inner loop :loop - lsr :MulA ; shift out the LSB - bcc :skip ; zero is no multiply + lsr :MulA ; shift out the LSB + bcc :skip ; zero is no multiply clc adc :MulB :skip - asl :MulB ; double the multplicand + asl :MulB ; double the multplicand ldx :MulA bne :loop @@ -388,6 +403,60 @@ MAX_TILE_Y equ 25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/blitter/DirectPage.s b/src/blitter/DirectPage.s index 04306ed..2506c53 100644 --- a/src/blitter/DirectPage.s +++ b/src/blitter/DirectPage.s @@ -1,81 +1,84 @@ ; Direct page locations used by the engine -ScreenHeight equ 0 ; Height of the playfield in scan lines -ScreenWidth equ 2 ; Width of the playfield in bytes -ScreenY0 equ 4 ; First vertical line on the physical screen of the playfield -ScreenY1 equ 6 ; End of playfield on the physical screen. If the height is 20 and Y0 is -ScreenX0 equ 8 ; 100, then ScreenY1 = 120. -ScreenX1 equ 10 -ScreenTileHeight equ 12 ; Height of the playfield in 8x8 blocks -ScreenTileWidth equ 14 ; Width of the playfield in 8x8 blocks +ScreenHeight equ 0 ; Height of the playfield in scan lines +ScreenWidth equ 2 ; Width of the playfield in bytes +ScreenY0 equ 4 ; First vertical line on the physical screen of the playfield +ScreenY1 equ 6 ; End of playfield on the physical screen. If the height is 20 and Y0 is +ScreenX0 equ 8 ; 100, then ScreenY1 = 120. +ScreenX1 equ 10 +ScreenTileHeight equ 12 ; Height of the playfield in 8x8 blocks +ScreenTileWidth equ 14 ; Width of the playfield in 8x8 blocks -StartX equ 16 ; Which code buffer byte is the left edge of the screen. Range = 0 to 167 -StartY equ 18 ; Which code buffer line is the top of the screen. Range = 0 to 207 -EngineMode equ 20 ; Defined the mode/capabilities that are enabled - ; bit 0: 0 = Single Background, 1 = Parallax -DirtyBits equ 22 ; Identify values that have changed between frames +StartX equ 16 ; Which code buffer byte is the left edge of the screen. Range = 0 to 167 +StartY equ 18 ; Which code buffer line is the top of the screen. Range = 0 to 207 +EngineMode equ 20 ; Defined the mode/capabilities that are enabled + ; bit 0: 0 = Single Background, 1 = Parallax +DirtyBits equ 22 ; Identify values that have changed between frames -BG1DataBank equ 24 ; Data bank that holds BG1 layer data -BG1AltBank equ 26 ; Alternate BG1 bank +BG1DataBank equ 24 ; Data bank that holds BG1 layer data +BG1AltBank equ 26 ; Alternate BG1 bank -BlitterDP equ 28 ; Direct page address the holder blitter data +BlitterDP equ 28 ; Direct page address the holder blitter data -OldStartX equ 30 -OldStartY equ 32 +OldStartX equ 30 +OldStartY equ 32 -LastPatchOffset equ 34 ; Offset into code field that was patched with BRA instructions -StartXMod164 equ 36 -StartYMod208 equ 38 +LastPatchOffset equ 34 ; Offset into code field that was patched with BRA instructions +StartXMod164 equ 36 +StartYMod208 equ 38 -BG1StartX equ 40 ; Logical offset of the second background -BG1StartXMod164 equ 42 +BG1StartX equ 40 ; Logical offset of the second background +BG1StartXMod164 equ 42 -BG1StartY equ 44 -BG1StartYMod208 equ 46 +BG1StartY equ 44 +BG1StartYMod208 equ 46 -OldBG1StartX equ 48 -OldBG1StartY equ 50 +OldBG1StartX equ 48 +OldBG1StartY equ 50 -BG1OffsetIndex equ 52 +BG1OffsetIndex equ 52 -BG0TileOriginX equ 54 ; Coordinate in the tile map that corresponds to the top-left corner -BG0TileOriginY equ 56 -OldBG0TileOriginX equ 58 -OldBG0TileOriginY equ 60 +BG0TileOriginX equ 54 ; Coordinate in the tile map that corresponds to the top-left corner +BG0TileOriginY equ 56 +OldBG0TileOriginX equ 58 +OldBG0TileOriginY equ 60 -BG1TileOriginX equ 62 ; Coordinate in the tile map that corresponds to the top-left corner -BG1TileOriginY equ 64 -OldBG1TileOriginX equ 66 -OldBG1TileOriginY equ 68 +BG1TileOriginX equ 62 ; Coordinate in the tile map that corresponds to the top-left corner +BG1TileOriginY equ 64 +OldBG1TileOriginX equ 66 +OldBG1TileOriginY equ 68 -TileMapWidth equ 70 -TileMapHeight equ 72 -TileMapPtr equ 74 +TileMapWidth equ 70 +TileMapHeight equ 72 +TileMapPtr equ 74 -Next equ 78 +Next equ 78 -BankLoad equ 128 +BankLoad equ 128 -blttmp equ 192 ; 32 bytes of local cache/scratch space +blttmp equ 192 ; 32 bytes of local cache/scratch space -tmp8 equ 224 -tmp9 equ 226 -tmp10 equ 228 -tmp11 equ 230 -tmp12 equ 232 -tmp13 equ 234 -tmp14 equ 236 -tmp15 equ 238 +tmp8 equ 224 +tmp9 equ 226 +tmp10 equ 228 +tmp11 equ 230 +tmp12 equ 232 +tmp13 equ 234 +tmp14 equ 236 +tmp15 equ 238 -tmp0 equ 240 ; 16 bytes of temporary space to be used as scratch -tmp1 equ 242 -tmp2 equ 244 -tmp3 equ 246 -tmp4 equ 248 -tmp5 equ 250 -tmp6 equ 252 -tmp7 equ 254 +tmp0 equ 240 ; 16 bytes of temporary space to be used as scratch +tmp1 equ 242 +tmp2 equ 244 +tmp3 equ 246 +tmp4 equ 248 +tmp5 equ 250 +tmp6 equ 252 +tmp7 equ 254 + +DIRTY_BIT_BG0_X equ $0001 +DIRTY_BIT_BG0_Y equ $0002 +DIRTY_BIT_BG1_X equ $0004 +DIRTY_BIT_BG1_Y equ $0008 +DIRTY_BIT_BG0_REFRESH equ $0010 +DIRTY_BIT_BG1_REFRESH equ $0020 -DIRTY_BIT_BG0_X equ $0001 -DIRTY_BIT_BG0_Y equ $0002 -DIRTY_BIT_BG1_X equ $0004 -DIRTY_BIT_BG1_Y equ $0008 diff --git a/src/blitter/Tiles.s b/src/blitter/Tiles.s index 695ae5b..041a724 100644 --- a/src/blitter/Tiles.s +++ b/src/blitter/Tiles.s @@ -42,6 +42,7 @@ CopyTile asl ; asl will clear the carry bit tax lda Col2CodeOffset,x + clc adc BTableLow,y tay @@ -239,3 +240,9 @@ CopyTile + + + + + + diff --git a/src/font.s b/src/font.s index 1833c74..8c71e10 100644 --- a/src/font.s +++ b/src/font.s @@ -37,6 +37,7 @@ DrawString NextChar lda ]F_CharIdx cmp ]F_Length bne :notDone + ldy ]F_StrClr ;restore the color pattern pld pla pla @@ -662,5 +663,6 @@ s_Template hex 00000000 +