def _change_map_bg(self, level_id: int, draw, drawer): if level_id!=-1: bma = self.map_bg_module.get_bma(self._get_map_id(level_id)) bpl = self.map_bg_module.get_bpl(self._get_map_id(level_id)) bpc = self.map_bg_module.get_bpc(self._get_map_id(level_id)) bpas = self.map_bg_module.get_bpas(self._get_map_id(level_id)) surface = pil_to_cairo_surface( bma.to_pil(bpc, bpl, bpas, False, False, single_frame=True)[0].convert('RGBA') ) if drawer: if level_id == WORLD_MAP_DEFAULT_ID: draw.set_size_request(504 * SCALE, 336 * SCALE) else: bma_width = bma.map_width_camera * BPC_TILE_DIM bma_height = bma.map_height_camera * BPC_TILE_DIM draw.set_size_request( bma_width * SCALE, bma_height * SCALE ) drawer.level_id = level_id drawer.map_bg = surface draw.queue_draw() else: surface = pil_to_cairo_surface( Image.new(mode="RGBA", size=(1,1), color=(0,0,0,0)) ) drawer.level_id = -1 drawer.map_bg = surface draw.set_size_request(1,1) draw.queue_draw()
def __init__(self, zmappa: ZMappaT): self._tiles = [] base = zmappa.to_pil_tiles_minimized(ZMappaTVariation.OPAQUE).convert('RGBA') for y in range(0, 4): for x in range(0, ZMAPPAT_NB_TILES_PER_LINE // 2): self._tiles.append(pil_to_cairo_surface(base.crop( (x * ZMAPPAT_DIM, y * ZMAPPAT_DIM, (x + 1) * ZMAPPAT_DIM, (y + 1) * ZMAPPAT_DIM) ))) self._secondary = pil_to_cairo_surface(Image.open(os.path.join(data_dir(), 'minimap_secondary.png'))) self._buried = pil_to_cairo_surface(Image.open(os.path.join(data_dir(), 'minimap_buried.png')))
def _switch_entry(self): surface = self.font.get_entry(int(self.builder.get_object('entry_id').get_text())) stack: Gtk.Stack = self.builder.get_object('entry_stack') if surface: stack.set_visible_child(self.builder.get_object('entry_viewer')) surface = surface.resize((surface.width*IMAGE_ZOOM, surface.height*IMAGE_ZOOM)) self.surface = pil_to_cairo_surface(surface.convert('RGBA')) self.builder.get_object('draw').queue_draw() else: stack.set_visible_child(self.builder.get_object('no_entry_label')) self.surface = pil_to_cairo_surface(Image.new('RGBA', size=(1,1)))
def _reinit_image(self): cb_store: Gtk.ListStore = self.builder.get_object('variation_store') cb: Gtk.ComboBoxText = self.builder.get_object('zmappat_variation') v: int = cb_store[cb.get_active_iter()][0] if self.builder.get_object('switch_minimized').get_active(): surface = self.zmappat.to_pil_tiles_minimized(ZMappaTVariation(v)) mask = self.zmappat.to_pil_masks_minimized(ZMappaTVariation(v)) else: surface = self.zmappat.to_pil_tiles(ZMappaTVariation(v)) mask = self.zmappat.to_pil_masks(ZMappaTVariation(v)) surface = surface.resize((surface.width * 4, surface.height * 4)) self.surface = pil_to_cairo_surface(surface.convert('RGBA')) mask = mask.resize((mask.width * 4, mask.height * 4)) self.mask = pil_to_cairo_surface(mask.convert('RGBA')) self.builder.get_object('draw_tiles').queue_draw() self.builder.get_object('draw_masks').queue_draw()
async def _load_object__impl(self, name, after_load_cb): try: with self._load_sprite_from_rom(f'GROUND/{name}.wan') as sprite: ani_group = sprite.anim_groups[0] frame_id = 0 mfg_id = ani_group[frame_id].frames[0].frame_id sprite_img, (cx, cy) = sprite.render_frame_group( sprite.frame_groups[mfg_id]) surf = pil_to_cairo_surface(sprite_img) with sprite_provider_lock: self._loaded__objects[ name] = surf, cx, cy, sprite_img.width, sprite_img.height except BaseException as e: # Error :( logger.warning(f"Error loading an object sprite for {name}.", exc_info=e) with sprite_provider_lock: self._loaded__objects[name] = self.get_error() with sprite_provider_lock: try: self._requests__objects.remove(name) except ValueError: pass after_load_cb()
async def _load_item__impl(self, item: ItemPEntry, after_load_cb): try: assert self._dungeon_bin is not None with self._dungeon_bin as dungeon_bin: items: ImgItm = dungeon_bin.get(ITM_FILENAME) img = items.to_pil(item.sprite, item.palette) alpha = [px % 16 != 0 for px in img.getdata()] img = img.convert('RGBA') alphaimg = Image.new('1', (img.width, img.height)) alphaimg.putdata(alpha) img.putalpha(alphaimg) surf = pil_to_cairo_surface(img) with sprite_provider_lock: self._loaded__items[item.item_id] = surf, 0, 0, 16, 16 except BaseException as e: # Error :( logger.warning(f"Error loading an item sprite for {item}.", exc_info=e) with sprite_provider_lock: self._loaded__items[item.item_id] = self.get_error() with sprite_provider_lock: try: self._requests__items.remove(item.item_id) except ValueError: pass after_load_cb()
def on_import_icon_clicked(self, *args): dialog = FileChooserNative.new( _("Import game icon from PNG..."), SkyTempleMainController.window(), FileChooserAction.OPEN, None, None ) add_dialog_png_filter(dialog) response = dialog.run() fn = dialog.get_filename() dialog.destroy() if response == ResponseType.ACCEPT: try: self.icon_banner.icon.from_pil(Image.open(fn)) except Exception as err: display_error( sys.exc_info(), _('Failed importing game icon:\n') + str(err), _("Could not import.") ) self.icon_surface = pil_to_cairo_surface(self.icon_banner.icon.to_pil().convert('RGBA')) self.builder.get_object('draw_icon').queue_draw() # Mark as modified self.module.mark_as_modified()
async def _load_monster_outline__impl(self, md_index, direction_id: int, after_load_cb): try: sprite_img, cx, cy, w, h = self._retrieve_monster_sprite( md_index, direction_id) # Convert to outline + stripes im_outline = sprite_img.filter(ImageFilter.FIND_EDGES) alpha_outline = im_outline.getchannel('A') im_outline = Image.new('RGBA', im_outline.size, color='white') im_outline.putalpha(alpha_outline) # / surf = pil_to_cairo_surface(im_outline) loaded = surf, cx, cy, w, h except BaseException: loaded = self.get_error() with sprite_provider_lock: self._loaded__monsters_outlines[(md_index, direction_id)] = loaded try: self._requests__monsters_outlines.remove( (md_index, direction_id)) except ValueError: pass after_load_cb()
def _load_dtef_rendering(self): self.dtef = ExplorersDtef(self.dma, self.dpc, self.dpci, self.dpl, self.dpla) box: Gtk.Box = self.builder.get_object('dungeon_image_placeholder') for child in box: box.remove(child) image: Gtk.Image = Gtk.Image.new_from_surface(pil_to_cairo_surface(self.dtef.get_tiles()[0].convert('RGBA'))) box.pack_start(image, True, True, 0) box.show_all()
def _single_tile(self, type): index = self.dma.get(type, False)[0] chunk_dim = DPC_TILING_DIM * DPCI_TILE_DIM chunk_width = int(self.chunks.width / chunk_dim) cy = int(index / chunk_width) * chunk_dim cx = index % chunk_width * chunk_dim return pil_to_cairo_surface( self.chunks.crop((cx, cy, cx + chunk_dim, cy + chunk_dim)))
def get_dungeon(self, rules: List[List[DmaType]]) -> cairo.Surface: # TODO: If rules change only update the parts that need to be updated if rules != self._cached_rules: mappings = self.dma_drawer.get_mappings_for_rules( rules, treat_outside_as_wall=True, variation_index=0) self._cached_dungeon_surface = pil_to_cairo_surface( self._draw_dungeon(mappings)) self._cached_rules = rules return self._cached_dungeon_surface
def _reinit_image(self): try: val = int( self.builder.get_object('wte_palette_variant').get_text()) except ValueError: val = 0 self.surface = pil_to_cairo_surface( self.wte.to_pil_canvas(val).convert('RGBA')) self.builder.get_object('draw').queue_draw()
def _load_frames(self): with self._monster_bin as monster_bin: sprite = self._load_sprite_from_bin_pack(monster_bin, self.item_id) ani_group = sprite.get_animations_for_group(sprite.anim_groups[0]) frame_id = 2 for frame in ani_group[frame_id].frames: mfg_id = frame.frame_id sprite_img, (cx, cy) = sprite.render_frame_group(sprite.frame_groups[mfg_id]) self._rendered_frame_info.append((frame.duration, (pil_to_cairo_surface(sprite_img), cx, cy, sprite_img.width, sprite_img.height)))
def _reinit_image(self): cb_store: Gtk.ListStore = self.builder.get_object('cb_weather_store') cb: Gtk.ComboBoxText = self.builder.get_object('cb_weather') v : int = cb_store[cb.get_active_iter()][0] surface = self.colvec.to_pil(v) surface = surface.resize((surface.width*16, surface.height*16), resample=Image.NEAREST) self.colormap = pil_to_cairo_surface(surface.convert('RGBA')) self.surface = None if self.dma: self.dtef = ExplorersDtef(self.dma, self.dpc, self.dpci, self.dpl, self.dpla) surface = self.dtef.get_tiles()[0] #Apply colormap surface.putpalette(self.colvec.apply_colormap(v, list(surface.palette.palette))) self.surface = pil_to_cairo_surface(surface.convert('RGBA')) self.builder.get_object('draw_tileset').queue_draw() self.builder.get_object('draw_colormap').queue_draw()
async def _load_monster__impl(self, md_index, direction_id: int, after_load_cb): try: pil_img, cx, cy, w, h = self._retrieve_monster_sprite( md_index, direction_id) surf = pil_to_cairo_surface(pil_img) loaded = surf, cx, cy, w, h except BaseException: loaded = self.get_error() with sprite_provider_lock: self._loaded__monsters[(md_index, direction_id)] = loaded self._requests__monsters.remove((md_index, direction_id)) after_load_cb()
def _init_chunk_imgs(self): """(Re)-draw the chunk images""" self.chunks_surfaces = [] # For each chunk... for chunk_idx in range(0, len(self.dpc.chunks)): # For each frame of palette animation... ( applicable for this chunk ) pal_ani_frames = [] self.chunks_surfaces.append(pal_ani_frames) chunk_data = self.dpc.chunks[chunk_idx] chunk_image = self.dpc.single_chunk_to_pil(chunk_idx, self.dpci, self.dpl.palettes) has_pal_ani = any(chunk.pal_idx >= 10 and self.dpla.has_for_palette(chunk.pal_idx - 10) for chunk in chunk_data) if not has_pal_ani: len_pal_ani = 1 else: ani_pal_lengths = [ self.dpla.get_frame_count_for_palette(x) for x in (0, 1) if self.dpla.has_for_palette(x) ] if len(ani_pal_lengths) < 2: len_pal_ani = ani_pal_lengths[0] else: len_pal_ani = lcm(*ani_pal_lengths) for pal_ani in range(0, len_pal_ani): # We don't have animated tiles, so ani_frames just has one entry. ani_frames = [] pal_ani_frames.append(ani_frames) # Switch out the palette with that from the palette animation if has_pal_ani: pal_for_frame = itertools.chain.from_iterable( self.dpla.apply_palette_animations( self.dpl.palettes, pal_ani)) chunk_image.putpalette(pal_for_frame) ani_frames.append( pil_to_cairo_surface(chunk_image.convert('RGBA'))) # TODO: No DPLA animations at different speeds supported at the moment ani_pal11 = 9999 ani_pal12 = 9999 if self.dpla.has_for_palette(0): ani_pal11 = self.dpla.get_duration_for_palette(0) if self.dpla.has_for_palette(1): ani_pal12 = self.dpla.get_duration_for_palette(1) self.pal_ani_durations = min(ani_pal11, ani_pal12)
async def _load_actor_placeholder__impl(self, actor_id, direction_id: int, after_load_cb): md_index = FALLBACK_STANDIN_ENTITIY if actor_id in self.get_standin_entities(): md_index = self.get_standin_entities()[actor_id] try: sprite_img, cx, cy, w, h = self._retrieve_monster_sprite( md_index, direction_id) # Convert to outline + stripes alpha_sprite = sprite_img.getchannel('A') im_outline = sprite_img.filter(ImageFilter.FIND_EDGES) alpha_outline = im_outline.getchannel('A') out_sprite = Image.new('RGBA', im_outline.size) for i in range(0, out_sprite.width, self._stripes.width): for j in range(0, out_sprite.height, self._stripes.height): out_sprite.paste(self._stripes, (i, j)) im_outline = Image.new('RGBA', im_outline.size, color='white') out_sprite.paste(im_outline, (0, 0, im_outline.width, im_outline.height), alpha_outline) out_sprite.putalpha(alpha_sprite) # Make red transparent data = out_sprite.getdata() new_data = [] for item in data: if item[0] > 200 and item[1] < 200 and item[2] < 200: new_data.append((255, 255, 255, 0)) else: new_data.append(item) out_sprite.putdata(new_data) # type: ignore # / surf = pil_to_cairo_surface(out_sprite) loaded = surf, cx, cy, w, h except BaseException: loaded = self.get_error() with sprite_provider_lock: self._loaded__actor_placeholders[(actor_id, direction_id)] = loaded try: self._requests__actor_placeholders.remove( (actor_id, direction_id)) except ValueError: pass after_load_cb()
def on_tool_choose_map_bg_cb_changed(self, w: Gtk.ComboBox): model, cbiter = w.get_model(), w.get_active_iter() if model is not None and cbiter is not None and cbiter != []: item_id = model[cbiter][0] self.mapbg_id = item_id bma = self.map_bg_module.get_bma(item_id) bpl = self.map_bg_module.get_bpl(item_id) bpc = self.map_bg_module.get_bpc(item_id) bpas = self.map_bg_module.get_bpas(item_id) self._map_bg_surface = pil_to_cairo_surface( bma.to_pil(bpc, bpl, bpas, False, False, single_frame=True)[0].convert('RGBA') ) bma_width = bma.map_width_camera * BPC_TILE_DIM bma_height = bma.map_height_camera * BPC_TILE_DIM if self.drawer: self._set_drawer_bg(self._map_bg_surface, bma_width, bma_height)
def _switch_table(self): cb_store: Gtk.ListStore = self.builder.get_object('table_store') cb: Gtk.ComboBoxText = self.builder.get_object('cb_table_select') if cb.get_active_iter()!=None: v : int = cb_store[cb.get_active_iter()][0] self.entries = self.font.get_entries_from_table(v) entry_tree: Gtk.TreeView = self.builder.get_object('entry_tree') store: Gtk.ListStore = entry_tree.get_model() store.clear() for e in self.entries: self._add_property_row(store, e) surface = self.tables[v].resize((self.tables[v].width*IMAGE_ZOOM, self.tables[v].height*IMAGE_ZOOM)) self.surface = pil_to_cairo_surface(surface.convert('RGBA')) self.builder.get_object('draw').queue_draw()
def get_view(self) -> Widget: self.builder = self._get_builder(__file__, 'rom.glade') file_name = os.path.basename(self.module.project.filename) self.builder.get_object('file_name').set_text(file_name) self.builder.get_object('name').set_text(self.project.get_rom_name()) self.builder.get_object('id_code').set_text(self.project.get_id_code()) self.icon_surface = pil_to_cairo_surface( self.icon_banner.icon.to_pil().convert('RGBA')) title_japanese_buffer = self.builder.get_object( 'title_japanese').get_buffer() title_japanese_buffer.set_text(self.icon_banner.title_japanese) title_japanese_buffer.connect('changed', self.on_title_japanese_changed) title_english_buffer = self.builder.get_object( 'title_english').get_buffer() title_english_buffer.set_text(self.icon_banner.title_english) title_english_buffer.connect('changed', self.on_title_english_changed) title_french_buffer = self.builder.get_object( 'title_french').get_buffer() title_french_buffer.set_text(self.icon_banner.title_french) title_french_buffer.connect('changed', self.on_title_french_changed) title_german_buffer = self.builder.get_object( 'title_german').get_buffer() title_german_buffer.set_text(self.icon_banner.title_german) title_german_buffer.connect('changed', self.on_title_german_changed) title_italian_buffer = self.builder.get_object( 'title_italian').get_buffer() title_italian_buffer.set_text(self.icon_banner.title_italian) title_italian_buffer.connect('changed', self.on_title_italian_changed) title_spanish_buffer = self.builder.get_object( 'title_spanish').get_buffer() title_spanish_buffer.set_text(self.icon_banner.title_spanish) title_spanish_buffer.connect('changed', self.on_title_spanish_changed) self.builder.connect_signals(self) return self.builder.get_object('box_list')
async def _load_trap__impl(self, trp: int, after_load_cb): try: with self._dungeon_bin as dungeon_bin: traps: ImgTrp = dungeon_bin.get(TRP_FILENAME) surf = pil_to_cairo_surface( traps.to_pil(trp, TRAP_PALETTE_MAP[trp]).convert('RGBA')) with sprite_provider_lock: self._loaded__traps[trp] = surf, 0, 0, 24, 24 except BaseException as e: # Error :( logger.warning(f"Error loading an trap sprite for {trp}.", exc_info=e) with sprite_provider_lock: self._loaded__traps[trp] = self.get_error() with sprite_provider_lock: self._requests__traps.remove(trp) after_load_cb()
def draw_full(self, ctx: cairo.Context, bma_chunks: List[int], bma_chunk_width: int, bma_chunk_height: int): if bma_chunk_width != self._cached__bma_chunk_width or self._cached__bma_chunks != bma_chunks: self._cached__bma_chunk_width = bma_chunk_width self._cached__bma_chunks = list(bma_chunks) self._cached = None if self._cached is None: drawer = DmaDrawer(self.dma) if self.fixed_room: rules = drawer.rules_from_fixed_room(self.fixed_room) else: rules = drawer.rules_from_bma(bma_chunks, bma_chunk_width) mappings = drawer.get_mappings_for_rules( rules, treat_outside_as_wall=True, variation_index=0) frame = pil_to_cairo_surface( drawer.draw(mappings, self.dpci, self.dpc, self.dpl, None)[0].convert('RGBA')) self._cached = frame ctx.set_source_surface(self._cached) ctx.get_source().set_filter(cairo.Filter.NEAREST) ctx.paint()
async def _load__impl(self, entry_id, sub_id, after_load_cb, allow_fallback): is_fallback = False try: kao = self._kao.get(entry_id, sub_id) if kao is None or kao.empty is True: if allow_fallback: is_fallback = True kao = self._kao.get(entry_id % NUM_ENTITIES, sub_id) if kao is None: raise RuntimeError() else: raise RuntimeError() portrait_pil = kao.get() surf = pil_to_cairo_surface(portrait_pil.convert('RGBA')) loaded = surf except (RuntimeError, ValueError): loaded = self.get_error() with portrait_provider_lock: self._loaded[(entry_id, sub_id)] = loaded self._loaded__is_fallback[(entry_id, sub_id)] = is_fallback self._requests.remove((entry_id, sub_id)) after_load_cb()
def get_dungeon(self, rules: List[List[DmaType]]) -> cairo.Surface: if rules != self._cached_rules: surf = pil_to_cairo_surface(Image.new( 'RGBA', size=(len(rules[0] * ZMAPPAT_DIM), len(rules * ZMAPPAT_DIM)), color=(0, 0, 231, 255) )) ctx = cairo.Context(surf) for y, row in enumerate(rules): for x, cell in enumerate(row): if cell == DmaType.WALL: continue self.paint(ctx, self.get_single_tile(cell), x * ZMAPPAT_DIM, y * ZMAPPAT_DIM) if cell == DmaType.WATER: self.paint(ctx, self.minimap_provider.get_secondary_tile(), x * ZMAPPAT_DIM, y * ZMAPPAT_DIM) else: w_below = self.w_below(rules, x, y) # 0001 w_right = self.w_right(rules, x, y) # 0010 w_above = self.w_above(rules, x, y) # 0100 w_left = self.w_left(rules, x, y) # 1000 idx = 16 + w_below + 2 * w_right + 4 * w_above + 8 * w_left self.paint(ctx, self.minimap_provider.get_minimap_tile(idx), x * ZMAPPAT_DIM, y * ZMAPPAT_DIM) self._cached_dungeon_surface = surf self._cached_rules = rules return self._cached_dungeon_surface # type: ignore
def _reinit_image(self): surface = self.module.get_cart_removed_data() self.surface = pil_to_cairo_surface(surface.convert('RGBA')) self.builder.get_object('draw').queue_draw()
def _single_tile(self, chunks, type): index = self.dma.get(type, False)[0] chunk_dim = DPC_TILING_DIM * DPCI_TILE_DIM return pil_to_cairo_surface( chunks.crop((0, index * chunk_dim, chunk_dim, index * chunk_dim + chunk_dim)).convert('RGBA') )
def _reinit_image(self): variant = int(self.builder.get_object('chr_palette_variant').get_text()) surface = self.chr.to_pil(variant) self.surface = pil_to_cairo_surface(surface.convert('RGBA')) self.builder.get_object('draw').queue_draw()
def __init__(self, parent_window, incoming_mappings: List[TilemapEntry], tile_graphics: AbstractTileGraphicsProvider, palettes: AbstractTilePalettesProvider, pal_ani_durations: int, animated_tile_graphics: List[ Optional[AbstractTileGraphicsProvider]] = None, animated_tile_durations=0): path = os.path.abspath(os.path.dirname(__file__)) self.builder = make_builder(os.path.join(path, 'chunk_editor.glade')) self.dialog: Gtk.Dialog = self.builder.get_object( 'map_bg_chunk_editor') self.dialog.set_attached_to(parent_window) self.dialog.set_transient_for(parent_window) self.tile_graphics = tile_graphics self.animated_tile_graphics = animated_tile_graphics self.palettes = palettes self.animated_tile_durations = animated_tile_durations self.pal_ani_durations = pal_ani_durations self.current_tile_id = 0 self.current_tile_drawer: DrawerTiled = None self.switching_tile = False self.edited_mappings = [] for mapping in incoming_mappings: self.edited_mappings.append(TilemapEntry.from_int( mapping.to_int())) self.tile_surfaces = [] # For each palette for pal in range(0, len(self.palettes.get())): all_bpc_tiles_for_current_pal = self.tile_graphics.get_pil( self.palettes.get(), pal) tiles_current_pal = [] self.tile_surfaces.append(tiles_current_pal) has_pal_ani = self.palettes.is_palette_affected_by_animation(pal) len_pal_ani = self.palettes.animation_length( ) if has_pal_ani else 1 # BPC tiles # For each tile... for tile_idx in range(0, self.tile_graphics.count()): # For each frame of palette animation... pal_ani_tile = [] tiles_current_pal.append(pal_ani_tile) for pal_ani in range(0, len_pal_ani): # Switch out the palette with that from the palette animation if has_pal_ani: pal_for_frame = itertools.chain.from_iterable( self.palettes.apply_palette_animations(pal_ani)) all_bpc_tiles_for_current_pal.putpalette(pal_for_frame) pal_ani_tile.append([ pil_to_cairo_surface( all_bpc_tiles_for_current_pal.crop( (0, tile_idx * TILE_DIM, TILE_DIM, tile_idx * TILE_DIM + TILE_DIM)).convert('RGBA')) ]) # BPA tiles # For each BPA... if self.animated_tile_graphics is not None: for ani_tile_g in self.animated_tile_graphics: if ani_tile_g is not None: all_bpa_tiles_for_current_pal = ani_tile_g.get_pil( self.palettes.get(), pal) # For each tile... for tile_idx in range(0, ani_tile_g.count()): pal_ani_tile = [] tiles_current_pal.append(pal_ani_tile) # For each frame of palette animation... for pal_ani in range(0, len_pal_ani): bpa_ani_tile = [] pal_ani_tile.append(bpa_ani_tile) # For each frame of BPA animation... for frame in all_bpa_tiles_for_current_pal: # Switch out the palette with that from the palette animation if has_pal_ani: pal_for_frame = itertools.chain.from_iterable( self.palettes. apply_palette_animations(pal_ani)) all_bpc_tiles_for_current_pal.putpalette( pal_for_frame) bpa_ani_tile.append( pil_to_cairo_surface( frame.crop( (0, tile_idx * TILE_DIM, TILE_DIM, tile_idx * TILE_DIM + TILE_DIM)).convert('RGBA'))) self.builder.connect_signals(self) self.dummy_tile_map = [] self.current_tile_picker_palette = 0 for i in range(0, self.tile_graphics.count()): self.dummy_tile_map.append( TilemapEntry(idx=i, pal_idx=self.current_tile_picker_palette, flip_x=False, flip_y=False)) if self.animated_tile_graphics: self.bpa_starts_cursor = len(self.dummy_tile_map) self.bpa_starts = [None, None, None, None] for i, ani_tile_g in enumerate(self.animated_tile_graphics): if ani_tile_g is not None: self.bpa_starts[i] = self.bpa_starts_cursor self.current_tile_picker_palette = 0 for j in range(0, ani_tile_g.count()): self.dummy_tile_map.append( TilemapEntry( idx=self.bpa_starts_cursor + j, pal_idx=self.current_tile_picker_palette, flip_x=False, flip_y=False)) self.bpa_starts_cursor += ani_tile_g.count()
def _init_chunk_imgs(self): """(Re)-draw the chunk images""" # Set the weird palette warning to false self.weird_palette = False if self.bpc.number_of_layers > 1: layer_idxs_bpc = [1, 0] else: layer_idxs_bpc = [0] self.chunks_surfaces = [] # For each layer... for layer_idx, layer_idx_bpc in enumerate(layer_idxs_bpc): chunks_current_layer = [] self.chunks_surfaces.append(chunks_current_layer) # For each chunk... for chunk_idx in range( 0, self.bpc.layers[layer_idx_bpc].chunk_tilemap_len): # For each frame of palette animation... ( applicable for this chunk ) pal_ani_frames = [] chunks_current_layer.append(pal_ani_frames) chunk_data = self.bpc.get_chunk(layer_idx_bpc, chunk_idx) chunk_images = self.bpc.single_chunk_animated_to_pil( layer_idx_bpc, chunk_idx, self.bpl.palettes, self.bpas) if not self.weird_palette: for x in chunk_images: for n in x.tobytes("raw", "P"): n //= 16 if n >= self.bpl.number_palettes or n >= BPL_NORMAL_MAX_PAL: # If one chunk uses weird palette values, display the warning self.weird_palette = True break if self.weird_palette: break has_pal_ani = any( self.bpl.is_palette_affected_by_animation(chunk.pal_idx) for chunk in chunk_data) len_pal_ani = len( self.bpl.animation_palette) if has_pal_ani else 1 for pal_ani in range(0, len_pal_ani): # For each frame of tile animation... bpa_ani_frames = [] pal_ani_frames.append(bpa_ani_frames) for img in chunk_images: # Switch out the palette with that from the palette animation if has_pal_ani: pal_for_frame = itertools.chain.from_iterable( self.bpl.apply_palette_animations(pal_ani)) img.putpalette(pal_for_frame) # Remove alpha first img_mask = img.copy() img_mask.putpalette(MASK_PAL) img_mask = img_mask.convert('1') img = img.convert('RGBA') img.putalpha(img_mask) bpa_ani_frames.append(pil_to_cairo_surface(img)) # TODO: No BPAs at different speeds supported at the moment self.bpa_durations = 0 for bpa in self.bpas: if bpa is not None: single_bpa_duration = max( info.duration_per_frame for info in bpa.frame_info) if len( bpa.frame_info) > 0 else 9999 if single_bpa_duration > self.bpa_durations: self.bpa_durations = single_bpa_duration # TODO: No BPL animations at different speeds supported at the moment self.pal_ani_durations = 0 if self.bpl.has_palette_animation: self.pal_ani_durations = max( spec.duration_per_frame for spec in self.bpl.animation_specs) self.set_warning_palette()
def get_background(self) -> Optional[cairo.Surface]: if not self._cached_bg: self._cached_bg = pil_to_cairo_surface( self.dbg.to_pil(self.dbg_dpc, self.dbg_dpci, self.dbg_dpl.palettes).convert('RGBA')) return self._cached_bg