diff --git a/plug-ins/file-dds/bc7.c b/plug-ins/file-dds/bc7.c new file mode 100644 index 0000000000000000000000000000000000000000..94f3c99664c4a3402517e570619d59f97145b93b --- /dev/null +++ b/plug-ins/file-dds/bc7.c @@ -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 +#include +#include +#include + +#include + +#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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_bit, 1); + + for (gint i = 1; i < 16; i++) + alpha_indexes[i] = get_bits (s, ¤t_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, ¤t_bit, precision); + } + + if (mode == 5 || (mode == 4 && ! selector)) + { + alpha_indexes[0] = get_bits (s, ¤t_bit, no_sel_precision - 1); + + for (gint i = 1; i < 16; i++) + alpha_indexes[i] = get_bits (s, ¤t_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; +} diff --git a/plug-ins/file-dds/bc7.h b/plug-ins/file-dds/bc7.h new file mode 100644 index 0000000000000000000000000000000000000000..95419300f392418729ed6180809611e678ef6179 --- /dev/null +++ b/plug-ins/file-dds/bc7.h @@ -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 . + */ + +#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__ */ \ No newline at end of file diff --git a/plug-ins/file-dds/dds.h b/plug-ins/file-dds/dds.h index 19bc8b480586d07bf4fc96eed2ff2628a83beadc..6caa27859042357db20d71f3c1610e2c1dd4d376 100644 --- a/plug-ins/file-dds/dds.h +++ b/plug-ins/file-dds/dds.h @@ -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 */ diff --git a/plug-ins/file-dds/ddsread.c b/plug-ins/file-dds/ddsread.c index 7931a72f49a752156c11a2a95f37cefae8e69ce8..94320ae3730c60a1b5822d42aea136f5f2eab96c 100644 --- a/plug-ins/file-dds/ddsread.c +++ b/plug-ins/file-dds/ddsread.c @@ -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; diff --git a/plug-ins/file-dds/dxt.c b/plug-ins/file-dds/dxt.c index 14e203c99e37b9015b4a8db273e28cb03681cfa0..ee7abe58712007483bb1714d47d2df982e95457d 100644 --- a/plug-ins/file-dds/dxt.c +++ b/plug-ins/file-dds/dxt.c @@ -36,6 +36,7 @@ #include +#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); diff --git a/plug-ins/file-dds/meson.build b/plug-ins/file-dds/meson.build index 6e0eb12bfedb423c643c39286c4dedff72a7b6a9..4c06e077672454995dfa4b07aa04d7c471f5e3df 100644 --- a/plug-ins/file-dds/meson.build +++ b/plug-ins/file-dds/meson.build @@ -1,6 +1,7 @@ plugin_name = 'file-dds' plugin_sources = [ + 'bc7.c', 'dds.c', 'ddsread.c', 'ddswrite.c',