# coding: utf-8 import typing from PIL.PngImagePlugin import PngImageFile from synergine2_xyz.map import TMXMap from synergine2_xyz.utils import get_direct_around_positions_of_position class InteriorMapConfiguration(object): def __init__( self, layer_name: str='interiors', exterior_id: str='ext', interior_id: str='int', separator_id: str='sep', ) -> None: self.layer_name = layer_name self.exterior_id = exterior_id self.interior_id = interior_id self.separator_id = separator_id class InteriorManager(object): def __init__( self, map_: TMXMap, original_image: PngImageFile, configuration: InteriorMapConfiguration=None, ) -> None: self.interiors = [] self.map = map_ self.original_image = original_image self.configuration = configuration or InteriorMapConfiguration() self.interiors = self._compute_interiors() self._cache = {} # type: typing.Dict[str, PngImageFile] def _compute_interiors(self) -> typing.List[typing.List[typing.Tuple[int, int]]]: interiors = [] layer_tiles = self.map.layer_tiles(self.configuration.layer_name) for tile_xy, tile in layer_tiles.items(): if tile.property('id') == self.configuration.interior_id: x, y = map(int, tile_xy.split('.')) if not any([(x, y) in i for i in interiors]): new_interior = [(x, y)] positions_to_parse = [] possible_positions_xyz = get_direct_around_positions_of_position((x, y, 0)) possible_positions_xy = [(p[0], p[1]) for p in possible_positions_xyz] positions_to_parse.extend(possible_positions_xy) for possible_position_xyz in positions_to_parse: test_tile = None new_tile_x = possible_position_xyz[0] new_tile_y = possible_position_xyz[1] possible_position_key = '{}.{}'.format(new_tile_x, new_tile_y) if (new_tile_x, new_tile_y) in new_interior: continue try: test_tile = layer_tiles[possible_position_key] except KeyError: continue if test_tile.property('id') not in [ self.configuration.interior_id, self.configuration.separator_id, ]: continue new_interior.append((new_tile_x, new_tile_y)) if not test_tile.property('id') == self.configuration.separator_id: new_position_neighbour = get_direct_around_positions_of_position((new_tile_x, new_tile_y, 0)) positions_to_parse.extend(new_position_neighbour) interiors.append(new_interior) return interiors def get_interiors( self, where_positions: typing.Iterable[typing.Tuple[int, int]]=None, ) -> typing.List[typing.List[typing.Tuple[int, int]]]: if where_positions is None: return self.interiors interiors = [] for interior in self.interiors: for where_position in where_positions: if where_position in interior and interior not in interiors: interiors.append(interior) return interiors def _get_interior_unique_key( self, interiors: typing.List[typing.List[typing.Tuple[int, int]]], ) -> str: """ Compute a key for given interior list. WARNING: For performance reasons, actual unique key is interior list ID concatenation: So, if same interior list is given, but in different python object, key will be different ! :param interiors: Interior list to build unique key :return: String or Int who id unique key of given interiors """ return '.'.join([str(id(i)) for i in interiors]) def update_image_for_interiors( self, interiors: typing.List[typing.List[typing.Tuple[int, int]]], tile_width: int, tile_height: int, invert_y: bool=True, ) -> PngImageFile: """ :param interiors: List of list of interior tile positions :param tile_width: Width of a tile :param tile_height: Height of a tile :param invert_y: If y reference is top left instead bottom left :return: Image givan at __init__ with all tile pixels replaces by transparent pixel """ try: return self._cache[self._get_interior_unique_key(interiors)] except KeyError: pass # compute it image = self.original_image.copy() image_height = image.height pixels = image.load() for interior in interiors: for tile_x, tile_y in interior: start_x = tile_x * tile_width start_y = tile_y * tile_height for x in range(start_x, start_x+tile_width): for y in range(start_y, start_y+tile_height): real_y = y if invert_y: real_y = image_height - 1 - y pixels[x, real_y] = (0, 0, 0, 0) self._cache[self._get_interior_unique_key(interiors)] = image return image