summaryrefslogtreecommitdiff
path: root/client/minimap-render.py
diff options
context:
space:
mode:
Diffstat (limited to 'client/minimap-render.py')
-rwxr-xr-xclient/minimap-render.py165
1 files changed, 165 insertions, 0 deletions
diff --git a/client/minimap-render.py b/client/minimap-render.py
new file mode 100755
index 0000000..716e9e3
--- /dev/null
+++ b/client/minimap-render.py
@@ -0,0 +1,165 @@
+#!/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',
+ )
+)
+
+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'
+
+ 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())