Пример #1
0
 def create_output(self, mem, args, traversal, platform):
     config = ppu_memory.PpuMemoryConfig(
         chr_order=args.order,
         traversal=traversal,
         platform=platform,
         is_sprite=args.is_sprite,
         is_locked_tiles=args.is_locked_tiles,
         lock_sprite_flips=args.lock_sprite_flips,
         select_chr_plane=args.select_chr_plane)
     if args.vertical_pixel_display:
         mem.chr_set.vertical_pixel_display()
     if args.output == '/dev/null':
         # Ignore output.
         pass
     elif args.output and args.output.endswith('.o'):
         # Output as a valiant object file.
         mem.save_valiant(args.output, config)
     elif args.output and args.output.endswith('.png'):
         # Render an image.
         renderer = pixel_art_renderer.PixelArtRenderer()
         img = renderer.render(mem)
         img.save(args.output)
     else:
         # Output as multiple files using a template.
         out_tmpl = args.output or '%s.dat'
         if out_tmpl[-1] == '/' or os.path.isdir(out_tmpl):
             out_tmpl = os.path.join(out_tmpl, '%s.dat')
         if not '%s' in out_tmpl:
             raise errors.CommandLineArgError(
                 'output needs "%s" in its template')
         mem.save_template(out_tmpl, config)
     if args.compile:
         # Compile a runnable ROM.
         builder = rom_builder.RomBuilder()
         builder.build(mem, args.compile)
Пример #2
0
 def create_output(self, mem, args, traversal):
     config = ppu_memory.PpuMemoryConfig(
         chr_order=args.order,
         traversal=traversal,
         is_sprite=args.is_sprite,
         is_locked_tiles=args.is_locked_tiles,
         lock_sprite_flips=args.lock_sprite_flips)
     if args.output == '/dev/null':
         pass
     elif args.output and args.output.endswith('.o'):
         mem.save_valiant(args.output, config)
     elif args.output and args.output.endswith('.png'):
         renderer = pixel_art_renderer.PixelArtRenderer()
         img = renderer.render(mem)
         img.save(args.output)
     else:
         out_tmpl = args.output or '%s.dat'
         if out_tmpl[-1] == '/' or os.path.isdir(out_tmpl):
             out_tmpl = os.path.join(out_tmpl, '%s.dat')
         if not '%s' in out_tmpl:
             raise errors.CommandLineArgError(
                 'output needs "%s" in its template')
         mem.save_template(out_tmpl, config)
     if args.compile:
         builder = rom_builder.RomBuilder()
         builder.build(mem, args.compile)
Пример #3
0
    def store_vert_pair(self, palette_option, cid_u, did_u, cid_l, did_l,
                        config):
        """Build vertical tile pair, and either retrieve from cache or add chr data.

    palette_option: Chosen palette option for creating the chr data.
    cid_u: Color needs id for upper tile.
    did_u: Dot profile id for upper tile.
    cid_l: Color needs id for lower tile.
    did_l: Dot profile id for lower tile.
    config: Configuration.
    """
        # Create upper tile.
        force = ppu_memory.PpuMemoryConfig(is_sprite=config.is_sprite,
                                           is_locked_tiles=True)
        color_needs = self._color_manifest.at(cid_u)
        xlat_u = self.get_dot_xlat(color_needs, palette_option)
        tile_u = self.build_tile(xlat_u, did_u)
        # Create lower tile.
        color_needs = self._color_manifest.at(cid_l)
        xlat_l = self.get_dot_xlat(color_needs, palette_option)
        tile_l = self.build_tile(xlat_l, did_l)
        # Check if the cache contains this key.
        vert = chr_data.VertTilePair(tile_u, tile_l)
        key = str(vert)
        if key in self._chrdata_cache and not config.is_locked_tiles:
            (chr_num_u, chr_num_l, flip_bits) = self._chrdata_cache[key]
        else:
            # Otherwise, force both tiles to be created.
            (chr_num_u, flip_bits) = self.store_chrdata(xlat_u, did_u, force)
            (chr_num_l, flip_bits) = self.store_chrdata(xlat_l, did_l, force)
            self._chrdata_cache[key] = (chr_num_u, chr_num_l, flip_bits)
            if not config.lock_sprite_flips:
                self.assign_tile_flips(vert, [chr_num_u, chr_num_l],
                                       self._chrdata_cache)
        return chr_num_u, chr_num_l, flip_bits
Пример #4
0
 def BuildConfigFromOptions(self):
     is_locked_tiles = self.lockedTilesCheckBox.GetValue()
     is_sprite = self.spriteModeCheckBox.GetValue()
     allow_s = 's' if self.allowSpriteOverflowCheckBox.GetValue() else ''
     traversal = self.traversalChoices[
         self.traversalComboBox.GetCurrentSelection()]
     allow_c = 'c' if self.allowChrOverflowCheckBox.GetValue() else ''
     config = ppu_memory.PpuMemoryConfig(traversal=traversal,
                                         is_sprite=is_sprite,
                                         is_locked_tiles=is_locked_tiles,
                                         allow_overflow=[allow_s, allow_c])
     return config
Пример #5
0
    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])
Пример #6
0
  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
Пример #7
0
    def process_image(self, img, palette_text, bg_color_mask, bg_color_fill,
                      traversal, is_sprite, is_locked_tiles, lock_sprite_flips,
                      allow_overflow):
        """Process an image, creating the ppu_memory necessary to display it.

    img: Pixel art image.
    palette_text: Optional string representing a palette to be parsed.
    bg_color_mask: Background color mask, if a mask is begin used.
    bg_color_fill: Background color fill.
    traversal: Strategy for traversing the nametable.
    is_sprite: Whether the image is of sprites.
    is_locked_tiles: Whether tiles are locked into place. If so, do not
        merge duplicates, and only handle first 256 tiles.
    lock_sprite_flips: Whether to only lock sprite flip bits.
    allow_overflow: Characters representing components. Only 's' is supported.
    """
        self.initialize()
        self.load_image(img)
        self.blocks_y = NUM_BLOCKS_Y
        self.blocks_x = NUM_BLOCKS_X
        # Assign configuration.
        config = ppu_memory.PpuMemoryConfig(
            is_sprite=is_sprite,
            is_locked_tiles=is_locked_tiles,
            lock_sprite_flips=lock_sprite_flips,
            allow_overflow=allow_overflow)
        if 'c' in config.allow_overflow:
            self._ppu_memory.upgrade_chr_set_to_bank()
        # TODO: Not being used anywhere.
        self._ppu_memory.nt_width = NUM_BLOCKS_X * 2
        # If image is exactly 128x128 and uses locked tiles, treat it as though it
        # represents CHR memory.
        if self.image_x == self.image_y == SMALL_SQUARE and config.is_locked_tiles:
            self.blocks_y = NUM_BLOCKS_SMALL_SQUARE
            self.blocks_x = NUM_BLOCKS_SMALL_SQUARE
            self._ppu_memory.nt_width = NUM_BLOCKS_SMALL_SQUARE * 2
        # In order to auto detect the background color, have to count color needs.
        if config.is_sprite and bg_color_fill is None:
            self._color_manifest = id_manifest.CountingIdManifest()
        # Process each block and tile to build artifacts.
        self.process_to_artifacts(bg_color_mask, bg_color_fill, config)
        if self._err.has():
            return
        # Make the palette, and store it.
        pal = self.make_palette(palette_text, bg_color_fill, config.is_sprite)
        if not pal:
            return
        if not config.is_sprite:
            self._ppu_memory.palette_nt = pal
        else:
            self._ppu_memory.palette_spr = pal
        # Replace mask with fill.
        self.replace_mask_with_fill(bg_color_mask, bg_color_fill)
        # Make colorization for each block and tile.
        self.make_colorization(pal, config)
        if self._err.has():
            return
        # Traverse the artifacts, building chr and other ppu_memory.
        self.traverse_artifacts(traversal, pal, config)
        if self._err.has():
            return
        # Build spritelist if necessary.
        if config.is_sprite:
            self.make_spritelist(traversal, pal, config)
Пример #8
0
    def process_image(self, img, palette_text, bg_color_mask, bg_color_fill,
                      traversal, is_sprite, is_locked_tiles, lock_sprite_flips,
                      allow_overflow):
        """Process an image, creating the ppu_memory necessary to display it.

    img: Pixel art image.
    palette_text: Optional string representing a palette to be parsed.
    bg_color_mask: Background color mask, if a mask is being used.
    bg_color_fill: Background color fill.
    traversal: Strategy for traversing the nametable.
    is_sprite: Whether the image is of sprites.
    is_locked_tiles: Whether tiles are locked into place. If so, do not
        merge duplicates, and only handle first 256 tiles.
    lock_sprite_flips: Whether to only lock sprite flip bits.
    allow_overflow: Characters representing components. Only 'c' and 's'
        are supported.
    """
        self.initialize()
        self.load_image(img)
        # Assign configuration.
        config = ppu_memory.PpuMemoryConfig(
            is_sprite=is_sprite,
            is_locked_tiles=is_locked_tiles,
            lock_sprite_flips=lock_sprite_flips,
            allow_overflow=allow_overflow)
        if 'c' in config.allow_overflow:
            self._ppu_memory.upgrade_chr_set_to_bank()
        # Parse the palette if provided.
        pal = None
        if palette_text or self.img.palette:
            pal = self.parse_palette(palette_text, bg_color_fill)
        # In order to auto detect the background color, have to count color needs.
        # Counting is slower, so don't do it by default.
        if config.is_sprite and bg_color_fill is None:
            self._color_manifest = id_manifest.CountingIdManifest()
        # Process each block and tile to build artifacts.
        self.process_to_artifacts(bg_color_mask, bg_color_fill, config)
        if self._err.has():
            return
        # Make the palette, if it doesn't already exist.
        if not pal:
            pal = self.make_palette(bg_color_fill, config.is_sprite)
        if not pal:
            self.maybe_find_palette_subset_errors()
            return
        if not config.is_sprite:
            self._ppu_memory.palette_nt = pal
        else:
            self._ppu_memory.palette_spr = pal
        # Replace mask with fill.
        self.replace_mask_with_fill(bg_color_mask, bg_color_fill)
        # Make colorization for each block and tile.
        self.make_colorization(pal, config)
        if self._err.has():
            return
        # Traverse the artifacts, building chr and other ppu_memory.
        self.traverse_artifacts(traversal, pal, config)
        if self._err.has():
            return
        # Build spritelist if necessary.
        if config.is_sprite:
            self.make_spritelist(traversal, pal, config)