plug-ins: Import DDS BC7 compression

This patch adds support for importing DDS images
with BC7 compression. The implementation references
ImageMagick's method.
This commit is contained in:
Alx Sa 2025-01-11 16:51:09 +00:00
parent 994aa79724
commit 73f30b0dc6
6 changed files with 628 additions and 0 deletions

361
plug-ins/file-dds/bc7.c Normal file
View file

@ -0,0 +1,361 @@
/*
* DDS GIMP plugin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
*/
/* ImageMagick's implementation of BC7 was referenced for our implementation.
* The relevant commit: https://github.com/ImageMagick/ImageMagick/pull/4126/files
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <glib.h>
#include <libgimp/gimp.h>
#include "bc7.h"
#define SWAP(a, b) do { typeof(a) t; t = a; a = b; b = t; } while(0)
static guchar get_bits (const guchar *block,
guchar *start_bit,
guchar length);
static void decode_rgba_channels (BC7_colors *colors,
guchar *src,
guint mode,
guchar *start);
static gboolean is_pixel_anchor (guchar subset_index,
guint precision,
guchar pixel_index,
guint partition_id);
gint
bc7_decompress (guchar *src,
guint size,
guchar *block)
{
/* BC7 blocks are always 16 bytes */
guchar s[16];
BC7_colors colors;
guchar rgb_indexes[16];
guchar alpha_indexes[16];
guchar subset_indexes[16];
guchar rgba[4];
guint mode = 0;
guint subset_count = 0;
guint partition_id = 0;
guint swap = 0;
guint selector = 0;
guchar current_bit = 0;
guint i_precision = 0;
guint no_sel_precision = 0;
for (gint i = 0; i < 16; i++)
s[i] = src[i];
/* BC7 blocks are read from the last bit of the last byte, backwards.
* The mode is determined by the first 1 bit encountered. For instance,
* 1 is mode 0, 10 is mode 1, 100 is mode 2, and so on. */
while (current_bit <= 8 && ! get_bits (s, &current_bit, 1))
{
continue;
}
mode = current_bit - 1;
if (mode > 7)
return 0;
/* For modes that support partitions, we start counting
* from left of the mode bit, and get the partition ID.
* The size of the partition ID is defined by the mode. */
subset_count = mode_info[mode].subset_count;
if (subset_count > 1)
{
partition_id = get_bits (s, &current_bit,
mode_info[mode].partition_bits);
if (partition_id > 63)
return 0;
}
/* Mode 4 and 5 might swap channels for better compression. 2 bits after the mode bit
* indicate which were swapped (if any) */
if (mode == 4 || mode == 5)
swap = get_bits (s, &current_bit, 2);
/* Mode 4 also has a single selector bit, to the left of its swap bits.
* This bit determines where the alpha channel indexes are located. */
if (mode == 4)
selector = get_bits (s, &current_bit, 1);
/* Channel values are stored in RnGnBn(An) format, where the mode determines
* how many bits of precision and how many values are stored. */
decode_rgba_channels (&colors, s, mode, &current_bit);
/* Next, we get the indexes to assemble pixels from the channel values. */
i_precision = mode_info[mode].index_precision;
no_sel_precision = mode_info[mode].no_sel_precision;
if (mode == 4 && selector)
{
i_precision = 3;
alpha_indexes[0] = get_bits (s, &current_bit, 1);
for (gint i = 1; i < 16; i++)
alpha_indexes[i] = get_bits (s, &current_bit, 2);
}
/* First, calculate the RGB channel indexes based on the partition ID
* and the number of subsets. */
for (gint i = 0; i < 16; i++)
{
guint precision = i_precision;
if (subset_count == 2)
subset_indexes[i] = partition_table[0][partition_id][i];
else if (subset_count == 3)
subset_indexes[i] = partition_table[1][partition_id][i];
else
subset_indexes[i] = 0;
if (is_pixel_anchor (subset_indexes[i], subset_count, i, partition_id))
precision--;
rgb_indexes[i]= get_bits (s, &current_bit, precision);
}
if (mode == 5 || (mode == 4 && ! selector))
{
alpha_indexes[0] = get_bits (s, &current_bit, no_sel_precision - 1);
for (gint i = 1; i < 16; i++)
alpha_indexes[i] = get_bits (s, &current_bit, no_sel_precision);
}
/* Create pixels from subset indexes */
for (gint i = 0; i < 16; i++)
{
guint weight;
guint c0 = 2 * subset_indexes[i];
guint c1 = (2 * subset_indexes[i]) + 1;
if (i_precision == 2)
weight = weight_2[rgb_indexes[i]];
else if (i_precision == 3)
weight = weight_3[rgb_indexes[i]];
else
weight = weight_4[rgb_indexes[i]];
rgba[0] = ((64 - weight) * colors.r[c0] + weight * colors.r[c1] + 32) >> 6;
rgba[1] = ((64 - weight) * colors.g[c0] + weight * colors.g[c1] + 32) >> 6;
rgba[2] = ((64 - weight) * colors.b[c0] + weight * colors.b[c1] + 32) >> 6;
if (mode == 4 || mode == 5)
{
weight = weight_2[alpha_indexes[i]];
if (mode == 4 && ! selector)
weight = weight_3[alpha_indexes[i]];
}
rgba[3] = ((64 - weight) * colors.a[c0] + weight * colors.a[c1] + 32) >> 6;
switch (swap)
{
case 1:
SWAP (rgba[3], rgba[0]);
break;
case 2:
SWAP (rgba[3], rgba[1]);
break;
case 3:
SWAP (rgba[3], rgba[2]);
break;
default:
break;
}
for (gint j = 0; j < 4; j++)
block[(i * 4) + j] = rgba[j];
}
return 1;
}
/* Private Functions */
static guchar
get_bits (const guchar *block,
guchar *start_bit,
guchar length)
{
guchar bits;
guint index;
guint base;
guint first_bits;
guint next_bits;
index = (*start_bit) >> 3;
base = (*start_bit) - (index << 3);
if (index > 15)
return 0;
if (base + length > 8)
{
first_bits = 8 - base;
next_bits = length - first_bits;
bits = block[index] >> base;
bits |= (block[index + 1] & ((1 << next_bits) - 1)) << first_bits;
}
else
{
bits = (block[index] >> base) & ((1 << length) - 1);
}
(*start_bit) += length;
return bits;
}
static void
decode_rgba_channels (BC7_colors *colors,
guchar *src,
guint mode,
guchar *start)
{
guint channel_count = mode_info[mode].subset_count * 2;
guint rgb_precision = mode_info[mode].rgb_precision;
guint alpha_precision = mode_info[mode].alpha_precision;
/* Get RGB channel values */
for (gint i = 0; i < channel_count; i++)
colors->r[i] = get_bits (src, start, rgb_precision);
for (gint i = 0; i < channel_count; i++)
colors->g[i] = get_bits (src, start, rgb_precision);
for (gint i = 0; i < channel_count; i++)
colors->b[i] = get_bits (src, start, rgb_precision);
/* Modes 4 - 7 also have alpha values */
if (alpha_precision)
{
for (gint i = 0; i < channel_count; i++)
colors->a[i] = get_bits (src, start, alpha_precision);
}
else
{
for (gint i = 0; i < channel_count; i++)
colors->a[i] = 255;
}
/* Modes 0, 1, 3, 6, and 7 have P-bits, which increase the precision
* by 1. */
if (mode_info[mode].p_bit_count)
{
rgb_precision++;
if (alpha_precision)
alpha_precision++;
/* P-bits are added at the least significant bit, so
* we have to shift existing channel values over by 1 */
for (gint i = 0; i < channel_count; i++)
{
colors->r[i] <<= 1;
colors->g[i] <<= 1;
colors->b[i] <<= 1;
if (alpha_precision)
colors->a[i] <<= 1;
}
if (mode == 1)
{
guint p_bit_1 = get_bits (src, start, 1);
guint p_bit_2 = get_bits (src, start, 1);
for (gint i = 0; i < 2; i++)
{
colors->r[i] |= p_bit_1;
colors->g[i] |= p_bit_1;
colors->b[i] |= p_bit_1;
colors->r[i + 2] |= p_bit_2;
colors->g[i + 2] |= p_bit_2;
colors->b[i + 2] |= p_bit_2;
}
}
else
{
for (gint i = 0; i < channel_count; i++)
{
guint p_bit = get_bits (src, start, 1);
colors->r[i] |= p_bit;
colors->g[i] |= p_bit;
colors->b[i] |= p_bit;
if (alpha_precision)
colors->a[i] |= p_bit;
}
}
}
/* Normalize all channel values to 8 bits */
for (gint i = 0; i < channel_count; i++)
{
colors->r[i] <<= (8 - rgb_precision);
colors->g[i] <<= (8 - rgb_precision);
colors->b[i] <<= (8 - rgb_precision);
colors->r[i] = colors->r[i] | (colors->r[i] >> rgb_precision);
colors->g[i] = colors->g[i] | (colors->g[i] >> rgb_precision);
colors->b[i] = colors->b[i] | (colors->b[i] >> rgb_precision);
if (alpha_precision)
{
colors->a[i] <<= (8 - alpha_precision);
colors->a[i] = colors->a[i] | (colors->a[i] >> alpha_precision);
}
}
}
static gboolean
is_pixel_anchor (guchar subset_index,
guint precision,
guchar pixel_index,
guint partition_id)
{
guint table_index;
if (subset_index == 0)
table_index = 0;
else if (subset_index == 1 && precision == 2)
table_index = 1;
else if (subset_index == 1 && precision == 3)
table_index = 2;
else
table_index = 3;
if (anchor_index_table[table_index][partition_id] == pixel_index)
return TRUE;
return FALSE;
}

247
plug-ins/file-dds/bc7.h Normal file
View file

@ -0,0 +1,247 @@
/*
* DDS GIMP plugin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __BC7_H__
#define __BC7_H__
/* Mode specifications:
* https://learn.microsoft.com/en-us/windows/win32/direct3d11/bc7-format-mode-reference
*/
typedef struct
{
guchar partition_bits;
guchar subset_count;
guchar rgb_precision;
guchar alpha_precision;
guchar p_bit_count;
guchar index_precision;
guchar no_sel_precision;
} BC7_mode_info;
typedef struct
{
guint r[6];
guint g[6];
guint b[6];
guint a[6];
} BC7_colors;
static const BC7_mode_info mode_info[8] =
{
{ 4, 3, 4, 0, 6, 3, 0 },
{ 6, 2, 6, 0, 2, 3, 0 },
{ 6, 3, 5, 0, 0, 2, 0 },
{ 6, 2, 7, 0, 4, 2, 0 },
{ 0, 1, 5, 6, 0, 2, 3 },
{ 0, 1, 7, 8, 0, 2, 2 },
{ 0, 1, 7, 7, 2, 4, 0 },
{ 6, 2, 5, 5, 4, 2, 0 },
};
/* RGB weights */
static const guchar weight_2[] = { 0, 21, 43, 64 };
static const guchar weight_3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
static const guchar weight_4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
static const guchar partition_table[2][64][16] =
{
{ /* BC7 Partition Set for 2 Subsets */
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
{ 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 },
{ 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 },
{ 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 },
{ 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 },
{ 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 },
{ 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 },
{ 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 },
{ 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 },
{ 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 },
{ 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 },
{ 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 },
{ 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 },
{ 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 },
{ 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 },
{ 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 },
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 },
{ 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
{ 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 },
{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 },
{ 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 },
{ 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 },
{ 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
{ 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 },
{ 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
{ 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 },
{ 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 },
{ 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 },
{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 }
},
{ /* BC7 Partition Set for 3 Subsets */
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 },
{ 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 },
{ 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
{ 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 },
{ 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
{ 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 },
{ 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 },
{ 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 },
{ 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
{ 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 },
{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 },
{ 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 },
{ 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 },
{ 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 },
{ 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 },
{ 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 },
{ 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 },
{ 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 },
{ 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 },
{ 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 },
{ 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 },
{ 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 },
{ 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 },
{ 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 },
{ 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
{ 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 },
{ 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 },
{ 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 },
{ 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 },
{ 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 },
{ 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 },
{ 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 },
{ 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 },
{ 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 },
{ 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 },
{ 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 },
{ 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 },
{ 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 },
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 },
{ 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 },
{ 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 },
{ 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 },
{ 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 },
{ 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 },
{ 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 },
{ 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 },
{ 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 },
{ 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 },
{ 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 },
{ 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 },
{ 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
{ 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 }
}
};
static const guchar anchor_index_table[4][64] =
{
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
},
{
15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,
15, 2, 8, 2, 2, 8, 8,15,
2, 8, 2, 2, 8, 8, 2, 2,
15,15, 6, 8, 2, 8,15,15,
2, 8, 2, 2, 2,15,15, 6,
6, 2, 6, 8,15,15, 2, 2,
15,15,15,15,15, 2, 2,15
},
{
3, 3,15,15, 8, 3,15,15,
8, 8, 6, 6, 6, 5, 3, 3,
3, 3, 8,15, 3, 3, 6,10,
5, 8, 8, 6, 8, 5,15,15,
8,15, 3, 5, 6,10, 8,15,
15, 3,15, 5,15,15,15,15,
3,15, 5, 5, 5, 8, 5,10,
5,10, 8,13,15,12, 3, 3
},
{
15, 8, 8, 3,15,15, 3, 8,
15,15,15,15,15,15,15, 8,
15, 8,15, 3,15, 8,15, 8,
3,15, 6,10,15,15,10, 8,
15, 3,15,10,10, 8, 9,10,
6,15, 8,15, 3, 6, 6, 8,
15, 3,15,15,15,15,15,15,
15,15,15,15, 3,15,15, 8
}
};
gint bc7_decompress (guchar *src,
guint size,
guchar *block);
#endif /* __BC7_H__ */

View file

@ -48,6 +48,7 @@ typedef enum
DDS_COMPRESS_BC3N, /* DXT5n */
DDS_COMPRESS_BC4, /* ATI1 */
DDS_COMPRESS_BC5, /* ATI2 */
DDS_COMPRESS_BC7,
DDS_COMPRESS_RXGB, /* DXT5 */
DDS_COMPRESS_AEXP, /* DXT5 */
DDS_COMPRESS_YCOCG, /* DXT5 */

View file

@ -289,6 +289,13 @@ read_dds (GFile *file,
case DXGI_FORMAT_BC5_SNORM:
load_info.comp_format = DDS_COMPRESS_BC5;
break;
/* TODO: Implement BC6 format */
case DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT_BC7_UNORM:
case DXGI_FORMAT_BC7_UNORM_SRGB:
load_info.comp_format = DDS_COMPRESS_BC7;
break;
default:
load_info.comp_format = DDS_COMPRESS_MAX;
break;
@ -971,6 +978,11 @@ validate_dx10_header (dds_header_dx10_t *dx10hdr,
case DXGI_FORMAT_BC5_TYPELESS:
case DXGI_FORMAT_BC5_UNORM:
case DXGI_FORMAT_BC5_SNORM:
/* TODO: Implement BC6 format */
case DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT_BC7_UNORM:
case DXGI_FORMAT_BC7_UNORM_SRGB:
/* Return early for supported compressed formats */
load_info->dxgi_format = dx10hdr->dxgiFormat & 0xFF;
return TRUE;

View file

@ -36,6 +36,7 @@
#include <libgimp/gimp.h>
#include "bc7.h"
#include "dds.h"
#include "dxt.h"
#include "endian_rw.h"
@ -1348,6 +1349,11 @@ dxt_decompress (unsigned char *dst,
decode_alpha_block_BC3(block + 1, s + 8, width);
s += 16;
}
else if (format == DDS_COMPRESS_BC7)
{
bc7_decompress (s, size, block);
s += 16;
}
if (normals)
normalize_block(block, format);

View file

@ -1,6 +1,7 @@
plugin_name = 'file-dds'
plugin_sources = [
'bc7.c',
'dds.c',
'ddsread.c',
'ddswrite.c',