diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index 2912d11da0d..e6f4bcefbbb 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -448,8 +448,10 @@ Dictionary ResourceImporterTexture::_load_editor_meta(const String &p_path) cons } void ResourceImporterTexture::_remap_channels(Ref &r_image, ChannelRemap p_options[4]) { - bool attempted_hdr_inverted = false; + ERR_FAIL_COND(r_image->is_compressed()); + // Currently HDR inverted remapping is not allowed. + bool attempted_hdr_inverted = false; if (r_image->get_format() >= Image::FORMAT_RF && r_image->get_format() <= Image::FORMAT_RGBE9995) { // Formats which can hold HDR data cannot be inverted the same way as unsigned normalized ones (1.0 - channel). for (int i = 0; i < 4; i++) { @@ -480,11 +482,127 @@ void ResourceImporterTexture::_remap_channels(Ref &r_image, ChannelRemap WARN_PRINT("Attempted to use an inverted channel remap on an HDR image. The remap has been changed to its uninverted equivalent."); } - if (p_options[0] == REMAP_R && p_options[1] == REMAP_G && p_options[2] == REMAP_B && p_options[3] == REMAP_A) { + // Optimization: Set the remap from 'unused' to either 0 or 1 to avoid repeated checks in the conversion loop. + for (int i = 0; i < 4; i++) { + if (p_options[i] == REMAP_UNUSED) { + p_options[i] = i == 3 ? REMAP_1 : REMAP_0; + } + } + + // Expand the image's channel count in the event that the current set of channels doesn't allow for the desired remap. + const Image::Format original_format = r_image->get_format(); + const uint32_t channel_mask = Image::get_format_component_mask(original_format); + + // Whether a channel is supported by the format itself. + const bool has_channel_r = channel_mask & 0x1; + const bool has_channel_g = channel_mask & 0x2; + const bool has_channel_b = channel_mask & 0x4; + const bool has_channel_a = channel_mask & 0x8; + + // Whether a certain channel needs to be remapped. + const bool remap_r = p_options[0] != REMAP_R ? !(!has_channel_r && p_options[0] == REMAP_0) : false; + const bool remap_g = p_options[1] != REMAP_G ? !(!has_channel_g && p_options[1] == REMAP_0) : false; + const bool remap_b = p_options[2] != REMAP_B ? !(!has_channel_b && p_options[2] == REMAP_0) : false; + const bool remap_a = p_options[3] != REMAP_A ? !(!has_channel_a && p_options[3] == REMAP_1) : false; + + if (!(remap_r || remap_g || remap_b || remap_a)) { // Default color map, do nothing. return; } + // Whether a certain channel set is needed, either from the source or the remap. + const bool needs_rg = remap_g || has_channel_g; + const bool needs_rgb = remap_b || has_channel_b; + const bool needs_rgba = remap_a || has_channel_a; + + bool could_not_expand = false; + switch (original_format) { + case Image::FORMAT_R8: + case Image::FORMAT_RG8: + case Image::FORMAT_RGB8: { + // Convert to either RGBA8, RGB8 or RG8. + if (needs_rgba) { + r_image->convert(Image::FORMAT_RGBA8); + } else if (needs_rgb) { + r_image->convert(Image::FORMAT_RGB8); + } else if (needs_rg) { + r_image->convert(Image::FORMAT_RG8); + } + } break; + case Image::FORMAT_RH: + case Image::FORMAT_RGH: + case Image::FORMAT_RGBH: { + // Convert to either RGBAH, RGBH or RGH. + if (needs_rgba) { + r_image->convert(Image::FORMAT_RGBAH); + } else if (needs_rgb) { + r_image->convert(Image::FORMAT_RGBH); + } else if (needs_rg) { + r_image->convert(Image::FORMAT_RGH); + } + } break; + case Image::FORMAT_RF: + case Image::FORMAT_RGF: + case Image::FORMAT_RGBF: { + // Convert to either RGBAF, RGBF or RGF. + if (needs_rgba) { + r_image->convert(Image::FORMAT_RGBAF); + } else if (needs_rgb) { + r_image->convert(Image::FORMAT_RGBF); + } else if (needs_rg) { + r_image->convert(Image::FORMAT_RGF); + } + } break; + case Image::FORMAT_L8: { + const bool uniform_rgb = (p_options[0] == p_options[1] && p_options[1] == p_options[2]) || !(remap_r || remap_g || remap_b); + if (uniform_rgb) { + // Uniform RGB. + if (needs_rgba) { + r_image->convert(Image::FORMAT_LA8); + } + } else { + // Non-uniform RGB. + if (needs_rgba) { + r_image->convert(Image::FORMAT_RGBA8); + } else { + r_image->convert(Image::FORMAT_RGB8); + } + could_not_expand = true; + } + } break; + case Image::FORMAT_LA8: { + const bool uniform_rgb = (p_options[0] == p_options[1] && p_options[1] == p_options[2]) || !(remap_r || remap_g || remap_b); + if (!uniform_rgb) { + // Non-uniform RGB. + r_image->convert(Image::FORMAT_RGBA8); + could_not_expand = true; + } + } break; + case Image::FORMAT_RGB565: { + if (needs_rgba) { + // RGB565 doesn't have an alpha expansion, convert to RGBA8. + r_image->convert(Image::FORMAT_RGBA8); + could_not_expand = true; + } + } break; + case Image::FORMAT_RGBE9995: { + if (needs_rgba) { + // RGB9995 doesn't have an alpha expansion, convert to RGBAH. + r_image->convert(Image::FORMAT_RGBAH); + could_not_expand = true; + } + } break; + + default: { + } break; + } + + if (could_not_expand) { + WARN_PRINT(vformat("Unable to expand image format %s's channels (the target format does not exist), converting to %s as a fallback.", + Image::get_format_name(original_format), Image::get_format_name(r_image->get_format()))); + } + + // Remap the channels. for (int x = 0; x < r_image->get_width(); x++) { for (int y = 0; y < r_image->get_height(); y++) { Color src = r_image->get_pixel(x, y); @@ -518,11 +636,6 @@ void ResourceImporterTexture::_remap_channels(Ref &r_image, ChannelRemap dst[i] = 1.0f - src.a; break; - case REMAP_UNUSED: - // For Alpha the unused value is 1, for other channels it's 0. - dst[i] = (i == 3) ? 1.0f : 0.0f; - break; - case REMAP_0: dst[i] = 0.0f; break;