Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- struct sheet_elment_data
- {
- /**
- * The spritesheet.
- *
- * Do note The texture class is really a "texture reference" class; it only
- * owns a shared pointer to the actual texture in memory. Therefor, having
- * this object does not mean we're keeping multiple copies of each sheet.
- */
- texture sheet;
- /** The coordinates of this image on the spritesheet. */
- SDL_Rect rect;
- /** Whether the image was rotated 90 degrees clockwise during packing. */
- bool rotated = false;
- };
- /** Map of path to rect. */
- std::map<std::string, sheet_elment_data> path_sheet_mapping;
- void build_sheet_from_images(const std::vector<std::string>& file_paths)
- {
- // Load all the images;
- std::vector<surface> surfs;
- surfs.reserve(file_paths.size());
- for(const auto& f : file_paths) {
- // TODO: handle case if surf is null?
- surfs.push_back(image::get_image(f));
- }
- if(surfs.empty()) {
- return;
- }
- // Sort surfaces by area, largest first.
- std::sort(surfs.begin(), surfs.end(),
- [](const surface& lhs, const surface rhs&) { return lhs->w * lhs->h < rhs->w * rhs->h; })
- // Get a rough estimate of rows and columns. This does not account for texture size.
- // Method taken from https://stackoverflow.com/a/4107092
- const unsigned elements_per_col = static_cast<unsigned>(std::sqrt(surfs.size()));
- const unsigned elements_per_row = static_cast<unsigned>(std::ceil(surfs.size() / static_cast<float>(cols));
- std::vector<sheet_elment_data> packaged_data;
- packaged_data.reserve(surfs.size());
- point origin(0, 0);
- unsigned current_row = 1;
- unsigned current_row_max_height = 0;
- unsigned current_row_max_width = 0;
- bool is_first_element_in_row = true;
- for(unsigned i = 0; i < surfs.size(); ++i) {
- sheet_elment_data data;
- SDL_Rect& r = data.rect = { origin.x, origin.y, s->w, s->h };
- const bool surf_h_exceeds_row_max = r.h > current_row_max_height;
- //
- // Rotate the rectangle 90 degrees clockwise if:
- // * The rectangle is the first in a new row OR
- // * The surface height exceeded the current maximum row height and its
- // width is less than its height. It makes no sense to swap height and
- // width if the width will only further exceed the current max. If that
- // happens, we'll fall back to simply bumping the max row height.
- //
- // This op preserves the blitting origin, so we just swap the width and height.
- //
- if(is_first_element_in_row || (surf_h_exceeds_row_max && r.w < r.h)) {
- std::swap(r.w, r.h);
- data.rotated = true;
- }
- if(is_first_element_in_row || (surf_h_exceeds_row_max && r.w >= r.h)) {
- current_row_max_height = std::max(current_row_max_height, r.h);
- }
- // Shift the rect origin to the next element
- origin.x += r.w;
- packaged_data.push_back(data);
- // The -1 is since this loop is 0-based and the element count is 1-based.
- const unsigned last_element_in_row_i = (current_row * elements_per_row) - 1;
- // Check if the current element is the last in this row.
- if(i == last_element_in_row_i) {
- is_first_element_in_row = true;
- origin.x = 0;
- origin.y += current_row_max_height;
- const unsigned max_width_for_this_row = std::accumulate(
- packaged_data.begin() + last_element_in_row_i,
- packaged_data.end()
- [](const auto& lhs, const auto& rhs&) { return lhs.rect.w + rhs.rect.w; }
- );
- current_row_max_width = std::max(current_row_max_width, max_width_for_this_row);
- } else {
- is_first_element_in_row = false;
- }
- }
- const unsigned res_w = current_row_max_width;
- const unsigned res_h = std::accumulate(packaged_data.begin(), packaged_data.end()
- [](const auto& lhs, const auto& rhs&) { return lhs.rect.h + rhs.rect.h; });
- // Check that we won't exceed max texture size. TODO: handle?
- assert(res_w <= 8192) && res_h <= 8192);
- // Assemble everything
- surface res = create_neutral_surface(res_w, res_h);
- for(unsigned i = 0; i < surfs.size(); ++i) {
- surface& s = surfs[i];
- if(packaged_data[i].rotated) {
- s = rotate_90_surface(s, true);
- }
- sdl_blit(s, nullptr, res, &packaged_data[i].rect);
- }
- // Upload the sheet to a texture.
- texture sheet_tex(res);
- // FIXME: wrong logic
- #if 0
- // Add path mappings to this texture.
- for(unsigned i = 0; i < file_paths.size(); ++i) {
- // Copy a texture reference;
- packaged_data[i].sheet = sheet_tex;
- path_sheet_mapping.emplace(file_paths[i], std::move(packaged_data[i]));
- }
- #endif
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement