diff --git a/.gitignore b/.gitignore index 57794ad..0829c50 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /gscats.lst /GSCats.xcodeproj/xcuserdata/qd.xcuserdatad/xcdebugger /loader.lst +/terrain_e1.lst diff --git a/GSCats.xcodeproj/project.pbxproj b/GSCats.xcodeproj/project.pbxproj index 099a370..875780a 100644 --- a/GSCats.xcodeproj/project.pbxproj +++ b/GSCats.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 700F21E01F4A3A5500D7007D /* GenerateTrigTables.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateTrigTables.py; sourceTree = ""; }; 700FFAFB1F40F3BF00A442DE /* font.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = font.s; sourceTree = ""; }; 7059502B1F37A0BE00BBE90F /* GenerateVRAMTable.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateVRAMTable.py; sourceTree = ""; }; + 705AAFA920040B0D001BB0ED /* terrain_e1.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = terrain_e1.s; sourceTree = ""; }; 706DF1641F2D39F700AA6680 /* loader.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = loader.s; sourceTree = ""; }; 706DF1651F2D4A8100AA6680 /* terrain.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = terrain.s; sourceTree = ""; }; 7088096D1F2ECE8D00D4C950 /* GenerateRenderSpans.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateRenderSpans.py; sourceTree = ""; }; @@ -20,6 +21,8 @@ 7099E3841F41022100182A82 /* gameobject.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gameobject.s; sourceTree = ""; }; 7099E3851F4107B100182A82 /* GenerateVRAMYOffset.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateVRAMYOffset.py; sourceTree = ""; }; 70A80FB01F43D7F200BD34C9 /* gamemanager.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gamemanager.s; sourceTree = ""; }; + 70BDCBC92006AD5F00CB51F1 /* linkerConfig */ = {isa = PBXFileReference; lastKnownFileType = text; path = linkerConfig; sourceTree = ""; }; + 70BDCBCA200A99F200CB51F1 /* ParseMapFile.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = ParseMapFile.py; sourceTree = ""; }; 70C073091F5BAA3E009844A9 /* collision.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = collision.s; sourceTree = ""; }; 70E266E31F6F262D005AC7E4 /* circleTable.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = circleTable.s; sourceTree = ""; }; 70E554C41F807ADB00F3C871 /* spritebank.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = spritebank.s; sourceTree = ""; }; @@ -45,6 +48,7 @@ 706DF1641F2D39F700AA6680 /* loader.s */, 700FFAFB1F40F3BF00A442DE /* font.s */, 706DF1651F2D4A8100AA6680 /* terrain.s */, + 705AAFA920040B0D001BB0ED /* terrain_e1.s */, 70C073091F5BAA3E009844A9 /* collision.s */, 70F086A01F4230CB002446C3 /* utility.s */, 700C39C51F2E5CA800C24F9C /* tables.s */, @@ -55,12 +59,14 @@ 70E554C41F807ADB00F3C871 /* spritebank.s */, 70E9D8611F2BD95400555C19 /* gscats.s */, 70E9D8631F2BD95400555C19 /* Makefile */, + 70BDCBC92006AD5F00CB51F1 /* linkerConfig */, 70FE79D21F8814A600E0095C /* MerlinToCA65.sh */, 7088096D1F2ECE8D00D4C950 /* GenerateRenderSpans.py */, 7059502B1F37A0BE00BBE90F /* GenerateVRAMTable.py */, 7099E3851F4107B100182A82 /* GenerateVRAMYOffset.py */, 700F21E01F4A3A5500D7007D /* GenerateTrigTables.py */, 709175C01F60D263008FAFAB /* GenerateCircles.py */, + 70BDCBCA200A99F200CB51F1 /* ParseMapFile.py */, ); sourceTree = ""; }; diff --git a/Makefile b/Makefile index 2b99679..fdc23eb 100644 --- a/Makefile +++ b/Makefile @@ -18,18 +18,21 @@ MRSPRITE=../MrSprite/mrsprite CHROMA=00ff00 PALETTE=a4dffb 008800 886611 cc9933 eebb44 dd6666 ff99aa 000000 0e7db1 ffff00 ffff00 ffff00 ffff00 ffff00 ffff00 ffffff SPRITES=SpriteBank +REMOTESYMBOLS=-Wl $(shell ./ParseMapFile.py *.map) -all: $(PGM) loader +all: terrain_e1 $(PGM) loader $(PGM): - @PATH=$(PATH):/usr/local/bin; $(CL65) -t apple2enh --cpu 65816 --start-addr 0000 -l$(PGM).lst $(PGM).s + @echo $(REMOTESYMBOLS) + @PATH=$(PATH):/usr/local/bin; $(CL65) -t apple2enh -C linkerConfig --cpu 65816 --start-addr 0000 -l$(PGM).lst $(REMOTESYMBOLS) $(PGM).s java -jar $(AC) -d $(PGM).2mg CODEBANK java -jar $(AC) -p $(PGM).2mg CODEBANK BIN 0x0000 < $(PGM) java -jar $(AC) -d $(PGM).2mg $(SPRITES)00 java -jar $(AC) -p $(PGM).2mg $(SPRITES)00 BIN 0x0000 < $(SPRITES)00.bin rm -f $(PGM) rm -f $(PGM).o + rm -f terrain_e1.map osascript V2Make.scpt $(PROJECT_DIR) $(PGM) loader: @@ -39,11 +42,21 @@ loader: rm -f loader rm -f loader.o +terrain_e1: + @PATH=$(PATH):/usr/local/bin; $(CL65) -t apple2enh -C linkerConfig --cpu 65816 --start-addr $(ADDR) -l -vm -m terrain_e1.map terrain_e1.s + java -jar $(AC) -d $(PGM).2mg CODEBANKE1 + java -jar $(AC) -p $(PGM).2mg CODEBANKE1 BIN 0x800 < terrain_e1 + rm -f terrain_e1 + rm -f terrain_e1.o + clean: rm -f $(PGM) rm -f $(PGM).o rm -f loader rm -f loader.o + rm -f terrain_e1.o + rm -f terrain_e1.map + rm -f terrain_e1 .PHONY: art art: diff --git a/ParseMapFile.py b/ParseMapFile.py new file mode 100755 index 0000000..b9ed593 --- /dev/null +++ b/ParseMapFile.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# Outputs a list of exported symbols found in an ld65 link map file +# suitable for passing as a commandline option to define those +# same symbols in a cl65 compile/assemble operation. This allows +# sharing symbols between code banks without having to actually +# link them together. Sort of a low-budget DLL mechanism. :) + +import sys + + +def parseInputFile(filename,bank): + + inputFile = open(filename) + contents = inputFile.readlines() + output = "" + + # Find exported symbols + lineNum = 0 + for line in contents: + if line.find("Exports list") != -1: + break + lineNum+=1 + + # Found the exports table, so look for our symbol names + first=1 + for line in contents[lineNum+1:]: + if line.startswith("_") or line.startswith("-"): + continue + if line.startswith("Imports") or len(line)<2: + break + + if first!=1: + output += "," + first = 0 + + columns = line.split() + if len(columns) > 3: + output += ("-D,%s=0x%s,-D,%s=0x%s" % (columns[0],bank+columns[1][2:],columns[3],bank+columns[4][2:])) + else: + output += ("-D,%s=0x%s" % (columns[0],bank+columns[1][2:])) + + inputFile.close() + return output + + +def main(argv): + commandline = "" + first=1 + + for file in argv: + + if first!=1: + commandline += "," + first = 0 + + bank = file[-6:-4] # Assumes filename_XX.map + commandline += parseInputFile(file,bank) + + print (commandline) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/collision.s b/collision.s index 5ae9c71..91c0249 100644 --- a/collision.s +++ b/collision.s @@ -50,7 +50,7 @@ intersectRectTerrain: ; Check Y bottom intersectRectTerrainBottomLoop: - lda terrainData,y + lda terrainDataFar,y cmp rectParams+6 bpl intersectRectTerrainYep dey diff --git a/equates.s b/equates.s index a6e9dc1..8f7b9ae 100644 --- a/equates.s +++ b/equates.s @@ -28,6 +28,26 @@ SCRATCHL2 = $67 ; Second 16-bit scratch PARAM24 = $67 ; 24-bit param (This is almost certainly messing up AppleSoft, but meh) CACHEPTR = $6A ; General purpose cache pointer (This is almost certainly messing up AppleSoft, but meh) CACHEDATA = $6C ; General purpose cache data (This is almost certainly messing up AppleSoft, but meh) +leftScreenEdge = $6E ; Reserved for leftScreenEdge (This is almost certainly messing up AppleSoft, but meh) STACKPTR = $70 ; Cache for stack pointer in fast graphics SHADOWREGISTER = $72 ; Cache for shadow register in fast graphics STACKREGISTER = $73 ; Cache for stack register in fast graphics + + +; Terrain constants +TERRAINWIDTH = 640 ; In pixels +MAXTERRAINHEIGHT = 100 ; In pixels +COMPILEDTERRAINROW = TERRAINWIDTH/4+3 ; In words, +2 to make room for clipping jump at end of row +VISIBLETERRAINWIDTH = TERRAINWIDTH/4 ; In words- width minus jump return padding +VISIBLETERRAINWINDOW = 80 ; In words +MAXSPANSPERROW = 15 +SPANROWBYTES = MAXSPANSPERROW*2 + 2 ; In bytes + + +; Terrain data, stored as height values 2 pixels wide (bytes) +terrainDataFar = $02f500 +terrainData = $f500 +; .repeat TERRAINWIDTH/2 +; .word 0 +; .endrepeat +terrainDataEnd = terrainData + (TERRAINWIDTH/2 * 2) diff --git a/gamemanager.s b/gamemanager.s index 64b3dc9..acb0f02 100644 --- a/gamemanager.s +++ b/gamemanager.s @@ -27,11 +27,13 @@ beginGameplay: jsr colorFill ; Generate, compile, and clip terrain + stz leftScreenEdge jsr generateTerrain - jsr compileTerrainSpans + + jsl compileTerrainSpans ; jsr compileTerrain ; jsr clipTerrain - jsr renderTerrainSpans + jsl renderTerrainSpans ; Create players lda #56 @@ -58,8 +60,8 @@ gameplayLoop: ; lda terrainDirty ; beq gameplayLoopKbd BORDER_COLOR #$3 - jsr unrenderTerrainSpans - jsr renderTerrainSpans + jsl unrenderTerrainSpans + jsl renderTerrainSpans stz terrainDirty BORDER_COLOR #$1 @@ -334,7 +336,7 @@ paused: ; c) Byte-distance from left edge of logical terrain to right edge of visible screen minus game object width in words mapScrollPos: .word 0 -leftScreenEdge: - .word 0 +;leftScreenEdge = $6E ; Moved to zero page for speed and cross-bank convenience +; .word 0 rightScreenEdge: .word 160-GAMEOBJECTWIDTH/4-1 diff --git a/gscats.2mg b/gscats.2mg index e9d254f..52f8229 100644 Binary files a/gscats.2mg and b/gscats.2mg differ diff --git a/gscats.s b/gscats.s index 4d35319..b786fbe 100644 --- a/gscats.s +++ b/gscats.s @@ -8,12 +8,15 @@ .include "macros.s" .include "equates.s" +.import renderTerrainSpans +.import unrenderTerrainSpans +.import compileTerrainSpans + .org $0000 mainBank2: SYNCDBR - BITS8 lda #$f0 sta TEXTCOLOR diff --git a/linkerConfig b/linkerConfig new file mode 100644 index 0000000..4a1b127 --- /dev/null +++ b/linkerConfig @@ -0,0 +1,44 @@ +FEATURES { + STARTADDRESS: default = $0803; +} + +MEMORY { + ZP: start = $0080, size = $001A, define = yes; + HEADER: start = $0000, size = $0004, file = %O; + RAM: start = %S, size = $9600 - %S, file = %O, define = yes; + MOVE: start = $0000, size = $FFFF, file = %O, define = yes; + LC: start = $D400, size = $0C00, define = yes; +} + +SEGMENTS { + ZEROPAGE: load = ZP, type = zp; + EXEHDR: load = HEADER, type = ro; + STARTUP: load = RAM, type = ro; + LOWCODE: load = RAM, type = ro; + CODE: load = RAM, type = ro; + RODATA: load = RAM, type = ro; + DATA: load = RAM, type = rw; + ZPSAVE: load = RAM, type = bss, define = yes; + BSS: load = RAM, type = bss, define = yes; + INIT: load = MOVE, run = RAM, type = ro, define = yes; + HIGHCODE: load = MOVE, run = LC, type = ro, optional = yes; +} + +FEATURES { + CONDES: segment = INIT, + type = constructor, + label = __CONSTRUCTOR_TABLE__, + count = __CONSTRUCTOR_COUNT__; + CONDES: segment = RODATA, + type = destructor, + label = __DESTRUCTOR_TABLE__, + count = __DESTRUCTOR_COUNT__; + CONDES: type = interruptor, + segment = RODATA, + label = __INTERRUPTOR_TABLE__, + count = __INTERRUPTOR_COUNT__; +} +SYMBOLS { + __STACKSIZE__: value = $0800, weak = yes; +} + diff --git a/loader.s b/loader.s index 07c3a13..865cd83 100644 --- a/loader.s +++ b/loader.s @@ -40,10 +40,42 @@ main: ; Copy code into bank 2 ldx fileReadLen lda #2 + ldy #0 jsr copyBytes EMULATION +;;;;;;;;;;;;;;;;;;;;; + + ; Open the E1 code file + jsr PRODOS + .byte $c8 + .addr fileOpenCodeE1 + bne ioError + + ; Load the code into bank 0 + jsr PRODOS + .byte $ca + .addr fileRead + bne ioError + + ; Close the file + jsr PRODOS + .byte $cc + .addr fileClose + + NATIVE + + ; Copy code into bank E1 + ldx fileReadLen + lda #$E1 + ldy #$800 ; Must match terrain_e1 .org + jsr copyBytes + + EMULATION + +;;;;;;;;;;;;;;;;;;;;; + ; Open the sprite bank file jsr PRODOS .byte $c8 @@ -66,6 +98,7 @@ main: ; Copy sprites into bank 3 ldx fileReadLen lda #3 + ldy #0 jsr copyBytes ; Set up a long jump into bank 2, and @@ -73,6 +106,7 @@ main: ; properly to ProDOS 8 lda #returnToProDOS sta PRODOSRETURN + jml MAINENTRY returnToProDOS: @@ -90,9 +124,13 @@ ioError: ; bottom of any other bank. Must be in native mode. ; ; X = Length of data in bytes +; Y = Origin within bank ; A = Bank number of destination ; copyBytes: + sty copyBytesDest+1 + sty copyBytesDest2+1 + phx BITS8 sta copyBytesDest+3 @@ -135,6 +173,13 @@ fileOpenCode: .byte 0 ; Result (file handle) .byte 0 ; Padding +fileOpenCodeE1: + .byte 3 + .addr codePathE1 + .addr $9200 ; 1k below BASIC.SYSTEM + .byte 0 ; Result (file handle) + .byte 0 ; Padding + fileRead: .byte 4 .byte 1 ; File handle (we know it's gonna be 1) @@ -156,5 +201,7 @@ fileOpenSprites: codePath: pstring "/GSAPP/CODEBANK" +codePathE1: + pstring "/GSAPP/CODEBANKE1" spritePath: pstring "/GSAPP/SPRITEBANK00" diff --git a/macros.s b/macros.s index 8d77782..4bfb12a 100644 --- a/macros.s +++ b/macros.s @@ -42,6 +42,15 @@ plb .endmacro +.macro SAVE_DBR + phb + phk + plb +.endmacro + +.macro RESTORE_DBR + plb +.endmacro .macro EMULATION sec ; Enable 8-bit mode diff --git a/tables.s b/tables.s index 355aa6f..6f18ab2 100644 --- a/tables.s +++ b/tables.s @@ -152,16 +152,4 @@ vramYOffset: .word $6400,$64a0,$6540,$65e0,$6680,$6720,$67c0,$6860,$6900,$69a0,$6a40,$6ae0,$6b80,$6c20,$6cc0,$6d60,$6e00,$6ea0,$6f40,$6fe0 .word $7080,$7120,$71c0,$7260,$7300,$73a0,$7440,$74e0,$7580,$7620,$76c0,$7760,$7800,$78a0,$7940,$79e0,$7a80,$7b20,$7bc0,$7c60 -vramRowInvertedSpanLookup: - .word $9d00,$9c60,$9bc0,$9b20,$9a80,$99e0,$9940,$98a0,$9800,$9760,$96c0,$9620,$9580,$94e0,$9440,$93a0,$9300,$9260,$91c0,$9120 - .word $9080,$8fe0,$8f40,$8ea0,$8e00,$8d60,$8cc0,$8c20,$8b80,$8ae0,$8a40,$89a0,$8900,$8860,$87c0,$8720,$8680,$85e0,$8540,$84a0 - .word $8400,$8360,$82c0,$8220,$8180,$80e0,$8040,$7fa0,$7f00,$7e60,$7dc0,$7d20,$7c80,$7be0,$7b40,$7aa0,$7a00,$7960,$78c0,$7820 - .word $7780,$76e0,$7640,$75a0,$7500,$7460,$73c0,$7320,$7280,$71e0,$7140,$70a0,$7000,$6f60,$6ec0,$6e20,$6d80,$6ce0,$6c40,$6ba0 - .word $6b00,$6a60,$69c0,$6920,$6880,$67e0,$6740,$66a0,$6600,$6560,$64c0,$6420,$6380,$62e0,$6240,$61a0,$6100,$6060,$5fc0,$5f20 - .word $5e80,$5de0,$5d40,$5ca0,$5c00,$5b60,$5ac0,$5a20,$5980,$58e0,$5840,$57a0,$5700,$5660,$55c0,$5520,$5480,$53e0,$5340,$52a0 - .word $5200,$5160,$50c0,$5020,$4f80,$4ee0,$4e40,$4da0,$4d00,$4c60,$4bc0,$4b20,$4a80,$49e0,$4940,$48a0,$4800,$4760,$46c0,$4620 - .word $4580,$44e0,$4440,$43a0,$4300,$4260,$41c0,$4120,$4080,$3fe0,$3f40,$3ea0,$3e00,$3d60,$3cc0,$3c20,$3b80,$3ae0,$3a40,$39a0 - .word $3900,$3860,$37c0,$3720,$3680,$35e0,$3540,$34a0,$3400,$3360,$32c0,$3220,$3180,$30e0,$3040,$2fa0,$2f00,$2e60,$2dc0,$2d20 - .word $2c80,$2be0,$2b40,$2aa0,$2a00,$2960,$28c0,$2820,$2780,$26e0,$2640,$25a0,$2500,$2460,$23c0,$2320,$2280,$21e0,$2140,$20a0 - .include "circleTable.s" diff --git a/terrain.s b/terrain.s index 1b02058..525ab3a 100644 --- a/terrain.s +++ b/terrain.s @@ -4,16 +4,6 @@ ; Created by Quinn Dunki on 7/29/17 ; - -TERRAINWIDTH = 640 ; In pixels -MAXTERRAINHEIGHT = 100 ; In pixels -COMPILEDTERRAINROW = TERRAINWIDTH/4+3 ; In words, +2 to make room for clipping jump at end of row -VISIBLETERRAINWIDTH = TERRAINWIDTH/4 ; In words- width minus jump return padding -VISIBLETERRAINWINDOW = 80 ; In words -MAXSPANSPERROW = 15 -SPANROWBYTES = MAXSPANSPERROW*2 + 2 ; In bytes - - .if 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; renderTerrain @@ -64,142 +54,6 @@ renderTerrainDone: rts .endif -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; renderTerrainSpans: -; -; -renderTerrainSpans: - SAVE_AXY - FASTGRAPHICS - - lda #$800 ; Prepare unrender cache - tcs - - lda #terrainSpanWriteCache - sta CACHEPTR - - lda #MAXTERRAINHEIGHT-1 - -renderTerrainSpansLoop: - sta PARAML1 - - ; Find row data - lda PARAML1 - asl ; Shifts must match SPANROWBYTES - asl - asl - asl - asl - tay - lda terrainSpanData,y - sta SCRATCHL ; Track span color - - ; Find VRAM row - lda PARAML1 - asl - tax - lda vramRowInvertedSpanLookup,x - tax - - adc #160 - sta PARAML0 ; Watch for end of VRAM row - - ; Find span that intersects left logical edge - lda #0 - clc - -renderTerrainRowSpansFindLeftLoop: - adc terrainSpanData+2,y - cmp leftScreenEdge - bpl renderTerrainRowSpansFoundLeft - iny - iny - sta CACHEDATA - lda SCRATCHL - eor #%110000 ; Toggle span color cache - sta SCRATCHL - lda CACHEDATA - bra renderTerrainRowSpansFindLeftLoop - -renderTerrainRowSpansFoundLeft: - sec - sbc leftScreenEdge ; A now holds remainder of leftmost span - ; and Y points to leftmost span - -renderTerrainRowSpansLoop: - sta SCRATCHL2 - - ; Set fill mode byte for this span - lda SCRATCHL - sta VRAMBANK,x - - ; Cache the index we wrote to so we can erase later - phx -; txa -; sta (CACHEPTR) -; inc CACHEPTR -; inc CACHEPTR - - ; Advance to end of span - clc - txa - adc SCRATCHL2 - cmp PARAML0 - bpl renderTerrainRowSpansDone - tax - - ; Prepare for next span - iny - iny - lda SCRATCHL - eor #%110000 ; Toggle span color cache - sta SCRATCHL - - lda terrainSpanData+2,y - bra renderTerrainRowSpansLoop - -renderTerrainRowSpansDone: - lda PARAML1 - dec - bne renderTerrainSpansLoop - - pea 0 ; Null-terminate the unrender cache - SLOWGRAPHICS - RESTORE_AXY - rts - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; unrenderTerrainSpans: -; -; - -unrenderTerrainSpans: - SAVE_AXY - phb - pea $e1e1 ; Work entirely in bank E1 for all local read/writes - plb - plb - - ldy #$800-1 - -unrenderTerrainSpansLoop: - lda 0,y - beq unrenderTerrainSpansDone - tax - lda #0 - sta a:0,x - dey - dey - bra unrenderTerrainSpansLoop - -unrenderTerrainSpansDone: - plb - RESTORE_AXY - rts - - .if 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -618,123 +472,6 @@ compileTerrainOpcode: .endif -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; compileTerrainSpans: -; -; -compileTerrainSpans: - pha - lda #0 - -compileTerrainSpansLoop: - sta PARAML1 - jsr compileTerrainSpansRow - lda PARAML1 - inc - cmp #MAXTERRAINHEIGHT - bne compileTerrainSpansLoop - - pla - rts - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; compileTerrainSpansRow: -; -; PARAML1 = Row index (bottom relative) -; -; Trashes SCRATCHL -; -compileTerrainSpansRow: - SAVE_AXY - - lda PARAML1 - asl ; Shifts must match SPANROWBYTES - asl - asl - asl - asl - clc - adc #terrainSpanData - sta SCRATCHL - - ldy #0 - ldx #TERRAINWIDTH-2 - - lda terrainData,x ; Figure out start value for row - cmp PARAML1 - bcs compileTerrainSpansRowInitGreen - -compileTerrainSpansRowInitBlack: - lda #$0020 ; First span is black - sta (SCRATCHL) ; Initialize the row - inc SCRATCHL - inc SCRATCHL - ldy #-1 - -compileTerrainSpansRowBlackStart: - iny - -compileTerrainSpansRowBlackLoop: - lda terrainData,x - cmp PARAML1 - bcs compileTerrainSpansBlackEnd - dex - dex - iny - cpx #-2 - bne compileTerrainSpansRowBlackLoop - -compileTerrainSpansBlackEnd: - tya ; Store this span's length - sta (SCRATCHL) - inc SCRATCHL - inc SCRATCHL - - dex ; Begin searching for next span - dex - cpx #0 - bmi compileTerrainSpansRowDone - ldy #0 - bra compileTerrainSpansRowGreenStart - -compileTerrainSpansRowDone: - RESTORE_AXY - rts - -compileTerrainSpansRowInitGreen: - lda #$0010 ; First span is green - sta (SCRATCHL) ; Initialize the row - inc SCRATCHL - inc SCRATCHL - ldy #-1 - -compileTerrainSpansRowGreenStart: - iny - -compileTerrainSpansRowGreenLoop: - lda terrainData,x - cmp PARAML1 - bcc compileTerrainSpansGreenEnd - dex - dex - iny - cpx #-2 - bne compileTerrainSpansRowGreenLoop - -compileTerrainSpansGreenEnd: - tya ; Store this span's length - sta (SCRATCHL) - inc SCRATCHL - inc SCRATCHL - - dex ; Begin searching for next span - dex - cpx #0 - bmi compileTerrainSpansRowDone - ldy #0 - bra compileTerrainSpansRowBlackStart - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; prepareRowRendering: @@ -820,15 +557,6 @@ generateTerrainLoop: rts - -; Terrain data, stored as height values 2 pixels wide (bytes) - -terrainData: - .repeat TERRAINWIDTH/2 - .word 0 - .endrepeat -terrainDataEnd: - .if 0 compiledTerrain: .repeat COMPILEDTERRAINROW * MAXTERRAINHEIGHT @@ -842,18 +570,3 @@ clippedTerrainData: .endrepeat .endif -terrainSpanData: - .repeat MAXTERRAINHEIGHT - .word 0 ; Start value (0=BG) - .repeat MAXSPANSPERROW - .word 0 ; Length (in bytes) - .endrepeat - .endrepeat - -terrainSpanWriteCacheNull: - .word 0 ; Null terminator for when popping off LIFO -terrainSpanWriteCache: - .repeat 512 - .word 0 ; LIFO for tracking span byte writes - .endrepeat - diff --git a/terrain_e1.s b/terrain_e1.s new file mode 100644 index 0000000..728faa7 --- /dev/null +++ b/terrain_e1.s @@ -0,0 +1,304 @@ +; +; terrain (in E1 bank) +; +; Fill-mode terrain rendering code snippets +; that live in bank E1 for maximum speed. +; +; Created by Quinn Dunki on 7/29/17 +; + +.include "equates.s" +.include "macros.s" + +UNRENDERCACHESTACK = $7ff + +OP16 + +.org $800 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; renderTerrainSpans: +; +; +renderTerrainSpans: + SAVE_AXY + SAVE_DBR + FASTGRAPHICS + + lda #UNRENDERCACHESTACK ; Prepare unrender cache + tcs + + lda #MAXTERRAINHEIGHT-1 + +renderTerrainSpansLoop: + sta PARAML1 + + ; Find row data + lda PARAML1 + asl ; Shifts must match SPANROWBYTES + asl + asl + asl + asl + tay + lda terrainSpanData,y + sta SCRATCHL ; Track span color + + ; Find VRAM row + lda PARAML1 + asl + tax + lda vramRowInvertedSpanLookup,x + tax + + adc #160 + sta PARAML0 ; Watch for end of VRAM row + + ; Find span that intersects left logical edge + lda #0 + clc + +renderTerrainRowSpansFindLeftLoop: + adc terrainSpanData+2,y + cmp leftScreenEdge + bpl renderTerrainRowSpansFoundLeft + iny + iny + sta CACHEDATA + lda SCRATCHL + eor #%110000 ; Toggle span color cache + sta SCRATCHL + lda CACHEDATA + bra renderTerrainRowSpansFindLeftLoop + +renderTerrainRowSpansFoundLeft: + sec + sbc leftScreenEdge ; A now holds remainder of leftmost span + ; and Y points to leftmost span + +renderTerrainRowSpansLoop: + sta SCRATCHL2 + + ; Set fill mode byte for this span + lda SCRATCHL + sta VRAMBANK,x + + ; Cache the index we wrote to so we can erase later + phx + + ; Advance to end of span + clc + txa + adc SCRATCHL2 + cmp PARAML0 + bpl renderTerrainRowSpansDone + tax + + ; Prepare for next span + iny + iny + lda SCRATCHL + eor #%110000 ; Toggle span color cache + sta SCRATCHL + + lda terrainSpanData+2,y + bra renderTerrainRowSpansLoop + +renderTerrainRowSpansDone: + lda PARAML1 + dec + bne renderTerrainSpansLoop + + pea 0 ; Null-terminate the unrender cache + SLOWGRAPHICS + RESTORE_DBR + RESTORE_AXY + rtl + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; unrenderTerrainSpans: +; +; + +unrenderTerrainSpans: + SAVE_AXY + SAVE_DBR + phb + pea $e1e1 ; Work entirely in bank E1 for all local read/writes + plb + plb + + ldy #UNRENDERCACHESTACK-1 + +unrenderTerrainSpansLoop: + lda 0,y + beq unrenderTerrainSpansDone + tax + lda #0 + sta a:0,x + dey + dey + bra unrenderTerrainSpansLoop + +unrenderTerrainSpansDone: + plb + RESTORE_DBR + RESTORE_AXY + rtl + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; compileTerrainSpans: +; +; +compileTerrainSpans: + pha + SAVE_DBR + lda #0 + +compileTerrainSpansLoop: + sta PARAML1 + jsr compileTerrainSpansRow + lda PARAML1 + inc + cmp #MAXTERRAINHEIGHT + bne compileTerrainSpansLoop + + RESTORE_DBR + pla + rtl + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; compileTerrainSpansRow: +; +; PARAML1 = Row index (bottom relative) +; +; Trashes SCRATCHL +; +compileTerrainSpansRow: + SAVE_AXY + + lda PARAML1 + asl ; Shifts must match SPANROWBYTES + asl + asl + asl + asl + clc + adc #terrainSpanData + sta SCRATCHL + + ldy #0 + ldx #TERRAINWIDTH-2 + + lda terrainDataFar,x ; Figure out start value for row + cmp PARAML1 + bcs compileTerrainSpansRowInitGreen + +compileTerrainSpansRowInitBlack: + lda #$0020 ; First span is black + sta (SCRATCHL) ; Initialize the row + inc SCRATCHL + inc SCRATCHL + ldy #-1 + +compileTerrainSpansRowBlackStart: + iny + +compileTerrainSpansRowBlackLoop: + lda terrainDataFar,x + cmp PARAML1 + bcs compileTerrainSpansBlackEnd + dex + dex + iny + cpx #-2 + bne compileTerrainSpansRowBlackLoop + +compileTerrainSpansBlackEnd: + tya ; Store this span's length + sta (SCRATCHL) + inc SCRATCHL + inc SCRATCHL + + dex ; Begin searching for next span + dex + cpx #0 + bmi compileTerrainSpansRowDone + ldy #0 + bra compileTerrainSpansRowGreenStart + +compileTerrainSpansRowDone: + RESTORE_AXY + rts + +compileTerrainSpansRowInitGreen: + lda #$0010 ; First span is green + sta (SCRATCHL) ; Initialize the row + inc SCRATCHL + inc SCRATCHL + ldy #-1 + +compileTerrainSpansRowGreenStart: + iny + +compileTerrainSpansRowGreenLoop: + lda terrainDataFar,x + cmp PARAML1 + bcc compileTerrainSpansGreenEnd + dex + dex + iny + cpx #-2 + bne compileTerrainSpansRowGreenLoop + +compileTerrainSpansGreenEnd: + tya ; Store this span's length + sta (SCRATCHL) + inc SCRATCHL + inc SCRATCHL + + dex ; Begin searching for next span + dex + cpx #0 + bmi compileTerrainSpansRowDone + ldy #0 + bra compileTerrainSpansRowBlackStart + +terrainSpanData: + .repeat MAXTERRAINHEIGHT + .word 0 ; Start value (0=BG) + .repeat MAXSPANSPERROW + .word 0 ; Length (in bytes) + .endrepeat + .endrepeat + + +vramRowInvertedSpanLookup: + .word $9d00,$9c60,$9bc0,$9b20,$9a80,$99e0,$9940,$98a0,$9800,$9760,$96c0,$9620,$9580,$94e0,$9440,$93a0,$9300,$9260,$91c0,$9120 + .word $9080,$8fe0,$8f40,$8ea0,$8e00,$8d60,$8cc0,$8c20,$8b80,$8ae0,$8a40,$89a0,$8900,$8860,$87c0,$8720,$8680,$85e0,$8540,$84a0 + .word $8400,$8360,$82c0,$8220,$8180,$80e0,$8040,$7fa0,$7f00,$7e60,$7dc0,$7d20,$7c80,$7be0,$7b40,$7aa0,$7a00,$7960,$78c0,$7820 + .word $7780,$76e0,$7640,$75a0,$7500,$7460,$73c0,$7320,$7280,$71e0,$7140,$70a0,$7000,$6f60,$6ec0,$6e20,$6d80,$6ce0,$6c40,$6ba0 + .word $6b00,$6a60,$69c0,$6920,$6880,$67e0,$6740,$66a0,$6600,$6560,$64c0,$6420,$6380,$62e0,$6240,$61a0,$6100,$6060,$5fc0,$5f20 + .word $5e80,$5de0,$5d40,$5ca0,$5c00,$5b60,$5ac0,$5a20,$5980,$58e0,$5840,$57a0,$5700,$5660,$55c0,$5520,$5480,$53e0,$5340,$52a0 + .word $5200,$5160,$50c0,$5020,$4f80,$4ee0,$4e40,$4da0,$4d00,$4c60,$4bc0,$4b20,$4a80,$49e0,$4940,$48a0,$4800,$4760,$46c0,$4620 + .word $4580,$44e0,$4440,$43a0,$4300,$4260,$41c0,$4120,$4080,$3fe0,$3f40,$3ea0,$3e00,$3d60,$3cc0,$3c20,$3b80,$3ae0,$3a40,$39a0 + .word $3900,$3860,$37c0,$3720,$3680,$35e0,$3540,$34a0,$3400,$3360,$32c0,$3220,$3180,$30e0,$3040,$2fa0,$2f00,$2e60,$2dc0,$2d20 + .word $2c80,$2be0,$2b40,$2aa0,$2a00,$2960,$28c0,$2820,$2780,$26e0,$2640,$25a0,$2500,$2460,$23c0,$2320,$2280,$21e0,$2140,$20a0 + + + + +.export renderTerrainSpans +.export unrenderTerrainSpans +.export compileTerrainSpans + + +; Suppress some linker warnings - Must be the last thing in the file +.SEGMENT "ZPSAVE" +.SEGMENT "EXEHDR" +.SEGMENT "STARTUP" +.SEGMENT "INIT" +.SEGMENT "LOWCODE"