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:
parent
994aa79724
commit
73f30b0dc6
6 changed files with 628 additions and 0 deletions
361
plug-ins/file-dds/bc7.c
Normal file
361
plug-ins/file-dds/bc7.c
Normal 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, ¤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;
|
||||
}
|
||||
247
plug-ins/file-dds/bc7.h
Normal file
247
plug-ins/file-dds/bc7.h
Normal 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__ */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
plugin_name = 'file-dds'
|
||||
|
||||
plugin_sources = [
|
||||
'bc7.c',
|
||||
'dds.c',
|
||||
'ddsread.c',
|
||||
'ddswrite.c',
|
||||
|
|
|
|||
Loading…
Reference in a new issue