plug-ins: issue #5556 Interpret transparency as black on DDS DXT1 textures

This adds an import option for DDS DXT1/BC1 images to always use
transparency. This is the default behavior, since this was what always
happened until now and it seems that DDPF_ALPHAPIXELS is very rarely
set for these type of images.

However, as the mentioned issues explains, advanced compression
algorithms can use this transparency data instead to mean a black
pixel. There is however, no certain way to determine this.

For that reason, we add an option here, that, if disabled, will
interpret fully transparent values as a black pixel.
This commit is contained in:
Jacob Boerema 2023-11-10 18:30:35 -05:00
parent dd45e3b462
commit f97e718e7a
4 changed files with 36 additions and 6 deletions

View file

@ -176,6 +176,14 @@ dds_create_procedure (GimpPlugIn *plug_in,
FALSE, FALSE,
G_PARAM_READWRITE); G_PARAM_READWRITE);
GIMP_PROC_ARG_BOOLEAN (procedure, "bc1-use-transparency",
_("Always use _transparency for BC1/DXT1"),
_("Interprets transparency for BC1/DXT1 images even when "
"DDPF_ALPHAPIXELS is not set; if disabled, sets it "
"to opaque black"),
TRUE,
G_PARAM_READWRITE);
GIMP_PROC_ARG_BOOLEAN (procedure, "decode-images", GIMP_PROC_ARG_BOOLEAN (procedure, "decode-images",
_("Automatically decode YCoCg/AE_xp images when detected"), _("Automatically decode YCoCg/AE_xp images when detected"),
_("Decode YCoCg/AExp images when detected"), _("Decode YCoCg/AExp images when detected"),

View file

@ -51,6 +51,7 @@ typedef enum
DDS_COMPRESS_AEXP, /* DXT5 */ DDS_COMPRESS_AEXP, /* DXT5 */
DDS_COMPRESS_YCOCG, /* DXT5 */ DDS_COMPRESS_YCOCG, /* DXT5 */
DDS_COMPRESS_YCOCGS, /* DXT5 */ DDS_COMPRESS_YCOCGS, /* DXT5 */
_DDS_COMPRESS_BC1_NO_ALPHA, /* For internal use only. */
DDS_COMPRESS_MAX DDS_COMPRESS_MAX
} DDS_COMPRESSION_TYPE; } DDS_COMPRESSION_TYPE;

View file

@ -139,6 +139,7 @@ read_dds (GFile *file,
gint i, j; gint i, j;
guint computed_pitch_or_linsize; guint computed_pitch_or_linsize;
gboolean flip_import; gboolean flip_import;
gboolean bc1_use_transparency;
if (interactive) if (interactive)
{ {
@ -151,6 +152,7 @@ read_dds (GFile *file,
g_object_get (config, g_object_get (config,
"load-mipmaps", &read_mipmaps, "load-mipmaps", &read_mipmaps,
"flip-image", &flip_import, "flip-image", &flip_import,
"bc1-use-transparency", &bc1_use_transparency,
"decode-images", &decode_images, "decode-images", &decode_images,
NULL); NULL);
@ -307,7 +309,8 @@ read_dds (GFile *file,
if (hdr.pixelfmt.flags & DDPF_FOURCC) if (hdr.pixelfmt.flags & DDPF_FOURCC)
{ {
/* fourcc is dXt* or rXgb */ /* fourcc is dXt* or rXgb */
if (hdr.pixelfmt.fourcc[1] == 'X') if (hdr.pixelfmt.fourcc[1] == 'X' &&
(hdr.pixelfmt.fourcc[3] != '1' || bc1_use_transparency))
hdr.pixelfmt.flags |= DDPF_ALPHAPIXELS; hdr.pixelfmt.flags |= DDPF_ALPHAPIXELS;
} }
@ -1841,6 +1844,12 @@ load_layer (FILE *fp,
dst[y * (width * 4) + (x * 4) + 3] = 255; dst[y * (width * 4) + (x * 4) + 3] = 255;
} }
if (format == DDS_COMPRESS_BC1 &&
! (hdr->pixelfmt.flags & DDPF_ALPHAPIXELS))
{
format = _DDS_COMPRESS_BC1_NO_ALPHA;
}
dxt_decompress (dst, buf, format, size, width, height, d->gimp_bpp, dxt_decompress (dst, buf, format, size, width, height, d->gimp_bpp,
hdr->pixelfmt.flags & DDPF_NORMAL); hdr->pixelfmt.flags & DDPF_NORMAL);
@ -2013,6 +2022,7 @@ load_dialog (GimpProcedure *procedure,
"dds-read-box", "dds-read-box",
"load-mipmaps", "load-mipmaps",
"flip-image", "flip-image",
"bc1-use-transparency",
"decode-images", "decode-images",
NULL); NULL);
gtk_box_set_spacing (GTK_BOX (vbox), 8); gtk_box_set_spacing (GTK_BOX (vbox), 8);

View file

@ -1329,7 +1329,18 @@ decode_color_block (unsigned char *block,
d[1] = colors[idx][1]; d[1] = colors[idx][1];
d[2] = colors[idx][0]; d[2] = colors[idx][0];
if (format == DDS_COMPRESS_BC1) if (format == DDS_COMPRESS_BC1)
{
d[3] = ((c0 <= c1) && idx == 3) ? 0 : 255; d[3] = ((c0 <= c1) && idx == 3) ? 0 : 255;
}
else if (format == _DDS_COMPRESS_BC1_NO_ALPHA)
{
/* BC1, but interpret transparent as black */
if ((c0 <= c1) && idx == 3)
{
d[0] = d[1] = d[2] = 0;
}
d[3] = 255;
}
indices >>= 2; indices >>= 2;
d += 4; d += 4;
} }
@ -1486,7 +1497,7 @@ dxt_decompress (unsigned char *dst,
{ {
memset(block, 0, 16 * 4); memset(block, 0, 16 * 4);
if (format == DDS_COMPRESS_BC1) if (format == DDS_COMPRESS_BC1 || format == _DDS_COMPRESS_BC1_NO_ALPHA)
{ {
decode_color_block(block, s, format); decode_color_block(block, s, format);
s += 8; s += 8;