diff --git a/HiSprite.py b/HiSprite.py index 87e87f2..318055a 100755 --- a/HiSprite.py +++ b/HiSprite.py @@ -206,7 +206,7 @@ class Listing(object): class Sprite(Listing): 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) self.screen = screen @@ -217,6 +217,7 @@ class Sprite(Listing): self.use_mask = use_mask self.backing_store = backing_store self.clobber = clobber + self.double_buffer = double_buffer self.processor = processor if not name: name = os.path.splitext(pngfile)[0] @@ -310,7 +311,8 @@ class Sprite(Listing): # SAVE_AXY + RESTORE_AXY + rts + sprite jump table 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) maskStreams = self.screen.byteStreamsFromPixels(shift, self, True) @@ -324,7 +326,7 @@ class Sprite(Listing): self.backing_store_sizes.add((byteWidth, self.height)) cycleCount += 6 - cycleCount, optimizationCount = self.generateBlitter(colorStreams, maskStreams, cycleCount) + cycleCount, optimizationCount = self.generateBlitter(colorStreams, maskStreams, cycleCount, baselabel) if not self.clobber: if self.processor == "any": @@ -343,14 +345,18 @@ class Sprite(Listing): self.asm("rts") 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]) cycleCount = baseCycleCount optimizationCount = 0 - for row in range(self.height): - cycleCount += self.rowStartCalculatorCode(row) + order = list(range(self.height)) + if self.double_buffer: + order = reversed(order) + + for row in order: + cycleCount += self.rowStartCalculatorCode(row, baselabel) byteSplits = colorStreams[row] maskSplits = maskStreams[row] @@ -405,16 +411,36 @@ class Sprite(Listing): return cycleCount, optimizationCount - def rowStartCalculatorCode(self, row): + def rowStartCalculatorCode(self, row, baselabel): self.out() self.comment_line("row %d" % row) - if row == 0: - self.asm("ldx PARAM1") - cycles = 3 + if self.double_buffer: + if row == self.height - 1: + 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: - self.asm("inx") - cycles = 2 - self.asm("lda HGRROWS_H1,x") + if row == 0: + self.asm("ldx PARAM1") + cycles = 3 + else: + self.asm("inx") + cycles = 2 + self.asm("lda HGRROWS_H1,x") + cycles += 4 self.asm("sta SCRATCH1") self.asm("lda HGRROWS_L,x") self.asm("sta SCRATCH0") @@ -427,7 +453,7 @@ class Sprite(Listing): else: self.asm("ldy PARAM2") cycles += 2 - return cycles + 4 + 3 + 4 + 3; + return cycles + 3 + 4 + 3; 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("-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("-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("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() @@ -945,7 +972,7 @@ if __name__ == "__main__": for pngfile in options.files: 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: print "%s: %s" % (pngfile, e) sys.exit(1) diff --git a/Makefile.rob b/Makefile.rob index 1abb932..53e3c75 100644 --- a/Makefile.rob +++ b/Makefile.rob @@ -29,7 +29,7 @@ colortest.dsk: HiSprite.py colortest.s bwsprite.s atrcopy colortest.dsk boot -b colortest.xex --brun 6000 -f 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 atasm -omultitest.xex multitest.s -Lmultitest.var -gmultitest.lst diff --git a/multitest.dsk b/multitest.dsk index 4661445..77a4af9 100644 Binary files a/multitest.dsk and b/multitest.dsk differ diff --git a/multitest.s b/multitest.s index 902c6b3..93f1bac 100644 --- a/multitest.s +++ b/multitest.s @@ -22,7 +22,10 @@ SCRATCH1 = $1a SPRITEPTR_L = $1b SPRITEPTR_H = $1c RENDERCOUNT = $ce +FRAMECOUNT = $cf ; used to determine page currently displayed: even -> page1, odd -> page2 +VISIBLEPAGE = $d7 BGSTORE = $fa +TEMPADDR = $fc BGTOP = $c0 ; page number of first byte beyond top of backing store stack @@ -40,10 +43,12 @@ start bit SETHIRES jsr clrscr + jsr initonce jsr initsprites gameloop jsr renderstart + jsr pageflip jsr movestart dec fasttoggle bpl gofast @@ -56,10 +61,29 @@ fasttoggle .byte 0 +initonce + lda #0 + sta FRAMECOUNT + rts + + initsprites jsr restorebg_init 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 renderstart @@ -197,20 +221,27 @@ wait_inner clrscr lda #0 sta clr1+1 + sta clr2+1 lda #$20 sta clr1+2 + lda #$40 + sta clr2+2 clr0 lda #0 ldy #0 clr1 sta $ffff,y +clr2 + sta $ffff,y iny bne clr1 inc clr1+2 + inc clr2+2 ldx clr1+2 cpx #$40 bcc clr1 +; put the same info on both screens clrscr2 ldy #1 clrouter @@ -218,14 +249,18 @@ clrouter clrloop lda HGRROWS_H1,x sta SCRATCH1 + lda HGRROWS_H2,x + sta TEMPADDR+1 lda HGRROWS_L,x sta SCRATCH0 + sta TEMPADDR lda tophalf,y cpx #96 bcc clrwrite lda bothalf,y clrwrite sta (SCRATCH0),y + sta (TEMPADDR),y inx cpx #192 bcc clrloop