| 473 | } |
| 474 | |
| 475 | Vector<uint8_t> save_hdr_buffer(const Ref<Image> &p_img, bool duplicate) { |
| 476 | ERR_FAIL_COND_V_MSG(p_img.is_null(), Vector<uint8_t>(), "Can't save invalid image as HDR."); |
| 477 | |
| 478 | Ref<Image> img = duplicate ? (Ref<Image>)p_img->duplicate() : p_img; |
| 479 | if (img->is_compressed() && img->decompress() != OK) { |
| 480 | ERR_FAIL_V_MSG(Vector<uint8_t>(), "Failed to decompress image."); |
| 481 | } |
| 482 | |
| 483 | img->clear_mipmaps(); |
| 484 | if (img->get_format() != Image::FORMAT_RGBE9995) { |
| 485 | img->convert(Image::FORMAT_RGBE9995); |
| 486 | } |
| 487 | |
| 488 | // Create a temporary file to write the HDR data |
| 489 | Vector<uint8_t> buffer; |
| 490 | |
| 491 | // Write Radiance HDR header |
| 492 | buffer.append_array(String("#?RADIANCE\n").to_utf8_buffer()); |
| 493 | buffer.append_array(String("FORMAT=32-bit_rle_rgbe\n").to_utf8_buffer()); |
| 494 | buffer.append_array(String("\n").to_utf8_buffer()); // Empty line to end header |
| 495 | |
| 496 | // Write resolution string (standard orientation: -Y height +X width) |
| 497 | String resolution = vformat("-Y %d +X %d\n", img->get_height(), img->get_width()); |
| 498 | buffer.append_array(resolution.to_utf8_buffer()); |
| 499 | |
| 500 | // Get image data |
| 501 | const Vector<uint8_t> &data = img->get_data(); |
| 502 | const uint32_t *rgbe_data = reinterpret_cast<const uint32_t *>(data.ptr()); |
| 503 | int width = img->get_width(); |
| 504 | int height = img->get_height(); |
| 505 | // Write scanlines |
| 506 | if (width < 8 || width >= 32768) { |
| 507 | // Write flat data |
| 508 | for (int y = 0; y < height; y++) { |
| 509 | for (int x = 0; x < width; x++) { |
| 510 | uint32_t rgbe = rgbe_data[y * width + x]; |
| 511 | buffer.push_back(get_r(rgbe)); |
| 512 | buffer.push_back(get_g(rgbe)); |
| 513 | buffer.push_back(get_b(rgbe)); |
| 514 | buffer.push_back(get_e(rgbe)); |
| 515 | } |
| 516 | } |
| 517 | } else { |
| 518 | // Write RLE-encoded data |
| 519 | for (int y = 0; y < height; y++) { |
| 520 | // For each scanline, we need to separate the RGBE components |
| 521 | Vector<uint8_t> scanline_r, scanline_g, scanline_b, scanline_e; |
| 522 | scanline_r.resize(width); |
| 523 | scanline_g.resize(width); |
| 524 | scanline_b.resize(width); |
| 525 | scanline_e.resize(width); |
| 526 | |
| 527 | // Extract RGBE components from RGBE9995 format and convert to Radiance HDR format |
| 528 | for (int x = 0; x < width; x++) { |
| 529 | uint32_t rgbe = rgbe_data[y * width + x]; |
| 530 | scanline_r.write[x] = get_r(rgbe); |
| 531 | scanline_g.write[x] = get_g(rgbe); |
| 532 | scanline_b.write[x] = get_b(rgbe); |
no test coverage detected