47 panic(
"anim '" + anim.
name() +
"' has no frames");
50 const auto &representative_frame = anim.
frames().begin()->second;
51 const auto &representative_palette = representative_frame.palette();
55 std::vector<std::string> err_msg{};
57 "Representative frame '{}' internal palette size '{}': must be '{}'.",
58 FormatParam{representative_frame.frame_name(), Style::bold},
59 FormatParam{representative_palette.size(), Style::bold},
61 err_msg.emplace_back(
"");
67 std::vector<std::size_t> extrinsic_transparency_slots;
69 const Rgba32 &color = representative_palette.at(slot);
71 extrinsic_transparency_slots.push_back(slot);
75 if (!extrinsic_transparency_slots.empty()) {
76 std::string slot_list;
77 for (
const auto &slot : extrinsic_transparency_slots) {
78 if (!slot_list.empty()) {
81 slot_list += std::to_string(slot);
83 std::vector<std::string> err_msg{};
85 "Representative frame '{}' palette contains extrinsic transparency color '{}' in non-zero slot(s): {}",
86 FormatParam{representative_frame.frame_name(), Style::bold},
87 FormatParam{extrinsic_transparency.value().to_jasc_str(), Style::bold},
89 err_msg.emplace_back(
"");
90 err_msg.emplace_back(
"The extrinsic transparency color should only appear in slot 0.");
91 err_msg.emplace_back(
"Either correct the PNG palette or change the extrinsic transparency setting.");
92 err_msg.emplace_back(
"");
100 for (
const auto &[frame_name, frame] : anim.frames()) {
101 if (&frame == &representative_frame) {
104 const auto &frame_palette = frame.palette();
105 bool palettes_match = (frame_palette.size() == representative_palette.size());
106 if (palettes_match) {
107 for (std::size_t slot = 0; slot < representative_palette.size(); ++slot) {
108 if (frame_palette.at(slot) != representative_palette.at(slot)) {
109 palettes_match =
false;
114 if (!palettes_match) {
115 std::vector<std::string> err_msg{};
117 "Animation '{}' frame '{}' has an internal palette that does not match the representative frame '{}' "
122 err_msg.emplace_back(
"");
126 err_msg.emplace_back(
"");
135 for (std::size_t palette_idx = 0; palette_idx < tileset_palettes.size(); ++palette_idx) {
138 const Rgba32 &png_palette_color = representative_palette.at(slot);
142 panic(
"png_palette slot " + std::to_string(slot) +
" is extrinsically transparent");
145 const Rgba32 &tileset_color = tileset_palettes[palette_idx].at(slot);
146 if (png_palette_color != tileset_color) {
154 std::vector<std::string> remark_lines;
156 "Animation '{}' representative frame '{}' internal palette matched Porymap palette '{}':",
158 FormatParam{representative_frame.frame_name(), Style::bold},
159 FormatParam{palette_filename(palette_idx), Style::bold}));
160 remark_lines.emplace_back(
"");
161 remark_lines.append_range(palette_printer.
print_rgba_palette(tileset_palettes[palette_idx]));
162 diag.
remark(
"animation-palette-resolution-strategy", remark_lines);
167 std::vector<std::string> err_msg{};
169 "Failed to find matching palette for internal palette of representative frame '{}'.",
170 FormatParam{representative_frame.frame_name(), Style::bold}));
171 err_msg.emplace_back(
"");
179 case AnimPaletteResolutionStrategy::palette_00:
181 case AnimPaletteResolutionStrategy::palette_01:
183 case AnimPaletteResolutionStrategy::palette_02:
185 case AnimPaletteResolutionStrategy::palette_03:
187 case AnimPaletteResolutionStrategy::palette_04:
189 case AnimPaletteResolutionStrategy::palette_05:
191 case AnimPaletteResolutionStrategy::palette_06:
193 case AnimPaletteResolutionStrategy::palette_07:
195 case AnimPaletteResolutionStrategy::palette_08:
197 case AnimPaletteResolutionStrategy::palette_09:
199 case AnimPaletteResolutionStrategy::palette_10:
201 case AnimPaletteResolutionStrategy::palette_11:
203 case AnimPaletteResolutionStrategy::palette_12:
205 case AnimPaletteResolutionStrategy::palette_13:
207 case AnimPaletteResolutionStrategy::palette_14:
209 case AnimPaletteResolutionStrategy::palette_15:
237 const std::string &anim_name,
238 std::size_t subtile_index,
239 std::size_t tile_index,
240 std::span<const TilemapEntry> metatiles_bin,
250 std::optional<std::size_t> &internal_png_palette_cache)
253 const auto explicit_palette = extract_palette_index(strategy.
value());
254 if (explicit_palette.has_value()) {
256 "animation-palette-resolution-strategy",
258 "Animation '{}' subtile {} using explicit palette '{}'.",
263 return *explicit_palette;
266 switch (strategy.
value()) {
267 case AnimPaletteResolutionStrategy::scan_local_metatiles: {
268 std::set<std::size_t> found_for_subtile{};
270 for (
const auto &entry : metatiles_bin) {
271 if (entry.tile_index() == tile_index) {
272 found_for_subtile.insert(entry.palette_index());
276 if (found_for_subtile.empty()) {
277 std::vector<std::string> err_msg{};
279 "Animation '{}' subtile {} at tile index '{}' is not referenced in local metatiles.",
283 err_msg.emplace_back(
284 "Consider using a different palette resolution strategy (e.g. 'palette-00', "
285 "'internal-png-palette', etc.).");
290 if (found_for_subtile.size() > 1) {
295 std::string palette_list;
296 for (
const auto &palette_idx : found_for_subtile) {
297 if (!palette_list.empty()) {
298 palette_list +=
", ";
303 switch (multi_palette_strategy.
value()) {
304 case AnimMultiPaletteSubtileResolutionStrategy::error: {
305 std::vector<std::string> err_msg;
307 "Animation '{}' subtile {} at tile index '{}' is referenced with multiple palettes: {}.",
312 err_msg.emplace_back(
313 "Picking one palette arbitrarily would produce incorrect RGBA output in the layer PNGs.");
316 err_msg.emplace_back(
"");
317 for (
const auto &palette_idx : found_for_subtile) {
319 index_tile, palettes.at(palette_idx), extrinsic_transparency.
value());
321 "Tile under palette '{}':",
FormatParam{palette_filename(palette_idx), Style::bold}));
322 err_msg.append_range(tile_printer.
print_tile(rgba_tile, extrinsic_transparency.
value()));
325 err_msg.emplace_back(
"");
326 err_msg.emplace_back(
327 "Consider using an explicit palette resolution strategy (e.g. 'palette-00') to resolve the "
332 case AnimMultiPaletteSubtileResolutionStrategy::warning: {
333 const std::size_t chosen_palette = *found_for_subtile.begin();
335 std::vector<std::string> warn_msg;
337 "Animation '{}' subtile {} at tile index '{}' is referenced with multiple palettes: {}.",
343 "Using palette '{}'. Set 'frame_linking: manual' to handle palette assignment via overrides.",
344 FormatParam{palette_filename(chosen_palette), Style::bold}));
347 warn_msg.emplace_back(
"");
348 for (
const auto &palette_idx : found_for_subtile) {
350 warn_index_tile, palettes.at(palette_idx), extrinsic_transparency.
value());
352 "Tile under palette '{}':",
FormatParam{palette_filename(palette_idx), Style::bold}));
353 warn_msg.append_range(tile_printer.
print_tile(rgba_tile, extrinsic_transparency.
value()));
357 diag.
warning(
"animation-multi-pal-subtile", warn_msg);
359 return chosen_palette;
361 case AnimMultiPaletteSubtileResolutionStrategy::split:
363 "The 'split' mode for multi-palette subtile resolution is not yet implemented."};
367 return *found_for_subtile.begin();
370 case AnimPaletteResolutionStrategy::internal_png_palette: {
371 if (internal_png_palette_cache.has_value()) {
372 return *internal_png_palette_cache;
374 std::vector<std::string> err_msg{};
376 "Palette resolution strategy '{}' failed.",
377 FormatParam{to_string(AnimPaletteResolutionStrategy::internal_png_palette), Style::bold}));
381 internal_png_palette_strategy(anim, palettes, extrinsic_transparency, diag, palette_printer),
384 internal_png_palette_cache = match;
388 case AnimPaletteResolutionStrategy::scan_all_tilesets:
389 panic(
"scan_all_tilesets not yet implemented");
392 panic(
"unhandled AnimPaletteResolutionStrategy value");
397 const std::string &anim_name,
398 std::size_t tile_offset,
399 std::size_t tile_count,
400 std::span<const TilemapEntry> metatiles_bin,
411 if (per_subtile_strategies.size() != tile_count) {
413 "per_subtile_strategies size " + std::to_string(per_subtile_strategies.size()) +
" != tile_count " +
414 std::to_string(tile_count));
417 std::vector<std::size_t> per_tile_palettes(tile_count);
418 std::optional<std::size_t> internal_png_palette_cache;
420 for (std::size_t i = 0; i < tile_count; ++i) {
421 const std::size_t tile_index = tile_offset + i;
424 resolve_subtile_palette(
429 per_subtile_strategies[i],
430 multi_palette_strategy,
434 extrinsic_transparency,
438 internal_png_palette_cache),
439 std::vector<std::size_t>,
441 "Failed to resolve palette for animation '{}' subtile {}.",
444 per_tile_palettes[i] = palette_idx;
448 if (tile_count > 1) {
449 const std::size_t first_palette = per_tile_palettes.at(0);
450 const bool uses_multiple_palettes =
451 !std::ranges::all_of(per_tile_palettes, [&](std::size_t idx) {
return idx == first_palette; });
452 if (uses_multiple_palettes) {
453 std::set<std::size_t> unique_palettes{per_tile_palettes.begin(), per_tile_palettes.end()};
454 std::string palette_list;
455 for (
const auto &palette_idx : unique_palettes) {
456 if (!palette_list.empty()) {
457 palette_list +=
", ";
462 "animation-palette-resolution-strategy",
464 "Animation '{}' uses multiple palettes across subtiles: {}.",
470 return per_tile_palettes;
473struct DuplicateInfo {
474 std::vector<std::size_t> inter_anim_indices;
475 std::vector<std::size_t> cross_range_indices;
476 std::vector<std::pair<std::size_t, std::size_t>> intra_anim_pairs;
478 [[nodiscard]]
bool any()
const
480 return !inter_anim_indices.empty() || !cross_range_indices.empty() || !intra_anim_pairs.empty();
497[[nodiscard]] DuplicateInfo categorize_duplicate_key_frame_tiles(
500 const std::vector<
const std::set<
PixelTile<Rgba32>> *> &external_canonical_rgba_tiles)
505 std::map<PixelTile<Rgba32>, std::size_t> seen;
507 for (std::size_t i = 0; i < key_frame_canonical_rgba_tiles.size(); ++i) {
511 if (inter_anim_canonical_tiles.contains(base)) {
512 info.inter_anim_indices.push_back(i);
514 else if (external_canonical_rgba_tiles[i]->contains(base)) {
515 info.cross_range_indices.push_back(i);
518 auto [it, inserted] = seen.emplace(base, i);
520 info.intra_anim_pairs.emplace_back(it->second, i);
532void backport_mangles_to_tiles_png(
541 for (
const auto &record : records) {
542 const std::size_t global_tile_idx = base_tile_offset + record.tile_index;
543 const std::size_t tile_row = global_tile_idx / tiles_per_row;
544 const std::size_t tile_col = global_tile_idx % tiles_per_row;
546 for (
const auto &change : record.pixel_changes) {
551 tiles_img.
set(img_row, img_col, change.mangled_pixel);
563 const std::string &tileset_name,
573 config_, global_anim_multi_palette_subtile_resolution_strategy, tileset_name,
Animation<Rgba32>);
578 const auto &palettes = porymap_component.
palettes();
579 const auto &metatiles_bin = porymap_component.
metatiles_bin();
580 const auto &tiles_png = porymap_component.
tiles_png();
583 result.params(anim.
params());
590 if (tile_count == 0) {
592 std::vector<std::string>{
593 "Animation '{}' has a tile count of '{}'.",
594 "The animation's generated C code may not have been parsed correctly, or the animation defines no "
596 std::vector<std::vector<FormatParam>>{
599 if (tile_offset == 0) {
601 std::vector<std::string>{
602 "Animation '{}' has a tile offset of '{}'.",
603 "Tile 0 in tiles.png is reserved and cannot be an animation tile."},
604 std::vector<std::vector<FormatParam>>{
612 std::vector<ConfigValue<AnimPaletteResolutionStrategy>> per_subtile_strategies;
613 per_subtile_strategies.reserve(tile_count);
615 const auto &configs_map = per_anim_overrides.value();
616 const auto anim_cfg_it = configs_map.find(anim.
name());
617 const PerAnimOverride *anim_cfg_ptr = (anim_cfg_it != configs_map.end()) ? &anim_cfg_it->second :
nullptr;
619 if (anim_cfg_ptr !=
nullptr) {
626 : global_anim_palette_resolution_strategy;
631 std::vector<std::string>{
632 "Animation '{}' config 'per_tile_palette_resolution_strategies' has '{}' entries, but "
633 "animation has '{}' subtiles.",
634 "The per_tile_palette_resolution_strategies list must have exactly one entry per subtile."},
635 std::vector<std::vector<FormatParam>>{
641 for (std::size_t i = 0; i < tile_count; ++i) {
643 per_subtile_strategies.push_back(
647 per_subtile_strategies.push_back(effective_default);
653 for (std::size_t i = 0; i < tile_count; ++i) {
654 per_subtile_strategies.push_back(effective_default);
660 for (std::size_t i = 0; i < tile_count; ++i) {
661 per_subtile_strategies.push_back(global_anim_palette_resolution_strategy);
670 : global_anim_multi_palette_subtile_resolution_strategy;
675 : global_frame_linking;
678 std::vector<std::string> err_msg{};
681 err_msg.emplace_back(
"Use 'automatic' or 'manual' frame linking until hybrid support.");
689 std::vector<AnimOverrideEntry> overrides;
691 for (std::size_t mt_idx = 0; mt_idx < num_metatiles; ++mt_idx) {
694 if (entry.tile_index() >= tile_offset && entry.tile_index() < tile_offset + tile_count) {
701 entry.tile_index() - tile_offset,
710 result_params.
overrides(std::move(overrides));
711 result.params(std::move(result_params));
715 manual_palette_indices,
716 find_palettes_for_anim_tiles(
721 per_subtile_strategies,
722 effective_multi_palette_strategy,
726 extrinsic_transparency,
732 "Failed to find palette for animation '{}'.",
FormatParam{anim.name(), Style::bold}));
735 std::vector<PixelTile<Rgba32>> rgba_tiles;
736 rgba_tiles.reserve(frame.tiles().size());
737 for (std::size_t i = 0; i < frame.tiles().size(); ++i) {
739 frame.tiles()[i], palettes.at(manual_palette_indices[i]), extrinsic_transparency.
value()));
742 result.put_frame(frame.frame_name(), std::move(rgba_frame));
751 find_palettes_for_anim_tiles(
756 per_subtile_strategies,
757 effective_multi_palette_strategy,
761 extrinsic_transparency,
769 std::vector<const Palette<Rgba32, palette::max_size> *> palette_ptrs;
770 palette_ptrs.reserve(palette_indices.size());
771 for (std::size_t idx : palette_indices) {
772 palette_ptrs.push_back(&palettes.at(idx));
776 std::vector<PixelTile<IndexPixel>> key_frame_index_tiles =
783 std::vector<PixelTile<Rgba32>> key_frame_canonical_rgba_tiles;
784 key_frame_canonical_rgba_tiles.reserve(tile_count);
785 for (std::size_t i = 0; i < key_frame_index_tiles.size(); ++i) {
787 key_frame_index_tiles[i], *palette_ptrs[i], extrinsic_transparency.
value()));
794 const std::size_t total_tiles =
796 const std::set<std::size_t> distinct_palette_indices{palette_indices.begin(), palette_indices.end()};
797 std::map<std::size_t, std::set<PixelTile<Rgba32>>> external_rgba_by_palette;
798 for (
const std::size_t palette_idx : distinct_palette_indices) {
799 auto &tile_set = external_rgba_by_palette[palette_idx];
800 for (std::size_t i = 0; i < total_tiles; ++i) {
801 if (i >= tile_offset && i < tile_offset + tile_count) {
812 std::map<std::size_t, std::set<PixelTile<Rgba32>>> combined_rgba_by_palette = external_rgba_by_palette;
813 for (
auto &tile_set : combined_rgba_by_palette | std::views::values) {
814 tile_set.insert(inter_anim_canonical_tiles.begin(), inter_anim_canonical_tiles.end());
817 std::vector<const std::set<PixelTile<Rgba32>> *> external_per_subtile;
818 std::vector<const std::set<PixelTile<Rgba32>> *> combined_per_subtile;
819 external_per_subtile.reserve(tile_count);
820 combined_per_subtile.reserve(tile_count);
821 for (
const std::size_t palette_idx : palette_indices) {
822 external_per_subtile.push_back(&external_rgba_by_palette.at(palette_idx));
823 combined_per_subtile.push_back(&combined_rgba_by_palette.at(palette_idx));
830 : global_anim_key_frame_resolution_strategy;
836 const auto dup_info = categorize_duplicate_key_frame_tiles(
837 key_frame_canonical_rgba_tiles, inter_anim_canonical_tiles, external_per_subtile);
838 if (dup_info.any()) {
839 switch (effective_key_frame_strategy.
value()) {
841 std::vector<std::string> err_msg{};
843 "Animation '{}' has duplicate key frame tiles:",
FormatParam{anim.name(), Style::bold}));
844 for (
const auto &idx : dup_info.inter_anim_indices) {
848 for (
const auto &idx : dup_info.cross_range_indices) {
852 for (
const auto &[i, j] : dup_info.intra_anim_pairs) {
856 err_msg.emplace_back(
"");
857 err_msg.emplace_back(
858 "Tiles are compared by resolved color: flip-equivalent tiles, and tiles that reference different "
859 "palette slots holding the same color, count as duplicates.");
860 err_msg.emplace_back(
"");
861 err_msg.emplace_back(
"Consider using 'mangle' strategy to auto-resolve.");
867 panic(
"warning not yet implemented");
874 mangler.mangle_duplicates(
876 std::move(key_frame_index_tiles),
878 extrinsic_transparency.
value(),
879 combined_per_subtile),
882 "Failed to mangle duplicate key frame tiles for animation '{}'.",
884 key_frame_index_tiles = std::move(mangle_result.tiles);
887 if (!mangle_result.mangle_records.empty()) {
888 backport_mangles_to_tiles_png(porymap_component, tile_offset, mangle_result.mangle_records);
894 panic(
"unhandled AnimKeyFrameResolutionStrategy value");
899 std::vector<PixelTile<Rgba32>> key_frame_rgba_tiles;
900 key_frame_rgba_tiles.reserve(key_frame_index_tiles.size());
901 for (std::size_t i = 0; i < key_frame_index_tiles.size(); ++i) {
903 key_frame_index_tiles[i], palettes.at(palette_indices[i]), extrinsic_transparency.
value()));
907 AnimFrame key_frame{
"key", std::move(key_frame_rgba_tiles)};
908 result.key_frame(std::move(key_frame));
911 if (frame.tiles().size() != tile_count) {
913 "frame '" + frame.frame_name() +
"' tile count " + std::to_string(frame.tiles().size()) +
914 " != animation tile_count " + std::to_string(tile_count));
917 std::vector<PixelTile<Rgba32>> rgba_tiles;
918 rgba_tiles.reserve(frame.tiles().size());
920 for (std::size_t i = 0; i < frame.tiles().size(); ++i) {
922 frame.tiles()[i], palettes.at(palette_indices[i]), extrinsic_transparency.
value()));
926 result.put_frame(frame.frame_name(), std::move(rgba_frame));
#define PT_TRY_ASSIGN_CHAIN_ERR(var, expr, return_type,...)
Unwraps a ChainableResult, chaining a new error message on failure.
ChainableResult< Animation< Rgba32 > > decompile_animation(const std::string &tileset_name, const Animation< IndexPixel > &anim, const std::set< PixelTile< Rgba32 > > &inter_anim_canonical_tiles, PorymapTilesetComponent &porymap_component) const
Decompiles an IndexPixel animation to Rgba32 format.
Represents a single frame of an animation, containing tiles and a frame name.
const std::string & frame_name() const
Service that mangles duplicate key frame tiles to make them unique.
Configuration parameters for a single tileset animation.
const std::vector< AnimOverrideEntry > & overrides() const
Returns the manual override entries for this animation.
std::size_t tile_offset() const
Returns the VRAM tile offset for this animation.
std::size_t tile_count() const
Returns the number of tiles per animation frame.
A complete tileset animation with name, configuration, and frame data.
const AnimParams & params() const
bool has_frames() const
Checks if this animation has any frames.
const std::string & name() const
std::vector< AnimFrame< PixelType > > frames_values() const
const std::map< std::string, AnimFrame< PixelType > > & frames() const
A result type that maintains a chainable sequence of errors for debugging and error reporting.
A container that wraps a configuration value with its name and source information.
ConfigValue< U > derive(const ConfigPODField< U > &override) const
Creates a child ConfigValue from a ConfigPODField, inheriting this value's source provenance.
const T & value() const &
A template for two-dimensional images with arbitrarily typed pixel values.
void set(std::size_t i, PixelType pixel)
Sets the pixel value at a given one-dimensional pixel index.
std::size_t width() const
std::size_t height() const
A collection of printer functions for the Palette and related types.
virtual std::vector< std::string > print_rgba_palette_with_highlights(const Palette< Rgba32 > &palette, const std::vector< std::size_t > &slots) const =0
virtual std::vector< std::string > print_rgba_palette(const Palette< Rgba32, palette::max_size > &palette) const =0
A generic palette container for colors that support transparency checking.
An 8x8 tile backed by literal-array-based per-pixel storage of an arbitrary pixel type.
const std::vector< TilemapEntry > & metatiles_bin() const
const Image< IndexPixel > & tiles_png() const
const std::array< Palette< Rgba32, palette::max_size >, palette::num_palettes > & palettes() const
Represents a 32-bit RGBA color.
bool is_transparent(const Rgba32 &extrinsic) const
Checks if this color should be treated as transparent.
bool is_extrinsically_transparent(const Rgba32 &extrinsic) const
Checks if this color matches the extrinsic transparency color.
static const Style bold
Bold text formatting.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > ¶ms) const
Formats a string with styled parameters using fmtlib syntax.
A collection of printer functions for various tile types.
virtual std::vector< std::string > print_tile(const PixelTile< Rgba32 > &tile, const Rgba32 &extrinsic_transparency) const =0
Abstract class for structured error reporting and diagnostic output.
virtual void remark(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged remark message.
const TextFormatter & formatter() const
virtual void warning(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged warning message.
virtual void remark_note(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged note message associated with a remark.
constexpr std::size_t max_size
constexpr std::size_t num_palettes
constexpr std::size_t side_length_pix
constexpr std::pair< std::size_t, std::size_t > index_to_row_col(std::size_t index)
Converts a linear index to row and column coordinates.
PixelTile< PixelType > extract_single_tile(const Image< PixelType > &img, std::size_t tile_idx, std::size_t tiles_per_row=metatile::metatiles_per_row *metatile::tiles_per_side)
Extracts a single tile from an image at a given tile index.
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
std::vector< PixelTile< PixelType > > extract_tiles_from_image(const Image< PixelType > &img, std::size_t tile_offset, std::size_t tile_count, std::size_t tiles_per_row=16)
Extracts a subset of 8x8 tiles from a tileset image at a specific offset.
AnimPaletteResolutionStrategy
Strategy for determining which palette to use when decompiling animation tiles.
PixelTile< ColorType > canonical_color_tile_from_index_tile(const PixelTile< IndexPixel > &index_tile, const Palette< ColorType, N > &palette, const ColorType &extrinsic)
Converts a PixelTile<IndexPixel> to its canonical color form using a palette (extrinsic transparency)...
std::vector< std::string > format_config_note(const TextFormatter &format, const ConfigValue< T > &config)
Format a ConfigValue into diagnostic note lines.
std::vector< std::string > format_config_note_with_separator(const TextFormatter &format, const ConfigValue< T > &config)
Format a ConfigValue into diagnostic note lines with a separator.
@ warning
Emit a warning and continue decompilation.
@ mangle
Mangle duplicate tiles to make them unique, then backport changes to tiles.png.
@ error
Emit a formatted error and fail decompilation.
std::string palette_filename(std::size_t palette_index)
Constructs a palette filename from a palette index.
@ manual
Use manual overrides in anim.json.
@ hybrid
Automatic key.png linking plus manual override pass (not yet implemented).
PixelTile< ColorType > color_tile_from_index_tile(const PixelTile< IndexPixel > &index_tile, const Palette< ColorType, N > &palette)
Converts a PixelTile<IndexPixel> to a PixelTile<ColorType> using a palette (intrinsic transparency).
A manual override that maps a specific metatile entry to an animation subtile.
std::size_t palette_index
The palette index to use for this tile.
bool has_value() const
Checks whether this field has a value set.
Per-animation configuration override for animation decompilation.
std::vector< ConfigPODField< AnimPaletteResolutionStrategy > > per_tile_palette_resolution_strategies
ConfigPODField< AnimKeyFrameResolutionStrategy > key_frame_resolution_strategy
ConfigPODField< AnimMultiPaletteSubtileResolutionStrategy > multi_palette_subtile_resolution_strategy
ConfigPODField< FrameLinking > linking
ConfigPODField< AnimPaletteResolutionStrategy > palette_resolution_strategy
#define PT_UNWRAP_TILESET_CONFIG_PTR(ptr, config, tileset_name, return_type)
Unwraps a tileset-scoped config value via pointer access, returning early if the value is not availab...