From 8817689276d5a6bc34b8287bf5489a6960d0a1f9 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Fri, 27 Aug 2010 23:44:29 -0400 Subject: [PATCH] added a command line interface --- chunk.py | 5 +++++ render.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ world.py | 17 ++++++++------ 3 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 render.py diff --git a/chunk.py b/chunk.py index 9d06a04..3037294 100644 --- a/chunk.py +++ b/chunk.py @@ -71,6 +71,11 @@ class ChunkRenderer(object): """Finds a hash of the block array""" h = hashlib.md5() h.update(self.level['Blocks']) + + # If the render algorithm changes, change this line to re-generate all + # the chunks automatically: + #h.update("1") + digest = h.hexdigest() # 6 digits ought to be plenty return digest[:6] diff --git a/render.py b/render.py new file mode 100644 index 0000000..ccc9843 --- /dev/null +++ b/render.py @@ -0,0 +1,66 @@ +#!/usr/bin/python + +import os +import sys +import os.path +from optparse import OptionParser +import re + +import world + +helptext = """ +%prog [-c] +%prog -d [-c] """ + +def remove_images(worlddir, cavemode): + if cavemode: + cavestr = "cave" + else: + cavestr = "nocave" + imgre = r"img\.[^.]+\.[^.]+\.{0}\.\w+\.png$".format(cavestr) + matcher = re.compile(imgre) + + for dirpath, dirnames, filenames in os.walk(worlddir): + for f in filenames: + if matcher.match(f): + filepath = os.path.join(dirpath, f) + print "Deleting {0}".format(filepath) + os.unlink(filepath) + +def confirm(imgfile): + answer = raw_input("Overwrite existing image at %r? [Y/n]" % imgfile).strip() + if not answer or answer.lower().startswith("y"): + return True + return False + +def main(): + parser = OptionParser(usage=helptext) + parser.add_option("-c", "--caves", dest="caves", help="Render only caves", action="store_true") + parser.add_option("-d", "--delete-cache", dest="delete", help="Deletes the image files cached in your world directory", action="store_true") + parser.add_option("-p", "--processes", dest="procs", help="How many chunks to render in parallel. A good number for this is 1 more than the number of cores in your computer. Default 2", default=2, action="store", type="int") + + options, args = parser.parse_args() + + if len(args) < 1: + print "You need to give me your world directory" + parser.print_help() + sys.exit(1) + worlddir = args[0] + + if options.delete: + remove_images(worlddir, options.caves) + else: + if len(args) != 2: + parser.error("What do you want to save the image as?") + imageout = args[1] + if not imageout.endswith(".png"): + imageout = imageout + ".png" + if os.path.exists(imageout) and not confirm(imageout): + return + imageobj = world.render_world(worlddir, options.caves, options.procs) + print "Saving image..." + imageobj.save(imageout) + print "Saved as", imageout + +if __name__ == "__main__": + main() diff --git a/world.py b/world.py index b0dc256..9d3f668 100644 --- a/world.py +++ b/world.py @@ -38,12 +38,13 @@ def find_chunkfiles(worlddir): for dirpath, dirnames, filenames in os.walk(worlddir): if not dirnames and filenames: for f in filenames: - p = f.split(".") - all_chunks.append((base36decode(p[1]), base36decode(p[2]), - os.path.join(dirpath, f))) + if f.startswith("c.") and f.endswith(".dat"): + p = f.split(".") + all_chunks.append((base36decode(p[1]), base36decode(p[2]), + os.path.join(dirpath, f))) return all_chunks -def render_world(worlddir, cavemode=False): +def render_world(worlddir, cavemode=False, procs=2): print "Scanning chunks..." all_chunks = find_chunkfiles(worlddir) @@ -101,6 +102,8 @@ def render_world(worlddir, cavemode=False): print "Final image will be {0}x{1}. (That's {2} bytes!)".format( width, height, width*height*4) + print "Don't worry though, that's just the memory requirements" + print "The final png will be much smaller" # Oh god create a giant ass image worldimg = Image.new("RGBA", (width, height)) @@ -110,8 +113,8 @@ def render_world(worlddir, cavemode=False): print "Sorting chunks..." all_chunks.sort(key=lambda x: x[1]-x[0]) - print "Starting chunk processors..." - pool = multiprocessing.Pool(processes=3) + print "Starting up {0} chunk processors...".format(procs) + pool = multiprocessing.Pool(processes=procs) resultsmap = {} for chunkx, chunky, chunkfile in all_chunks: result = pool.apply_async(chunk.render_and_save, args=(chunkfile,), @@ -143,7 +146,7 @@ def render_world(worlddir, cavemode=False): # Draw the image sans alpha layer, using the alpha layer as a mask. (We # don't want the alpha layer actually drawn on the image, this pastes # it as if it was a layer) - worldimg.paste(chunkimg.convert("RGB"), (imgx, imgy), chunkimg.split()[3]) + worldimg.paste(chunkimg.convert("RGB"), (imgx, imgy), chunkimg) processed += 1