| 1 | /**************************************************************************/ | 
|---|
| 2 | /*  image_loader_hdr.cpp                                                  */ | 
|---|
| 3 | /**************************************************************************/ | 
|---|
| 4 | /*                         This file is part of:                          */ | 
|---|
| 5 | /*                             GODOT ENGINE                               */ | 
|---|
| 6 | /*                        https://godotengine.org                         */ | 
|---|
| 7 | /**************************************************************************/ | 
|---|
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
|---|
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
|---|
| 10 | /*                                                                        */ | 
|---|
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining  */ | 
|---|
| 12 | /* a copy of this software and associated documentation files (the        */ | 
|---|
| 13 | /* "Software"), to deal in the Software without restriction, including    */ | 
|---|
| 14 | /* without limitation the rights to use, copy, modify, merge, publish,    */ | 
|---|
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to     */ | 
|---|
| 16 | /* permit persons to whom the Software is furnished to do so, subject to  */ | 
|---|
| 17 | /* the following conditions:                                              */ | 
|---|
| 18 | /*                                                                        */ | 
|---|
| 19 | /* The above copyright notice and this permission notice shall be         */ | 
|---|
| 20 | /* included in all copies or substantial portions of the Software.        */ | 
|---|
| 21 | /*                                                                        */ | 
|---|
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | 
|---|
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | 
|---|
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | 
|---|
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | 
|---|
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | 
|---|
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | 
|---|
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | 
|---|
| 29 | /**************************************************************************/ | 
|---|
| 30 |  | 
|---|
| 31 | #include "image_loader_hdr.h" | 
|---|
| 32 |  | 
|---|
| 33 | #include "core/os/os.h" | 
|---|
| 34 | #include "core/string/print_string.h" | 
|---|
| 35 |  | 
|---|
| 36 | Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { | 
|---|
| 37 | String  = f->get_token(); | 
|---|
| 38 |  | 
|---|
| 39 | ERR_FAIL_COND_V_MSG(header != "#?RADIANCE"&& header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: "+ header + "."); | 
|---|
| 40 |  | 
|---|
| 41 | while (true) { | 
|---|
| 42 | String line = f->get_line(); | 
|---|
| 43 | ERR_FAIL_COND_V(f->eof_reached(), ERR_FILE_UNRECOGNIZED); | 
|---|
| 44 | if (line.is_empty()) { // empty line indicates end of header | 
|---|
| 45 | break; | 
|---|
| 46 | } | 
|---|
| 47 | if (line.begins_with( "FORMAT=")) { // leave option to implement other commands | 
|---|
| 48 | ERR_FAIL_COND_V_MSG(line != "FORMAT=32-bit_rle_rgbe", ERR_FILE_UNRECOGNIZED, "Only 32-bit_rle_rgbe is supported for HDR files."); | 
|---|
| 49 | } else if (!line.begins_with( "#")) { // not comment | 
|---|
| 50 | WARN_PRINT( "Ignoring unsupported header information in HDR: "+ line + "."); | 
|---|
| 51 | } | 
|---|
| 52 | } | 
|---|
| 53 |  | 
|---|
| 54 | String token = f->get_token(); | 
|---|
| 55 |  | 
|---|
| 56 | ERR_FAIL_COND_V(token != "-Y", ERR_FILE_CORRUPT); | 
|---|
| 57 |  | 
|---|
| 58 | int height = f->get_token().to_int(); | 
|---|
| 59 |  | 
|---|
| 60 | token = f->get_token(); | 
|---|
| 61 |  | 
|---|
| 62 | ERR_FAIL_COND_V(token != "+X", ERR_FILE_CORRUPT); | 
|---|
| 63 |  | 
|---|
| 64 | int width = f->get_line().to_int(); | 
|---|
| 65 |  | 
|---|
| 66 | Vector<uint8_t> imgdata; | 
|---|
| 67 |  | 
|---|
| 68 | imgdata.resize(height * width * (int)sizeof(uint32_t)); | 
|---|
| 69 |  | 
|---|
| 70 | { | 
|---|
| 71 | uint8_t *w = imgdata.ptrw(); | 
|---|
| 72 |  | 
|---|
| 73 | uint8_t *ptr = (uint8_t *)w; | 
|---|
| 74 |  | 
|---|
| 75 | if (width < 8 || width >= 32768) { | 
|---|
| 76 | // Read flat data | 
|---|
| 77 |  | 
|---|
| 78 | f->get_buffer(ptr, (uint64_t)width * height * 4); | 
|---|
| 79 | } else { | 
|---|
| 80 | // Read RLE-encoded data | 
|---|
| 81 |  | 
|---|
| 82 | for (int j = 0; j < height; ++j) { | 
|---|
| 83 | int c1 = f->get_8(); | 
|---|
| 84 | int c2 = f->get_8(); | 
|---|
| 85 | int len = f->get_8(); | 
|---|
| 86 | if (c1 != 2 || c2 != 2 || (len & 0x80)) { | 
|---|
| 87 | // not run-length encoded, so we have to actually use THIS data as a decoded | 
|---|
| 88 | // pixel (note this can't be a valid pixel--one of RGB must be >= 128) | 
|---|
| 89 |  | 
|---|
| 90 | ptr[(j * width) * 4 + 0] = uint8_t(c1); | 
|---|
| 91 | ptr[(j * width) * 4 + 1] = uint8_t(c2); | 
|---|
| 92 | ptr[(j * width) * 4 + 2] = uint8_t(len); | 
|---|
| 93 | ptr[(j * width) * 4 + 3] = f->get_8(); | 
|---|
| 94 |  | 
|---|
| 95 | f->get_buffer(&ptr[(j * width + 1) * 4], (width - 1) * 4); | 
|---|
| 96 | continue; | 
|---|
| 97 | } | 
|---|
| 98 | len <<= 8; | 
|---|
| 99 | len |= f->get_8(); | 
|---|
| 100 |  | 
|---|
| 101 | ERR_FAIL_COND_V_MSG(len != width, ERR_FILE_CORRUPT, "Invalid decoded scanline length, corrupt HDR."); | 
|---|
| 102 |  | 
|---|
| 103 | for (int k = 0; k < 4; ++k) { | 
|---|
| 104 | int i = 0; | 
|---|
| 105 | while (i < width) { | 
|---|
| 106 | int count = f->get_8(); | 
|---|
| 107 | if (count > 128) { | 
|---|
| 108 | // Run | 
|---|
| 109 | int value = f->get_8(); | 
|---|
| 110 | count -= 128; | 
|---|
| 111 | for (int z = 0; z < count; ++z) { | 
|---|
| 112 | ptr[(j * width + i++) * 4 + k] = uint8_t(value); | 
|---|
| 113 | } | 
|---|
| 114 | } else { | 
|---|
| 115 | // Dump | 
|---|
| 116 | for (int z = 0; z < count; ++z) { | 
|---|
| 117 | ptr[(j * width + i++) * 4 + k] = f->get_8(); | 
|---|
| 118 | } | 
|---|
| 119 | } | 
|---|
| 120 | } | 
|---|
| 121 | } | 
|---|
| 122 | } | 
|---|
| 123 | } | 
|---|
| 124 |  | 
|---|
| 125 | //convert | 
|---|
| 126 | for (int i = 0; i < width * height; i++) { | 
|---|
| 127 | float exp = pow(2.0f, ptr[3] - 128.0f); | 
|---|
| 128 |  | 
|---|
| 129 | Color c( | 
|---|
| 130 | ptr[0] * exp / 255.0, | 
|---|
| 131 | ptr[1] * exp / 255.0, | 
|---|
| 132 | ptr[2] * exp / 255.0); | 
|---|
| 133 |  | 
|---|
| 134 | if (p_flags & FLAG_FORCE_LINEAR) { | 
|---|
| 135 | c = c.srgb_to_linear(); | 
|---|
| 136 | } | 
|---|
| 137 |  | 
|---|
| 138 | *(uint32_t *)ptr = c.to_rgbe9995(); | 
|---|
| 139 | ptr += 4; | 
|---|
| 140 | } | 
|---|
| 141 | } | 
|---|
| 142 |  | 
|---|
| 143 | p_image->set_data(width, height, false, Image::FORMAT_RGBE9995, imgdata); | 
|---|
| 144 |  | 
|---|
| 145 | return OK; | 
|---|
| 146 | } | 
|---|
| 147 |  | 
|---|
| 148 | void ImageLoaderHDR::get_recognized_extensions(List<String> *p_extensions) const { | 
|---|
| 149 | p_extensions->push_back( "hdr"); | 
|---|
| 150 | } | 
|---|
| 151 |  | 
|---|
| 152 | ImageLoaderHDR::ImageLoaderHDR() { | 
|---|
| 153 | } | 
|---|
| 154 |  | 
|---|