You've already forked godot
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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user