67 std::size_t metatile_index,
68 std::size_t internal_tile_index,
71 const std::string &diagnostic_code,
72 const std::string &error_message,
73 const Rgba32 &extrinsic_transparency)
82 metatile, layer, subtile, row, col, extrinsic_transparency);
83 errors.append_range(highlight);
84 services.
diag.
error(diagnostic_code, errors);
107 const std::string &anim_name,
108 const std::string &frame_name,
109 std::size_t internal_tile_index,
112 const std::string &diagnostic_code,
113 const std::string &error_message,
114 const Rgba32 &extrinsic_transparency)
123 errors.append_range(highlight);
124 services.
diag.
error(diagnostic_code, errors);
145 const std::string &anim_name,
146 const std::string &frame_name,
147 std::size_t internal_tile_index,
148 const std::string &diagnostic_code,
149 const std::string &error_message,
150 const Rgba32 &extrinsic_transparency)
158 errors.append_range(tile_visual);
159 services.
diag.
error(diagnostic_code, errors);
172 const std::string &tag,
174 const std::map<Rgba32, unsigned int> &color_counts)
176 std::vector<std::string> color_lines;
177 color_lines.emplace_back(
"color counts:");
179 color_lines.append_range(counts);
202 const std::string &tileset_name,
209 std::size_t metatile_limit = is_secondary ? (num_metatiles_total.value() - num_metatiles_in_primary.value())
210 : num_metatiles_in_primary.value();
212 if (metatiles.size() > metatile_limit) {
214 "metatile-limit-exceeded",
215 "Too many metatiles ({}) in Porytiles component for tileset '{}'.",
219 std::vector<std::string> note_text;
226 num_metatiles_in_primary));
231 note_text.emplace_back(
"");
237 "Found '{}' metatiles, limit is '{}'.",
265 const std::string &tileset_name,
267 std::size_t palette_index)
271 bool hit_error =
false;
273 std::vector<std::size_t> violating_slots{};
276 panic(
"unexpected wildcard in Porymap palette slot 0");
282 std::vector<std::string> warning_lines;
284 "Porymap palette '{}' slot 0 color '{}' does not match extrinsic transparency '{}'",
286 FormatParam{slot0_color.to_jasc_str(), Style::bold},
287 FormatParam{extrinsic_transparency.value().to_jasc_str(), Style::bold}));
288 warning_lines.emplace_back(
"Slot 0 is typically reserved for the transparency color.");
289 warning_lines.emplace_back(
"If you are using slot 0 for a .pla blend color, you can ignore this warning.");
290 services.
diag.
warning(
"porymap-palette-slot-0", warning_lines);
293 "porymap-palette-slot-0",
297 "reserved transparency slot",
300 std::vector<std::size_t>{0}));
306 for (std::size_t slot = 1; slot < palette.
size(); ++slot) {
308 panic(
"unexpected wildcard in Porymap palette");
310 const Rgba32 color = palette.
at(slot);
313 violating_slots.push_back(slot);
314 std::vector<std::string> error_lines;
316 "Porymap palette '{}' slot '{}' contains extrinsic transparency color '{}'",
320 error_lines.emplace_back(
"Extrinsic transparency is not allowed in non-slot-0 positions.");
321 services.
diag.
error(
"porymap-palette-transparency", error_lines);
328 "porymap-palette-transparency",
332 "slots with invalid extrinsic transparency",
366 const std::string &tileset_name,
368 std::size_t palette_index)
372 bool hit_error =
false;
374 std::vector<std::size_t> violating_slots;
381 std::vector<std::string> warning_text;
383 "Porytiles palette '{}' slot 0 color '{}' does not match extrinsic transparency '{}'",
385 FormatParam{slot0_color.to_jasc_str(), Style::bold},
386 FormatParam{extrinsic_transparency.value().to_jasc_str(), Style::bold}));
387 warning_text.emplace_back(
"Slot 0 is typically reserved for the transparency color.");
388 warning_text.emplace_back(
"If you are using slot 0 for a .pla blend color, you can ignore this warning.");
389 services.
diag.
warning(
"porytiles-palette-slot-0", warning_text);
393 "porytiles-palette-slot-0",
397 "reserved transparency slot",
400 std::vector<std::size_t>{0}));
407 for (std::size_t slot = 1; slot < palette.
size(); ++slot) {
411 const Rgba32 color = palette.
at(slot);
414 violating_slots.push_back(slot);
415 std::vector<std::string> error_lines;
417 "Porytiles palette '{}' slot '{}' contains extrinsic transparency color '{}'",
421 error_lines.emplace_back(
"Extrinsic transparency is not allowed in non-slot-0 positions.");
422 services.
diag.
error(
"porytiles-palette-transparency", error_lines);
429 "porytiles-palette-transparency",
433 "slots with invalid extrinsic transparency",
473 bool hit_any_error =
false;
474 const std::string &hint_name = hint.
name();
478 "palette-hint-size-violation",
480 "palette hint '{}' has size '{}', max allowed size is '{}'",
485 "palette-hint-size-violation",
489 "invalid extra slots start here",
492 std::vector{palette::max_size}));
496 std::set<Rgba32> seen_colors{};
497 std::vector<std::size_t> violating_slots{};
500 for (std::size_t slot = 0; slot < hint.
palette().size(); ++slot) {
501 if (hint.
palette().is_wildcard(slot)) {
507 hit_any_error =
true;
508 violating_slots.push_back(slot);
509 std::vector<std::string> error_lines;
511 "palette hint '{}' slot '{}' contains extrinsic transparency color '{}'",
515 error_lines.emplace_back(
"Extrinsic transparency is not allowed in palette hints.");
516 services.
diag.
error(
"palette-hint-transparency", error_lines);
519 if (!violating_slots.empty()) {
521 "palette-hint-transparency",
525 "slots with invalid extrinsic transparency",
532 violating_slots.clear();
535 for (std::size_t slot = 0; slot < hint.
palette().size(); ++slot) {
536 if (hint.
palette().is_wildcard(slot)) {
541 if (seen_colors.contains(color)) {
542 hit_any_error =
true;
543 violating_slots.push_back(slot);
544 std::vector<std::string> error_lines;
546 "palette hint '{}' contains duplicate color '{}' at slot '{}'",
550 error_lines.emplace_back(
"Duplicate colors are not allowed in palette hints.");
551 services.
diag.
error(
"palette-hint-duplicate-color", error_lines);
553 seen_colors.insert(color);
555 if (!violating_slots.empty()) {
557 "palette-hint-duplicate-color",
561 "slots with invalid duplicate colors",
588 const std::string &tileset_name,
594 bool hit_error =
false;
597 std::size_t metatile_index = 0;
598 for (
const auto &metatile : metatiles) {
599 const auto decomposed_metatile = metatile.decompose();
602 for (std::size_t internal_tile_index = 0; internal_tile_index < decomposed_metatile.size();
603 ++internal_tile_index) {
604 const auto &tile = decomposed_metatile[internal_tile_index];
609 const auto &pixel = tile.at(row, col);
621 "alpha-channel-violation",
623 extrinsic_transparency);
632 auto validate_anim_frame = [&services, &hit_error, &extrinsic_transparency](
634 const auto &frame_tiles = frame.tiles();
637 for (std::size_t internal_tile_index = 0; internal_tile_index < frame_tiles.size(); ++internal_tile_index) {
638 const auto &tile = frame_tiles.at(internal_tile_index);
643 const auto &pixel = tile.at(row, col);
658 "alpha-channel-violation",
660 extrinsic_transparency);
668 for (
const auto &[anim_name, anim] : anims) {
669 if (anim.has_key_frame()) {
670 const auto &key_frame = anim.key_frame();
671 validate_anim_frame(anim_name, key_frame);
674 validate_anim_frame(anim_name, frame);
679 return FormattableError{
"Found input pixel(s) with invalid alpha channel value(s)."};
705 const std::string &tileset_name,
719 const bool ignore_triple = ignore_triple_layer_content.value();
721 bool hit_error =
false;
722 bool hit_violation =
false;
723 std::size_t metatile_index = 0;
725 for (
const auto &metatile : metatiles) {
729 const auto &bottom_tile = metatile.bottom(subtile_idx);
730 const auto &middle_tile = metatile.middle(subtile_idx);
731 const auto &top_tile = metatile.top(subtile_idx);
735 const bool bottom_has_opaque = !bottom_tile.is_transparent(extrinsic_transparency.value());
736 const bool middle_has_opaque = !middle_tile.is_transparent(extrinsic_transparency.value());
737 const bool top_has_opaque = !top_tile.is_transparent(extrinsic_transparency.value());
740 const bool triple_layer_region = bottom_has_opaque && middle_has_opaque && top_has_opaque;
745 hit_violation =
true;
750 FormatParam{
"non-transparent content on all three layers"})};
757 lines.append_range(bottom_highlight);
758 lines.append_range(middle_highlight);
759 lines.append_range(top_highlight);
761 services.
diag.
warning(
"layer-mode-violation", lines);
765 services.
diag.
error(
"layer-mode-violation", lines);
774 std::vector<std::string> note_text;
777 note_text.emplace_back(
"");
779 note_text.emplace_back(
"");
780 note_text.emplace_back(
"Consider enabling triple-layer metatiles.");
784 " - set '{}' = '{}'",
788 " - follow the steps here: {}",
790 note_text.emplace_back(
"");
792 "Alternatively, set '{}' to force compilation in dual-layer mode. Porytiles will then drop a layer per "
793 "offending metatile, either by respecting a layer_type pin or by forcing each to layer type '{}'.",
800 return FormattableError{
"Found metatile(s) with mismatched implied layer mode."};
806 std::vector<std::string> note_text;
808 "Porytiles will drop a layer per offending metatile, either by respecting a layer_type pin or by forcing "
809 "each to layer type '{}'. This violation was explicitly downgraded from error to warning by:",
811 note_text.emplace_back(
"");
836 const std::string &tileset_name,
842 bool hit_error =
false;
843 std::size_t metatile_index = 0;
844 for (
const auto &metatile : metatiles) {
845 const auto decomposed_metatile = metatile.decompose();
848 for (std::size_t internal_tile_index = 0; internal_tile_index < decomposed_metatile.size();
849 ++internal_tile_index) {
850 const auto &tile = decomposed_metatile[internal_tile_index];
851 std::map<Rgba32, unsigned int> color_counts;
856 const auto &pixel = tile.at(row, col);
858 color_counts[pixel]++;
864 "found {}th unique tile color: {}",
874 "tile-color-count-violation",
876 extrinsic_transparency);
887 auto validate_anim_frame = [&services, &hit_error, &extrinsic_transparency](
889 const auto &frame_tiles = frame.tiles();
891 for (std::size_t internal_tile_index = 0; internal_tile_index < frame_tiles.size(); ++internal_tile_index) {
892 const auto &tile = frame_tiles[internal_tile_index];
893 std::map<Rgba32, unsigned int> color_counts;
898 const auto &pixel = tile.at(row, col);
900 color_counts[pixel]++;
906 "found {}th unique frame tile color: {}",
917 "tile-color-count-violation",
919 extrinsic_transparency);
930 for (
const auto &[anim_name, anim] : anims) {
931 if (anim.has_key_frame()) {
932 const auto &key_frame = anim.key_frame();
933 validate_anim_frame(anim_name, key_frame);
936 validate_anim_frame(anim_name, frame);
971 const std::string &tileset_name,
976 const std::vector<PaletteHint> &hints)
985 std::map<Rgba32, unsigned int> color_counts{};
986 bool hit_first_violation =
false;
989 std::size_t metatile_index = 0;
990 for (
const auto &metatile : metatiles) {
991 const auto decomposed_metatile = metatile.decompose();
992 for (std::size_t internal_tile_index = 0; internal_tile_index < decomposed_metatile.size();
993 ++internal_tile_index) {
994 const auto &tile = decomposed_metatile[internal_tile_index];
997 const auto &pixel = tile.at(row, col);
998 if (!pixel.is_transparent(extrinsic_transparency)) {
999 color_counts[pixel]++;
1004 if (color_counts.size() > count_max && !hit_first_violation) {
1005 hit_first_violation =
true;
1007 "found {}th globally unique color: {}",
1014 internal_tile_index,
1017 "global-color-count-violation",
1019 extrinsic_transparency);
1028 auto validate_anim_frame = [&services, &hit_first_violation, &color_counts, &count_max, &extrinsic_transparency](
1030 const auto &frame_tiles = frame.tiles();
1032 for (std::size_t internal_tile_index = 0; internal_tile_index < frame_tiles.size(); ++internal_tile_index) {
1033 const auto &tile = frame_tiles.at(internal_tile_index);
1038 const auto &pixel = tile.at(row, col);
1040 if (!pixel.is_transparent(extrinsic_transparency)) {
1041 color_counts[pixel]++;
1046 if (color_counts.size() > count_max && !hit_first_violation) {
1047 hit_first_violation =
true;
1049 "found {}th globally unique color: {}",
1057 internal_tile_index,
1060 "global-color-count-violation",
1062 extrinsic_transparency);
1069 for (
const auto &[anim_name, anim] : anims) {
1070 if (anim.has_key_frame()) {
1071 const auto &key_frame = anim.key_frame();
1072 validate_anim_frame(anim_name, key_frame);
1075 validate_anim_frame(anim_name, frame);
1082 std::set<Rgba32> unused_manual_colors{};
1083 for (std::size_t palette_index = 0; palette_index < num_palettes_cfg; ++palette_index) {
1086 if (porytiles_palettes.at(palette_index).has_value()) {
1087 const auto &palette = porytiles_palettes.at(palette_index).value();
1088 std::vector<std::size_t> unused_slots{};
1090 for (std::size_t slot_index = 0; slot_index < palette.size(); ++slot_index) {
1091 if (palette.is_wildcard(slot_index)) {
1095 const auto &pixel = palette.at(slot_index);
1103 if ((!color_counts.contains(pixel) || unused_manual_colors.contains(pixel)) &&
1104 !pixel.is_transparent(extrinsic_transparency)) {
1106 "unused-manual-color",
1108 "color '{}' in slot '{}' of Porytiles palette '{}' is unused",
1112 unused_slots.push_back(slot_index);
1113 unused_manual_colors.insert(pixel);
1117 if (!pixel.is_transparent(extrinsic_transparency)) {
1118 color_counts[pixel]++;
1123 if (color_counts.size() > count_max && !hit_first_violation) {
1124 hit_first_violation =
true;
1126 "in Porytiles palette '{}': found {}th globally unique color: {}",
1130 services.
diag.
error(
"global-color-count-violation", error_message);
1131 std::vector<std::size_t> violating_slot{};
1132 violating_slot.push_back(slot_index);
1134 "global-color-count-violation",
1146 if (!unused_slots.empty()) {
1148 "unused-manual-color",
1152 "slots with unused colors",
1157 unused_slots.clear();
1161 for (
const auto &hint : hints) {
1162 std::vector<std::size_t> unused_slots{};
1164 for (std::size_t slot_index = 0; slot_index < hint.palette().size(); ++slot_index) {
1165 const auto &pixel = hint.palette().at(slot_index);
1174 if ((!color_counts.contains(pixel) || unused_manual_colors.contains(pixel)) &&
1175 !pixel.is_transparent(extrinsic_transparency)) {
1177 "unused-manual-color",
1179 "color '{}' in slot '{}' of palette hint '{}' is unused",
1183 unused_slots.push_back(slot_index);
1184 unused_manual_colors.insert(pixel);
1188 if (!pixel.is_transparent(extrinsic_transparency)) {
1189 color_counts[pixel]++;
1194 if (color_counts.size() > count_max && !hit_first_violation) {
1195 hit_first_violation =
true;
1197 "in palette hint '{}': found {}th globally unique color: {}",
1201 services.
diag.
error(
"global-color-count-violation", error_message);
1202 std::vector<std::size_t> violating_slot{};
1203 violating_slot.push_back(slot_index);
1205 "global-color-count-violation",
1217 if (!unused_slots.empty()) {
1219 "unused-manual-color",
1223 "slots with unused colors",
1228 unused_slots.clear();
1231 if (color_counts.size() > count_max) {
1233 "global-color-count-violation",
1235 "global color count violation: found '{}' unique colors, limit is '{}'",
1240 "global-color-count-violation",
1243 "Found '{}' unique colors globally, limit is '{}'.",
1271 const std::string &tileset_name,
1275 const std::vector<PaletteHint> &hints,
1305 const std::string &tileset_name,
1312 bool hit_error =
false;
1319 for (
const auto &[anim_name, anim] : anims) {
1320 bool has_per_anim_override = per_anim_overrides.value().contains(anim_name);
1322 (has_per_anim_override && per_anim_overrides.value().at(anim_name).linking.has_value())
1323 ? per_anim_overrides.
derive(per_anim_overrides.value().at(anim_name).linking)
1324 : global_frame_linking;
1327 std::vector<std::string> warning_lines;
1329 "Animation '{}' has frame_linking '{}' but no key frame (key.png) was found.",
1332 warning_lines.emplace_back(
"Animation tiles will not be linked to any metatiles.");
1333 services.
diag.
warning(
"missing-key-frame", warning_lines);
1335 if (has_per_anim_override) {
1336 std::vector<std::string> note_lines;
1338 "Per-animation override for '{}' sets frame_linking to '{}'.",
1341 note_lines.emplace_back(
"");
1359 for (
const auto &[anim_name, anim] : anims) {
1360 if (!anim.has_key_frame()) {
1364 const auto &key_frame = anim.key_frame();
1365 const auto &tiles = key_frame.tiles();
1367 for (std::size_t tile_idx = 0; tile_idx < tiles.size(); ++tile_idx) {
1368 const auto &tile = tiles.at(tile_idx);
1370 if (tile.is_transparent(extrinsic_transparency.value())) {
1372 std::string error_message =
"key frame tile is fully transparent";
1377 key_frame.frame_name(),
1379 "transparent-key-frame",
1381 extrinsic_transparency);
1384 "transparent-key-frame",
1385 std::vector<std::string>{
1386 "Key frame tiles cannot be fully transparent because they would be indistinguishable "
1387 "from the actual transparent tile on the layer PNGs."});
1393 return FormattableError{
"Found animation(s) with transparent key frame tile(s)."};
1400 std::map<PixelTile<Rgba32>, std::vector<std::pair<std::string, std::size_t>>> key_frame_occurrences;
1402 for (
const auto &[anim_name, anim] : anims) {
1403 if (!anim.has_key_frame()) {
1407 const auto &key_frame = anim.key_frame();
1408 const auto &tiles = key_frame.tiles();
1410 for (std::size_t tile_idx = 0; tile_idx < tiles.size(); ++tile_idx) {
1411 const auto &tile = tiles.at(tile_idx);
1412 key_frame_occurrences[tile].emplace_back(anim_name, tile_idx);
1416 for (
const auto &[tile, occurrences] : key_frame_occurrences) {
1417 if (occurrences.size() > 1) {
1421 const auto &[first_anim, first_idx] = occurrences.at(0);
1422 std::string error_message =
"duplicate key frame tile";
1429 "duplicate-key-frame",
1431 extrinsic_transparency);
1434 std::vector<std::string> note_lines;
1435 note_lines.emplace_back(
"This tile appears as a key frame in multiple locations:");
1436 for (
const auto &[anim_name, tile_idx] : occurrences) {
1440 note_lines.emplace_back(
"");
1441 note_lines.emplace_back(
1442 "Each key frame tile must be unique so that Porytiles can identify which "
1443 "animation a tile belongs to at runtime.");
1455 for (
const auto &[anim_name, anim] : anims) {
1456 if (!anim.has_key_frame()) {
1460 const auto &key_frame = anim.key_frame();
1461 const std::size_t tile_count = key_frame.tile_count();
1463 for (std::size_t tile_idx = 0; tile_idx < tile_count; ++tile_idx) {
1465 std::map<Rgba32, unsigned int> color_counts;
1468 bool found_violation =
false;
1469 std::string violation_frame_name;
1471 std::size_t violation_row = 0;
1472 std::size_t violation_col = 0;
1476 auto process_tile_pixels = [&](
const PixelTile<Rgba32> &tile,
const std::string &frame_name) {
1479 const auto &pixel = tile.
at(row, col);
1480 if (!pixel.is_transparent(extrinsic_transparency)) {
1481 color_counts[pixel]++;
1486 found_violation =
true;
1487 violation_frame_name = frame_name;
1488 violation_tile = &tile;
1489 violation_row = row;
1490 violation_col = col;
1491 violation_pixel = pixel;
1498 process_tile_pixels(key_frame.tile_at(tile_idx), key_frame.frame_name());
1501 for (
const auto &[frame_name, frame] : anim.frames()) {
1502 process_tile_pixels(frame.tile_at(tile_idx), frame_name);
1506 if (found_violation) {
1510 "found {}th unique composite frame tile color: {}",
1517 violation_frame_name,
1521 "composite-color-count-violation",
1523 extrinsic_transparency);
1525 std::vector<std::string> note_lines;
1526 note_lines.emplace_back(
1527 "The composite frame aggregates all colors across all animation frames for each tile position. "
1528 "Since the palette index is fixed for the entire animation lifecycle, each composite tile cannot "
1529 "exceed 15 colors.");
1530 services.
diag.
error_note(
"composite-color-count-violation", note_lines);
1533 std::vector<std::string> frame_tiles_note;
1534 frame_tiles_note.emplace_back(
"Tiles at this position across all frames:");
1537 frame_tiles_note.emplace_back(
"");
1540 auto key_tile_visual =
1542 frame_tiles_note.append_range(key_tile_visual);
1545 for (
const auto &[frame_name, frame] : anim.frames()) {
1546 frame_tiles_note.emplace_back(
"");
1549 auto frame_tile_visual =
1551 frame_tiles_note.append_range(frame_tile_visual);
1554 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 > & palette() const
A collection of printer functions for the Palette and related types.
std::vector< std::string > print_rgba_palette_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 max_size
constexpr std::size_t num_palettes
constexpr std::size_t side_length_pix
ChainableResult< void > validate_palette_hint(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const PaletteHint &hint)
Validates a user-specified palette hint for correctness.
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
ChainableResult< void > validate_porymap_palette(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const Palette< Rgba32, palette::max_size > &palette, std::size_t palette_index)
Validates a Porymap palette for correctness according to GBA hardware constraints.
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.
LayerMode layer_mode_from_val(std::size_t s)
Converts a numeric value to LayerMode.
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, palette::max_size > >, palette::num_palettes > &porytiles_palettes, const std::vector< PaletteHint > &hints)
Validates that the total unique color count across all input does not exceed the global limit.
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.
ChainableResult< void > validate_porytiles_palette(const TilesetCompileValidatorServices &services, const std::string &tileset_name, const Palette< Rgba32, palette::max_size > &palette, std::size_t palette_index)
Validates a user-specified Porytiles override palette for correctness.
std::vector< std::string > build_global_color_limit_lines(const TextFormatter &format, std::size_t color_count_limit, const ConfigValue< std::size_t > &num_palettes)
Builds note lines explaining the global color count limit for primary tileset compilation.
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, palette::max_size > >, palette::num_palettes > &porytiles_palettes, const std::vector< PaletteHint > &hints, const std::optional< std::array< Palette< Rgba32, palette::max_size >, palette::num_palettes > > &porymap_palettes)
Validates that no colors will suffer unacceptable precision loss during GBA color conversion.
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.
std::string palette_filename(std::size_t palette_index)
Constructs a palette filename from a palette index.
@ automatic
Use key.png for frame linking.
std::vector< std::string > build_porymap_palette_highlight_lines(const TextFormatter &format, const PalettePrinter &palette_printer, const std::string &message, const Palette< Rgba32, N > &palette, const std::string &palette_label, const std::vector< std::size_t > &violating_slots)
Builds note lines displaying a Porymap palette with highlighted violating slots.
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::string to_string(const PrimaryPairingMode m)
Converts a PrimaryPairingMode to its canonical string representation.
std::vector< std::string > build_palette_hint_highlight_lines(const TextFormatter &format, const PalettePrinter &palette_printer, const std::string &message, const PaletteHint &hint, const std::string &palette_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_palette_highlight_lines(const TextFormatter &format, const PalettePrinter &palette_printer, const std::string &message, const Palette< Rgba32, N > &palette, const std::string &palette_label, const std::vector< std::size_t > &violating_slots)
Builds note lines displaying a Porytiles palette with highlighted violating slots.
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 & palette_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...