#!/usr/bin/env python #-*- coding:utf-8 -*- import sys import os import subprocess import tempfile CLIENT_DATA_ROOT = os.path.realpath( os.path.join( os.path.dirname(__file__), u'../../client-data', ) ) SKIP_DOMAIN="030-" class MinimapRenderer(object): PROGRAMS = { 'default': { 'tmxrasterizer': 'tmxrasterizer', 'im_convert': 'convert', }, 'win32': { 'tmxrasterizer': 'tmxrasterizer.exe', 'im_convert': 'convert.exe', }, } def __init__(self, map_name, tilesize, useAntiAliasing): self.map_name = map_name self.tilesize = tilesize self.useAntiAliasing = useAntiAliasing def render(self): """ Processes a map """ if not os.path.exists(os.path.join(CLIENT_DATA_ROOT, u'maps', self.map_name+u'.tmx')): sys.stderr.write(u'Invalid map name: %s. Skipping.\n' % self.map_name) return 1 if not self.map_name.endswith(u'.tmx'): self.map_name = self.map_name+u'.tmx' if SKIP_DOMAIN in self.map_name: print(u'Skipping %s (regex)...\n' % self.map_name) return 0 map_number = os.path.splitext(os.path.basename(self.map_name))[0] tmx_file = os.path.join(CLIENT_DATA_ROOT, u'maps', self.map_name) minimap_file = os.path.join(CLIENT_DATA_ROOT, u'graphics', u'minimaps', map_number+u'.png') prefix = os.path.commonprefix((tmx_file, minimap_file)) sys.stdout.write(u'%s -> %s\n' % (os.path.relpath(tmx_file, prefix), os.path.relpath(minimap_file, prefix))) try: self.do_render(tmx_file, minimap_file) except Exception as e: sys.stderr.write(u'\x1b[31m\x1b[1mError while rendering %s: %s\x1b[0m\n' % (self.map_name, e)) return 1 else: return 0 def do_render(self, tmx_file, bitmap_file): """ The map rendering implementation """ platform_programs = MinimapRenderer.PROGRAMS.get(sys.platform, MinimapRenderer.PROGRAMS.get('default')) # tmx rasterize mrf, map_raster = tempfile.mkstemp(suffix='.png') tmxrasterizer_cmd = [ platform_programs.get('tmxrasterizer'), '--tilesize', str(self.tilesize), '--hide-layer', 'Collision','--hide-layer', 'Height','--hide-layer', 'Collisions','--hide-layer', 'collision','--hide-layer', 'height','--hide-layer', 'Heights', '--hide-layer', 'height', '--ignore-visibility', ] if self.useAntiAliasing: tmxrasterizer_cmd.append('--anti-aliasing') tmxrasterizer_cmd += [tmx_file, map_raster] subprocess.check_call(tmxrasterizer_cmd) if os.stat(map_raster).st_size == 0: raise Exception('A problem was encountered when rendering a map') # add cell-shading to the minimap to improve readability ebf, edges_bitmap = tempfile.mkstemp(suffix='.png') subprocess.check_call([ platform_programs.get('im_convert'), map_raster, '-set', 'option:convolve:scale', '-1!', '-morphology', 'Convolve', 'Laplacian:0', '-colorspace', 'gray', '-auto-level', '-threshold', '2.8%', '-negate', '-transparent', 'white', edges_bitmap ]) subprocess.check_call([ platform_programs.get('im_convert'), map_raster, edges_bitmap, '-compose', 'Dissolve', '-define', 'compose:args=35', '-composite', bitmap_file ]) os.unlink(map_raster) os.unlink(edges_bitmap) @staticmethod def check_programs(): """ Checks the require programs are available """ def which(program): import os def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file return None platform_programs = MinimapRenderer.PROGRAMS.get(sys.platform, MinimapRenderer.PROGRAMS.get('default')) for program in platform_programs.values(): if not which(program): raise Exception('The required "%s" program is missing from your PATH.' % program) def usage(): sys.stderr.write(u'''Usage: %s MAP_NAME... Example: $ ./minimap-render.py 007-1 will render the map at maps/007-1.tmx in the graphics/minimaps directory. $ ./minimap-render.py all will render all existing maps found in the maps directory. $ ./minimap-render.py update will update all existing minimaps found in the graphics/minimaps directory. For convenience, $ ./minimap-render.py 007-1.tmx is also accepted. \n''' % sys.argv[0]) def main(): if not len(sys.argv) > 1: usage() return 127 try: MinimapRenderer.check_programs() except Exception as e: sys.stderr.write(u'%s\n' % e) return 126 status = 0 if sys.argv[1].lower() == 'all': map_names = sorted([os.path.splitext(p)[0] for p in os.listdir(os.path.join(CLIENT_DATA_ROOT, u'maps'))]) elif sys.argv[1].lower() == 'update': map_names = sorted([os.path.splitext(p)[0] for p in os.listdir(os.path.join(CLIENT_DATA_ROOT, u'graphics', u'minimaps'))]) else: map_names = sys.argv[1:] for map_name in map_names: # Render tiles at 1 pixel size map_renderer = MinimapRenderer(map_name, 1, True) status += map_renderer.render() return 0 if __name__ == '__main__': sys.exit(main())