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,
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",
_("Automatically decode YCoCg/AE_xp images when detected"),
_("Decode YCoCg/AExp images when detected"),

View file

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

View file

@ -139,6 +139,7 @@ read_dds (GFile *file,
gint i, j;
guint computed_pitch_or_linsize;
gboolean flip_import;
gboolean bc1_use_transparency;
if (interactive)
{
@ -149,9 +150,10 @@ read_dds (GFile *file,
}
g_object_get (config,
"load-mipmaps", &read_mipmaps,
"flip-image", &flip_import,
"decode-images", &decode_images,
"load-mipmaps", &read_mipmaps,
"flip-image", &flip_import,
"bc1-use-transparency", &bc1_use_transparency,
"decode-images", &decode_images,
NULL);
fp = g_fopen (g_file_peek_path (file), "rb");
@ -307,7 +309,8 @@ read_dds (GFile *file,
if (hdr.pixelfmt.flags & DDPF_FOURCC)
{
/* 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;
}
@ -1841,6 +1844,12 @@ load_layer (FILE *fp,
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,
hdr->pixelfmt.flags & DDPF_NORMAL);
@ -2013,6 +2022,7 @@ load_dialog (GimpProcedure *procedure,
"dds-read-box",
"load-mipmaps",
"flip-image",
"bc1-use-transparency",
"decode-images",
NULL);
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[2] = colors[idx][0];
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;
d += 4;
}
@ -1486,7 +1497,7 @@ dxt_decompress (unsigned char *dst,
{
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);
s += 8;