Advertisement
Vultraz

Untitled

Apr 9th, 2018
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.40 KB | None | 0 0
  1. struct sheet_elment_data
  2. {
  3.     /**
  4.      * The spritesheet.
  5.      *
  6.      * Do note The texture class is really a "texture reference" class; it only
  7.      * owns a shared pointer to the actual texture in memory. Therefor, having
  8.      * this object does not mean we're keeping multiple copies of each sheet.
  9.      */
  10.     texture sheet;
  11.  
  12.     /** The coordinates of this image on the spritesheet. */
  13.     SDL_Rect rect;
  14.  
  15.     /** Whether the image was rotated 90 degrees clockwise during packing. */
  16.     bool rotated = false;
  17. };
  18.  
  19. /** Map of path to rect. */
  20. std::map<std::string, sheet_elment_data> path_sheet_mapping;
  21.  
  22. void build_sheet_from_images(const std::vector<std::string>& file_paths)
  23. {
  24.     // Load all the images;
  25.     std::vector<surface> surfs;
  26.     surfs.reserve(file_paths.size());
  27.  
  28.     for(const auto& f : file_paths) {
  29.         // TODO: handle case if surf is null?
  30.         surfs.push_back(image::get_image(f));
  31.     }
  32.  
  33.     if(surfs.empty()) {
  34.         return;
  35.     }
  36.  
  37.     // Sort surfaces by area, largest first.
  38.     std::sort(surfs.begin(), surfs.end(),
  39.         [](const surface& lhs, const surface rhs&) { return lhs->w * lhs->h < rhs->w * rhs->h; })
  40.  
  41.     // Get a rough estimate of rows and columns. This does not account for texture size.
  42.     // Method taken from https://stackoverflow.com/a/4107092
  43.     const unsigned elements_per_col = static_cast<unsigned>(std::sqrt(surfs.size()));
  44.     const unsigned elements_per_row = static_cast<unsigned>(std::ceil(surfs.size() / static_cast<float>(cols));
  45.  
  46.     std::vector<sheet_elment_data> packaged_data;
  47.     packaged_data.reserve(surfs.size());
  48.  
  49.     point origin(0, 0);
  50.  
  51.     unsigned current_row = 1;
  52.     unsigned current_row_max_height = 0;
  53.     unsigned current_row_max_width = 0;
  54.  
  55.     bool is_first_element_in_row = true;
  56.  
  57.     for(unsigned i = 0; i < surfs.size(); ++i) {
  58.         sheet_elment_data data;
  59.         SDL_Rect& r = data.rect = { origin.x, origin.y, s->w, s->h };
  60.  
  61.         const bool surf_h_exceeds_row_max = r.h > current_row_max_height;
  62.  
  63.         //
  64.         // Rotate the rectangle 90 degrees clockwise if:
  65.         // * The rectangle is the first in a new row OR
  66.         // * The surface height exceeded the current maximum row height and its
  67.         //   width is less than its height. It makes no sense to swap height and
  68.         //   width if the width will only further exceed the current max. If that
  69.         //   happens, we'll fall back to simply bumping the max row height.
  70.         //
  71.         // This op preserves the blitting origin, so we just swap the width and height.
  72.         //
  73.         if(is_first_element_in_row || (surf_h_exceeds_row_max && r.w < r.h)) {
  74.             std::swap(r.w, r.h);
  75.             data.rotated = true;
  76.         }
  77.  
  78.         if(is_first_element_in_row || (surf_h_exceeds_row_max && r.w >= r.h)) {
  79.             current_row_max_height = std::max(current_row_max_height, r.h);
  80.         }
  81.  
  82.         // Shift the rect origin to the next element
  83.         origin.x += r.w;
  84.  
  85.         packaged_data.push_back(data);
  86.  
  87.         // The -1 is since this loop is 0-based and the element count is 1-based.
  88.         const unsigned last_element_in_row_i = (current_row * elements_per_row) - 1;
  89.    
  90.         // Check if the current element is the last in this row.
  91.         if(i == last_element_in_row_i) {
  92.             is_first_element_in_row = true;
  93.  
  94.             origin.x = 0;
  95.             origin.y += current_row_max_height;
  96.  
  97.             const unsigned max_width_for_this_row = std::accumulate(
  98.                 packaged_data.begin() + last_element_in_row_i,
  99.                 packaged_data.end()
  100.                 [](const auto& lhs, const auto& rhs&) { return lhs.rect.w + rhs.rect.w; }
  101.             );
  102.    
  103.             current_row_max_width = std::max(current_row_max_width, max_width_for_this_row);
  104.         } else {
  105.             is_first_element_in_row = false;
  106.         }
  107.     }
  108.  
  109.     const unsigned res_w = current_row_max_width;
  110.     const unsigned res_h = std::accumulate(packaged_data.begin(), packaged_data.end()
  111.         [](const auto& lhs, const auto& rhs&) { return lhs.rect.h + rhs.rect.h; });
  112.    
  113.     // Check that we won't exceed max texture size. TODO: handle?
  114.     assert(res_w <= 8192) && res_h <= 8192);
  115.  
  116.     // Assemble everything
  117.     surface res = create_neutral_surface(res_w, res_h);
  118.  
  119.     for(unsigned i = 0; i < surfs.size(); ++i) {
  120.         surface& s = surfs[i];
  121.  
  122.         if(packaged_data[i].rotated) {
  123.             s = rotate_90_surface(s, true);
  124.         }
  125.  
  126.         sdl_blit(s, nullptr, res, &packaged_data[i].rect);
  127.     }
  128.  
  129.     // Upload the sheet to a texture.
  130.     texture sheet_tex(res);
  131.  
  132.     // FIXME: wrong logic
  133. #if 0
  134.     // Add path mappings to this texture.
  135.     for(unsigned i = 0; i < file_paths.size(); ++i) {
  136.         // Copy a texture reference;
  137.         packaged_data[i].sheet = sheet_tex;
  138.  
  139.         path_sheet_mapping.emplace(file_paths[i], std::move(packaged_data[i]));
  140.     }
  141. #endif
  142. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement