| 260 | } |
| 261 | |
| 262 | void Image::generate_mipmaps() |
| 263 | { |
| 264 | assert(mipmaps.size() == 1 && "Mipmaps already generated"); |
| 265 | |
| 266 | if (mipmaps.size() > 1) |
| 267 | { |
| 268 | return; // Do not generate again |
| 269 | } |
| 270 | |
| 271 | auto extent = get_extent(); |
| 272 | auto next_width = std::max<uint32_t>(1u, extent.width / 2); |
| 273 | auto next_height = std::max<uint32_t>(1u, extent.height / 2); |
| 274 | auto channels = 4; |
| 275 | auto next_size = next_width * next_height * channels; |
| 276 | |
| 277 | // Allocate for all the mips at once. The function returns the total size needed for the |
| 278 | // existing base mip as well as all the mips that will be generated. |
| 279 | data.reserve(get_required_mipmaps_size(extent)); |
| 280 | |
| 281 | while (true) |
| 282 | { |
| 283 | // Make space for next mipmap |
| 284 | auto old_size = to_u32(data.size()); |
| 285 | data.resize(old_size + next_size); |
| 286 | |
| 287 | auto &prev_mipmap = mipmaps.back(); |
| 288 | // Update mipmaps |
| 289 | Mipmap next_mipmap{}; |
| 290 | next_mipmap.level = prev_mipmap.level + 1; |
| 291 | next_mipmap.offset = old_size; |
| 292 | next_mipmap.extent = {next_width, next_height, 1u}; |
| 293 | |
| 294 | // Fill next mipmap memory |
| 295 | stbir_resize_uint8(data.data() + prev_mipmap.offset, prev_mipmap.extent.width, prev_mipmap.extent.height, 0, |
| 296 | data.data() + next_mipmap.offset, next_mipmap.extent.width, next_mipmap.extent.height, 0, channels); |
| 297 | |
| 298 | mipmaps.emplace_back(std::move(next_mipmap)); |
| 299 | |
| 300 | // Next mipmap values |
| 301 | next_width = std::max<uint32_t>(1u, next_width / 2); |
| 302 | next_height = std::max<uint32_t>(1u, next_height / 2); |
| 303 | next_size = next_width * next_height * channels; |
| 304 | |
| 305 | if (next_width == 1 && next_height == 1) |
| 306 | { |
| 307 | break; |
| 308 | } |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | std::vector<Mipmap> &Image::get_mut_mipmaps() |
| 313 | { |
no test coverage detected