def add(self, tile): if self.is_full(): raise errors.ChrPageFull() ret = self.lower self.tiles[self.lower] = tile self._adjust_lower() return ret
def process_image(self, img, palette_text, bg_color_mask, bg_color_fill, is_locked_tiles, lock_sprite_flips, allow_overflow): """Process free sprites image, creating the ppu_memory it represents. The image represents the entire screen, and is mostly filled with bg_color_fill. Anywhere that contains other pixel data is considered to be made of sprites. Those sprites are located, treated as tiles, and processed to be converted into PPU memory. img: Pixel art image. palette_text: Optional string representing a palette to be parsed. bg_color_mask: Background color that masks existing free sprite tiles. bg_color_fill: Background color which fills up the outside space. is_locked_tiles: Whether tiles are locked or not. allow_overflow: List of components for which to allow overflows. """ self.initialize() self.load_image(img) config = ppu_memory.PpuMemoryConfig( is_sprite=True, is_locked_tiles=is_locked_tiles, lock_sprite_flips=lock_sprite_flips, allow_overflow=allow_overflow) is_tall = '8x16' in self.traversal # Scan the image, find corners of each tile based upon region merging. zones = self._find_zones(bg_color_fill) # HACK: Assign zones to ppu_memory so that they can be used by the # view renderer. self._ppu_memory.zones = zones # Convert zones into artifacts. artifacts = [] for z in zones: vert_color_needs = None for sprite_y, sprite_x in z.each_sprite(is_tall): (color_needs, dot_profile) = self.process_tile(sprite_y / 8, sprite_x / 8, sprite_y % 8, sprite_x % 8) cid = self._color_manifest.id(color_needs) did = self._dot_manifest.id(dot_profile) artifacts.append([cid, did, None, sprite_y, sprite_x]) if not is_tall: continue elif vert_color_needs is None: vert_color_needs = color_needs else: try: self.combine_color_needs(vert_color_needs, color_needs) except errors.PaletteOverflowError as e: e.tile_y = sprite_y / 8 e.tile_x = sprite_x / 8 self._err.add(e) continue vcid = self._vert_color_manifest.id(vert_color_needs) artifacts[-1][ARTIFACT_VCID] = vcid vert_color_needs = None if self._err.has(): return self._needs_provider = self._color_manifest if is_tall: self._needs_provider = self._vert_color_manifest # Build the palette. pal = self.make_palette(palette_text, bg_color_mask, True) # Build the PPU memory. if not is_tall: for cid, did, unused, y, x in artifacts: color_needs = self._color_manifest.at(cid) (pid, palette_option) = pal.select(color_needs) dot_xlat = self.get_dot_xlat(color_needs, palette_option) try: (chr_num, flip_bits) = self.store_chrdata(dot_xlat, did, config) except errors.NametableOverflow, e: self._err.add(errors.NametableOverflow(e.chr_num, y, x)) chr_num = 0 if (config.is_locked_tiles and self._ppu_memory.chr_set.is_full() and chr_num == 0): raise errors.ChrPageFull() self._ppu_memory.spritelist.append( [y - 1, chr_num, pid | flip_bits, x])
[y - 1, chr_num, pid | flip_bits, x]) else: ebs_processor = eight_by_sixteen_processor.EightBySixteenProcessor( ) ebs_processor.link_from(self) for i in xrange(0, len(artifacts), 2): (cid_u, did_u, unused, y, x) = artifacts[i] (cid_l, did_l, vcid, unused_y, unused_x) = artifacts[i + 1] color_needs = self._vert_color_manifest.at(vcid) (pid, palette_option) = pal.select(color_needs) chr_num_u, chr_num_l, flip_bits = ebs_processor.store_vert_pair( palette_option, cid_u, did_u, cid_l, did_l, config) if (config.is_locked_tiles and self._ppu_memory.chr_set.is_full() and chr_num_u == 0 and chr_num_l == 0): raise errors.ChrPageFull() # TODO: Only add this 1 if the sprite chr order is 1. chr_num = chr_num_u + 1 if not 's' in config.allow_overflow: if len(self._ppu_memory.spritelist) >= 0x40: self._err.add(errors.SpritelistOverflow(y, x)) continue self._ppu_memory.spritelist.append( [y - 1, chr_num, pid | flip_bits, x]) self._ppu_memory.palette_spr = pal def _find_zones(self, fill): """Scan the entire image. Calculate the positions of tile corners.""" if self._verbose: print('') self._regions = []
def add(self, tile): if self.is_full(): raise errors.ChrPageFull() ret = self.size() self.tiles.append(tile) return ret
def process_image(self, img, palette_text, bg_color_mask, bg_color_fill, platform, is_locked_tiles, lock_sprite_flips, allow_overflow): """Process free sprites image, creating the ppu_memory it represents. The image represents the entire screen, and is mostly filled with bg_color_fill. Anywhere that contains other pixel data is considered to be made of sprites. Those sprites are located, treated as tiles, and processed to be converted into PPU memory. img: Pixel art image. palette_text: Optional string representing a palette to be parsed. bg_color_mask: Background color that masks existing free sprite tiles. bg_color_fill: Background color which fills up the outside space. is_locked_tiles: Whether tiles are locked or not. allow_overflow: List of components for which to allow overflows. """ self.initialize() self.load_image(img) self.set_platform(platform) config = ppu_memory.PpuMemoryConfig(is_sprite=True, is_locked_tiles=is_locked_tiles, lock_sprite_flips=lock_sprite_flips, allow_overflow=allow_overflow) is_tall = '8x16' in self.traversal # Scan the image, find corners of each tile based upon region merging. try: zones = self._find_zones(bg_color_fill) except errors.CouldntConvertRGB as e: self._err.add(e) return None # HACK: Assign zones to ppu_memory so that they can be used by the # view renderer. self._ppu_memory.zones = zones # Parse the palette if provided. pal = None if palette_text or self.img.palette: pal = self.parse_palette(palette_text, bg_color_mask) # Convert zones into artifacts. artifacts = [] for z in zones: vert_color_needs = None for sprite_y, sprite_x in z.each_sprite(is_tall): (color_needs, dot_profile) = self.process_tile( sprite_y // 8, sprite_x // 8, sprite_y % 8, sprite_x % 8) cid = self._color_manifest.id(color_needs) did = self._dot_manifest.id(dot_profile) artifacts.append([cid, did, None, sprite_y, sprite_x]) if not is_tall: continue elif vert_color_needs is None: vert_color_needs = color_needs else: try: self.combine_color_needs(vert_color_needs, color_needs) except errors.PaletteOverflowError as e: e.tile_y = sprite_y // 8 e.tile_x = sprite_x // 8 self._err.add(e) continue vcid = self._vert_color_manifest.id(vert_color_needs) artifacts[-1][ARTIFACT_VCID] = vcid vert_color_needs = None if self._err.has(): return self._needs_provider = self._color_manifest if is_tall: self._needs_provider = self._vert_color_manifest # Build the palette. if not pal: pal = self.make_palette(bg_color_mask, True) # Build the PPU memory. if not is_tall: for cid, did, unused, y, x in artifacts: color_needs = self._color_manifest.at(cid) (pid, palette_option) = pal.select(color_needs) dot_xlat = self.get_dot_xlat(color_needs, palette_option) try: (chr_num, flip_bits) = self.store_chrdata(dot_xlat, did, config) except errors.NametableOverflow as e: self._err.add(errors.NametableOverflow(e.chr_num, y, x)) chr_num = 0 if (config.is_locked_tiles and self._ppu_memory.chr_set.is_full() and chr_num == 0): raise errors.ChrPageFull() self._ppu_memory.spritelist.append([y - 1, chr_num, pid | flip_bits, x]) else: ebs_processor = eight_by_sixteen_processor.EightBySixteenProcessor() ebs_processor.link_from(self) for i in range(0, len(artifacts), 2): (cid_u, did_u, unused, y, x) = artifacts[i] (cid_l, did_l, vcid, unused_y, unused_x) = artifacts[i+1] color_needs = self._vert_color_manifest.at(vcid) (pid, palette_option) = pal.select(color_needs) chr_num_u, chr_num_l, flip_bits = ebs_processor.store_vert_pair( palette_option, cid_u, did_u, cid_l, did_l, config) if (config.is_locked_tiles and self._ppu_memory.chr_set.is_full() and chr_num_u == 0 and chr_num_l == 0): raise errors.ChrPageFull() # TODO: Only add this 1 if the sprite chr order is 1. chr_num = chr_num_u + 1 if not 's' in config.allow_overflow: if len(self._ppu_memory.spritelist) >= 0x40: self._err.add(errors.SpritelistOverflow(y, x)) continue self._ppu_memory.spritelist.append([y - 1, chr_num, pid | flip_bits, x]) self._ppu_memory.palette_spr = pal