push/pull framework for drawing sprites to either page

This commit is contained in:
Rob McMullen 2017-07-02 21:38:32 -07:00
parent cf5c47e121
commit d748e2b737
4 changed files with 78 additions and 16 deletions

View File

@ -206,7 +206,7 @@ class Listing(object):
class Sprite(Listing): class Sprite(Listing):
backing_store_sizes = set() backing_store_sizes = set()
def __init__(self, pngfile, assembler, screen, xdraw=False, use_mask=False, backing_store=False, clobber=False, processor="any", name=""): def __init__(self, pngfile, assembler, screen, xdraw=False, use_mask=False, backing_store=False, clobber=False, double_buffer=False, processor="any", name=""):
Listing.__init__(self, assembler) Listing.__init__(self, assembler)
self.screen = screen self.screen = screen
@ -217,6 +217,7 @@ class Sprite(Listing):
self.use_mask = use_mask self.use_mask = use_mask
self.backing_store = backing_store self.backing_store = backing_store
self.clobber = clobber self.clobber = clobber
self.double_buffer = double_buffer
self.processor = processor self.processor = processor
if not name: if not name:
name = os.path.splitext(pngfile)[0] name = os.path.splitext(pngfile)[0]
@ -310,7 +311,8 @@ class Sprite(Listing):
# SAVE_AXY + RESTORE_AXY + rts + sprite jump table # SAVE_AXY + RESTORE_AXY + rts + sprite jump table
cycleCount = 9 + 12 + 6 + 3 + 4 + 6 cycleCount = 9 + 12 + 6 + 3 + 4 + 6
self.label("%s_SHIFT%d" % (self.slug,shift)) baselabel = "%s_SHIFT%d" % (self.slug,shift)
self.label(baselabel)
colorStreams = self.screen.byteStreamsFromPixels(shift, self) colorStreams = self.screen.byteStreamsFromPixels(shift, self)
maskStreams = self.screen.byteStreamsFromPixels(shift, self, True) maskStreams = self.screen.byteStreamsFromPixels(shift, self, True)
@ -324,7 +326,7 @@ class Sprite(Listing):
self.backing_store_sizes.add((byteWidth, self.height)) self.backing_store_sizes.add((byteWidth, self.height))
cycleCount += 6 cycleCount += 6
cycleCount, optimizationCount = self.generateBlitter(colorStreams, maskStreams, cycleCount) cycleCount, optimizationCount = self.generateBlitter(colorStreams, maskStreams, cycleCount, baselabel)
if not self.clobber: if not self.clobber:
if self.processor == "any": if self.processor == "any":
@ -343,14 +345,18 @@ class Sprite(Listing):
self.asm("rts") self.asm("rts")
self.comment("Cycle count: %d, Optimized %d rows." % (cycleCount,optimizationCount)) self.comment("Cycle count: %d, Optimized %d rows." % (cycleCount,optimizationCount))
def generateBlitter(self, colorStreams, maskStreams, baseCycleCount): def generateBlitter(self, colorStreams, maskStreams, baseCycleCount, baselabel):
byteWidth = len(colorStreams[0]) byteWidth = len(colorStreams[0])
cycleCount = baseCycleCount cycleCount = baseCycleCount
optimizationCount = 0 optimizationCount = 0
for row in range(self.height): order = list(range(self.height))
cycleCount += self.rowStartCalculatorCode(row) if self.double_buffer:
order = reversed(order)
for row in order:
cycleCount += self.rowStartCalculatorCode(row, baselabel)
byteSplits = colorStreams[row] byteSplits = colorStreams[row]
maskSplits = maskStreams[row] maskSplits = maskStreams[row]
@ -405,16 +411,36 @@ class Sprite(Listing):
return cycleCount, optimizationCount return cycleCount, optimizationCount
def rowStartCalculatorCode(self, row): def rowStartCalculatorCode(self, row, baselabel):
self.out() self.out()
self.comment_line("row %d" % row) self.comment_line("row %d" % row)
if row == 0: if self.double_buffer:
self.asm("ldx PARAM1") if row == self.height - 1:
cycles = 3 label = "%s_pageloop" % (baselabel)
self.asm("ldx PARAM1")
self.asm("ldy #%d" % self.height)
self.label(label)
self.asm("lda HGRROWS_H1,x")
self.asm("pha")
self.asm("inx")
self.asm("dey")
self.asm("bne %s" % label)
self.asm("dex")
self.asm("pla")
cycles = 3
else:
self.asm("dex")
self.asm("pla")
cycles = 4
else: else:
self.asm("inx") if row == 0:
cycles = 2 self.asm("ldx PARAM1")
self.asm("lda HGRROWS_H1,x") cycles = 3
else:
self.asm("inx")
cycles = 2
self.asm("lda HGRROWS_H1,x")
cycles += 4
self.asm("sta SCRATCH1") self.asm("sta SCRATCH1")
self.asm("lda HGRROWS_L,x") self.asm("lda HGRROWS_L,x")
self.asm("sta SCRATCH0") self.asm("sta SCRATCH0")
@ -427,7 +453,7 @@ class Sprite(Listing):
else: else:
self.asm("ldy PARAM2") self.asm("ldy PARAM2")
cycles += 2 cycles += 2
return cycles + 4 + 3 + 4 + 3; return cycles + 3 + 4 + 3;
def shiftStringRight(string, shift, bitsPerPixel, fillerBit): def shiftStringRight(string, shift, bitsPerPixel, fillerBit):
@ -918,6 +944,7 @@ if __name__ == "__main__":
parser.add_argument("-s", "--screen", default="hgrcolor", choices=["hgrcolor","hgrbw"], help="Screen format (default: %(default)s)") parser.add_argument("-s", "--screen", default="hgrcolor", choices=["hgrcolor","hgrbw"], help="Screen format (default: %(default)s)")
parser.add_argument("-n", "--name", default="", help="Name for generated assembly function (default: based on image filename)") parser.add_argument("-n", "--name", default="", help="Name for generated assembly function (default: based on image filename)")
parser.add_argument("-k", "--clobber", action="store_true", default=False, help="don't save the registers on the stack") parser.add_argument("-k", "--clobber", action="store_true", default=False, help="don't save the registers on the stack")
parser.add_argument("-d", "--double-buffer", action="store_true", default=False, help="add code blit to either page (default: page 1 only)")
parser.add_argument("-o", "--output-prefix", default="", help="Base name to create a set of output files. If not supplied, all code will be sent to stdout.") parser.add_argument("-o", "--output-prefix", default="", help="Base name to create a set of output files. If not supplied, all code will be sent to stdout.")
parser.add_argument("files", metavar="IMAGE", nargs="*", help="a PNG image [or a list of them]. PNG files must not have an alpha channel!") parser.add_argument("files", metavar="IMAGE", nargs="*", help="a PNG image [or a list of them]. PNG files must not have an alpha channel!")
options, extra_args = parser.parse_known_args() options, extra_args = parser.parse_known_args()
@ -945,7 +972,7 @@ if __name__ == "__main__":
for pngfile in options.files: for pngfile in options.files:
try: try:
sprite_code = Sprite(pngfile, assembler, screen, options.xdraw, options.mask, options.backing_store, options.clobber, options.processor, options.name) sprite_code = Sprite(pngfile, assembler, screen, options.xdraw, options.mask, options.backing_store, options.clobber, options.double_buffer, options.processor, options.name)
except RuntimeError, e: except RuntimeError, e:
print "%s: %s" % (pngfile, e) print "%s: %s" % (pngfile, e)
sys.exit(1) sys.exit(1)

View File

@ -29,7 +29,7 @@ colortest.dsk: HiSprite.py colortest.s bwsprite.s
atrcopy colortest.dsk boot -b colortest.xex --brun 6000 -f atrcopy colortest.dsk boot -b colortest.xex --brun 6000 -f
multitest-sprite-driver.s: HiSprite.py $(BWSPRITE) multitest-sprite-driver.s: HiSprite.py $(BWSPRITE)
python HiSprite.py -a mac65 -p 6502 -s hgrbw -m -b -k -o multitest $(BWSPRITE) $(COLORSPRITE) python HiSprite.py -a mac65 -p 6502 -s hgrbw -m -b -k -d -o multitest $(BWSPRITE) $(COLORSPRITE)
multitest.dsk: HiSprite.py multitest.s multitest-sprite-driver.s multitest.dsk: HiSprite.py multitest.s multitest-sprite-driver.s
atasm -omultitest.xex multitest.s -Lmultitest.var -gmultitest.lst atasm -omultitest.xex multitest.s -Lmultitest.var -gmultitest.lst

Binary file not shown.

View File

@ -22,7 +22,10 @@ SCRATCH1 = $1a
SPRITEPTR_L = $1b SPRITEPTR_L = $1b
SPRITEPTR_H = $1c SPRITEPTR_H = $1c
RENDERCOUNT = $ce RENDERCOUNT = $ce
FRAMECOUNT = $cf ; used to determine page currently displayed: even -> page1, odd -> page2
VISIBLEPAGE = $d7
BGSTORE = $fa BGSTORE = $fa
TEMPADDR = $fc
BGTOP = $c0 ; page number of first byte beyond top of backing store stack BGTOP = $c0 ; page number of first byte beyond top of backing store stack
@ -40,10 +43,12 @@ start
bit SETHIRES bit SETHIRES
jsr clrscr jsr clrscr
jsr initonce
jsr initsprites jsr initsprites
gameloop gameloop
jsr renderstart jsr renderstart
jsr pageflip
jsr movestart jsr movestart
dec fasttoggle dec fasttoggle
bpl gofast bpl gofast
@ -56,10 +61,29 @@ fasttoggle
.byte 0 .byte 0
initonce
lda #0
sta FRAMECOUNT
rts
initsprites initsprites
jsr restorebg_init jsr restorebg_init
rts rts
pageflip
inc FRAMECOUNT
lda FRAMECOUNT
and #1
sta VISIBLEPAGE
beq pageflip1
bit TXTPAGE2
rts
pageflip1
bit TXTPAGE1
rts
; Draw sprites by looping through the list of sprites ; Draw sprites by looping through the list of sprites
renderstart renderstart
@ -197,20 +221,27 @@ wait_inner
clrscr clrscr
lda #0 lda #0
sta clr1+1 sta clr1+1
sta clr2+1
lda #$20 lda #$20
sta clr1+2 sta clr1+2
lda #$40
sta clr2+2
clr0 clr0
lda #0 lda #0
ldy #0 ldy #0
clr1 clr1
sta $ffff,y sta $ffff,y
clr2
sta $ffff,y
iny iny
bne clr1 bne clr1
inc clr1+2 inc clr1+2
inc clr2+2
ldx clr1+2 ldx clr1+2
cpx #$40 cpx #$40
bcc clr1 bcc clr1
; put the same info on both screens
clrscr2 clrscr2
ldy #1 ldy #1
clrouter clrouter
@ -218,14 +249,18 @@ clrouter
clrloop clrloop
lda HGRROWS_H1,x lda HGRROWS_H1,x
sta SCRATCH1 sta SCRATCH1
lda HGRROWS_H2,x
sta TEMPADDR+1
lda HGRROWS_L,x lda HGRROWS_L,x
sta SCRATCH0 sta SCRATCH0
sta TEMPADDR
lda tophalf,y lda tophalf,y
cpx #96 cpx #96
bcc clrwrite bcc clrwrite
lda bothalf,y lda bothalf,y
clrwrite clrwrite
sta (SCRATCH0),y sta (SCRATCH0),y
sta (TEMPADDR),y
inx inx
cpx #192 cpx #192
bcc clrloop bcc clrloop