1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-15 13:51:40 +00:00

Backport EXR compression support from master

This commit is contained in:
JFonS
2021-02-15 12:03:45 +01:00
parent 40c30adf04
commit 7241139356
4 changed files with 151 additions and 83 deletions

View File

@@ -58,7 +58,8 @@ static bool is_supported_format(Image::Format p_format) {
enum SrcPixelType {
SRC_FLOAT,
SRC_HALF,
SRC_BYTE
SRC_BYTE,
SRC_UNSUPPORTED
};
static SrcPixelType get_source_pixel_type(Image::Format p_format) {
@@ -79,7 +80,7 @@ static SrcPixelType get_source_pixel_type(Image::Format p_format) {
case Image::FORMAT_RGBA8:
return SRC_BYTE;
default:
CRASH_NOW();
return SRC_UNSUPPORTED;
}
}
@@ -101,7 +102,7 @@ static int get_target_pixel_type(Image::Format p_format) {
case Image::FORMAT_RGBA8:
return TINYEXR_PIXELTYPE_HALF;
default:
CRASH_NOW();
return -1;
}
}
@@ -112,7 +113,7 @@ static int get_pixel_type_size(int p_pixel_type) {
case TINYEXR_PIXELTYPE_FLOAT:
return 4;
}
CRASH_NOW();
return -1;
}
static int get_channel_count(Image::Format p_format) {
@@ -134,12 +135,11 @@ static int get_channel_count(Image::Format p_format) {
case Image::FORMAT_RGBA8:
return 4;
default:
CRASH_NOW();
return -1;
}
}
Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) {
Image::Format format = p_img->get_format();
if (!is_supported_format(format)) {
@@ -173,11 +173,15 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
};
int channel_count = get_channel_count(format);
ERR_FAIL_COND_V(channel_count < 0, ERR_UNAVAILABLE);
ERR_FAIL_COND_V(p_grayscale && channel_count != 1, ERR_INVALID_PARAMETER);
int target_pixel_type = get_target_pixel_type(format);
ERR_FAIL_COND_V(target_pixel_type < 0, ERR_UNAVAILABLE);
int target_pixel_type_size = get_pixel_type_size(target_pixel_type);
ERR_FAIL_COND_V(target_pixel_type_size < 0, ERR_UNAVAILABLE);
SrcPixelType src_pixel_type = get_source_pixel_type(format);
ERR_FAIL_COND_V(src_pixel_type == SRC_UNSUPPORTED, ERR_UNAVAILABLE);
const int pixel_count = p_img->get_width() * p_img->get_height();
const int *channel_mapping = channel_mappings[channel_count - 1];
@@ -187,7 +191,6 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
PoolByteArray::Read src_r = src_data.read();
for (int channel_index = 0; channel_index < channel_count; ++channel_index) {
// De-interleave channels
PoolByteArray &dst = channels[channel_index];
@@ -196,7 +199,6 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
PoolByteArray::Write dst_w = dst.write();
if (src_pixel_type == SRC_FLOAT && target_pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
// Note: we don't save mipmaps
CRASH_COND(src_data.size() < pixel_count * channel_count * target_pixel_type_size);
@@ -208,7 +210,6 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
}
} else if (src_pixel_type == SRC_HALF && target_pixel_type == TINYEXR_PIXELTYPE_HALF) {
CRASH_COND(src_data.size() < pixel_count * channel_count * target_pixel_type_size);
const uint16_t *src_rp = (uint16_t *)src_r.ptr();
@@ -219,7 +220,6 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
}
} else if (src_pixel_type == SRC_BYTE && target_pixel_type == TINYEXR_PIXELTYPE_HALF) {
CRASH_COND(src_data.size() < pixel_count * channel_count);
const uint8_t *src_rp = (uint8_t *)src_r.ptr();
@@ -262,13 +262,21 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
header.channels = channel_infos;
header.pixel_types = pixel_types;
header.requested_pixel_types = requested_pixel_types;
header.compression_type = TINYEXR_COMPRESSIONTYPE_PIZ;
CharString utf8_filename = p_path.utf8();
const char *err;
int ret = SaveEXRImageToFile(&image, &header, utf8_filename.ptr(), &err);
if (ret != TINYEXR_SUCCESS) {
unsigned char *mem = nullptr;
const char *err = nullptr;
size_t bytes = SaveEXRImageToMemory(&image, &header, &mem, &err);
if (bytes == 0) {
print_error(String("Saving EXR failed. Error: {0}").format(varray(err)));
return ERR_FILE_CANT_WRITE;
} else {
FileAccessRef ref = FileAccess::open(p_path, FileAccess::WRITE);
ERR_FAIL_COND_V(!ref, ERR_FILE_CANT_WRITE);
ref->store_buffer(mem, bytes);
free(mem);
}
return OK;