From d748e2b73744a6328bcda96cb37e1563feab8ed5 Mon Sep 17 00:00:00 2001 From: Rob McMullen Date: Sun, 2 Jul 2017 21:38:32 -0700 Subject: [PATCH] push/pull framework for drawing sprites to either page --- HiSprite.py | 57 +++++++++++++++++++++++++++++++++++++------------- Makefile.rob | 2 +- multitest.dsk | Bin 143360 -> 143360 bytes multitest.s | 35 +++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 16 deletions(-) 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 4661445ac11843cb5aa6b51916498a26061d9f2b..77a4af986d041f8069cda09dadc8f0def2e8a21f 100644 GIT binary patch literal 143360 zcmeI%Z;TY>9l-IuKkV*F0jt#5P+w49T!0#KC27S2dwrgH_LewD;oDkoA^jw>`9K^}~;>S=;{Ty2l=0-?3rirp<|D zHgwe@wm+PCr6U#XJrrvgFAjFaa&lvbc&aOA#hVicBHhuxV;h@K?aH4&ye2id@4n5c z*#4;8Wvb}b`)(IM>57%MjTd>{wpFCc+XhYBPcN@6Wb)*OzrRYy3?7S_wLYjj;gN%y z##lo{{Pj{2-fVpbQA!bUN_VhbJnbKKM4UHmWrCI43KH8znMCEhz_E`1fya=zFHUxi8h;Z0&AudUVFR$&b}N z9$x?c`ij@xV#QY~>N`PE*-7AO3^=o)E^q!*#fb{@m&aTp-Yn@^O=gpLuDGsfnl6A9 z|A$&at_fH|RQ5gMx5e2}zrOok?dVsRRh3Um$quDjBZ+RkI((aWxpW+|Zku?fxUOhs z?wl_%vsL1k#o1ABJaVH+{2{ol{IfUOInnjO$GXh6(aulth&KwyKVq*JOZ;lowt$(A z7loy|Qd__=y}T=J3+T_CgI;es#LxY+sMMpk%m$3cYYRB$$8HPg&l~3k@qEb~)F<2b z3n!?0mlq( ztFBTpEJJ@K$J(0vCbczNGuxUTdTQ05R)6&H9cvz3JNoySoZAHPe#wO=tGvDf=Iyol z$Eeo-pi^z?{l~h}`jUQk<^O4=L(Yx1GsRBFoq9Xn~Gq3+P0;bHkVm;c~wy?u77 z{hNCGL{sOP?y7wu`E@QI1zy;c`pA7ANL|cW_6e)ACevki#kww@I+5*sFPEKtusVOt z3hip0BmYFz%bYrQyWZW_^?Ti#y>3mtyB*s5&a3jzF7@(iox2@%w{?A?wW!`bf%0Xn z8(X%txzXOkTk$8XBaK#FP5hh{uTLzUXob?D)KM!wAz=+1?K#>|m3nuuwy`y9 z$!sefO&vMgVs(dhiXPDr>CODn9*kuU+s8d^F z;iUcHkllaKO{i{@2`AlzllC^ZS|!NpgR(j&JKb${hxZMi(Q!Ec@1h0LeMYJL)aNZ- zTT5?`)H>lk5q5}Y{nvxH2nQ@jmD>t8_8sLn_LcLx^|j<1OTZ%RKBHEcwYnlZ%5Q)? z2}}IKKii_VvYVsIZH3ud<+H7vm({cNjiu;|(sc-$DEKrB16 z^RT7UHzp56RQi^rvm@!G-1KD9c_QiTl<9|tUJk``r%H-}h@1ZZhsfviErpPqZpgdb zp>#HNLEg+B8gk|(a`JV)dQFAZOC%?6U?;t}dMGv2b75^Lb)i4o`Hr=qXXtdjsyQud zx9twRNQ(G_o)2IO5y$`;ruP(oOIKV zC7k04=kGGTM73ZnaaFn+;>@BUE>lDN?)^VpeD}AO-M8|AADOagN%PW{72o@TDewCF zJ@>Y7UFW>`_E^^_w&E})#UDfp#}pk?b;NZ{({YoI={jcUn5pAt9kX=&PtIK7 ze>Bxoo-JM~d6H9gP2%-{y3!x;^?pHh@^NnDhqLJD`<3)j^wegnXG^QFeiVM^sMb-V zqgKZl9bp|29Z?-ZhyHnF>@_;B)iG|IS)3>lKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ N1Q0*~fls=?e*uF;pTPhC literal 143360 zcmeI%eQ+FQ9l-I+OYiOhG@%IXVQ8D-FrH58`VVtqoEV%bI!+z(hs4xzI)^h5xH86P_qpe| zyWP74>P%KzD^xJO;aRxn=9N?e{OYcUSkGz58Nu zJ8;>e`JnjTvB>0b-QL9Y!%yr>L{5cIN18)o@>nD-Hx7zNysdR&Otl^o-#r#FqDNx= zp@IVhQ?GUt$KLn?!{f@zi4a3&%AxF5poFnHJNag1}-*h#X>GaaBuNA*i2d~_1-|OHVl=lX{M*Oq<NgX?)S#INMW?4H#EYY2e{z$019I0D zJ2G2RXUzI}E9Gu)zhI7Jdln?Cj-N4;f#dyV{k8LD^#Qj!l$>^|v$8rh>Lv`DZ@*}c z47mxTPQsv@FlZidtDOW{JtV8s@}xg9dV?pY|Docgu{V#7y>27})|*B$YE8+l-oWwc z>GW9k!jv&MRlMkuw|4&J&iAcsq3A8Ry(=v5^Rq_E` z`m+7vffFNu00Iaga2W;mS#@#iy0~>i{N(iM?9+j0da|gP2-yuiFBvQQvgem1vV9lN z2ND;11Ib5^Wz)&H{OAihAE87<7X88DSG%m;@&1ThOj~>6)`7TnI4)mPt?szBKW=?T zo?|!=m3vMW6%!GAi9Cl&A5_01vwjh`ejT@d=cfNWZl&UuUA~J>`ujs{QZbN=_FRnR z;=TTy3?#BiJ8@C2l22!??pRuW?r}a7LFXfsmMi1=Pi@aSlshElh~0D6#ce3Sos>e! znB(ff{e4W~{vl?)60`mqb8tsv*4dbKE>;%Txqu4y${cQe+?p4+7D(K+Uta&UP4|3j zO|ERcqitRL#?9Z<zM@3LYNJUtMP;rHdD^*;j;sYu^sG?3qy^5<<%vEuXiVvx{R>gHH=Bb#k zBBJ7Y6(3g7pyCD<3sfvr5mm8B#f>T!tGG$U5*15TG^)s7T=y?O@@3NdR;J$M++Xzj z|AEul!SuY$Ikm0g`I1*WRqOYskyg(uU8Q~fkKlJUQ~X%IrRL@j=l3Eqs#VmesC7b5 zFq8-&fB*srAb 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