24[[nodiscard]] std::filesystem::path fourBpp_to_png_path(
const std::string &path_4bpp)
26 std::filesystem::path p{path_4bpp};
27 p.replace_extension(
".png");
38 std::map<std::string, Animation<IndexPixel>> result;
43 if (!metadata_provider.exists(tileset_name)) {
47 auto metadata_result = metadata_provider.metadata_for(tileset_name);
48 if (!metadata_result.has_value()) {
52 auto metadata = std::move(metadata_result).value();
54 if (!metadata.has_animations()) {
59 const std::string callback_func = metadata.callback_func().value();
63 const auto tileset_anims_path = project_root_ /
"src" /
"tileset_anims.c";
65 if (!std::filesystem::exists(tileset_anims_path)) {
71 auto anim_params_result =
72 anim_parser.parse_from_callback(tileset_anims_path, callback_func, tileset_cased,
false);
73 if (!anim_params_result.has_value()) {
76 "Failed to parse animation parameters for '{}' from '{}'.",
81 std::map<DynamicCasedName, AnimParams> anim_params_map = std::move(anim_params_result).value();
83 if (anim_params_map.empty()) {
93 auto incbin_decls_result = c_parser.parse_incbin_arrays();
94 if (!incbin_decls_result.has_value()) {
96 FormattableError{
"Failed to parse INCBIN declarations."}, incbin_decls_result};
98 auto incbin_decls = std::move(incbin_decls_result).value();
101 std::map<std::string, std::filesystem::path> frame_paths;
102 for (
const auto &decl : incbin_decls) {
103 if (decl.variable_name().find(
"_Frame") != std::string::npos && !decl.paths().empty()) {
104 frame_paths[decl.variable_name()] = project_root_ / fourBpp_to_png_path(decl.paths().front());
109 for (
const auto &[anim_name, params] : anim_params_map) {
113 for (
const auto &frame_name : params.frame_names()) {
115 const std::string frame_name_snake = frame_name.to_snake_case();
116 const std::string frame_var = params.frame_array_identifier() +
"_Frame" + frame_name.to_pascal_case();
118 auto it = frame_paths.find(frame_var);
119 if (it == frame_paths.end()) {
121 "frame variable '{}' not found in INCBIN declarations for frame '{}'",
126 const auto &frame_png_path = it->second;
127 if (!std::filesystem::exists(frame_png_path)) {
129 "frame PNG '{}' not found for frame '{}'",
135 auto frame_load_result =
136 load_animation_frame_from_png<IndexPixel>(frame_png_path, frame_name_snake, png_loader);
137 if (!frame_load_result.has_value()) {
140 "failed to load frame '{}' for animation '{}'",
146 auto &load_result = frame_load_result.value();
147 anim.put_frame(frame_name_snake, std::move(load_result.frame));
150 auto animation_params = anim.params();
151 if (animation_params.width_tiles() == 0 && animation_params.height_tiles() == 0) {
152 animation_params.width_tiles(load_result.width_tiles);
153 animation_params.height_tiles(load_result.height_tiles);
154 anim.params(std::move(animation_params));
158 result[anim_name.to_snake_case()] = std::move(anim);
Shared helper for loading animation frames from PNG files.
Parses C code to extract tileset animation parameters using callback chain discovery.
A complete tileset animation with name, configuration, and frame data.
const AnimParams & params() const
High-level facade for parsing C/C++ source files.
A result type that maintains a chainable sequence of errors for debugging and error reporting.
An image loader that reads PNG files to create an Image with an index pixel type.
ChainableResult< std::map< std::string, Animation< IndexPixel > > > import_animations(const std::string &tileset_name) const
Import animations from a vanilla tileset.
static const Style bold
Bold text formatting.
DynamicCasedName extract_tileset_cased_name(const std::string &tileset_name)
Extracts the tileset short name and wraps it in a DynamicCasedName.
Utility functions for string manipulation and formatting.