Optimized span rendering moved to $E1

This commit is contained in:
blondie7575 2018-01-16 12:56:53 -08:00
parent c82e9d8a30
commit f90edac57d
15 changed files with 523 additions and 309 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
/gscats.lst
/GSCats.xcodeproj/xcuserdata/qd.xcuserdatad/xcdebugger
/loader.lst
/terrain_e1.lst

View File

@ -13,6 +13,7 @@
700F21E01F4A3A5500D7007D /* GenerateTrigTables.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateTrigTables.py; sourceTree = "<group>"; };
700FFAFB1F40F3BF00A442DE /* font.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = font.s; sourceTree = "<group>"; };
7059502B1F37A0BE00BBE90F /* GenerateVRAMTable.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateVRAMTable.py; sourceTree = "<group>"; };
705AAFA920040B0D001BB0ED /* terrain_e1.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = terrain_e1.s; sourceTree = "<group>"; };
706DF1641F2D39F700AA6680 /* loader.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = loader.s; sourceTree = "<group>"; };
706DF1651F2D4A8100AA6680 /* terrain.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = terrain.s; sourceTree = "<group>"; };
7088096D1F2ECE8D00D4C950 /* GenerateRenderSpans.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateRenderSpans.py; sourceTree = "<group>"; };
@ -20,6 +21,8 @@
7099E3841F41022100182A82 /* gameobject.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gameobject.s; sourceTree = "<group>"; };
7099E3851F4107B100182A82 /* GenerateVRAMYOffset.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateVRAMYOffset.py; sourceTree = "<group>"; };
70A80FB01F43D7F200BD34C9 /* gamemanager.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gamemanager.s; sourceTree = "<group>"; };
70BDCBC92006AD5F00CB51F1 /* linkerConfig */ = {isa = PBXFileReference; lastKnownFileType = text; path = linkerConfig; sourceTree = "<group>"; };
70BDCBCA200A99F200CB51F1 /* ParseMapFile.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = ParseMapFile.py; sourceTree = "<group>"; };
70C073091F5BAA3E009844A9 /* collision.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = collision.s; sourceTree = "<group>"; };
70E266E31F6F262D005AC7E4 /* circleTable.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = circleTable.s; sourceTree = "<group>"; };
70E554C41F807ADB00F3C871 /* spritebank.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = spritebank.s; sourceTree = "<group>"; };
@ -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 = "<group>";
};

View File

@ -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:

64
ParseMapFile.py Executable file
View File

@ -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:])

View File

@ -50,7 +50,7 @@ intersectRectTerrain:
; Check Y bottom
intersectRectTerrainBottomLoop:
lda terrainData,y
lda terrainDataFar,y
cmp rectParams+6
bpl intersectRectTerrainYep
dey

View File

@ -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)

View File

@ -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

Binary file not shown.

View File

@ -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

44
linkerConfig Normal file
View File

@ -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;
}

View File

@ -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"

View File

@ -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

View File

@ -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"

287
terrain.s
View File

@ -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

304
terrain_e1.s Normal file
View File

@ -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"