diff --git a/HiSprite.py b/HiSprite.py index e0204da..eb3c0d2 100755 --- a/HiSprite.py +++ b/HiSprite.py @@ -166,7 +166,7 @@ class Listing(object): class Sprite(Listing): - def __init__(self, pngfile, assembler, screen, xdraw=False, use_mask=False, processor="any", name=""): + def __init__(self, pngfile, assembler, screen, xdraw=False, use_mask=False, backing_store=False, processor="any", name=""): Listing.__init__(self, assembler) self.screen = screen @@ -175,6 +175,7 @@ class Sprite(Listing): self.xdraw = xdraw self.use_mask = use_mask + self.backing_store = backing_store self.processor = processor if not name: name = os.path.splitext(pngfile)[0] @@ -274,6 +275,10 @@ class Sprite(Listing): self.comment_line(str(c) + " " + str(m)) self.out("") + if self.backing_store: + byteWidth = len(colorStreams[0]) + self.asm("jsr savebg_%dx%d" % (byteWidth, self.height)) + self.asm("ldx PARAM1") cycleCount += 3 rowStartCode,extraCycles = self.rowStartCalculatorCode(); @@ -317,7 +322,7 @@ class Sprite(Listing): for chunkIndex in range(len(byteSplits)): # Optimization - if maskSplits[chunkIndex] == "01111111": + if maskSplits[chunkIndex] == "01111111" and not self.backing_store: optimizationCount += 1 else: value = self.binary_constant(byteSplits[chunkIndex]) @@ -638,6 +643,7 @@ if __name__ == "__main__": parser.add_argument("-r", "--rows", action="store_true", default=False, help="output row (y position) lookup tables") parser.add_argument("-x", "--xdraw", action="store_true", default=False, help="use XOR for sprite drawing") parser.add_argument("-m", "--mask", action="store_true", default=False, help="use mask for sprite drawing") + parser.add_argument("-b", "--backing-store", action="store_true", default=False, help="add code to store background") parser.add_argument("-a", "--assembler", default="cc65", choices=["cc65","mac65"], help="Assembler syntax (default: %(default)s)") parser.add_argument("-p", "--processor", default="any", choices=["any","6502", "65C02"], help="Processor type (default: %(default)s)") parser.add_argument("-s", "--screen", default="hgrcolor", choices=["hgrcolor","hgrbw"], help="Screen format (default: %(default)s)") @@ -667,7 +673,7 @@ if __name__ == "__main__": for pngfile in options.files: try: - listings.append(Sprite(pngfile, assembler, screen, options.xdraw, options.mask, options.processor, options.name)) + listings.append(Sprite(pngfile, assembler, screen, options.xdraw, options.mask, options.backing_store, options.processor, options.name)) except RuntimeError, e: print "%s: %s" % (pngfile, e) sys.exit(1) diff --git a/Makefile.rob b/Makefile.rob index ddb5922..0940bdc 100644 --- a/Makefile.rob +++ b/Makefile.rob @@ -15,7 +15,7 @@ collookupcolor.s: HiSprite.py python HiSprite.py -a mac65 -p 6502 -c > collookupcolor.s bwsprite.s: HiSprite.py collookupbw.s rowlookup.s $(BWSPRITE) - python HiSprite.py -a mac65 -p 6502 -s hgrbw $(BWSPRITE) -n bwsprite -m > bwsprite.s + python HiSprite.py -a mac65 -p 6502 -s hgrbw $(BWSPRITE) -n bwsprite -m -b > bwsprite.s colorsprite.s: HiSprite.py collookupcolor.s rowlookup.s $(COLORSPRITE) python HiSprite.py -a mac65 -p 6502 -s hgrcolor $(COLORSPRITE) -n colorsprite -m > colorsprite.s diff --git a/backingstore-3x11.s b/backingstore-3x11.s new file mode 100644 index 0000000..ef0a137 --- /dev/null +++ b/backingstore-3x11.s @@ -0,0 +1,133 @@ +; backing store test, hardcoded for 3x11 apple.png-sized sprite +; +; The backing store memory starts from some high address +; and grows downward in order to facilitate speedier restoring, because +; there will be different sized chunks to restore +; +; +; +; +; needs: +; bgstore: (lo byte, hi byte) 1 + the first byte of free memory. +; I.e. points just beyond the last byte +; PARAM0: (byte) x coord +; PARAM1: (byte) y coord +; +; everything else is known because the sizes of each erase/restore +; routine will be hardcoded. + +; modification of quinn's column sweep + +; memory needed for this chunk of background: +; 2: address of restore routine +; 1: x coordinate +; 1: y coordinate +; 33: number of bytes of background to save +SIZE_3X11 = 2 + 1 + 1 + 3*11 + +savebg_3x11 + sec + lda bgstore + sbc #SIZE_3X11 + sta bgstore + lda bgstore+1 + sbc #0 + sta bgstore+1 + ldy #0 + + lda #restorebg_3x11 + sta (bgstore),y + iny + lda PARAM0 + sta (bgstore),y + iny + lda PARAM1 + sta bgline + sta (bgstore),y + iny + +savebg_3x11_line + ldx bgline ; Calculate Y line + + lda HGRROWS_H1,x ; Compute hires row + sta savebg_3x11_col0+2 + sta savebg_3x11_col1+2 + sta savebg_3x11_col2+2 + lda HGRROWS_L,x + sta savebg_3x11_col0+1 + sta savebg_3x11_col1+1 + sta savebg_3x11_col2+1 + + ldx PARAM0 ; Compute hires column + lda DIV7_1,x + tax + +savebg_3x11_col0 + lda $2000,x + sta (bgstore),y + iny + inx +savebg_3x11_col1 + lda $2000,x + sta (bgstore),y + iny + inx +savebg_3x11_col2 + lda $2000,x + sta (bgstore),y + iny + + inc bgline + + cpy #SIZE_3X11 + bcc savebg_3x11_line + + rts + +; bgstore will be pointing right to the data to be blitted back to the screen, +; which is 4 bytes into the bgstore array. Everything before the data will have +; already been pulled off by the driver in order to figure out which restore +; routine to call. Y will be 4 upon entry, and PARAM0 and PARAM1 will be +; filled with the x & y values. +; +; also, no need to save registers because this is being called from a driver +; that will do all of that. +restorebg_3x11 + ldx PARAM1 ; Calculate Y line + + lda HGRROWS_H1,x ; Compute hires row + sta restorebg_3x11_col0+2 + sta restorebg_3x11_col1+2 + sta restorebg_3x11_col2+2 + lda HGRROWS_L,x + sta restorebg_3x11_col0+1 + sta restorebg_3x11_col1+1 + sta restorebg_3x11_col2+1 + + ldx PARAM0 ; Compute hires column + lda DIV7_1,x + tax + + lda (bgstore),y +restorebg_3x11_col0 + sta $2000,x + iny + inx + lda (bgstore),y +restorebg_3x11_col1 + sta $2000,x + iny + inx + lda (bgstore),y +restorebg_3x11_col2 + sta $2000,x + iny + + inc PARAM1 + + cpy #SIZE_3X11 + bcc restorebg_3x11 + rts diff --git a/backingstore.s b/backingstore.s new file mode 100644 index 0000000..a23c127 --- /dev/null +++ b/backingstore.s @@ -0,0 +1,59 @@ +; Driver to restore the screen using all the saved data. +; +; The backing store is a stack that grows downward in order to restore the +; chunks in reverse order that they were saved. Each entry in the stack +; includes: +; +; 2 bytes: address of restore routine +; 1 byte: x coordinate +; 1 byte: y coordinate +; nn: x * y bytes of data, in lists of rows +; +; Note that sprites of different sizes will have different sized entries +; in the stack, so the entire list has to be processed in order. But you want +; that anyway, so it's not a big deal. +; +; The global variable 'bgstore' is used as the stack pointer. It musts be +; initialized to a page boundary, the stack grows downward from there. +; starting from the last byte on the previous page. E.g. if the initial +; value is $c000, the stack grows down using $bfff as the highest address, +; the initial bgstore value must point to 1 + the last usable byte +; +; All registers are clobbered because there's no real need to save them since +; this will be called from the main game loop. + +restorebg_init + lda #0 ; init backing store to end of free memory, $c000 + sta bgstore + lda #BGTOP + sta bgstore+1 + rts + + +restorebg_driver + ldy #0 + lda (bgstore),y + sta restorebg_jsr+1 + iny + lda (bgstore),y + sta restorebg_jsr+2 + iny + lda (bgstore),y + sta PARAM0 + iny + lda (bgstore),y + sta PARAM1 + iny +restorebg_jsr + jsr $ffff + + clc + lda bgstore + adc #SIZE_3X11 + sta bgstore + lda bgstore+1 + adc #0 + sta bgstore+1 + cmp #BGTOP + bcc restorebg_driver + rts diff --git a/multitest.dsk b/multitest.dsk index 132fbc1..6a57e27 100644 Binary files a/multitest.dsk and b/multitest.dsk differ diff --git a/multitest.s b/multitest.s index 1165bee..ba550c8 100644 --- a/multitest.s +++ b/multitest.s @@ -22,6 +22,10 @@ SCRATCH1 = $1a SPRITEPTR_L = $1b SPRITEPTR_H = $1c +BGTOP = $c0 ; page number of first byte beyond top of backing store stack +bgstore = $80 +bgline = $82 + ; constants MAXPOSX = 127 ; This demo doesn't wanna do 16 bit math MAXPOSY = 127 @@ -42,12 +46,12 @@ gameloop jsr renderstart jsr movestart jsr wait - jsr erasestart + jsr restorebg_driver jmp gameloop initsprites - nop + jsr restorebg_init rts @@ -132,12 +136,9 @@ flipY clc adc #1 sta sprite_dy,y - jmp moveloop + jmp movenext -erasestart - rts - wait ldy #$06 ; Loop a bit @@ -176,26 +177,32 @@ clr1 bcc clr1 rts +; Sprite data is interleaved so a simple indexed mode can be used. This is not +; convenient to set up but makes faster accessing because you don't have to +; increment the index register. For example, all the info about sprite #2 can +; be indexed using Y = 2 on the indexed operators, e.g. "lda sprite_active,y", +; "lda sprite_x,y", etc. + sprite_active - .byte 1, 1, 0, $ff ; 1 = active, 0 = skip, $ff = end of list + .byte 1, 1, 1, 1, 1, 1, 1, 1, $ff ; 1 = active, 0 = skip, $ff = end of list sprite_l - .byte COLORSPRITE, >BWSPRITE, 0, 0 + .byte >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE sprite_x - .byte 80, 64, 0, 0 + .byte 80, 64, 33, 83, 4, 9, 55, 18 sprite_y - .byte 116, 126, 0, 0 + .byte 116, 126, 40, 60, 80, 100, 120, 140 sprite_dx - .byte -1, 4, 0, 0 + .byte -1, -2, -3, -4, 1, 2, 3, 4 sprite_dy - .byte -3, 1, 0, 0 + .byte -4, -3, -2, -1, 4, 3, 2, 1 .include colorsprite.s @@ -203,3 +210,5 @@ sprite_dy .include rowlookup.s .include collookupbw.s .include collookupcolor.s + .include backingstore.s + .include backingstore-3x11.s