asmgen/HiSprite.py

233 lines
4.9 KiB
Python
Raw Normal View History

#!/usr/bin/python
import sys,os,png
class Colors:
2016-12-21 22:03:28 +00:00
black,magenta,green,orange,blue,white = range(6)
2016-09-10 18:04:57 +00:00
def main(argv):
if len(argv)<1:
2016-09-10 18:04:57 +00:00
printHorzontalLookup()
exit(0)
pngfile = sys.argv[1]
reader = png.Reader(pngfile)
try:
pngdata = reader.asRGB8()
except:
usage()
2016-09-10 18:04:57 +00:00
width = pngdata[0]
height = pngdata[1]
pixeldata = pngdata[2]
byteWidth = width/2+1+1 # TODO: Calculate a power of two for this
niceName = os.path.splitext(pngfile)[0].upper()
disclaimer()
2016-12-21 22:03:28 +00:00
# Prologue
2016-09-10 18:04:57 +00:00
print "%s: ;%d bytes per row" % (niceName,byteWidth)
print "\tSAVE_AXY"
print "\tldy PARAM0"
print "\tldx MOD7_2,y"
print "\tjmp (%s_JMP,x)\n" % (niceName)
2016-12-21 22:03:28 +00:00
# Bit-shift jump table
2016-09-10 18:04:57 +00:00
print "%s_JMP:" % (niceName)
for shift in range(0,7):
print "\t.addr %s_SHIFT%d" % (niceName,shift)
2016-12-21 22:03:28 +00:00
# Blitting functions
2016-09-10 18:04:57 +00:00
print "\n"
for shift in range(0,7):
print "%s_SHIFT%d:" % (niceName,shift)
print "\tldy PARAM0\n"
print "\tldx PARAM1"
print rowStartCalculatorCode();
spriteChunks = layoutSpriteChunk(pixeldata,width,height,shift)
for row in range(height):
for chunkIndex in range(len(spriteChunks)):
print spriteChunks[chunkIndex][row]
print "\n"
def layoutSpriteChunk(pixeldata,width,height,shift):
bitmap = [[0 for x in range(width)] for y in range(height)]
2016-09-10 18:04:57 +00:00
byteWidth = width/2+1+1 # TODO: Calculate a power of two for this
spriteChunks = [["" for y in range(height)] for x in range(byteWidth)]
2016-12-21 22:03:28 +00:00
# Layout rows
2016-09-10 18:04:57 +00:00
for row in range(height):
pixelRow = bitmap[row]
bitStream = ""
2016-12-21 22:03:28 +00:00
# Compute raw bitstream for row from PNG pixels
2016-09-10 18:04:57 +00:00
for pixelIndex in range(width):
pixel = pixelColor(pixeldata,row,pixelIndex)
if pixel == Colors.black:
bitStream += "00"
else:
2016-12-21 22:03:28 +00:00
if pixel == Colors.white:
bitStream += "11"
2016-09-10 18:04:57 +00:00
else:
2016-12-21 22:03:28 +00:00
if pixel == Colors.green or pixel == Colors.orange:
bitStream += "01"
else:
bitStream += "10"
# Shift bit stream as needed
2016-09-10 18:04:57 +00:00
bitStream = shiftStringRight(bitStream,shift)
bitStream = bitStream[:byteWidth*8]
2016-12-21 22:03:28 +00:00
# Split bitstream into bytes
2016-09-10 18:04:57 +00:00
bitPos = 0
byteSplits = [0 for x in range(byteWidth)]
for byteIndex in range(byteWidth):
remainingBits = len(bitStream) - bitPos
2016-09-10 18:04:57 +00:00
bitChunk = ""
2016-09-10 18:04:57 +00:00
if remainingBits < 0:
bitChunk = "0000000"
else:
if remainingBits < 7:
bitChunk = bitStream[bitPos:]
bitChunk += fillOutByte(7-remainingBits)
else:
bitChunk = bitStream[bitPos:bitPos+7]
bitChunk = bitChunk[::-1]
2016-12-21 22:03:28 +00:00
# Set palette bit as needed. Note that we prefer high-bit white
# because blue fringe is less noticeable than magenta
2016-09-10 18:04:57 +00:00
highBit = "0"
2016-12-21 22:03:28 +00:00
if pixel == Colors.orange or pixel == Colors.blue or pixel == Colors.white:
2016-09-10 18:04:57 +00:00
highBit = "1"
byteSplits[byteIndex] = highBit + bitChunk
bitPos += 7
2016-12-21 22:03:28 +00:00
# Generate blitting code
2016-09-10 18:04:57 +00:00
for chunkIndex in range(len(byteSplits)):
2016-12-21 22:03:28 +00:00
# Store byte into video memory
spriteChunks[chunkIndex][row] = \
"\tlda #%%%s\n" % byteSplits[chunkIndex] + \
"\tsta (SCRATCH0),y\n";
2016-09-10 18:04:57 +00:00
2016-12-21 22:03:28 +00:00
# Increment indices
2016-09-10 18:04:57 +00:00
if chunkIndex == len(byteSplits)-1:
spriteChunks[chunkIndex][row] += "\n"
else:
spriteChunks[chunkIndex][row] += "\tiny"
2016-12-21 22:03:28 +00:00
# Finish the row
2016-09-10 18:04:57 +00:00
if row<height-1:
spriteChunks[chunkIndex][row] += "\tinx\n" + rowStartCalculatorCode();
else:
spriteChunks[chunkIndex][row] += "\tRESTORE_AXY\n"
spriteChunks[chunkIndex][row] += "\trts\n"
return spriteChunks
2016-09-10 18:04:57 +00:00
def rowStartCalculatorCode():
return \
"\tlda HGRROWS_H,x\n" + \
"\tsta SCRATCH1\n" + \
"\tlda HGRROWS_L,x\n" + \
"\tsta SCRATCH0\n" + \
"\tldy PARAM0\n" + \
"\tlda DIV7_2,y\n" + \
"\ttay\n";
def fillOutByte(numBits):
filler = ""
for bit in range(numBits):
filler += "0"
2016-09-10 18:04:57 +00:00
return filler
2016-09-10 18:04:57 +00:00
def shiftStringRight(string,shift):
if shift==0:
return string
shift *=2
result = ""
for i in range(shift):
result += "0"
result += string
return result
def pixelColor(pixeldata,row,col):
r = pixeldata[row][col*3]
g = pixeldata[row][col*3+1]
b = pixeldata[row][col*3+2]
color = Colors.black
if r==255 and g==0 and b==255:
color = Colors.magenta
else:
if r==0 and g==255 and b==0:
color = Colors.green
2016-09-10 18:04:57 +00:00
else:
if r==0 and g==0 and b==255:
color = Colors.blue
else:
if r==255 and g>0 and b==0:
color = Colors.orange
2016-12-21 22:03:28 +00:00
else:
if r==255 and g==255 and b==255:
color = Colors.white
return color
2016-09-10 18:04:57 +00:00
def printHorzontalLookup():
disclaimer()
2016-09-10 18:04:57 +00:00
print "DIV7_2:"
for pixel in range(140):
print "\t.byte $%02x" % ((pixel / 7)*2)
2016-09-10 18:04:57 +00:00
print "\n\nMOD7_2:"
for pixel in range(140):
print "\t.byte $%02x" % ((pixel % 7)*2)
def usage():
print '''
Usage: HiSprite <png file>
PNG file must not have an alpha channel!
'''
sys.exit(2)
2016-09-10 18:04:57 +00:00
2016-09-10 18:04:57 +00:00
def disclaimer():
print '''
2016-12-21 22:03:28 +00:00
; This file was generated by HiSprite.py, a sprite compiler by Quinn Dunki.
2016-09-10 18:04:57 +00:00
; If you feel the need to modify this file, you are probably doing it wrong.
'''
return
if __name__ == "__main__":
2016-09-10 18:04:57 +00:00
main(sys.argv[1:])
2016-12-21 22:03:28 +00:00