29 #include <SDL2/SDL_image.h>
36 #ifdef __cpp_lib_ranges
41 #include <boost/filesystem.hpp>
42 namespace fs = boost::filesystem;
45 namespace fs = std::filesystem;
93 constexpr
double max_items_per_loader = 8.0;
95 void build_sheet_from_images(
const std::vector<fs::path>& file_paths)
97 const unsigned num_loaders = std::ceil(file_paths.size() / max_items_per_loader);
98 const unsigned num_to_load = std::ceil(file_paths.size() /
double(num_loaders));
100 std::vector<std::future<std::vector<sheet_element>>> loaders;
101 loaders.reserve(num_loaders);
103 #ifdef __cpp_lib_ranges_chunk
104 for(
auto span : file_paths | std::views::chunk(num_to_load)) {
105 loaders.push_back(std::async(std::launch::async,
106 [span]() {
return std::vector<sheet_element>(span.begin(), span.end()); }
110 for(
unsigned i = 0;
i < num_loaders; ++
i) {
111 loaders.push_back(std::async(std::launch::async, [&file_paths, &num_to_load,
i]() {
112 std::vector<sheet_element> res;
113 #ifdef __cpp_lib_ranges
114 for(
const fs::path&
p : file_paths | std::views::drop(num_to_load *
i) | std::views::take(num_to_load)) {
118 for(
unsigned k = num_to_load *
i; k < std::min<unsigned>(num_to_load * (
i + 1u), file_paths.size()); ++k) {
119 res.emplace_back(file_paths[k]);
127 std::vector<sheet_element> elements;
128 elements.reserve(file_paths.size());
131 for(
auto& loader : loaders) {
132 auto res = loader.get();
133 std::move(res.begin(), res.end(), std::back_inserter(elements));
138 std::stable_sort(elements.begin(), elements.end(),
139 [](
const auto& lhs,
const auto& rhs) { return lhs.surf.area() < rhs.surf.area(); });
141 const unsigned total_area = std::accumulate(elements.begin(), elements.end(), 0,
142 [](
const int val,
const auto&
s) { return val + s.surf.area(); });
144 const unsigned side_length =
static_cast<unsigned>(std::sqrt(total_area) * 1.3);
146 unsigned current_row_max_height = 0;
147 unsigned total_height = 0;
155 for(
auto&
s : elements) {
156 current_row_max_height = std::max<unsigned>(current_row_max_height,
s.src.h);
159 if(
static_cast<unsigned>(origin.x +
s.src.w) > side_length) {
162 origin.y += current_row_max_height;
165 total_height += current_row_max_height;
166 current_row_max_height = 0;
170 s.dst = { origin.x, origin.y,
s.src.w,
s.src.h };
178 const unsigned res_w = side_length;
179 const unsigned res_h = total_height > 0 ? std::min<unsigned>(side_length, total_height) : current_row_max_height;
182 assert(res_w > 0 && res_w <= 8192 && res_h > 0 && res_h <= 8192);
185 assert(res &&
"Spritesheet surface is null!");
192 for(
auto&
s : elements) {
194 mapping_data.write_child(
"image",
s.to_config());
202 std::vector<fs::path> files_found;
203 for(
const auto& entry : fs::directory_iterator{
path}) {
204 if(entry.is_directory()) {
205 handle_dir_contents(entry);
206 }
else if(entry.is_regular_file()) {
209 if(
auto path = entry.path();
path.extension() ==
".png" &&
path.stem() !=
"_sheet") {
210 files_found.push_back(std::move(
path));
215 if(!files_found.empty()) {
219 fs::current_path(
path);
220 }
catch(
const fs::filesystem_error&) {
224 build_sheet_from_images(files_found);
233 PLAIN_LOG <<
"Spritesheet generation of '" << entry_point <<
"' took: " << timer;
238 handle_dir_contents(*
path);
239 }
catch(
const fs::filesystem_error&
e) {
240 PLAIN_LOG <<
"Filesystem Error generating spritesheet: " <<
e.what();
243 PLAIN_LOG <<
"Cannot find entry point to build spritesheet: " << entry_point;
Class for writing a config out to a file in pieces.
A config object defines a single node in a WML file, with access to child nodes.
Definitions for the interface to Wesnoth Markup Language (WML).
Declarations for File-IO.
Standard logging facilities (interface).
rwops_ptr make_read_RWops(const std::string &path)
utils::optional< std::string > get_binary_file_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual file of a given type, if it exists.
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
Functions to load and save images from/to disk.
void build_spritesheet_from(const std::string &entry_point)
save_result save_image(const locator &i_locator, const std::string &filename)
Contains the SDL_Rect helper code.
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
std::string filename
Filename.
An abstract description of a rectangle with integer coordinates.
Reports time elapsed at the end of an object scope.
static map_location::direction s
rect get_non_transparent_portion(const surface &nsurf)
void sdl_blit(const surface &src, const SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)