From 40623c146ac1e5210d20bcb47d313c2659c665f2 Mon Sep 17 00:00:00 2001 From: Vincent Petithory Date: Sat, 22 Sep 2012 21:51:47 +0200 Subject: Add a tool to render minimaps --- client/minimap-render.py | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100755 client/minimap-render.py (limited to 'client/minimap-render.py') diff --git a/client/minimap-render.py b/client/minimap-render.py new file mode 100755 index 0000000..402630b --- /dev/null +++ b/client/minimap-render.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +import sys +import os +import subprocess +import tempfile +import re + + +class MinimapRenderer(object): + + MAP_RE = re.compile(r'^\d{3}-\d{1}(\.tmx)?$') + PROGRAMS = { + 'default': { + 'tmxrasterizer': 'tmxrasterizer', + 'im_convert': 'convert', + }, + 'win32': { + 'tmxrasterizer': 'tmxrasterizer.exe', + 'im_convert': 'convert.exe', + }, + } + + def __init__(self, map_name, scale): + self.map_name = map_name + self.scale = scale + + def render(self): + """ + Processes a map + """ + if not MinimapRenderer.MAP_RE.match(self.map_name): + 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' + + map_number = os.path.splitext(os.path.basename(self.map_name))[0] + tmx_file = os.path.normpath(os.path.join(os.getcwdu(), u'..', u'maps', self.map_name)) + minimap_file = os.path.normpath(os.path.join(os.getcwdu(), u'..', 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') + subprocess.check_call([platform_programs.get('tmxrasterizer'), '--scale', str(self.scale), tmx_file, map_raster]) + if os.stat(map_raster).st_size == 0: + # the image couldnt be rendered. The most probable reason is + # that the map was too big (e.g 024-4, 500x500 tiles) + raise Exception('Map too large to be rendered.') + # 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. + + For convenience, + $ ./minimap-render.py 007-1.tmx + is also acceptable, for e.g running things like, + $ ./minimap-render.py $(ls ../maps/) + that would render all existing maps. + \n''' % sys.argv[0]) + +def main(): + if not len(sys.argv) > 1: + usage() + return 127 + if not os.path.basename(os.path.dirname(os.getcwdu())) == u'client-data': + sys.stderr.write(u'This script must be run from client-data/tools.\n') + return 1 + try: + MinimapRenderer.check_programs() + except Exception as e: + sys.stderr.write(u'%s\n' % e) + return 126 + + status = 0 + for map_name in sys.argv[1:]: + map_renderer = MinimapRenderer(map_name, 0.03125) # this scale renders 1px for a tile of 32px + status += map_renderer.render() + return status + +if __name__ == '__main__': + sys.exit(main()) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 2daee52eec6ace68bf49779acba61056aeba11be Mon Sep 17 00:00:00 2001 From: Vincent Petithory Date: Mon, 18 Feb 2013 23:11:40 +0100 Subject: Map tools: use new --tilesize option of tmwrasterizer and update some things --- client/map-diff.py | 20 ++++++++++++-------- client/minimap-render.py | 23 +++++++++++++++-------- 2 files changed, 27 insertions(+), 16 deletions(-) (limited to 'client/minimap-render.py') diff --git a/client/map-diff.py b/client/map-diff.py index b872d47..1da5cde 100755 --- a/client/map-diff.py +++ b/client/map-diff.py @@ -75,11 +75,13 @@ class MapDiff(object): def _rastermap(self, tmx): tmxf, tmxraster = tempfile.mkstemp(suffix='.png') - subprocess.check_call([self.platform_programs.get('tmxrasterizer'), tmx, tmxraster]) + subprocess.check_call([ + self.platform_programs.get('tmxrasterizer'), + '--scale', '1.0', + tmx, tmxraster + ]) if os.stat(tmxraster).st_size == 0: - # the image couldnt be rendered. The most probable reason is - # that the map was too big (e.g 024-4, 500x500 tiles) - raise Exception('Map too large to be rendered.') + raise Exception('A problem was encountered when rendering a map') return tmxraster @@ -107,10 +109,12 @@ class MapGitRevDiff(MapDiff): # We have the 2 revs to compare. Let's extract the related tmx file p1 = self._mktmx_from_rev(c1) p2 = self._mktmx_from_rev(c2) - difftmxpath = '%s_%s-%s.png' % (self.map_number, c1, c2) - self._diffmaps(p1, p2, difftmxpath) - os.unlink(p1) - os.unlink(p2) + try: + difftmxpath = '%s_%s-%s.png' % (self.map_number, c1, c2) + self._diffmaps(p1, p2, difftmxpath) + finally: + os.unlink(p1) + os.unlink(p2) def _mktmx_from_rev(self, rev): p = subprocess.Popen([self.platform_programs.get('git'), '--no-pager', 'show', '%s:%s' % (rev, self.tmx_path)], stdout=subprocess.PIPE) diff --git a/client/minimap-render.py b/client/minimap-render.py index 402630b..6b6b009 100755 --- a/client/minimap-render.py +++ b/client/minimap-render.py @@ -22,9 +22,10 @@ class MinimapRenderer(object): }, } - def __init__(self, map_name, scale): + def __init__(self, map_name, tilesize, useAntiAliasing): self.map_name = map_name - self.scale = scale + self.tilesize = tilesize + self.useAntiAliasing = useAntiAliasing def render(self): """ @@ -58,11 +59,16 @@ class MinimapRenderer(object): platform_programs = MinimapRenderer.PROGRAMS.get(sys.platform, MinimapRenderer.PROGRAMS.get('default')) # tmx rasterize mrf, map_raster = tempfile.mkstemp(suffix='.png') - subprocess.check_call([platform_programs.get('tmxrasterizer'), '--scale', str(self.scale), tmx_file, map_raster]) + tmxrasterizer_cmd = [ + platform_programs.get('tmxrasterizer'), + '--tilesize', str(self.tilesize), + ] + 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: - # the image couldnt be rendered. The most probable reason is - # that the map was too big (e.g 024-4, 500x500 tiles) - raise Exception('Map too large to be rendered.') + 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([ @@ -140,9 +146,10 @@ def main(): status = 0 for map_name in sys.argv[1:]: - map_renderer = MinimapRenderer(map_name, 0.03125) # this scale renders 1px for a tile of 32px + # Render tiles at 1 pixel size + map_renderer = MinimapRenderer(map_name, 1, True) status += map_renderer.render() return status if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file + sys.exit(main()) -- cgit v1.2.3-70-g09d2 From 795fe02f1080ff254d279ae28187df8fb1beb78e Mon Sep 17 00:00:00 2001 From: Vincent Petithory Date: Wed, 27 Mar 2013 20:49:16 +0100 Subject: Minimap renderer: allow to run elsewhere than tools/ --- client/minimap-render.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'client/minimap-render.py') diff --git a/client/minimap-render.py b/client/minimap-render.py index 6b6b009..33917ee 100755 --- a/client/minimap-render.py +++ b/client/minimap-render.py @@ -7,6 +7,12 @@ import subprocess import tempfile import re +CLIENT_DATA_ROOT = os.path.realpath( + os.path.join( + os.path.dirname(__file__), + u'..', + ) +) class MinimapRenderer(object): @@ -38,8 +44,8 @@ class MinimapRenderer(object): self.map_name = self.map_name+u'.tmx' map_number = os.path.splitext(os.path.basename(self.map_name))[0] - tmx_file = os.path.normpath(os.path.join(os.getcwdu(), u'..', u'maps', self.map_name)) - minimap_file = os.path.normpath(os.path.join(os.getcwdu(), u'..', u'graphics', u'minimaps', map_number+u'.png')) + 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))) @@ -135,9 +141,6 @@ def main(): if not len(sys.argv) > 1: usage() return 127 - if not os.path.basename(os.path.dirname(os.getcwdu())) == u'client-data': - sys.stderr.write(u'This script must be run from client-data/tools.\n') - return 1 try: MinimapRenderer.check_programs() except Exception as e: -- cgit v1.2.3-70-g09d2 From 15257e49db8a6bfa383306c8ec35f60bfa354468 Mon Sep 17 00:00:00 2001 From: Vincent Petithory Date: Wed, 27 Mar 2013 21:00:47 +0100 Subject: Minimap renderer: add special args: * "all" to create minimaps of all existing maps * "update" to update all existing minimaps --- client/minimap-render.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'client/minimap-render.py') diff --git a/client/minimap-render.py b/client/minimap-render.py index 33917ee..c9cb4a1 100755 --- a/client/minimap-render.py +++ b/client/minimap-render.py @@ -129,12 +129,14 @@ def usage(): 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 acceptable, for e.g running things like, - $ ./minimap-render.py $(ls ../maps/) - that would render all existing maps. + is also accepted. \n''' % sys.argv[0]) def main(): @@ -148,7 +150,14 @@ def main(): return 126 status = 0 - for map_name in sys.argv[1:]: + 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() -- cgit v1.2.3-70-g09d2