Skip to content

Commit 92cfd2b

Browse files
committed
Expand the imported texture channel count for remapping if necessary
1 parent 428a762 commit 92cfd2b

File tree

1 file changed

+120
-7
lines changed

1 file changed

+120
-7
lines changed

editor/import/resource_importer_texture.cpp

Lines changed: 120 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,10 @@ Dictionary ResourceImporterTexture::_load_editor_meta(const String &p_path) cons
448448
}
449449

450450
void ResourceImporterTexture::_remap_channels(Ref<Image> &r_image, ChannelRemap p_options[4]) {
451-
bool attempted_hdr_inverted = false;
451+
ERR_FAIL_COND(r_image->is_compressed());
452452

453+
// Currently HDR inverted remapping is not allowed.
454+
bool attempted_hdr_inverted = false;
453455
if (r_image->get_format() >= Image::FORMAT_RF && r_image->get_format() <= Image::FORMAT_RGBE9995) {
454456
// Formats which can hold HDR data cannot be inverted the same way as unsigned normalized ones (1.0 - channel).
455457
for (int i = 0; i < 4; i++) {
@@ -480,11 +482,127 @@ void ResourceImporterTexture::_remap_channels(Ref<Image> &r_image, ChannelRemap
480482
WARN_PRINT("Attempted to use an inverted channel remap on an HDR image. The remap has been changed to its uninverted equivalent.");
481483
}
482484

483-
if (p_options[0] == REMAP_R && p_options[1] == REMAP_G && p_options[2] == REMAP_B && p_options[3] == REMAP_A) {
485+
// Optimization: Set the remap from 'unused' to either 0 or 1 to avoid repeated checks in the conversion loop.
486+
for (int i = 0; i < 4; i++) {
487+
if (p_options[i] == REMAP_UNUSED) {
488+
p_options[i] = i == 3 ? REMAP_1 : REMAP_0;
489+
}
490+
}
491+
492+
// Expand the image's channel count in the event that the current set of channels doesn't allow for the desired remap.
493+
const Image::Format original_format = r_image->get_format();
494+
const uint32_t channel_mask = Image::get_format_component_mask(original_format);
495+
496+
// Whether a channel is supported by the format itself.
497+
const bool has_channel_r = channel_mask & 0x1;
498+
const bool has_channel_g = channel_mask & 0x2;
499+
const bool has_channel_b = channel_mask & 0x4;
500+
const bool has_channel_a = channel_mask & 0x8;
501+
502+
// Whether a certain channel needs to be remapped.
503+
const bool remap_r = p_options[0] != REMAP_R ? !(!has_channel_r && p_options[0] == REMAP_0) : false;
504+
const bool remap_g = p_options[1] != REMAP_G ? !(!has_channel_g && p_options[1] == REMAP_0) : false;
505+
const bool remap_b = p_options[2] != REMAP_B ? !(!has_channel_b && p_options[2] == REMAP_0) : false;
506+
const bool remap_a = p_options[3] != REMAP_A ? !(!has_channel_a && p_options[3] == REMAP_1) : false;
507+
508+
if (!(remap_r || remap_g || remap_b || remap_a)) {
484509
// Default color map, do nothing.
485510
return;
486511
}
487512

513+
// Whether a certain channel set is needed, either from the source or the remap.
514+
const bool needs_rg = remap_g || has_channel_g;
515+
const bool needs_rgb = remap_b || has_channel_b;
516+
const bool needs_rgba = remap_a || has_channel_a;
517+
518+
bool could_not_expand = false;
519+
switch (original_format) {
520+
case Image::FORMAT_R8:
521+
case Image::FORMAT_RG8:
522+
case Image::FORMAT_RGB8: {
523+
// Convert to either RGBA8, RGB8 or RG8.
524+
if (needs_rgba) {
525+
r_image->convert(Image::FORMAT_RGBA8);
526+
} else if (needs_rgb) {
527+
r_image->convert(Image::FORMAT_RGB8);
528+
} else if (needs_rg) {
529+
r_image->convert(Image::FORMAT_RG8);
530+
}
531+
} break;
532+
case Image::FORMAT_RH:
533+
case Image::FORMAT_RGH:
534+
case Image::FORMAT_RGBH: {
535+
// Convert to either RGBAH, RGBH or RGH.
536+
if (needs_rgba) {
537+
r_image->convert(Image::FORMAT_RGBAH);
538+
} else if (needs_rgb) {
539+
r_image->convert(Image::FORMAT_RGBH);
540+
} else if (needs_rg) {
541+
r_image->convert(Image::FORMAT_RGH);
542+
}
543+
} break;
544+
case Image::FORMAT_RF:
545+
case Image::FORMAT_RGF:
546+
case Image::FORMAT_RGBF: {
547+
// Convert to either RGBAF, RGBF or RGF.
548+
if (needs_rgba) {
549+
r_image->convert(Image::FORMAT_RGBAF);
550+
} else if (needs_rgb) {
551+
r_image->convert(Image::FORMAT_RGBF);
552+
} else if (needs_rg) {
553+
r_image->convert(Image::FORMAT_RGF);
554+
}
555+
} break;
556+
case Image::FORMAT_L8: {
557+
const bool uniform_rgb = (p_options[0] == p_options[1] && p_options[1] == p_options[2]) || !(remap_r || remap_g || remap_b);
558+
if (uniform_rgb) {
559+
// Uniform RGB.
560+
if (needs_rgba) {
561+
r_image->convert(Image::FORMAT_LA8);
562+
}
563+
} else {
564+
// Non-uniform RGB.
565+
if (needs_rgba) {
566+
r_image->convert(Image::FORMAT_RGBA8);
567+
} else {
568+
r_image->convert(Image::FORMAT_RGB8);
569+
}
570+
could_not_expand = true;
571+
}
572+
} break;
573+
case Image::FORMAT_LA8: {
574+
const bool uniform_rgb = (p_options[0] == p_options[1] && p_options[1] == p_options[2]) || !(remap_r || remap_g || remap_b);
575+
if (!uniform_rgb) {
576+
// Non-uniform RGB.
577+
r_image->convert(Image::FORMAT_RGBA8);
578+
could_not_expand = true;
579+
}
580+
} break;
581+
case Image::FORMAT_RGB565: {
582+
if (needs_rgba) {
583+
// RGB565 doesn't have an alpha expansion, convert to RGBA8.
584+
r_image->convert(Image::FORMAT_RGBA8);
585+
could_not_expand = true;
586+
}
587+
} break;
588+
case Image::FORMAT_RGBE9995: {
589+
if (needs_rgba) {
590+
// RGB9995 doesn't have an alpha expansion, convert to RGBAH.
591+
r_image->convert(Image::FORMAT_RGBAH);
592+
could_not_expand = true;
593+
}
594+
} break;
595+
596+
default: {
597+
} break;
598+
}
599+
600+
if (could_not_expand) {
601+
WARN_PRINT(vformat("Unable to expand image format %s's channels (the target format does not exist), converting to %s as a fallback.",
602+
Image::get_format_name(original_format), Image::get_format_name(r_image->get_format())));
603+
}
604+
605+
// Remap the channels.
488606
for (int x = 0; x < r_image->get_width(); x++) {
489607
for (int y = 0; y < r_image->get_height(); y++) {
490608
Color src = r_image->get_pixel(x, y);
@@ -518,11 +636,6 @@ void ResourceImporterTexture::_remap_channels(Ref<Image> &r_image, ChannelRemap
518636
dst[i] = 1.0f - src.a;
519637
break;
520638

521-
case REMAP_UNUSED:
522-
// For Alpha the unused value is 1, for other channels it's 0.
523-
dst[i] = (i == 3) ? 1.0f : 0.0f;
524-
break;
525-
526639
case REMAP_0:
527640
dst[i] = 0.0f;
528641
break;

0 commit comments

Comments
 (0)