73 std::size_t metatile_index,
74 std::size_t internal_tile_index,
77 const std::string &diagnostic_code,
78 const std::string &error_message,
79 const Rgba32 &extrinsic_transparency)
88 metatile, layer, subtile, row, col, extrinsic_transparency);
89 errors.append_range(highlight);
90 services.
diag.
error(diagnostic_code, errors);
115 const std::string &anim_name,
116 const std::string &frame_name,
117 std::size_t internal_tile_index,
120 const std::string &diagnostic_code,
121 const std::string &error_message,
122 const Rgba32 &extrinsic_transparency)
131 errors.append_range(highlight);
132 services.
diag.
error(diagnostic_code, errors);
155 const std::string &anim_name,
156 const std::string &frame_name,
157 std::size_t internal_tile_index,
158 const std::string &diagnostic_code,
159 const std::string &error_message,
160 const Rgba32 &extrinsic_transparency)
168 errors.append_range(tile_visual);
169 services.
diag.
error(diagnostic_code, errors);
184 const std::string &tag,
186 const std::map<Rgba32, unsigned int> &color_counts)
188 std::vector<std::string> color_lines;
189 color_lines.emplace_back(
"color counts:");
191 color_lines.append_range(counts);
216 const std::string &tileset_name,
223 std::size_t metatile_limit = is_secondary ? (num_metatiles_total.value() - num_metatiles_in_primary.value())
224 : num_metatiles_in_primary.value();
226 if (metatiles.size() > metatile_limit) {
228 "metatile-limit-exceeded",
229 "Too many metatiles ({}) in Porytiles component for tileset '{}'.",
233 std::vector<std::string> note_text;
240 num_metatiles_in_primary));
245 note_text.emplace_back(
"");
251 "Found '{}' metatiles, limit is '{}'.",
280 const std::string &tileset_name,
282 std::size_t pal_index)
286 bool hit_error =
false;
288 std::vector<std::size_t> violating_slots{};
291 panic(
"unexpected wildcard in Porymap palette slot 0");
297 std::vector<std::string> warning_lines;
299 "Porymap palette '{}' slot 0 color '{}' does not match extrinsic transparency '{}'",
301 FormatParam{slot0_color.to_jasc_str(), Style::bold},
302 FormatParam{extrinsic_transparency.value().to_jasc_str(), Style::bold}));
303 warning_lines.emplace_back(
"Slot 0 is typically reserved for the transparency color.");
304 warning_lines.emplace_back(
"If you are using slot 0 for a .pla blend color, you can ignore this warning.");
305 services.
diag.
warning(
"porymap-palette-slot-0", warning_lines);
308 "porymap-palette-slot-0",
312 "reserved transparency slot",
315 std::vector<std::size_t>{0}));
321 for (std::size_t slot = 1; slot < pal.
size(); ++slot) {
323 panic(
"unexpected wildcard in Porymap palette");
328 violating_slots.push_back(slot);
329 std::vector<std::string> error_lines;
331 "Porymap palette '{}' slot '{}' contains extrinsic transparency color '{}'",
335 error_lines.emplace_back(
"Extrinsic transparency is not allowed in non-slot-0 positions.");
336 services.
diag.
error(
"porymap-palette-transparency", error_lines);
343 "porymap-palette-transparency",
347 "slots with invalid extrinsic transparency",
383 const std::string &tileset_name,
385 std::size_t pal_index)
389 bool hit_error =
false;
391 std::vector<std::size_t> violating_slots;
398 std::vector<std::string> warning_text;
400 "Porytiles palette '{}' slot 0 color '{}' does not match extrinsic transparency '{}'",
402 FormatParam{slot0_color.to_jasc_str(), Style::bold},
403 FormatParam{extrinsic_transparency.value().to_jasc_str(), Style::bold}));
404 warning_text.emplace_back(
"Slot 0 is typically reserved for the transparency color.");
405 warning_text.emplace_back(
"If you are using slot 0 for a .pla blend color, you can ignore this warning.");
406 services.
diag.
warning(
"porytiles-palette-slot-0", warning_text);
410 "porytiles-palette-slot-0",
414 "reserved transparency slot",
417 std::vector<std::size_t>{0}));
424 for (std::size_t slot = 1; slot < pal.
size(); ++slot) {
431 violating_slots.push_back(slot);
432 std::vector<std::string> error_lines;
434 "Porytiles palette '{}' slot '{}' contains extrinsic transparency color '{}'",
438 error_lines.emplace_back(
"Extrinsic transparency is not allowed in non-slot-0 positions.");
439 services.
diag.
error(
"porytiles-palette-transparency", error_lines);
446 "porytiles-palette-transparency",
450 "slots with invalid extrinsic transparency",
491 bool hit_any_error =
false;
492 const std::string &hint_name = hint.
name();
496 "palette-hint-size-violation",
498 "palette hint '{}' has size '{}', max allowed size is '{}'",
503 "palette-hint-size-violation",
507 "invalid extra slots start here",
510 std::vector{pal::max_size}));
514 std::set<Rgba32> seen_colors{};
515 std::vector<std::size_t> violating_slots{};
518 for (std::size_t slot = 0; slot < hint.
pal().size(); ++slot) {
519 if (hint.
pal().is_wildcard(slot)) {
522 const Rgba32 color = hint.
pal().at(slot);
525 hit_any_error =
true;
526 violating_slots.push_back(slot);
527 std::vector<std::string> error_lines;
529 "palette hint '{}' slot '{}' contains extrinsic transparency color '{}'",
533 error_lines.emplace_back(
"Extrinsic transparency is not allowed in palette hints.");
534 services.
diag.
error(
"palette-hint-transparency", error_lines);
537 if (!violating_slots.empty()) {
539 "palette-hint-transparency",
543 "slots with invalid extrinsic transparency",
550 violating_slots.clear();
553 for (std::size_t slot = 0; slot < hint.
pal().size(); ++slot) {
554 if (hint.
pal().is_wildcard(slot)) {
557 const Rgba32 color = hint.
pal().at(slot);
559 if (seen_colors.contains(color)) {
560 hit_any_error =
true;
561 violating_slots.push_back(slot);
562 std::vector<std::string> error_lines;
564 "palette hint '{}' contains duplicate color '{}' at slot '{}'",
568 error_lines.emplace_back(
"Duplicate colors are not allowed in palette hints.");
569 services.
diag.
error(
"palette-hint-duplicate-color", error_lines);
571 seen_colors.insert(color);
573 if (!violating_slots.empty()) {
575 "palette-hint-duplicate-color",
579 "slots with invalid duplicate colors",
608 const std::string &tileset_name,
614 bool hit_error =
false;
617 std::size_t metatile_index = 0;
618 for (
const auto &metatile : metatiles) {
619 const auto decomposed_metatile = metatile.decompose();
622 for (std::size_t internal_tile_index = 0; internal_tile_index < decomposed_metatile.size();
623 ++internal_tile_index) {
624 const auto &tile = decomposed_metatile[internal_tile_index];
629 const auto &pixel = tile.at(row, col);
641 "alpha-channel-violation",
643 extrinsic_transparency);
652 auto validate_anim_frame = [&services, &hit_error, &extrinsic_transparency](
654 const auto &frame_tiles = frame.tiles();
657 for (std::size_t internal_tile_index = 0; internal_tile_index < frame_tiles.size(); ++internal_tile_index) {
658 const auto &tile = frame_tiles.at(internal_tile_index);
663 const auto &pixel = tile.at(row, col);
678 "alpha-channel-violation",
680 extrinsic_transparency);
688 for (
const auto &[anim_name, anim] : anims) {
689 if (anim.has_key_frame()) {
690 const auto &key_frame = anim.key_frame();
691 validate_anim_frame(anim_name, key_frame);
694 validate_anim_frame(anim_name, frame);
699 return FormattableError{
"Found input pixel(s) with invalid alpha channel value(s)."};
727 const std::string &tileset_name,
739 bool hit_error =
false;
740 std::size_t metatile_index = 0;
742 for (
const auto &metatile : metatiles) {
745 bool found_triple_layer_region =
false;
748 const auto &bottom_tile = metatile.bottom(subtile_idx);
749 const auto &middle_tile = metatile.middle(subtile_idx);
750 const auto &top_tile = metatile.top(subtile_idx);
754 const bool bottom_has_opaque = !bottom_tile.is_transparent(extrinsic_transparency.value());
755 const bool middle_has_opaque = !middle_tile.is_transparent(extrinsic_transparency.value());
756 const bool top_has_opaque = !top_tile.is_transparent(extrinsic_transparency.value());
759 if (bottom_has_opaque && middle_has_opaque && top_has_opaque) {
760 found_triple_layer_region =
true;
772 FormatParam{
"non-transparent content on all three layers"})};
779 errors.append_range(bottom_highlight);
780 errors.append_range(middle_highlight);
781 errors.append_range(top_highlight);
782 services.
diag.
error(
"layer-mode-violation", errors);
790 std::vector<std::string> note_text;
793 note_text.emplace_back(
"");
795 note_text.emplace_back(
"");
796 note_text.emplace_back(
"Consider enabling triple-layer metatiles.");
800 " - set '{}' = '{}'",
804 " - follow the steps here: {}",
810 return FormattableError{
"Found metatile(s) with mismatched implied layer mode."};
835 const std::string &tileset_name,
841 bool hit_error =
false;
842 std::size_t metatile_index = 0;
843 for (
const auto &metatile : metatiles) {
844 const auto decomposed_metatile = metatile.decompose();
847 for (std::size_t internal_tile_index = 0; internal_tile_index < decomposed_metatile.size();
848 ++internal_tile_index) {
849 const auto &tile = decomposed_metatile[internal_tile_index];
850 std::map<Rgba32, unsigned int> color_counts;
855 const auto &pixel = tile.at(row, col);
857 color_counts[pixel]++;
863 "found {}th unique tile color: {}",
873 "tile-color-count-violation",
875 extrinsic_transparency);
886 auto validate_anim_frame = [&services, &hit_error, &extrinsic_transparency](
888 const auto &frame_tiles = frame.tiles();
890 for (std::size_t internal_tile_index = 0; internal_tile_index < frame_tiles.size(); ++internal_tile_index) {
891 const auto &tile = frame_tiles[internal_tile_index];
892 std::map<Rgba32, unsigned int> color_counts;
897 const auto &pixel = tile.at(row, col);
899 color_counts[pixel]++;
905 "found {}th unique frame tile color: {}",
916 "tile-color-count-violation",
918 extrinsic_transparency);
929 for (
const auto &[anim_name, anim] : anims) {
930 if (anim.has_key_frame()) {
931 const auto &key_frame = anim.key_frame();
932 validate_anim_frame(anim_name, key_frame);
935 validate_anim_frame(anim_name, frame);
972 const std::string &tileset_name,
977 const std::vector<PaletteHint> &hints)
986 std::map<Rgba32, unsigned int> color_counts{};
987 bool hit_first_violation =
false;
990 std::size_t metatile_index = 0;
991 for (
const auto &metatile : metatiles) {
992 const auto decomposed_metatile = metatile.decompose();
993 for (std::size_t internal_tile_index = 0; internal_tile_index < decomposed_metatile.size();
994 ++internal_tile_index) {
995 const auto &tile = decomposed_metatile[internal_tile_index];
998 const auto &pixel = tile.at(row, col);
999 if (!pixel.is_transparent(extrinsic_transparency)) {
1000 color_counts[pixel]++;
1007 if (color_counts.size() > count_max && !hit_first_violation) {
1008 hit_first_violation =
true;
1010 "found {}th globally unique color: {}",
1017 internal_tile_index,
1020 "global-color-count-violation",
1022 extrinsic_transparency);
1031 auto validate_anim_frame = [&services, &hit_first_violation, &color_counts, &count_max, &extrinsic_transparency](
1033 const auto &frame_tiles = frame.tiles();
1035 for (std::size_t internal_tile_index = 0; internal_tile_index < frame_tiles.size(); ++internal_tile_index) {
1036 const auto &tile = frame_tiles.at(internal_tile_index);
1041 const auto &pixel = tile.at(row, col);
1043 if (!pixel.is_transparent(extrinsic_transparency)) {
1044 color_counts[pixel]++;
1051 if (color_counts.size() > count_max && !hit_first_violation) {
1052 hit_first_violation =
true;
1054 "found {}th globally unique color: {}",
1062 internal_tile_index,
1065 "global-color-count-violation",
1067 extrinsic_transparency);
1074 for (
const auto &[anim_name, anim] : anims) {
1075 if (anim.has_key_frame()) {
1076 const auto &key_frame = anim.key_frame();
1077 validate_anim_frame(anim_name, key_frame);
1080 validate_anim_frame(anim_name, frame);
1089 std::set<Rgba32> unused_manual_colors{};
1090 for (std::size_t pal_index = 0; pal_index < num_pals_cfg; ++pal_index) {
1093 if (porytiles_pals.at(pal_index).has_value()) {
1094 const auto &pal = porytiles_pals.at(pal_index).value();
1095 std::vector<std::size_t> unused_slots{};
1097 for (std::size_t slot_index = 0; slot_index < pal.size(); ++slot_index) {
1098 if (pal.is_wildcard(slot_index)) {
1102 const auto &pixel = pal.at(slot_index);
1112 if ((!color_counts.contains(pixel) || unused_manual_colors.contains(pixel)) &&
1113 !pixel.is_transparent(extrinsic_transparency)) {
1115 "unused-manual-color",
1117 "color '{}' in slot '{}' of Porytiles palette '{}' is unused",
1121 unused_slots.push_back(slot_index);
1122 unused_manual_colors.insert(pixel);
1126 if (!pixel.is_transparent(extrinsic_transparency)) {
1127 color_counts[pixel]++;
1134 if (color_counts.size() > count_max && !hit_first_violation) {
1135 hit_first_violation =
true;
1137 "in Porytiles palette '{}': found {}th globally unique color: {}",
1141 services.
diag.
error(
"global-color-count-violation", error_message);
1142 std::vector<std::size_t> violating_slot{};
1143 violating_slot.push_back(slot_index);
1145 "global-color-count-violation",
1157 if (!unused_slots.empty()) {
1159 "unused-manual-color",
1163 "slots with unused colors",
1168 unused_slots.clear();
1172 for (
const auto &hint : hints) {
1173 std::vector<std::size_t> unused_slots{};
1175 for (std::size_t slot_index = 0; slot_index < hint.pal().size(); ++slot_index) {
1176 const auto &pixel = hint.pal().at(slot_index);
1187 if ((!color_counts.contains(pixel) || unused_manual_colors.contains(pixel)) &&
1188 !pixel.is_transparent(extrinsic_transparency)) {
1190 "unused-manual-color",
1192 "color '{}' in slot '{}' of palette hint '{}' is unused",
1196 unused_slots.push_back(slot_index);
1197 unused_manual_colors.insert(pixel);
1201 if (!pixel.is_transparent(extrinsic_transparency)) {
1202 color_counts[pixel]++;
1209 if (color_counts.size() > count_max && !hit_first_violation) {
1210 hit_first_violation =
true;
1212 "in palette hint '{}': found {}th globally unique color: {}",
1216 services.
diag.
error(
"global-color-count-violation", error_message);
1217 std::vector<std::size_t> violating_slot{};
1218 violating_slot.push_back(slot_index);
1220 "global-color-count-violation",
1232 if (!unused_slots.empty()) {
1234 "unused-manual-color",
1238 "slots with unused colors",
1243 unused_slots.clear();
1246 if (color_counts.size() > count_max) {
1248 "global-color-count-violation",
1250 "global color count violation: found '{}' unique colors, limit is '{}'",
1255 "global-color-count-violation",
1258 "Found '{}' unique colors globally, limit is '{}'.",
1288 const std::string &tileset_name,
1292 const std::vector<PaletteHint> &hints,
1324 const std::string &tileset_name,
1331 bool hit_error =
false;
1340 for (
const auto &[anim_name, anim] : anims) {
1341 bool has_per_anim_override = per_anim_overrides.value().contains(anim_name);
1343 (has_per_anim_override && per_anim_overrides.value().at(anim_name).linking.has_value())
1344 ? per_anim_overrides.
derive(per_anim_overrides.value().at(anim_name).linking)
1345 : global_frame_linking;
1348 std::vector<std::string> warning_lines;
1350 "Animation '{}' has frame_linking '{}' but no key frame (key.png) was found.",
1353 warning_lines.emplace_back(
"Animation tiles will not be linked to any metatiles.");
1354 services.
diag.
warning(
"missing-key-frame", warning_lines);
1356 if (has_per_anim_override) {
1357 std::vector<std::string> note_lines;
1359 "Per-animation override for '{}' sets frame_linking to '{}'.",
1362 note_lines.emplace_back(
"");
1382 for (
const auto &[anim_name, anim] : anims) {
1383 if (!anim.has_key_frame()) {
1387 const auto &key_frame = anim.key_frame();
1388 const auto &tiles = key_frame.tiles();
1390 for (std::size_t tile_idx = 0; tile_idx < tiles.size(); ++tile_idx) {
1391 const auto &tile = tiles.at(tile_idx);
1393 if (tile.is_transparent(extrinsic_transparency.value())) {
1395 std::string error_message =
"key frame tile is fully transparent";
1400 key_frame.frame_name(),
1402 "transparent-key-frame",
1404 extrinsic_transparency);
1407 "transparent-key-frame",
1408 std::vector<std::string>{
1409 "Key frame tiles cannot be fully transparent because they would be",
1410 "indistinguishable from the actual transparent tile on the layer PNGs."});
1416 return FormattableError{
"Found animation(s) with transparent key frame tile(s)."};
1425 std::map<PixelTile<Rgba32>, std::vector<std::pair<std::string, std::size_t>>> key_frame_occurrences;
1427 for (
const auto &[anim_name, anim] : anims) {
1428 if (!anim.has_key_frame()) {
1432 const auto &key_frame = anim.key_frame();
1433 const auto &tiles = key_frame.tiles();
1435 for (std::size_t tile_idx = 0; tile_idx < tiles.size(); ++tile_idx) {
1436 const auto &tile = tiles.at(tile_idx);
1437 key_frame_occurrences[tile].emplace_back(anim_name, tile_idx);
1441 for (
const auto &[tile, occurrences] : key_frame_occurrences) {
1442 if (occurrences.size() > 1) {
1446 const auto &[first_anim, first_idx] = occurrences.at(0);
1447 std::string error_message =
"duplicate key frame tile";
1454 "duplicate-key-frame",
1456 extrinsic_transparency);
1459 std::vector<std::string> note_lines;
1460 note_lines.emplace_back(
"This tile appears as a key frame in multiple locations:");
1461 for (
const auto &[anim_name, tile_idx] : occurrences) {
1465 note_lines.emplace_back(
"");
1466 note_lines.emplace_back(
"Each key frame tile must be unique so that Porytiles can");
1467 note_lines.emplace_back(
"identify which animation a tile belongs to at runtime.");
1481 for (
const auto &[anim_name, anim] : anims) {
1482 if (!anim.has_key_frame()) {
1486 const auto &key_frame = anim.key_frame();
1487 const std::size_t tile_count = key_frame.tile_count();
1489 for (std::size_t tile_idx = 0; tile_idx < tile_count; ++tile_idx) {
1491 std::map<Rgba32, unsigned int> color_counts;
1494 bool found_violation =
false;
1495 std::string violation_frame_name;
1497 std::size_t violation_row = 0;
1498 std::size_t violation_col = 0;
1502 auto process_tile_pixels = [&](
const PixelTile<Rgba32> &tile,
const std::string &frame_name) {
1505 const auto &pixel = tile.
at(row, col);
1506 if (!pixel.is_transparent(extrinsic_transparency)) {
1507 color_counts[pixel]++;
1511 if (color_counts.size() >
pal::max_size - 1 && !found_violation) {
1512 found_violation =
true;
1513 violation_frame_name = frame_name;
1514 violation_tile = &tile;
1515 violation_row = row;
1516 violation_col = col;
1517 violation_pixel = pixel;
1524 process_tile_pixels(key_frame.tile_at(tile_idx), key_frame.frame_name());
1527 for (
const auto &[frame_name, frame] : anim.frames()) {
1528 process_tile_pixels(frame.tile_at(tile_idx), frame_name);
1532 if (found_violation) {
1536 "found {}th unique composite frame tile color: {}",
1543 violation_frame_name,
1547 "composite-color-count-violation",
1549 extrinsic_transparency);
1551 std::vector<std::string> note_lines;
1552 note_lines.emplace_back(
"The composite frame aggregates all colors across all animation frames");
1553 note_lines.emplace_back(
"for each tile position. Since the palette index is fixed for the");
1554 note_lines.emplace_back(
"entire animation lifecycle, each composite tile cannot exceed 15 colors.");
1555 services.
diag.
error_note(
"composite-color-count-violation", note_lines);
1558 std::vector<std::string> frame_tiles_note;
1559 frame_tiles_note.emplace_back(
"Tiles at this position across all frames:");
1562 frame_tiles_note.emplace_back(
"");
1565 auto key_tile_visual =
1567 frame_tiles_note.append_range(key_tile_visual);
1570 for (
const auto &[frame_name, frame] : anim.frames()) {
1571 frame_tiles_note.emplace_back(
"");
1574 auto frame_tile_visual =
1576 frame_tiles_note.append_range(frame_tile_visual);
1579 services.
diag.
error_note(
"composite-color-count-violation", frame_tiles_note);
Represents a single frame of an animation, containing tiles and a frame name.
A complete tileset animation with name, configuration, and frame data.
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 &
Interface that defines a complete domain layer configuration.
Represents a palette hint for the palette packing algorithm.
const std::string & name() const
const Palette< Rgba32 > & pal() const
A collection of printer functions for the Palette and related types.
std::vector< std::string > print_rgba_pal_counts(const std::map< Rgba32, unsigned int > &color_counts) const
A generic palette container for colors that support transparency checking.
ColorType slot_zero_color() const
Get the slot 0 palette color.
std::size_t size() const
Returns the number of slots in the palette.
ColorType at(std::size_t index) const
Gets the color at a specific index.
bool is_wildcard(std::size_t index) const
Checks if a slot is a wildcard.
An 8x8 tile backed by literal-array-based per-pixel storage of an arbitrary pixel type.
PixelType at(std::size_t i) const
Represents a 32-bit RGBA color.
static constexpr std::uint8_t alpha_transparent
bool is_extrinsically_transparent(const Rgba32 &extrinsic) const
Checks if this color matches the extrinsic transparency color.
std::string to_jasc_str() const
static constexpr std::uint8_t alpha_opaque
static const Style underline
Underline text formatting.
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_metatile_pixel_highlight(const Metatile< Rgba32 > &metatile, metatile::Layer layer, metatile::Subtile subtile, std::size_t row, std::size_t col, const Rgba32 &extrinsic_transparency) const =0
virtual std::vector< std::string > print_tile_pixel_highlight(const PixelTile< Rgba32 > &tile, std::size_t row, std::size_t col, const Rgba32 &extrinsic_transparency) const =0
virtual std::vector< std::string > print_tile(const PixelTile< Rgba32 > &tile, const Rgba32 &extrinsic_transparency) const =0
virtual std::vector< std::string > print_metatile_tile_highlight(const Metatile< Rgba32 > &metatile, metatile::Layer layer, metatile::Subtile subtile, const Rgba32 &extrinsic_transparency) const =0
Abstract class for structured error reporting and diagnostic output.
virtual void warning_note(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged note message associated with a warning.
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 error(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged error message.
virtual void error_note(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged note message associated with an error.
std::string message_header(const TextFormatter &format, const std::string &anim_name, const std::string &frame_name, std::size_t internal_tile_index, std::size_t subtile_row, std::size_t subtile_col)
void report_validation_error_in_anim(const TilesetCompileValidatorServices &services, const PixelTile< Rgba32 > &tile, const std::string &anim_name, const std::string &frame_name, std::size_t internal_tile_index, std::size_t row, std::size_t col, const std::string &diagnostic_code, const std::string &error_message, const Rgba32 &extrinsic_transparency)
Reports a validation error at a specific pixel location within an animation frame tile.
void report_color_counts(const std::string &tag, const TilesetCompileValidatorServices &services, const std::map< Rgba32, unsigned int > &color_counts)
Emits a diagnostic note displaying the count of each unique color.
void report_validation_error_in_metatile(const TilesetCompileValidatorServices &services, const Metatile< Rgba32 > &metatile, std::size_t metatile_index, std::size_t internal_tile_index, std::size_t row, std::size_t col, const std::string &diagnostic_code, const std::string &error_message, const Rgba32 &extrinsic_transparency)
Reports a validation error at a specific pixel location within a metatile.
void report_validation_error_in_anim_tile(const TilesetCompileValidatorServices &services, const PixelTile< Rgba32 > &tile, const std::string &anim_name, const std::string &frame_name, std::size_t internal_tile_index, const std::string &diagnostic_code, const std::string &error_message, const Rgba32 &extrinsic_transparency)
Reports a validation error for an entire animation frame tile.
constexpr std::size_t num_pals
constexpr std::size_t max_size
constexpr std::size_t side_length_pix
std::vector< std::string > build_pal_hint_highlight_lines(const TextFormatter &format, const PalettePrinter &pal_printer, const std::string &message, const PaletteHint &hint, const std::string &pal_label, const std::vector< std::size_t > &violating_slots)
Builds note lines displaying a palette hint with highlighted violating slots.
std::vector< std::string > build_porytiles_pal_highlight_lines(const TextFormatter &format, const PalettePrinter &pal_printer, const std::string &message, const Palette< Rgba32, N > &pal, const std::string &pal_label, const std::vector< std::size_t > &violating_slots)
Builds note lines displaying a Porytiles palette with highlighted violating slots.
LayerMode
Specifies whether a metatile uses dual-layer or triple-layer mode.
ChainableResult< void > validate_porymap_pal(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const Palette< Rgba32, pal::max_size > &pal, std::size_t pal_index)
Validates a Porymap palette for correctness according to GBA hardware constraints.
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
ChainableResult< void > validate_porytiles_pal(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const Palette< Rgba32, pal::max_size > &pal, std::size_t pal_index)
Validates a user-specified Porytiles override palette for correctness.
ChainableResult< void > validate_anim_frames(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const std::map< std::string, Animation< Rgba32 > > &anims)
Validates animation frames for correctness according to tileset compilation constraints.
ChainableResult< void > validate_alpha_channels(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const std::vector< Metatile< Rgba32 > > &metatiles, const std::map< std::string, Animation< Rgba32 > > &anims)
Validates that all pixel alpha channels in provided input have valid values.
ChainableResult< void > validate_pal_hint(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const PaletteHint &hint)
Validates a user-specified palette hint for correctness.
LayerMode layer_mode_from_val(std::size_t s)
Converts a numeric value to LayerMode.
std::vector< std::string > build_subtraction_limit_lines(const TextFormatter &format, std::string_view label, std::size_t computed_limit, const ConfigValue< std::size_t > &total_cfg, const ConfigValue< std::size_t > &primary_cfg)
Builds note lines explaining a derived limit computed as total minus primary.
std::string pal_filename(std::size_t pal_index)
Constructs a palette filename from a palette index.
std::vector< std::string > format_config_note(const TextFormatter &format, const ConfigValue< T > &config)
Format a ConfigValue into diagnostic note lines.
ChainableResult< void > validate_metatile_count(const TilesetCompileValidatorServices &services, const std::string &tileset_name, bool is_secondary, const std::vector< Metatile< Rgba32 > > &metatiles)
Validates that the metatile count does not exceed the configured limit.
ChainableResult< void > validate_layer_mode(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const std::vector< Metatile< Rgba32 > > &metatiles)
Validates that metatiles conform to the configured layer mode.
ChainableResult< void > validate_precision_loss(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const std::vector< Metatile< Rgba32 > > &metatiles, const std::map< std::string, Animation< Rgba32 > > &anims, const std::array< std::optional< Palette< Rgba32, pal::max_size > >, pal::num_pals > &porytiles_pals, const std::vector< PaletteHint > &hints, const std::optional< std::array< Palette< Rgba32, pal::max_size >, pal::num_pals > > &porymap_pals)
Validates that no colors will suffer unacceptable precision loss during GBA color conversion.
std::vector< std::string > build_porymap_pal_highlight_lines(const TextFormatter &format, const PalettePrinter &pal_printer, const std::string &message, const Palette< Rgba32, N > &pal, const std::string &pal_label, const std::vector< std::size_t > &violating_slots)
Builds note lines displaying a Porymap palette with highlighted violating slots.
@ automatic
Use key.png for frame linking.
ChainableResult< void > validate_tile_color_count(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const std::vector< Metatile< Rgba32 > > &metatiles, const std::map< std::string, Animation< Rgba32 > > &anims)
Validates that each individual tile does not exceed the per-tile color limit.
std::vector< std::string > build_global_color_limit_lines(const TextFormatter &format, std::size_t color_count_limit, const ConfigValue< std::size_t > &num_pals)
Builds note lines explaining the global color count limit for primary tileset compilation.
ChainableResult< void > validate_global_color_count(const TilesetCompileValidatorServices &services, const std::string &tileset_name, bool is_secondary, const std::vector< Metatile< Rgba32 > > &metatiles, const std::map< std::string, Animation< Rgba32 > > &anims, const std::array< std::optional< Palette< Rgba32, pal::max_size > >, pal::num_pals > &porytiles_pals, const std::vector< PaletteHint > &hints)
Validates that the total unique color count across all input does not exceed the global limit.
Utility functions for string manipulation and formatting.
Parameter store for common services used by tileset compile validators.
const DomainConfig & config
const UserDiagnostics & diag
const TilePrinter & tile_printer
const PalettePrinter & pal_printer
#define PT_UNWRAP_TILESET_CONFIG_REF(ref, config, tileset_name, return_type)
Unwraps a tileset-scoped config value via reference access, returning early if the value is not avail...