|
@@ -501,6 +501,38 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+template <typename T, uint32_t read_channels, uint32_t write_channels, T def_zero, T def_one>
|
|
|
|
+static void _convert_fast(int p_width, int p_height, const T *p_src, T *p_dst) {
|
|
|
|
+ uint32_t dst_count = 0;
|
|
|
|
+ uint32_t src_count = 0;
|
|
|
|
+
|
|
|
|
+ const int resolution = p_width * p_height;
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < resolution; i++) {
|
|
|
|
+ memcpy(p_dst + dst_count, p_src + src_count, MIN(read_channels, write_channels) * sizeof(T));
|
|
|
|
+
|
|
|
|
+ if constexpr (write_channels > read_channels) {
|
|
|
|
+ const T def_value[4] = { def_zero, def_zero, def_zero, def_one };
|
|
|
|
+ memcpy(p_dst + dst_count + read_channels, &def_value[read_channels], (write_channels - read_channels) * sizeof(T));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dst_count += write_channels;
|
|
|
|
+ src_count += read_channels;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool _are_formats_compatible(Image::Format p_format0, Image::Format p_format1) {
|
|
|
|
+ if (p_format0 <= Image::FORMAT_RGBA8 && p_format1 <= Image::FORMAT_RGBA8) {
|
|
|
|
+ return true;
|
|
|
|
+ } else if (p_format0 <= Image::FORMAT_RGBAH && p_format0 >= Image::FORMAT_RH && p_format1 <= Image::FORMAT_RGBAH && p_format1 >= Image::FORMAT_RH) {
|
|
|
|
+ return true;
|
|
|
|
+ } else if (p_format0 <= Image::FORMAT_RGBAF && p_format0 >= Image::FORMAT_RF && p_format1 <= Image::FORMAT_RGBAF && p_format1 >= Image::FORMAT_RF) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
void Image::convert(Format p_new_format) {
|
|
void Image::convert(Format p_new_format) {
|
|
ERR_FAIL_INDEX_MSG(p_new_format, FORMAT_MAX, "The Image format specified (" + itos(p_new_format) + ") is out of range. See Image's Format enum.");
|
|
ERR_FAIL_INDEX_MSG(p_new_format, FORMAT_MAX, "The Image format specified (" + itos(p_new_format) + ") is out of range. See Image's Format enum.");
|
|
if (data.size() == 0) {
|
|
if (data.size() == 0) {
|
|
@@ -517,7 +549,7 @@ void Image::convert(Format p_new_format) {
|
|
if (Image::is_format_compressed(format) || Image::is_format_compressed(p_new_format)) {
|
|
if (Image::is_format_compressed(format) || Image::is_format_compressed(p_new_format)) {
|
|
ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
|
|
ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
|
|
|
|
|
|
- } else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8) {
|
|
|
|
|
|
+ } else if (!_are_formats_compatible(format, p_new_format)) {
|
|
//use put/set pixel which is slower but works with non byte formats
|
|
//use put/set pixel which is slower but works with non byte formats
|
|
Image new_img(width, height, mipmaps, p_new_format);
|
|
Image new_img(width, height, mipmaps, p_new_format);
|
|
|
|
|
|
@@ -648,6 +680,78 @@ void Image::convert(Format p_new_format) {
|
|
case FORMAT_RGBA8 | (FORMAT_RGB8 << 8):
|
|
case FORMAT_RGBA8 | (FORMAT_RGB8 << 8):
|
|
_convert<3, true, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
|
|
_convert<3, true, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
|
|
break;
|
|
break;
|
|
|
|
+ case FORMAT_RH | (FORMAT_RGH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 1, 2, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RH | (FORMAT_RGBH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 1, 3, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RH | (FORMAT_RGBAH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 1, 4, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGH | (FORMAT_RH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 2, 1, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGH | (FORMAT_RGBH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 2, 3, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGH | (FORMAT_RGBAH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 2, 4, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBH | (FORMAT_RH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 3, 1, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBH | (FORMAT_RGH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 3, 2, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBH | (FORMAT_RGBAH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 3, 4, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBAH | (FORMAT_RH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 4, 1, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBAH | (FORMAT_RGH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 4, 2, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBAH | (FORMAT_RGBH << 8):
|
|
|
|
+ _convert_fast<uint16_t, 4, 3, 0x0000, 0x3C00>(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RF | (FORMAT_RGF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 1, 2, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RF | (FORMAT_RGBF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 1, 3, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RF | (FORMAT_RGBAF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 1, 4, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGF | (FORMAT_RF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 2, 1, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGF | (FORMAT_RGBF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 2, 3, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGF | (FORMAT_RGBAF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 2, 4, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBF | (FORMAT_RF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 3, 1, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBF | (FORMAT_RGF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 3, 2, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBF | (FORMAT_RGBAF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 3, 4, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBAF | (FORMAT_RF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 4, 1, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBAF | (FORMAT_RGF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 4, 2, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
|
|
+ case FORMAT_RGBAF | (FORMAT_RGBF << 8):
|
|
|
|
+ _convert_fast<uint32_t, 4, 3, 0x00000000, 0x3F800000>(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|