diff --git a/core/io/image.cpp b/core/io/image.cpp index 73d2dc2cde9..8931dde9797 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -78,6 +78,14 @@ const char *Image::format_names[Image::FORMAT_MAX] = { "ASTC_4x4_HDR", "ASTC_8x8", "ASTC_8x8_HDR", + "R16", + "RG16", + "RGB16", + "RGBA16", + "R16Int", + "RG16Int", + "RGB16Int", + "RGBA16Int", }; // External VRAM compression function pointers. @@ -201,6 +209,22 @@ int Image::get_format_pixel_size(Format p_format) { return 1; case FORMAT_ASTC_8x8_HDR: return 1; + case FORMAT_R16: + return 2; + case FORMAT_RG16: + return 4; + case FORMAT_RGB16: + return 6; + case FORMAT_RGBA16: + return 8; + case FORMAT_R16I: + return 2; + case FORMAT_RG16I: + return 4; + case FORMAT_RGB16I: + return 6; + case FORMAT_RGBA16I: + return 8; case FORMAT_MAX: { } } @@ -759,6 +783,78 @@ void Image::convert(Format p_new_format) { case FORMAT_RGBAF | (FORMAT_RGBF << 8): _convert_fast(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr); break; + case FORMAT_R16 | (FORMAT_RG16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_R16 | (FORMAT_RGB16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_R16 | (FORMAT_RGBA16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RG16 | (FORMAT_R16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RG16 | (FORMAT_RGB16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RG16 | (FORMAT_RGBA16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGB16 | (FORMAT_R16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGB16 | (FORMAT_RG16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGB16 | (FORMAT_RGBA16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGBA16 | (FORMAT_R16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGBA16 | (FORMAT_RG16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGBA16 | (FORMAT_RGB16 << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_R16I | (FORMAT_RG16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_R16I | (FORMAT_RGB16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_R16I | (FORMAT_RGBA16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RG16I | (FORMAT_R16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RG16I | (FORMAT_RGB16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RG16I | (FORMAT_RGBA16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGB16I | (FORMAT_R16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGB16I | (FORMAT_RG16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGB16I | (FORMAT_RGBA16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGBA16I | (FORMAT_R16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGBA16I | (FORMAT_RG16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; + case FORMAT_RGBA16I | (FORMAT_RGB16I << 8): + _convert_fast(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr); + break; } } @@ -769,6 +865,11 @@ Image::Format Image::get_format() const { return format; } +enum ImageScaleType { + IMAGE_SCALING_INT, + IMAGE_SCALING_FLOAT, +}; + static double _bicubic_interp_kernel(double x) { x = Math::abs(x); @@ -783,7 +884,7 @@ static double _bicubic_interp_kernel(double x) { return bc; } -template +template static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { // get source image size int width = p_src_width; @@ -845,7 +946,7 @@ static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_ const T *__restrict p = ((T *)p_src) + (oy2 * p_src_width + ox2) * CC; for (int i = 0; i < CC; i++) { - if constexpr (sizeof(T) == 2) { //half float + if constexpr (sizeof(T) == 2 && TYPE == IMAGE_SCALING_FLOAT) { //half float color[i] = Math::half_to_float(p[i]); } else { color[i] += p[i] * k2; @@ -857,8 +958,12 @@ static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_ for (int i = 0; i < CC; i++) { if constexpr (sizeof(T) == 1) { //byte dst[i] = CLAMP(Math::fast_ftoi(color[i]), 0, 255); - } else if constexpr (sizeof(T) == 2) { //half float - dst[i] = Math::make_half_float(color[i]); + } else if constexpr (sizeof(T) == 2) { + if constexpr (TYPE == IMAGE_SCALING_FLOAT) { + dst[i] = Math::make_half_float(color[i]); //half float + } else { + dst[i] = CLAMP(Math::fast_ftoi(color[i]), 0, 65535); // uint16 + } } else { dst[i] = color[i]; } @@ -867,7 +972,7 @@ static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_ } } -template +template static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { constexpr uint32_t FRAC_BITS = 8; constexpr uint32_t FRAC_LEN = (1 << FRAC_BITS); @@ -915,23 +1020,40 @@ static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict uint32_t interp = interp_up + (((interp_down - interp_up) * src_yofs_frac) >> FRAC_BITS); interp >>= FRAC_BITS; p_dst[i * p_dst_width * CC + j * CC + l] = uint8_t(interp); - } else if constexpr (sizeof(T) == 2) { //half float + } else if constexpr (sizeof(T) == 2) { + if constexpr (TYPE == IMAGE_SCALING_FLOAT) { //half float + float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS); + float yofs_frac = float(src_yofs_frac) / (1 << FRAC_BITS); + const T *src = ((const T *)p_src); + T *dst = ((T *)p_dst); - float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS); - float yofs_frac = float(src_yofs_frac) / (1 << FRAC_BITS); - const T *src = ((const T *)p_src); - T *dst = ((T *)p_dst); + float p00 = Math::half_to_float(src[y_ofs_up + src_xofs_left + l]); + float p10 = Math::half_to_float(src[y_ofs_up + src_xofs_right + l]); + float p01 = Math::half_to_float(src[y_ofs_down + src_xofs_left + l]); + float p11 = Math::half_to_float(src[y_ofs_down + src_xofs_right + l]); - float p00 = Math::half_to_float(src[y_ofs_up + src_xofs_left + l]); - float p10 = Math::half_to_float(src[y_ofs_up + src_xofs_right + l]); - float p01 = Math::half_to_float(src[y_ofs_down + src_xofs_left + l]); - float p11 = Math::half_to_float(src[y_ofs_down + src_xofs_right + l]); + float interp_up = p00 + (p10 - p00) * xofs_frac; + float interp_down = p01 + (p11 - p01) * xofs_frac; + float interp = interp_up + ((interp_down - interp_up) * yofs_frac); - float interp_up = p00 + (p10 - p00) * xofs_frac; - float interp_down = p01 + (p11 - p01) * xofs_frac; - float interp = interp_up + ((interp_down - interp_up) * yofs_frac); + dst[i * p_dst_width * CC + j * CC + l] = Math::make_half_float(interp); + } else { //uint16 + float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS); + float yofs_frac = float(src_yofs_frac) / (1 << FRAC_BITS); + const T *src = ((const T *)p_src); + T *dst = ((T *)p_dst); - dst[i * p_dst_width * CC + j * CC + l] = Math::make_half_float(interp); + float p00 = src[y_ofs_up + src_xofs_left + l]; + float p10 = src[y_ofs_up + src_xofs_right + l]; + float p01 = src[y_ofs_down + src_xofs_left + l]; + float p11 = src[y_ofs_down + src_xofs_right + l]; + + float interp_up = p00 + (p10 - p00) * xofs_frac; + float interp_down = p01 + (p11 - p01) * xofs_frac; + float interp = interp_up + ((interp_down - interp_up) * yofs_frac); + + dst[i * p_dst_width * CC + j * CC + l] = uint16_t(interp); + } } else if constexpr (sizeof(T) == 4) { //float float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS); @@ -982,7 +1104,7 @@ static float _lanczos(float p_x) { return Math::abs(p_x) >= LANCZOS_TYPE ? 0 : Math::sincn(p_x) * Math::sincn(p_x / LANCZOS_TYPE); } -template +template static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { int32_t src_width = p_src_width; int32_t src_height = p_src_height; @@ -1023,7 +1145,7 @@ static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict const T *__restrict src_data = ((const T *)p_src) + (buffer_y * src_width + target_x) * CC; for (uint32_t i = 0; i < CC; i++) { - if constexpr (sizeof(T) == 2) { //half float + if constexpr (sizeof(T) == 2 && TYPE == IMAGE_SCALING_FLOAT) { //half float pixel[i] += Math::half_to_float(src_data[i]) * lanczos_val; } else { pixel[i] += src_data[i] * lanczos_val; @@ -1082,8 +1204,13 @@ static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict if constexpr (sizeof(T) == 1) { //byte dst_data[i] = CLAMP(Math::fast_ftoi(pixel[i]), 0, 255); - } else if constexpr (sizeof(T) == 2) { //half float - dst_data[i] = Math::make_half_float(pixel[i]); + } else if constexpr (sizeof(T) == 2) { + if constexpr (TYPE == IMAGE_SCALING_FLOAT) { //half float + dst_data[i] = Math::make_half_float(pixel[i]); + } else { //uint16 + dst_data[i] = CLAMP(Math::fast_ftoi(pixel[i]), 0, 65535); + } + } else { // float dst_data[i] = pixel[i]; } @@ -1226,6 +1353,21 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { _scale_nearest<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break; } + } else if (format >= FORMAT_R16 && format <= FORMAT_RGBA16I) { + switch (get_format_pixel_size(format)) { + case 2: + _scale_nearest<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + case 4: + _scale_nearest<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + case 6: + _scale_nearest<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + case 8: + _scale_nearest<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + } } } break; @@ -1270,46 +1412,61 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) { switch (get_format_pixel_size(format)) { case 1: - _scale_bilinear<1, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<1, uint8_t, IMAGE_SCALING_INT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; case 2: - _scale_bilinear<2, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<2, uint8_t, IMAGE_SCALING_INT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; case 3: - _scale_bilinear<3, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<3, uint8_t, IMAGE_SCALING_INT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; case 4: - _scale_bilinear<4, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<4, uint8_t, IMAGE_SCALING_INT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; } } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) { switch (get_format_pixel_size(format)) { case 4: - _scale_bilinear<1, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<1, float, IMAGE_SCALING_FLOAT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; case 8: - _scale_bilinear<2, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<2, float, IMAGE_SCALING_FLOAT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; case 12: - _scale_bilinear<3, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<3, float, IMAGE_SCALING_FLOAT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; case 16: - _scale_bilinear<4, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<4, float, IMAGE_SCALING_FLOAT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; } } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) { switch (get_format_pixel_size(format)) { case 2: - _scale_bilinear<1, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<1, uint16_t, IMAGE_SCALING_FLOAT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; case 4: - _scale_bilinear<2, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<2, uint16_t, IMAGE_SCALING_FLOAT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; case 6: - _scale_bilinear<3, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<3, uint16_t, IMAGE_SCALING_FLOAT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; case 8: - _scale_bilinear<4, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + _scale_bilinear<4, uint16_t, IMAGE_SCALING_FLOAT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + break; + } + } else if (format >= FORMAT_R16 && format <= FORMAT_RGBA16I) { + switch (get_format_pixel_size(format)) { + case 2: + _scale_bilinear<1, uint16_t, IMAGE_SCALING_INT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + break; + case 4: + _scale_bilinear<2, uint16_t, IMAGE_SCALING_INT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + break; + case 6: + _scale_bilinear<3, uint16_t, IMAGE_SCALING_INT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); + break; + case 8: + _scale_bilinear<4, uint16_t, IMAGE_SCALING_INT>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; } } @@ -1326,46 +1483,61 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) { switch (get_format_pixel_size(format)) { case 1: - _scale_cubic<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<1, uint8_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 2: - _scale_cubic<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<2, uint8_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 3: - _scale_cubic<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<3, uint8_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 4: - _scale_cubic<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<4, uint8_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; } } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) { switch (get_format_pixel_size(format)) { case 4: - _scale_cubic<1, float>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<1, float, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 8: - _scale_cubic<2, float>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<2, float, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 12: - _scale_cubic<3, float>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<3, float, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 16: - _scale_cubic<4, float>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<4, float, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; } } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) { switch (get_format_pixel_size(format)) { case 2: - _scale_cubic<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<1, uint16_t, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 4: - _scale_cubic<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<2, uint16_t, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 6: - _scale_cubic<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<3, uint16_t, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 8: - _scale_cubic<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_cubic<4, uint16_t, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + } + } else if (format >= FORMAT_R16 && format <= FORMAT_RGBA16I) { + switch (get_format_pixel_size(format)) { + case 2: + _scale_cubic<1, uint16_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + case 4: + _scale_cubic<2, uint16_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + case 6: + _scale_cubic<3, uint16_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + case 8: + _scale_cubic<4, uint16_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; } } @@ -1374,46 +1546,61 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) { switch (get_format_pixel_size(format)) { case 1: - _scale_lanczos<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<1, uint8_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 2: - _scale_lanczos<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<2, uint8_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 3: - _scale_lanczos<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<3, uint8_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 4: - _scale_lanczos<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<4, uint8_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; } } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) { switch (get_format_pixel_size(format)) { case 4: - _scale_lanczos<1, float>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<1, float, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 8: - _scale_lanczos<2, float>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<2, float, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 12: - _scale_lanczos<3, float>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<3, float, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 16: - _scale_lanczos<4, float>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<4, float, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; } } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) { switch (get_format_pixel_size(format)) { case 2: - _scale_lanczos<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<1, uint16_t, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 4: - _scale_lanczos<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<2, uint16_t, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 6: - _scale_lanczos<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<3, uint16_t, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); break; case 8: - _scale_lanczos<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); + _scale_lanczos<4, uint16_t, IMAGE_SCALING_FLOAT>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + } + } else if (format >= FORMAT_R16 && format <= FORMAT_RGBA16I) { + switch (get_format_pixel_size(format)) { + case 2: + _scale_lanczos<1, uint16_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + case 4: + _scale_lanczos<2, uint16_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + case 6: + _scale_lanczos<3, uint16_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); + break; + case 8: + _scale_lanczos<4, uint16_t, IMAGE_SCALING_INT>(r_ptr, w_ptr, width, height, p_width, p_height); break; } } @@ -1871,6 +2058,30 @@ void Image::_generate_mipmap_from_format(Image::Format p_format, const uint8_t * case Image::FORMAT_RGBE9995: _generate_po2_mipmap(src_u32, dst_u32, p_width, p_height); break; + case Image::FORMAT_R16: + case Image::FORMAT_R16I: + _generate_po2_mipmap(src_u16, dst_u16, p_width, p_height); + break; + case Image::FORMAT_RG16: + case Image::FORMAT_RG16I: + _generate_po2_mipmap(src_u16, dst_u16, p_width, p_height); + break; + case Image::FORMAT_RGB16: + case Image::FORMAT_RGB16I: { + if (p_renormalize) { + _generate_po2_mipmap(src_u16, dst_u16, p_width, p_height); + } else { + _generate_po2_mipmap(src_u16, dst_u16, p_width, p_height); + } + } break; + case Image::FORMAT_RGBA16: + case Image::FORMAT_RGBA16I: { + if (p_renormalize) { + _generate_po2_mipmap(src_u16, dst_u16, p_width, p_height); + } else { + _generate_po2_mipmap(src_u16, dst_u16, p_width, p_height); + } + } break; default: return; @@ -2468,6 +2679,17 @@ bool Image::is_invisible() const { } } } break; + case FORMAT_RGBA16: + case FORMAT_RGBA16I: { + const int pixel_count = len / 8; + const uint16_t *pixeldata = reinterpret_cast(data.ptr()); + + for (int i = 0; i < pixel_count; i++) { + if (pixeldata[i * 4 + 3] != 0) { + return false; + } + } + } break; default: { // Formats that are compressed or don't support alpha channels are presumed to be visible. return false; @@ -2671,7 +2893,7 @@ bool Image::is_compressed() const { } bool Image::is_format_compressed(Format p_format) { - return p_format > FORMAT_RGBE9995; + return p_format > FORMAT_RGBE9995 && p_format < FORMAT_R16; } Error Image::decompress() { @@ -3252,6 +3474,50 @@ Color Image::_get_color_at_ofs(const uint8_t *ptr, uint32_t ofs) const { case FORMAT_RGBE9995: { return Color::from_rgbe9995(((uint32_t *)ptr)[ofs]); } + case FORMAT_R16: { + float r = ((uint16_t *)ptr)[ofs] / 65535.0f; + return Color(r, 0, 0, 1); + } + case FORMAT_RG16: { + float r = ((uint16_t *)ptr)[ofs * 2 + 0] / 65535.0f; + float g = ((uint16_t *)ptr)[ofs * 2 + 1] / 65535.0f; + return Color(r, g, 0, 1); + } + case FORMAT_RGB16: { + float r = ((uint16_t *)ptr)[ofs * 3 + 0] / 65535.0f; + float g = ((uint16_t *)ptr)[ofs * 3 + 1] / 65535.0f; + float b = ((uint16_t *)ptr)[ofs * 3 + 2] / 65535.0f; + return Color(r, g, b, 1); + } + case FORMAT_RGBA16: { + float r = ((uint16_t *)ptr)[ofs * 4 + 0] / 65535.0f; + float g = ((uint16_t *)ptr)[ofs * 4 + 1] / 65535.0f; + float b = ((uint16_t *)ptr)[ofs * 4 + 2] / 65535.0f; + float a = ((uint16_t *)ptr)[ofs * 4 + 3] / 65535.0f; + return Color(r, g, b, a); + } + case FORMAT_R16I: { + uint16_t r = ((uint16_t *)ptr)[ofs]; + return Color(r, 0, 0, 1); + } + case FORMAT_RG16I: { + uint16_t r = ((uint16_t *)ptr)[ofs * 2 + 0]; + uint16_t g = ((uint16_t *)ptr)[ofs * 2 + 1]; + return Color(r, g, 0, 1); + } + case FORMAT_RGB16I: { + uint16_t r = ((uint16_t *)ptr)[ofs * 3 + 0]; + uint16_t g = ((uint16_t *)ptr)[ofs * 3 + 1]; + uint16_t b = ((uint16_t *)ptr)[ofs * 3 + 2]; + return Color(r, g, b, 1); + } + case FORMAT_RGBA16I: { + uint16_t r = ((uint16_t *)ptr)[ofs * 4 + 0]; + uint16_t g = ((uint16_t *)ptr)[ofs * 4 + 1]; + uint16_t b = ((uint16_t *)ptr)[ofs * 4 + 2]; + uint16_t a = ((uint16_t *)ptr)[ofs * 4 + 3]; + return Color(r, g, b, a); + } default: { ERR_FAIL_V_MSG(Color(), "Can't get_pixel() on compressed image, sorry."); @@ -3344,6 +3610,42 @@ void Image::_set_color_at_ofs(uint8_t *ptr, uint32_t ofs, const Color &p_color) case FORMAT_RGBE9995: { ((uint32_t *)ptr)[ofs] = p_color.to_rgbe9995(); } break; + case FORMAT_R16: { + ((uint16_t *)ptr)[ofs] = uint16_t(CLAMP(p_color.r * 65535.0, 0, 65535)); + } break; + case FORMAT_RG16: { + ((uint16_t *)ptr)[ofs * 2 + 0] = uint16_t(CLAMP(p_color.r * 65535.0, 0, 65535)); + ((uint16_t *)ptr)[ofs * 2 + 1] = uint16_t(CLAMP(p_color.g * 65535.0, 0, 65535)); + } break; + case FORMAT_RGB16: { + ((uint16_t *)ptr)[ofs * 3 + 0] = uint16_t(CLAMP(p_color.r * 65535.0, 0, 65535)); + ((uint16_t *)ptr)[ofs * 3 + 1] = uint16_t(CLAMP(p_color.g * 65535.0, 0, 65535)); + ((uint16_t *)ptr)[ofs * 3 + 2] = uint16_t(CLAMP(p_color.b * 65535.0, 0, 65535)); + } break; + case FORMAT_RGBA16: { + ((uint16_t *)ptr)[ofs * 4 + 0] = uint16_t(CLAMP(p_color.r * 65535.0, 0, 65535)); + ((uint16_t *)ptr)[ofs * 4 + 1] = uint16_t(CLAMP(p_color.g * 65535.0, 0, 65535)); + ((uint16_t *)ptr)[ofs * 4 + 2] = uint16_t(CLAMP(p_color.b * 65535.0, 0, 65535)); + ((uint16_t *)ptr)[ofs * 4 + 3] = uint16_t(CLAMP(p_color.a * 65535.0, 0, 65535)); + } break; + case FORMAT_R16I: { + ((uint16_t *)ptr)[ofs] = uint16_t(CLAMP(p_color.r, 0, 65535)); + } break; + case FORMAT_RG16I: { + ((uint16_t *)ptr)[ofs * 2 + 0] = uint16_t(CLAMP(p_color.r, 0, 65535)); + ((uint16_t *)ptr)[ofs * 2 + 1] = uint16_t(CLAMP(p_color.g, 0, 65535)); + } break; + case FORMAT_RGB16I: { + ((uint16_t *)ptr)[ofs * 3 + 0] = uint16_t(CLAMP(p_color.r, 0, 65535)); + ((uint16_t *)ptr)[ofs * 3 + 1] = uint16_t(CLAMP(p_color.g, 0, 65535)); + ((uint16_t *)ptr)[ofs * 3 + 2] = uint16_t(CLAMP(p_color.b, 0, 65535)); + } break; + case FORMAT_RGBA16I: { + ((uint16_t *)ptr)[ofs * 4 + 0] = uint16_t(CLAMP(p_color.r, 0, 65535)); + ((uint16_t *)ptr)[ofs * 4 + 1] = uint16_t(CLAMP(p_color.g, 0, 65535)); + ((uint16_t *)ptr)[ofs * 4 + 2] = uint16_t(CLAMP(p_color.b, 0, 65535)); + ((uint16_t *)ptr)[ofs * 4 + 3] = uint16_t(CLAMP(p_color.a, 0, 65535)); + } break; default: { ERR_FAIL_MSG("Can't set_pixel() on compressed image, sorry."); @@ -3419,11 +3721,11 @@ Image::UsedChannels Image::detect_used_channels(CompressSource p_source) const { if (format == FORMAT_L8) { return USED_CHANNELS_L; // Grayscale only cannot have any channel less. - } else if (format == FORMAT_R8 || format == FORMAT_RH || format == FORMAT_RF) { + } else if (format == FORMAT_R8 || format == FORMAT_RH || format == FORMAT_RF || format == FORMAT_R16 || format == FORMAT_R16I) { return USED_CHANNELS_R; // Red only cannot have any channel less. } - const bool supports_alpha = format == FORMAT_RGBA8 || format == FORMAT_RGBA4444 || format == FORMAT_RGBAH || format == FORMAT_RGBAF; + const bool supports_alpha = format == FORMAT_RGBA8 || format == FORMAT_RGBA4444 || format == FORMAT_RGBAH || format == FORMAT_RGBAF || format == FORMAT_RGBA16 || format == FORMAT_RGBA16I; bool r = false, g = false, b = false, a = false, c = false; const uint8_t *data_ptr = data.ptr(); @@ -3657,6 +3959,14 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4_HDR); BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8); BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8_HDR); + BIND_ENUM_CONSTANT(FORMAT_R16); + BIND_ENUM_CONSTANT(FORMAT_RG16); + BIND_ENUM_CONSTANT(FORMAT_RGB16); + BIND_ENUM_CONSTANT(FORMAT_RGBA16); + BIND_ENUM_CONSTANT(FORMAT_R16I); + BIND_ENUM_CONSTANT(FORMAT_RG16I); + BIND_ENUM_CONSTANT(FORMAT_RGB16I); + BIND_ENUM_CONSTANT(FORMAT_RGBA16I); BIND_ENUM_CONSTANT(FORMAT_MAX); BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST); @@ -4070,6 +4380,22 @@ uint32_t Image::get_format_component_mask(Format p_format) { return rgba; case FORMAT_ASTC_8x8_HDR: return rgba; + case FORMAT_R16: + return r; + case FORMAT_RG16: + return rg; + case FORMAT_RGB16: + return rgb; + case FORMAT_RGBA16: + return rgba; + case FORMAT_R16I: + return r; + case FORMAT_RG16I: + return rg; + case FORMAT_RGB16I: + return rgb; + case FORMAT_RGBA16I: + return rgba; default: ERR_PRINT("Unhandled format."); return rgba; @@ -4213,6 +4539,10 @@ void Image::average_4_rgbe9995(uint32_t &p_out, const uint32_t &p_a, const uint3 p_out = ((Color::from_rgbe9995(p_a) + Color::from_rgbe9995(p_b) + Color::from_rgbe9995(p_c) + Color::from_rgbe9995(p_d)) * 0.25f).to_rgbe9995(); } +void Image::average_4_uint16(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d) { + p_out = static_cast((p_a + p_b + p_c + p_d + 2) >> 2); +} + void Image::renormalize_uint8(uint8_t *p_rgb) { Vector3 n(p_rgb[0] / 255.0, p_rgb[1] / 255.0, p_rgb[2] / 255.0); n *= 2.0; @@ -4246,6 +4576,19 @@ void Image::renormalize_rgbe9995(uint32_t *p_rgb) { // Never used. } +void Image::renormalize_uint16(uint16_t *p_rgb) { + Vector3 n(p_rgb[0] / 65535.0, p_rgb[1] / 65535.0, p_rgb[2] / 65535.0); + n *= 2.0; + n -= Vector3(1, 1, 1); + n.normalize(); + n += Vector3(1, 1, 1); + n *= 0.5; + n *= 65535; + p_rgb[0] = CLAMP(int(n.x), 0, 65535); + p_rgb[1] = CLAMP(int(n.y), 0, 65535); + p_rgb[2] = CLAMP(int(n.z), 0, 65535); +} + Image::Image(const uint8_t *p_mem_png_jpg, int p_len) { width = 0; height = 0; diff --git a/core/io/image.h b/core/io/image.h index fe17fb16593..af1c3ef4a0a 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -111,6 +111,14 @@ public: FORMAT_ASTC_4x4_HDR, FORMAT_ASTC_8x8, FORMAT_ASTC_8x8_HDR, + FORMAT_R16, + FORMAT_RG16, + FORMAT_RGB16, + FORMAT_RGBA16, + FORMAT_R16I, + FORMAT_RG16I, + FORMAT_RGB16I, + FORMAT_RGBA16I, FORMAT_MAX }; @@ -282,10 +290,12 @@ private: static void average_4_float(float &p_out, const float &p_a, const float &p_b, const float &p_c, const float &p_d); static void average_4_half(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d); static void average_4_rgbe9995(uint32_t &p_out, const uint32_t &p_a, const uint32_t &p_b, const uint32_t &p_c, const uint32_t &p_d); + static void average_4_uint16(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d); static void renormalize_uint8(uint8_t *p_rgb); static void renormalize_float(float *p_rgb); static void renormalize_half(uint16_t *p_rgb); static void renormalize_rgbe9995(uint32_t *p_rgb); + static void renormalize_uint16(uint16_t *p_rgb); public: int get_width() const; diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 39e6b812d8c..d0fbfb2458a 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -761,7 +761,43 @@ Same format as [constant FORMAT_ASTC_8x8], but with the hint to let the GPU know it is used for HDR. - + + OpenGL texture format [code]GL_R16[/code] where there's one component, a 16-bit unsigned normalized integer value. Since the value is normalized, each component is clamped between [code]0.0[/code] and [code]1.0[/code] (inclusive). + [b]Note:[/b] Due to limited hardware support, it is mainly recommended to be used on desktop or console devices. It may be unsupported on mobile or web, and will consequently be converted to [constant FORMAT_RF]. + + + OpenGL texture format [code]GL_RG16[/code] where there are two components, each a 16-bit unsigned normalized integer value. Since the value is normalized, each component is clamped between [code]0.0[/code] and [code]1.0[/code] (inclusive). + [b]Note:[/b] Due to limited hardware support, it is mainly recommended to be used on desktop or console devices. It may be unsupported on mobile or web, and will consequently be converted to [constant FORMAT_RGF]. + + + OpenGL texture format [code]GL_RGB16[/code] where there are three components, each a 16-bit unsigned normalized integer value. Since the value is normalized, each component is clamped between [code]0.0[/code] and [code]1.0[/code] (inclusive). + [b]Note:[/b] Due to limited hardware support, it is mainly recommended to be used on desktop or console devices. It may be unsupported on mobile or web, and will consequently be converted to [constant FORMAT_RGBF]. + + + OpenGL texture format [code]GL_RGBA16[/code] where there are four components, each a 16-bit unsigned normalized integer value. Since the value is normalized, each component is clamped between [code]0.0[/code] and [code]1.0[/code] (inclusive). + [b]Note:[/b] Due to limited hardware support, it is mainly recommended to be used on desktop or console devices. It may be unsupported on mobile or web, and will consequently be converted to [constant FORMAT_RGBAF]. + + + OpenGL texture format [code]GL_R16UI[/code] where there's one component, a 16-bit unsigned integer value. Each component is clamped between [code]0[/code] and [code]65535[/code] (inclusive). + [b]Note:[/b] When used in a shader, the texture requires usage of [code]usampler[/code] samplers. Additionally, it only supports nearest-neighbor filtering under the Compatibility renderer. + [b]Note:[/b] When sampling using [method Image.get_pixel], returned [Color]s have to be divided by [code]65535[/code] to get the correct color value. + + + OpenGL texture format [code]GL_RG16UI[/code] where there are two components, each a 16-bit unsigned integer value. Each component is clamped between [code]0[/code] and [code]65535[/code] (inclusive). + [b]Note:[/b] When used in a shader, the texture requires usage of [code]usampler[/code] samplers. Additionally, it only supports nearest-neighbor filtering under the Compatibility renderer. + [b]Note:[/b] When sampling using [method Image.get_pixel], returned [Color]s have to be divided by [code]65535[/code] to get the correct color value. + + + OpenGL texture format [code]GL_RGB16UI[/code] where there are three components, each a 16-bit unsigned integer value. Each component is clamped between [code]0[/code] and [code]65535[/code] (inclusive). + [b]Note:[/b] When used in a shader, the texture requires usage of [code]usampler[/code] samplers. Additionally, it only supports nearest-neighbor filtering under the Compatibility renderer. + [b]Note:[/b] When sampling using [method Image.get_pixel], returned [Color]s have to be divided by [code]65535[/code] to get the correct color value. + + + OpenGL texture format [code]GL_RGBA16UI[/code] where there are four components, each a 16-bit unsigned integer value. Each component is clamped between [code]0[/code] and [code]65535[/code] (inclusive). + [b]Note:[/b] When used in a shader, the texture requires usage of [code]usampler[/code] samplers. Additionally, it only supports nearest-neighbor filtering under the Compatibility renderer. + [b]Note:[/b] When sampling using [method Image.get_pixel], returned [Color]s have to be divided by [code]65535[/code] to get the correct color value. + + Represents the size of the [enum Format] enum. diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 25e26a748c6..e6eae95538d 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -90,6 +90,7 @@ Config::Config() { s3tc_supported = true; rgtc_supported = true; //RGTC - core since OpenGL version 3.0 srgb_framebuffer_supported = true; + unorm16_texture_supported = true; } else { float_texture_supported = extensions.has("GL_EXT_color_buffer_float"); float_texture_linear_supported = extensions.has("GL_OES_texture_float_linear"); @@ -104,6 +105,7 @@ Config::Config() { #endif rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc"); srgb_framebuffer_supported = extensions.has("GL_EXT_sRGB_write_control"); + unorm16_texture_supported = extensions.has("GL_EXT_texture_norm16"); } glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units); diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index 63b12089e3b..81142594359 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -82,6 +82,7 @@ public: bool astc_layered_supported = false; bool astc_3d_supported = false; bool srgb_framebuffer_supported = false; + bool unorm16_texture_supported = false; bool force_vertex_shading = false; bool specular_occlusion = false; diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index b6784e429e1..30c8c1cbb9e 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -505,6 +505,126 @@ static inline Error _get_gl_uncompressed_format(const Ref &p_image, Image r_gl_format = GL_RGB; r_gl_type = GL_UNSIGNED_INT_5_9_9_9_REV; } break; + case Image::FORMAT_R16: { + if (config->unorm16_texture_supported) { + r_gl_internal_format = _EXT_R16; + r_gl_format = GL_RED; + r_gl_type = GL_UNSIGNED_SHORT; + } else { + if (config->float_texture_linear_supported) { + if (p_image.is_valid()) { + p_image->convert(Image::FORMAT_RF); + } + r_real_format = Image::FORMAT_RF; + r_gl_internal_format = GL_R32F; + r_gl_format = GL_RED; + r_gl_type = GL_FLOAT; + } else { + if (p_image.is_valid()) { + p_image->convert(Image::FORMAT_RH); + } + r_real_format = Image::FORMAT_RH; + r_gl_internal_format = GL_R16F; + r_gl_format = GL_RED; + r_gl_type = GL_HALF_FLOAT; + } + } + } break; + case Image::FORMAT_RG16: { + if (config->unorm16_texture_supported) { + r_gl_internal_format = _EXT_RG16; + r_gl_format = GL_RG; + r_gl_type = GL_UNSIGNED_SHORT; + } else { + if (config->float_texture_linear_supported) { + if (p_image.is_valid()) { + p_image->convert(Image::FORMAT_RGF); + } + r_real_format = Image::FORMAT_RGF; + r_gl_internal_format = GL_RG32F; + r_gl_format = GL_RG; + r_gl_type = GL_FLOAT; + } else { + if (p_image.is_valid()) { + p_image->convert(Image::FORMAT_RGH); + } + r_real_format = Image::FORMAT_RGH; + r_gl_internal_format = GL_RG16F; + r_gl_format = GL_RG; + r_gl_type = GL_HALF_FLOAT; + } + } + } break; + case Image::FORMAT_RGB16: { + if (config->unorm16_texture_supported) { + r_gl_internal_format = _EXT_RGB16; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_SHORT; + } else { + if (config->float_texture_linear_supported) { + if (p_image.is_valid()) { + p_image->convert(Image::FORMAT_RGBF); + } + r_real_format = Image::FORMAT_RGBF; + r_gl_internal_format = GL_RGB32F; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; + } else { + if (p_image.is_valid()) { + p_image->convert(Image::FORMAT_RGBH); + } + r_real_format = Image::FORMAT_RGBH; + r_gl_internal_format = GL_RGB16F; + r_gl_format = GL_RGB; + r_gl_type = GL_HALF_FLOAT; + } + } + } break; + case Image::FORMAT_RGBA16: { + if (config->unorm16_texture_supported) { + r_gl_internal_format = _EXT_RGBA16; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_SHORT; + } else { + if (config->float_texture_linear_supported) { + if (p_image.is_valid()) { + p_image->convert(Image::FORMAT_RGBAF); + } + r_real_format = Image::FORMAT_RGBAF; + r_gl_internal_format = GL_RGBA32F; + r_gl_format = GL_RGBA; + r_gl_type = GL_FLOAT; + } else { + if (p_image.is_valid()) { + p_image->convert(Image::FORMAT_RGH); + } + r_real_format = Image::FORMAT_RGH; + r_gl_internal_format = GL_RGBA16F; + r_gl_format = GL_RGBA; + r_gl_type = GL_HALF_FLOAT; + } + } + } break; + case Image::FORMAT_R16I: { + r_gl_internal_format = GL_R16UI; + r_gl_format = GL_RED_INTEGER; + r_gl_type = GL_UNSIGNED_SHORT; + } break; + case Image::FORMAT_RG16I: { + r_gl_internal_format = GL_RG16UI; + r_gl_format = GL_RG_INTEGER; + r_gl_type = GL_UNSIGNED_SHORT; + } break; + case Image::FORMAT_RGB16I: { + r_gl_internal_format = GL_RGB16UI; + r_gl_format = GL_RGB_INTEGER; + r_gl_type = GL_UNSIGNED_SHORT; + } break; + case Image::FORMAT_RGBA16I: { + r_gl_internal_format = GL_RGBA16UI; + r_gl_format = GL_RGBA_INTEGER; + r_gl_type = GL_UNSIGNED_SHORT; + } break; default: { return ERR_UNAVAILABLE; } diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 52c98741aa8..0fe48744056 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -112,6 +112,11 @@ namespace GLES3 { #define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define _EXT_R16 0x822A +#define _EXT_RG16 0x822C +#define _EXT_RGB16 0x8054 +#define _EXT_RGBA16 0x805B + enum DefaultGLTexture { DEFAULT_GL_TEXTURE_WHITE, DEFAULT_GL_TEXTURE_BLACK, diff --git a/modules/betsy/image_compress_betsy.cpp b/modules/betsy/image_compress_betsy.cpp index df4f8613ac1..dc7bdaff9ab 100644 --- a/modules/betsy/image_compress_betsy.cpp +++ b/modules/betsy/image_compress_betsy.cpp @@ -351,6 +351,40 @@ static Error get_src_texture_format(Image *r_img, RD::DataFormat &r_format) { r_format = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32; break; + case Image::FORMAT_R16: + r_format = RD::DATA_FORMAT_R16_UNORM; + break; + + case Image::FORMAT_RG16: + r_format = RD::DATA_FORMAT_R16G16_UNORM; + break; + + case Image::FORMAT_RGB16: + r_img->convert(Image::FORMAT_RGBA16); + r_format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + break; + + case Image::FORMAT_RGBA16: + r_format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + break; + + case Image::FORMAT_R16I: + r_format = RD::DATA_FORMAT_R16_UINT; + break; + + case Image::FORMAT_RG16I: + r_format = RD::DATA_FORMAT_R16G16_UINT; + break; + + case Image::FORMAT_RGB16I: + r_img->convert(Image::FORMAT_RGBA16I); + r_format = RD::DATA_FORMAT_R16G16B16A16_UINT; + break; + + case Image::FORMAT_RGBA16I: + r_format = RD::DATA_FORMAT_R16G16B16A16_UINT; + break; + default: { return ERR_UNAVAILABLE; } diff --git a/modules/dds/dds_enums.h b/modules/dds/dds_enums.h index 2faa4d3de5b..aa5fcf9d358 100644 --- a/modules/dds/dds_enums.h +++ b/modules/dds/dds_enums.h @@ -74,6 +74,7 @@ enum DDSFourCC { DDFCC_BC5U = PF_FOURCC("BC5U"), DDFCC_A2XY = PF_FOURCC("A2XY"), DDFCC_DX10 = PF_FOURCC("DX10"), + DDFCC_RGBA16 = 36, DDFCC_R16F = 111, DDFCC_RG16F = 112, DDFCC_RGBA16F = 113, @@ -87,14 +88,20 @@ enum DXGIFormat { DXGI_R32G32B32A32_FLOAT = 2, DXGI_R32G32B32_FLOAT = 6, DXGI_R16G16B16A16_FLOAT = 10, + DXGI_R16G16B16A16_UNORM = 11, + DXGI_R16G16B16A16_UINT = 12, DXGI_R32G32_FLOAT = 16, DXGI_R10G10B10A2_UNORM = 24, DXGI_R8G8B8A8_UNORM = 28, DXGI_R8G8B8A8_UNORM_SRGB = 29, DXGI_R16G16_FLOAT = 34, + DXGI_R16G16_UNORM = 35, + DXGI_R16G16_UINT = 36, DXGI_R32_FLOAT = 41, DXGI_R8G8_UNORM = 49, DXGI_R16_FLOAT = 54, + DXGI_R16_UNORM = 56, + DXGI_R16_UINT = 57, DXGI_R8_UNORM = 61, DXGI_A8_UNORM = 65, DXGI_R9G9B9E5 = 67, @@ -127,6 +134,12 @@ enum DDSFormat { DDS_BC6U, DDS_BC6S, DDS_BC7, + DDS_R16, + DDS_RG16, + DDS_RGBA16, + DDS_R16I, + DDS_RG16I, + DDS_RGBA16I, DDS_R16F, DDS_RG16F, DDS_RGBA16F, @@ -180,6 +193,12 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = { { "BC6UF", true, 4, 16, Image::FORMAT_BPTC_RGBFU }, { "BC6SF", true, 4, 16, Image::FORMAT_BPTC_RGBF }, { "BC7", true, 4, 16, Image::FORMAT_BPTC_RGBA }, + { "R16", false, 1, 2, Image::FORMAT_R16 }, + { "RG16", false, 1, 4, Image::FORMAT_RG16 }, + { "RGBA16", false, 1, 8, Image::FORMAT_RGBA16 }, + { "R16I", false, 1, 2, Image::FORMAT_R16I }, + { "RG16I", false, 1, 4, Image::FORMAT_RG16I }, + { "RGBA16I", false, 1, 8, Image::FORMAT_RGBA16I }, { "R16F", false, 1, 2, Image::FORMAT_RH }, { "RG16F", false, 1, 4, Image::FORMAT_RGH }, { "RGBA16F", false, 1, 8, Image::FORMAT_RGBAH }, diff --git a/modules/dds/image_saver_dds.cpp b/modules/dds/image_saver_dds.cpp index f12e2c684f2..dcc40a34a9a 100644 --- a/modules/dds/image_saver_dds.cpp +++ b/modules/dds/image_saver_dds.cpp @@ -67,6 +67,7 @@ DDSFormatType _dds_format_get_type(DDSFormat p_format) { case DDS_R32F: case DDS_RG32F: case DDS_RGBA32F: + case DDS_RGBA16: return DDFT_FOURCC; case DDS_BC6S: @@ -74,6 +75,9 @@ DDSFormatType _dds_format_get_type(DDSFormat p_format) { case DDS_BC7: case DDS_RGB9E5: case DDS_RGB32F: + case DDS_R16I: + case DDS_RG16I: + case DDS_RGBA16I: return DDFT_DXGI; default: @@ -151,6 +155,24 @@ DDSFormat _image_format_to_dds_format(Image::Format p_image_format) { case Image::FORMAT_BPTC_RGBA: { return DDS_BC7; } + case Image::FORMAT_R16: { + return DDS_R16; + } + case Image::FORMAT_RG16: { + return DDS_RG16; + } + case Image::FORMAT_RGBA16: { + return DDS_RGBA16; + } + case Image::FORMAT_R16I: { + return DDS_R16I; + } + case Image::FORMAT_RG16I: { + return DDS_RG16I; + } + case Image::FORMAT_RGBA16I: { + return DDS_RGBA16I; + } default: { return DDS_MAX; } @@ -181,6 +203,8 @@ uint32_t _image_format_to_fourcc_format(Image::Format p_format) { return DDFCC_RG16F; case Image::FORMAT_RGBAH: return DDFCC_RGBA16F; + case Image::FORMAT_RGBA16: + return DDFCC_RGBA16; default: return 0; @@ -221,6 +245,18 @@ uint32_t _image_format_to_dxgi_format(Image::Format p_format) { return DXGI_R16G16B16A16_FLOAT; case Image::FORMAT_RGBE9995: return DXGI_R9G9B9E5; + case Image::FORMAT_R16: + return DXGI_R16_UNORM; + case Image::FORMAT_RG16: + return DXGI_R16G16_UNORM; + case Image::FORMAT_RGBA16: + return DXGI_R16G16B16A16_UNORM; + case Image::FORMAT_R16I: + return DXGI_R16_UINT; + case Image::FORMAT_RG16I: + return DXGI_R16G16_UINT; + case Image::FORMAT_RGBA16I: + return DXGI_R16G16B16A16_UINT; default: return 0; @@ -276,6 +312,20 @@ void _get_dds_pixel_bitmask(Image::Format p_format, uint32_t &r_bit_count, uint3 r_blue_mask = 0x1f; r_alpha_mask = 0; } break; + case Image::FORMAT_R16: { + r_bit_count = 16; + r_red_mask = 0xffff; + r_green_mask = 0; + r_blue_mask = 0; + r_alpha_mask = 0; + } break; + case Image::FORMAT_RG16: { + r_bit_count = 32; + r_red_mask = 0xffff; + r_green_mask = 0xffff0000; + r_blue_mask = 0; + r_alpha_mask = 0; + } break; default: { r_bit_count = 0; diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index 95cef61885e..15ff5eac0d5 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -47,6 +47,12 @@ DDSFormat _dxgi_to_dds_format(uint32_t p_dxgi_format) { case DXGI_R16G16B16A16_FLOAT: { return DDS_RGBA16F; } + case DXGI_R16G16B16A16_UNORM: { + return DDS_RGBA16; + } + case DXGI_R16G16B16A16_UINT: { + return DDS_RGBA16I; + } case DXGI_R32G32_FLOAT: { return DDS_RG32F; } @@ -60,6 +66,12 @@ DDSFormat _dxgi_to_dds_format(uint32_t p_dxgi_format) { case DXGI_R16G16_FLOAT: { return DDS_RG16F; } + case DXGI_R16G16_UNORM: { + return DDS_RG16; + } + case DXGI_R16G16_UINT: { + return DDS_RG16I; + } case DXGI_R32_FLOAT: { return DDS_R32F; } @@ -70,6 +82,12 @@ DDSFormat _dxgi_to_dds_format(uint32_t p_dxgi_format) { case DXGI_R16_FLOAT: { return DDS_R16F; } + case DXGI_R16_UNORM: { + return DDS_R16; + } + case DXGI_R16_UINT: { + return DDS_R16I; + } case DXGI_R8G8_UNORM: { return DDS_LUMINANCE_ALPHA; } @@ -550,6 +568,9 @@ static Vector> _dds_load_images_from_buffer(Ref p_f, DDSF case DDFCC_A2XY: { r_dds_format = DDS_ATI2; } break; + case DDFCC_RGBA16: { + r_dds_format = DDS_RGBA16; + } break; case DDFCC_R16F: { r_dds_format = DDS_R16F; } break; @@ -630,6 +651,10 @@ static Vector> _dds_load_images_from_buffer(Ref p_f, DDSF } } + if (format_rgb_bits == 32 && format_red_mask == 0xffff && format_green_mask == 0xffff0000) { + r_dds_format = DDS_RG16; + } + } else { // Other formats. if (format_flags & DDPF_ALPHAONLY && format_rgb_bits == 8 && format_alpha_mask == 0xff) { @@ -653,6 +678,8 @@ static Vector> _dds_load_images_from_buffer(Ref p_f, DDSF // Without alpha. if (format_rgb_bits == 8 && format_red_mask == 0xff) { r_dds_format = DDS_LUMINANCE; + } else if (format_rgb_bits == 16 && format_red_mask == 0xffff) { + r_dds_format = DDS_R16; } } } diff --git a/modules/ktx/texture_loader_ktx.cpp b/modules/ktx/texture_loader_ktx.cpp index c088abcde99..aa8b3d63e6f 100644 --- a/modules/ktx/texture_loader_ktx.cpp +++ b/modules/ktx/texture_loader_ktx.cpp @@ -186,6 +186,30 @@ static Ref load_from_file_access(Ref f, Error *r_error) { case GL_RGB9_E5: format = Image::FORMAT_RGBE9995; break; + case GL_R16: + format = Image::FORMAT_R16; + break; + case GL_RG16: + format = Image::FORMAT_RG16; + break; + case GL_RGB16: + format = Image::FORMAT_RGB16; + break; + case GL_RGBA16: + format = Image::FORMAT_RGBA16; + break; + case GL_R16UI: + format = Image::FORMAT_R16I; + break; + case GL_RG16UI: + format = Image::FORMAT_RG16I; + break; + case GL_RGB16UI: + format = Image::FORMAT_RGB16I; + break; + case GL_RGBA16UI: + format = Image::FORMAT_RGBA16I; + break; case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: format = Image::FORMAT_DXT1; @@ -382,6 +406,30 @@ static Ref load_from_file_access(Ref f, Error *r_error) { case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: format = Image::FORMAT_RGBE9995; break; + case VK_FORMAT_R16_UNORM: + format = Image::FORMAT_R16; + break; + case VK_FORMAT_R16G16_UNORM: + format = Image::FORMAT_RG16; + break; + case VK_FORMAT_R16G16B16_UNORM: + format = Image::FORMAT_RGB16; + break; + case VK_FORMAT_R16G16B16A16_UNORM: + format = Image::FORMAT_RGBA16; + break; + case VK_FORMAT_R16_UINT: + format = Image::FORMAT_R16I; + break; + case VK_FORMAT_R16G16_UINT: + format = Image::FORMAT_RG16I; + break; + case VK_FORMAT_R16G16B16_UINT: + format = Image::FORMAT_RGB16I; + break; + case VK_FORMAT_R16G16B16A16_UINT: + format = Image::FORMAT_RGBA16I; + break; case VK_FORMAT_BC1_RGB_UNORM_BLOCK: case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: format = Image::FORMAT_DXT1; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 657807560e1..24bfbe03162 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2324,6 +2324,98 @@ Ref TextureStorage::_validate_texture_format(const Ref &p_image, T r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; } break; // astc 8x8 HDR + case Image::FORMAT_R16: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R16_UNORM; + } else { + // Not supported, reconvert. + r_format.format = RD::DATA_FORMAT_R32_SFLOAT; + image->convert(Image::FORMAT_RF); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; // unorm16 + case Image::FORMAT_RG16: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16G16_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R16G16_UNORM; + } else { + // Not supported, reconvert. + r_format.format = RD::DATA_FORMAT_R32G32_SFLOAT; + image->convert(Image::FORMAT_RGF); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGB16: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16G16B16_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R16G16B16_UNORM; + } else { + // Not supported, reconvert. + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16G16B16A16_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + image->convert(Image::FORMAT_RGBA16); + } else { + r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + image->convert(Image::FORMAT_RGBAF); + } + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGBA16: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16G16B16A16_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + } else { + // Not supported, reconvert. + r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + image->convert(Image::FORMAT_RGBAF); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_R16I: { + r_format.format = RD::DATA_FORMAT_R16_UINT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; // uint16 + case Image::FORMAT_RG16I: { + r_format.format = RD::DATA_FORMAT_R16G16_UINT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGB16I: { + //this format is not mandatory for specification, check if supported first + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16G16B16_UINT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R16G16B16_UINT; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R16G16B16A16_UINT; + image->convert(Image::FORMAT_RGBA16I); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGBA16I: { + r_format.format = RD::DATA_FORMAT_R16G16B16A16_UINT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; default: { } @@ -2716,7 +2808,7 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; } break; // astc 8x8 case RD::DATA_FORMAT_D16_UNORM: { - r_format.image_format = Image::FORMAT_RH; + r_format.image_format = Image::FORMAT_R16; r_format.rd_format = RD::DATA_FORMAT_D16_UNORM; r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; @@ -2731,6 +2823,70 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; + case RD::DATA_FORMAT_R16_UNORM: { + r_format.image_format = Image::FORMAT_R16; + r_format.rd_format = RD::DATA_FORMAT_R16_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; // unorm16 + case RD::DATA_FORMAT_R16G16_UNORM: { + r_format.image_format = Image::FORMAT_RG16; + r_format.rd_format = RD::DATA_FORMAT_R16G16_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case RD::DATA_FORMAT_R16G16B16_UNORM: { + r_format.image_format = Image::FORMAT_RGB16; + r_format.rd_format = RD::DATA_FORMAT_R16G16B16_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case RD::DATA_FORMAT_R16G16B16A16_UNORM: { + r_format.image_format = Image::FORMAT_RGBA16; + r_format.rd_format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case RD::DATA_FORMAT_R16_UINT: { + r_format.image_format = Image::FORMAT_R16I; + r_format.rd_format = RD::DATA_FORMAT_R16_UINT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; // uint16 + case RD::DATA_FORMAT_R16G16_UINT: { + r_format.image_format = Image::FORMAT_RG16I; + r_format.rd_format = RD::DATA_FORMAT_R16G16_UINT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case RD::DATA_FORMAT_R16G16B16_UINT: { + r_format.image_format = Image::FORMAT_RGB16I; + r_format.rd_format = RD::DATA_FORMAT_R16G16B16_UINT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case RD::DATA_FORMAT_R16G16B16A16_UINT: { + r_format.image_format = Image::FORMAT_RGBA16I; + r_format.rd_format = RD::DATA_FORMAT_R16G16B16A16_UINT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; default: { ERR_FAIL_MSG("Unsupported image format");