28 #include <SDL2/SDL_image.h>
35 #ifdef __cpp_lib_ranges
40 #include <boost/filesystem.hpp>
41 namespace fs = boost::filesystem;
44 namespace fs = std::filesystem;
92 constexpr
double max_items_per_loader = 8.0;
94 void build_sheet_from_images(
const std::vector<fs::path>& file_paths)
96 const unsigned num_loaders = std::ceil(file_paths.size() / max_items_per_loader);
97 const unsigned num_to_load = std::ceil(file_paths.size() /
double(num_loaders));
99 std::vector<std::future<std::vector<sheet_element>>> loaders;
100 loaders.reserve(num_loaders);
102 #ifdef __cpp_lib_ranges_chunk
103 for(
auto span : file_paths | std::views::chunk(num_to_load)) {
104 loaders.push_back(std::async(std::launch::async,
105 [span]() {
return std::vector<sheet_element>(span.begin(), span.end()); }
109 for(
unsigned i = 0;
i < num_loaders; ++
i) {
110 loaders.push_back(std::async(std::launch::async, [&file_paths, &num_to_load,
i]() {
111 std::vector<sheet_element> res;
112 #ifdef __cpp_lib_ranges
113 for(
const fs::path&
p : file_paths | std::views::drop(num_to_load *
i) | std::views::take(num_to_load)) {
117 for(
unsigned k = num_to_load *
i; k < std::min<unsigned>(num_to_load * (
i + 1u), file_paths.size()); ++k) {
118 res.emplace_back(file_paths[k]);
126 std::vector<sheet_element> elements;
127 elements.reserve(file_paths.size());
130 for(
auto& loader : loaders) {
131 auto res = loader.get();
132 std::move(res.begin(), res.end(), std::back_inserter(elements));
137 std::stable_sort(elements.begin(), elements.end(),
138 [](
const auto& lhs,
const auto& rhs) { return lhs.surf.area() < rhs.surf.area(); });
140 const unsigned total_area = std::accumulate(elements.begin(), elements.end(), 0,
141 [](
const int val,
const auto&
s) { return val + s.surf.area(); });
143 const unsigned side_length =
static_cast<unsigned>(std::sqrt(total_area) * 1.3);
145 unsigned current_row_max_height = 0;
146 unsigned total_height = 0;
154 for(
auto&
s : elements) {
155 current_row_max_height = std::max<unsigned>(current_row_max_height,
s.src.h);
158 if(
static_cast<unsigned>(origin.x +
s.src.w) > side_length) {
161 origin.y += current_row_max_height;
164 total_height += current_row_max_height;
165 current_row_max_height = 0;
169 s.dst = { origin.x, origin.y,
s.src.w,
s.src.h };
177 const unsigned res_w = side_length;
178 const unsigned res_h = total_height > 0 ? std::min<unsigned>(side_length, total_height) : current_row_max_height;
181 assert(res_w > 0 && res_w <= 8192 && res_h > 0 && res_h <= 8192);
184 assert(res &&
"Spritesheet surface is null!");
191 for(
auto&
s : elements) {
193 mapping_data.write_child(
"image",
s.to_config());
201 std::vector<fs::path> files_found;
202 for(
const auto& entry : fs::directory_iterator{
path}) {
203 if(entry.is_directory()) {
204 handle_dir_contents(entry);
205 }
else if(entry.is_regular_file()) {
208 if(
auto path = entry.path();
path.extension() ==
".png" &&
path.stem() !=
"_sheet") {
209 files_found.push_back(std::move(
path));
214 if(!files_found.empty()) {
218 fs::current_path(
path);
219 }
catch(
const fs::filesystem_error&) {
223 build_sheet_from_images(files_found);
231 #ifdef DEBUG_SPRITESHEET_OUTPUT
232 const std::size_t
start = SDL_GetTicks();
237 handle_dir_contents(*
path);
238 }
catch(
const fs::filesystem_error&
e) {
239 PLAIN_LOG <<
"Filesystem Error generating spritesheet: " <<
e.what();
242 PLAIN_LOG <<
"Cannot find entry point to build spritesheet: " << entry_point;
245 #ifdef DEBUG_SPRITESHEET_OUTPUT
246 PLAIN_LOG <<
"Spritesheet generation of '" << entry_point <<
"' took: " << (SDL_GetTicks() -
start) <<
"ms\n";
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).
EXIT_STATUS start(bool clear_id, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
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.
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)