Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions core/io/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3464,18 +3464,24 @@ Image::UsedChannels Image::detect_used_channels(CompressSource p_source) const {

UsedChannels used_channels;

if (!c && !a) {
used_channels = USED_CHANNELS_L;
} else if (!c && a) {
used_channels = USED_CHANNELS_LA;
} else if (r && !g && !b && !a) {
used_channels = USED_CHANNELS_R;
} else if (r && g && !b && !a) {
used_channels = USED_CHANNELS_RG;
} else if (r && g && b && !a) {
used_channels = USED_CHANNELS_RGB;
if (!c) {
// Uniform RGB (grayscale).
if (a) {
used_channels = USED_CHANNELS_LA;
} else {
used_channels = USED_CHANNELS_L;
}
} else {
used_channels = USED_CHANNELS_RGBA;
// Colored image.
if (a) {
used_channels = USED_CHANNELS_RGBA;
} else if (b) {
used_channels = USED_CHANNELS_RGB;
} else if (g) {
used_channels = USED_CHANNELS_RG;
} else {
used_channels = USED_CHANNELS_R;
}
}

if (p_source == COMPRESS_SOURCE_SRGB && (used_channels == USED_CHANNELS_R || used_channels == USED_CHANNELS_RG)) {
Expand Down
127 changes: 120 additions & 7 deletions editor/import/resource_importer_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,10 @@ Dictionary ResourceImporterTexture::_load_editor_meta(const String &p_path) cons
}

void ResourceImporterTexture::_remap_channels(Ref<Image> &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++) {
Expand Down Expand Up @@ -480,11 +482,127 @@ void ResourceImporterTexture::_remap_channels(Ref<Image> &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);
Expand Down Expand Up @@ -518,11 +636,6 @@ void ResourceImporterTexture::_remap_channels(Ref<Image> &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;
Expand Down