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)