diff options
author | Bryan Bishop <kanzure@gmail.com> | 2013-02-11 17:40:54 -0800 |
---|---|---|
committer | Bryan Bishop <kanzure@gmail.com> | 2013-02-11 17:40:54 -0800 |
commit | b62d644d93f4c435fab792278cf2754e72cf62a4 (patch) | |
tree | 5f32f9378e1fd4828f3f21998ae2948f0afd4036 /extras/gfx.py | |
parent | 706361ea5f5b7339e44ac4886fa6e793605ae0fd (diff) | |
parent | 8b8f7200a9bdae9396180bebedce69298677e8a6 (diff) |
Merge pull request #108 from yenatch/master
png->lz and palettes
Diffstat (limited to 'extras/gfx.py')
-rw-r--r-- | extras/gfx.py | 242 |
1 files changed, 213 insertions, 29 deletions
diff --git a/extras/gfx.py b/extras/gfx.py index 65eac7183..c641ab7f1 100644 --- a/extras/gfx.py +++ b/extras/gfx.py @@ -8,10 +8,11 @@ from math import sqrt, floor, ceil from crystal import load_rom from pokemon_constants import pokemon_constants +from trainers import trainer_group_names - -rom = load_rom() +if __name__ != "__main__": + rom = load_rom() def mkdir_p(path): @@ -953,17 +954,6 @@ def decompress_misc(): def decompress_all(debug = False): """decompress all known compressed data in baserom""" - #mkdir_p('../gfx/') - #mkdir_p('../gfx/frontpics/') - #mkdir_p('../gfx/anim/') - #mkdir_p('../gfx/backpics/') - #mkdir_p('../gfx/trainers/') - #mkdir_p('../gfx/fx/') - #mkdir_p('../gfx/intro/') - #mkdir_p('../gfx/title/') - #mkdir_p('../gfx/tilesets/') - #mkdir_p('../gfx/misc/') - if debug: print 'fronts' decompress_monsters(front) if debug: print 'backs' @@ -1032,7 +1022,7 @@ def compress_monster_frontpic(id, fileout): anim = open(fanim, 'rb').read() image = pic + anim - lz = Compressed(image, mode, 5) + lz = Compressed(image, mode, sizes[id-1]) out = '../gfx/pics/' + str(id).zfill(3) + '/front.lz' @@ -1081,6 +1071,8 @@ def grab_palettes(address, length = 0x80): def dump_monster_pals(): + rom = load_rom() + pals = 0xa8d6 pal_length = 0x4 for mon in range(251): @@ -1116,6 +1108,31 @@ def dump_monster_pals(): #print name+'ShinyPalette:'+spacing+' INCBIN "'+dir+filename+'"' +def dump_trainer_pals(): + rom = load_rom() + + pals = 0xb0d2 + pal_length = 0x4 + for trainer in range(67): + + name = trainer_group_names[trainer+1]['constant'].title().replace('_','') + num = str(trainer).zfill(3) + dir = 'gfx/trainers/' + + address = pals + trainer*pal_length + + pal_data = [] + for byte in range(pal_length): + pal_data.append(ord(rom[address])) + address += 1 + + filename = num+'.pal' + to_file('../'+dir+filename, pal_data) + + spacing = ' ' * (12 - len(name)) + print name+'Palette:'+spacing+' INCBIN"'+dir+filename+'"' + + def flatten(planar): """ @@ -1184,22 +1201,58 @@ def to_png(filein, fileout=None, pal_file=None, height=None, width=None): Takes a planar 2bpp graphics file and converts it to png. """ - if fileout == None: fileout = ''.join(filein.split('.')[:-1]) + '.png' + if fileout == None: fileout = '.'.join(filein.split('.')[:-1]) + '.png' image = open(filein, 'rb').read() - + num_pixels = len(image) * 4 + + if num_pixels == 0: return 'empty image!' + + # unless the pic is square, at least one dimension should be given - if height == None and width == None: - height = int(sqrt(len(image)*4)) - width = height + if width == None and height == None: + width = int(sqrt(num_pixels)) + height = width - elif height == None: height = len(image)*4 / width + elif height == None: + height = num_pixels / width - elif width == None: width = len(image)*4 / height + elif width == None: + width = num_pixels / height + + + # but try to see if it can be made rectangular + + if width * height != num_pixels: + + # look for possible combos of width/height that would form a rectangle + matches = [] + + # this is pretty inefficient, and there is probably a simpler way + for width in range(8,256+1,8): # we only want dimensions that fit in tiles + height = num_pixels / width + if height % 8 == 0: + matches.append((width, height)) + + # go for the most square image + width, height = sorted(matches, key=lambda (x,y): x+y)[0] # favors height + + + # if it can't, the only option is a width of 1 tile + + if width * height != num_pixels: + width = 8 + height = num_pixels / width + + + # if this still isn't rectangular, then the image isn't made of tiles - assert height * width == len(image)*4, 'Please specify dimensions for non-square image!' + # for now we'll just spit out a warning + if width * height != num_pixels: + print 'Warning! ' + fileout + ' is ' + width + 'x' + height + '(' + width*height + ' pixels),\n' +\ + 'but ' + filein + ' is ' + num_pixels + ' pixels!' # map it out @@ -1233,7 +1286,7 @@ def to_2bpp(filein, fileout=None, palout=None): Takes a png and converts it to planar 2bpp. """ - if fileout == None: fileout = ''.join(filein.split('.')[:-1]) + '.2bpp' + if fileout == None: fileout = '.'.join(filein.split('.')[:-1]) + '.2bpp' with open(filein, 'rb') as file: @@ -1355,6 +1408,87 @@ def to_2bpp(filein, fileout=None, palout=None): to_file(fileout, image) +def png_to_lz(filein): + + name = os.path.splitext(filein)[0] + + to_2bpp(filein) + image = open(name+'.2bpp', 'rb').read() + to_file(name+'.lz', Compressed(image).output) + + + + +def mass_to_png(debug=False): + # greyscale + for root, dirs, files in os.walk('../gfx/'): + for name in files: + if debug: print os.path.splitext(name), os.path.join(root, name) + if os.path.splitext(name)[1] == '.2bpp': + to_png(os.path.join(root, name)) + +def mass_to_colored_png(debug=False): + # greyscale + for root, dirs, files in os.walk('../gfx/'): + if 'pics' not in root and 'trainers' not in root: + for name in files: + if debug: print os.path.splitext(name), os.path.join(root, name) + if os.path.splitext(name)[1] == '.2bpp': + to_png(os.path.join(root, name)) + + # only monster and trainer pics for now + for root, dirs, files in os.walk('../gfx/pics/'): + for name in files: + if debug: print os.path.splitext(name), os.path.join(root, name) + if os.path.splitext(name)[1] == '.2bpp': + if 'normal.pal' in files: + to_png(os.path.join(root, name), None, os.path.join(root, 'normal.pal')) + else: + to_png(os.path.join(root, name)) + for root, dirs, files in os.walk('../gfx/trainers/'): + for name in files: + if debug: print os.path.splitext(name), os.path.join(root, name) + if os.path.splitext(name)[1] == '.2bpp': + to_png(os.path.join(root, name), None, os.path.join(root, name[:-5] + '.pal')) + + +def mass_decompress(debug=False): + for root, dirs, files in os.walk('../gfx/'): + for file in files: + if 'lz' in file: + if '/pics' in root: + if 'front' in file: + id = root.split('pics/')[1][:3] + if id != 'egg': + with open(root+'/'+file, 'rb') as lz: de = Decompressed(lz.read(), 'vert', sizes[int(id)-1]) + else: + with open(root+'/'+file, 'rb') as lz: de = Decompressed(lz.read(), 'vert', 4) + to_file(root+'/'+'front.2bpp', de.pic) + to_file(root+'/'+'tiles.2bpp', de.animtiles) + elif 'back' in file: + with open(root+'/'+file, 'rb') as lz: de = Decompressed(lz.read(), 'vert') + to_file(root+'/'+'back.2bpp', de.output) + elif '/trainers' in root or '/fx' in root: + with open(root+'/'+file, 'rb') as lz: de = Decompressed(lz.read(), 'vert') + to_file(root+'/'+file[:-3]+'.2bpp', de.output) + else: + with open(root+'/'+file, 'rb') as lz: de = Decompressed(lz.read()) + to_file(root+file[:-3]+'.2bpp', de.output) + +def append_terminator_to_lzs(directory): + # fix lzs that were extracted with a missing terminator + for root, dirs, files in os.walk(directory): + for file in files: + if '.lz' in file: + data = open(root+file,'rb').read() + if data[-1] != chr(0xff): + data += chr(0xff) + new = open(root+file,'wb') + new.write(data) + new.close() + + + if __name__ == "__main__": parser = argparse.ArgumentParser() @@ -1362,12 +1496,60 @@ if __name__ == "__main__": parser.add_argument('arg1', nargs='?', metavar='arg1', type=str) parser.add_argument('arg2', nargs='?', metavar='arg2', type=str) parser.add_argument('arg3', nargs='?', metavar='arg3', type=str) + parser.add_argument('arg4', nargs='?', metavar='arg4', type=str) + parser.add_argument('arg5', nargs='?', metavar='arg5', type=str) args = parser.parse_args() - debug = True + debug = False + + if args.cmd == 'dump-pngs': + mass_to_colored_png() + + elif args.cmd == 'png-to-lz': + # python gfx.py png-to-lz [--front anim(2bpp) | --vert] [png] + + # python gfx.py png-to-lz --front [anim(2bpp)] [png] + if args.arg1 == '--front': + + # front.png and tiles.png are combined before compression, + # so we have to pass in things like anim file and pic size + name = os.path.splitext(args.arg3)[0] + + to_2bpp(name+'.png', name+'.2bpp') + pic = open(name+'.2bpp', 'rb').read() + anim = open(args.arg2, 'rb').read() + size = int(sqrt(len(pic)/16)) # assume square pic + to_file(name+'.lz', Compressed(pic + anim, 'vert', size).output) + + + # python gfx.py png-to-lz --vert [png] + elif args.arg1 == '--vert': + + # others are vertically oriented (frontpics are always vertical) + + name = os.path.splitext(args.arg2)[0] + + to_2bpp(name+'.png', name+'.2bpp') + pic = open(name+'.2bpp', 'rb').read() + to_file(name+'.lz', Compressed(pic + anim, 'vert').output) + + + # python gfx.py png-to-lz [png] + else: + + # standard usage + + png_to_lz(args.arg1) + + elif args.cmd == 'png-to-2bpp': + to_2bpp(args.arg1) - if args.cmd == 'de': + + elif args.cmd == 'de': # python gfx.py de [addr] [fileout] [mode] + + rom = load_rom() + addr = int(args.arg1,16) fileout = args.arg2 mode = args.arg3 @@ -1388,10 +1570,12 @@ if __name__ == "__main__": elif args.cmd == 'un': # python gfx.py un [address] [num_tiles] [filename] + rom = load_rom() get_uncompressed_gfx(int(args.arg1,16), int(args.arg2), args.arg3) elif args.cmd == 'pal': # python gfx.py pal [address] [length] + rom = load_rom() print grab_palettes(int(args.arg1,16), int(args.arg2)) elif args.cmd == 'png': @@ -1405,8 +1589,8 @@ if __name__ == "__main__": elif '.png' in args.arg1: to_2bpp(args.arg1, args.arg2) - #else: - ## python gfx.py - #decompress_all() - #if debug: print 'decompressed known gfx to ../gfx/!' + elif args.cmd == 'mass-decompress': + mass_decompress() + if debug: print 'decompressed known gfx to pokecrystal/gfx/!' + |