Add BC4, BC5 and BC7 formats decompression support on non-Windows platforms

This commit is contained in:
Wojtek Figat
2023-02-28 15:51:05 +01:00
parent 127c575752
commit b2f7ffa545
9 changed files with 1196 additions and 56 deletions

45
Source/ThirdParty/detex/bits.cpp vendored Normal file
View File

@@ -0,0 +1,45 @@
/*
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "detex.h"
#include "bits.h"
uint32_t detexBlock128ExtractBits(detexBlock128 *block, int nu_bits) {
uint32_t value = 0;
for (int i = 0; i < nu_bits; i++) {
if (block->index < 64) {
int shift = block->index - i;
if (shift < 0)
value |= (block->data0 & ((uint64_t)1 << block->index)) << (- shift);
else
value |= (block->data0 & ((uint64_t)1 << block->index)) >> shift;
}
else {
int shift = ((block->index - 64) - i);
if (shift < 0)
value |= (block->data1 & ((uint64_t)1 << (block->index - 64))) << (- shift);
else
value |= (block->data1 & ((uint64_t)1 << (block->index - 64))) >> shift;
}
block->index++;
}
// if (block->index > 128)
// printf("Block overflow (%d)\n", block->index);
return value;
}

62
Source/ThirdParty/detex/bits.h vendored Normal file
View File

@@ -0,0 +1,62 @@
/*
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Data structure used to extract bits from 128-bit bitstring. */
typedef struct {
uint64_t data0;
uint64_t data1;
int index;
} detexBlock128;
uint32_t detexBlock128ExtractBits(detexBlock128 *block, int nu_bits);
/* Return bitfield from bit0 to bit1 from 64-bit bitstring. */
static DETEX_INLINE_ONLY uint32_t detexGetBits64(uint64_t data, int bit0, int bit1) {
return (data & (((uint64_t)1 << (bit1 + 1)) - 1)) >> bit0;
}
/* Return reversed bitfield (bit1 to bit0) from 64-bit bitstring. */
static DETEX_INLINE_ONLY uint32_t detexGetBits64Reversed(uint64_t data, int bit0, int bit1) {
// Assumes bit0 > bit1.
// Reverse the bits.
uint32_t val = 0;
for (int i = 0; i <= bit0 - bit1; i++) {
int shift_right = bit0 - 2 * i;
if (shift_right >= 0)
val |= (data & ((uint64_t)1 << (bit0 - i))) >> shift_right;
else
val |= (data & ((uint64_t)1 << (bit0 - i))) << (- shift_right);
}
return val;
}
/* Clear bit0 to bit1 of 64-bit bitstring. */
static DETEX_INLINE_ONLY uint64_t detexClearBits64(uint64_t data, int bit0, int bit1) {
uint64_t mask = ~(((uint64_t)1 << (bit1 + 1)) - 1);
mask |= ((uint64_t)1 << bit0) - 1;
return data & mask;
}
/* Set bit0 to bit1 of 64-bit bitstring. */
static DETEX_INLINE_ONLY uint64_t detexSetBits64(uint64_t data, int bit0, int bit1, uint64_t val) {
uint64_t d = detexClearBits64(data, bit0, bit1);
d |= val << bit0;
return d;
}

203
Source/ThirdParty/detex/bptc-tables.cpp vendored Normal file
View File

@@ -0,0 +1,203 @@
/*
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "detex.h"
#include "bits.h"
#include "bptc-tables.h"
const uint8_t detex_bptc_table_P2[64 * 16] = {
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
};
const uint8_t detex_bptc_table_P3[64 * 16] = {
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,
};
const uint8_t detex_bptc_table_anchor_index_second_subset[64] = {
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
};
const uint8_t detex_bptc_table_anchor_index_second_subset_of_three[64] = {
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
};
const uint8_t detex_bptc_table_anchor_index_third_subset[64] = {
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
};
const uint16_t detex_bptc_table_aWeight2[4] = {
0, 21, 43, 64
};
const uint16_t detex_bptc_table_aWeight3[8] = {
0, 9, 18, 27, 37, 46, 55, 64
};
const uint16_t detex_bptc_table_aWeight4[16] = {
0, 4, 9, 13, 17, 21, 26, 30,
34, 38, 43, 47, 51, 55, 60, 64
};

29
Source/ThirdParty/detex/bptc-tables.h vendored Normal file
View File

@@ -0,0 +1,29 @@
/*
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
extern const uint8_t detex_bptc_table_P2[64 * 16];
extern const uint8_t detex_bptc_table_P3[64 * 16];
extern const uint8_t detex_bptc_table_anchor_index_second_subset[64];
extern const uint8_t detex_bptc_table_anchor_index_second_subset_of_three[64];
extern const uint8_t detex_bptc_table_anchor_index_third_subset[64];
extern const uint16_t detex_bptc_table_aWeight2[4];
extern const uint16_t detex_bptc_table_aWeight3[8];
extern const uint16_t detex_bptc_table_aWeight4[16];

View File

@@ -0,0 +1,623 @@
/*
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "detex.h"
#include "bits.h"
#include "bptc-tables.h"
// BPTC mode layout:
//
// Number of subsets = { 3, 2, 3, 2, 1, 1, 1, 2 };
// Partition bits = { 4, 6, 6, 6, 0, 0, 0, 6 };
// Rotation bits = { 0, 0, 0, 0, 2, 2, 0, 0 };
// Mode 4 has one index selection bit.
//
// #subsets color alpha before color index after color index after After Index
// alpha pbits bits (*)
// Mode 0 3 4 0 1 + 4 = 5 5 + 6 * 3 * 4 = 77 77 + 6 = 83 + 48 - 3 = 128
// Mode 1 2 6 0 2 + 6 = 8 8 + 4 * 3 * 6 = 80 80 + 2 = 82 + 48 - 2 = 128
// Mode 2 3 5 0 3 + 6 = 9 9 + 6 * 3 * 5 = 99 99 99 + 32 - 3 = 128
// Mode 3 2 7 0 4 + 6 = 10 10 + 4 * 3 * 7 = 94 94 + 4 = 98 + 32 - 2 = 128
// Mode 4 1 5 6 5 + 2 + 1 = 8 8 + 2 * 3 * 5 = 38 37 + 2 * 6 = 50 50 + 80 - 2 = 128
// Mode 5 1 7 8 6 + 2 = 8 8 + 2 * 3 * 7 = 50 50 + 2 * 8 = 66 66 + 64 - 2 = 128
// Mode 6 1 7 7 7 7 + 2 * 3 * 7 = 49 49 + 2 * 7 = 63 + 2 = 65 + 64 - 1 = 128
// Mode 7 2 5 5 8 + 6 = 14 14 + 4 * 3 * 5 = 74 74 + 4 * 5 = 94 + 4 = 98 + 32 - 2 = 128
//
// (*) For formats without alpha, the number of index bits is reduced by #subsets anchor bits.
// For formats with alpha, the number of index bits is reduced by 2 * #subsets by the anchor bits.
static const uint8_t color_precision_table[8] = { 4, 6, 5, 7, 5, 7, 7, 5 };
// Note: precision includes P-bits!
static const uint8_t color_precision_plus_pbit_table[8] = { 5, 7, 5, 8, 5, 7, 8, 6 };
static DETEX_INLINE_ONLY uint8_t GetColorComponentPrecision(int mode) {
return color_precision_table[mode];
}
static DETEX_INLINE_ONLY uint8_t GetColorComponentPrecisionPlusPbit(int mode) {
return color_precision_plus_pbit_table[mode];
}
static const int8_t alpha_precision_table[8] = { 0, 0, 0, 0, 6, 8, 7, 5 };
// Note: precision include P-bits!
static const uint8_t alpha_precision_plus_pbit_table[8] = { 0, 0, 0, 0, 6, 8, 8, 6 };
static DETEX_INLINE_ONLY uint8_t GetAlphaComponentPrecision(int mode) {
return alpha_precision_table[mode];
}
static DETEX_INLINE_ONLY uint8_t GetAlphaComponentPrecisionPlusPbit(int mode) {
return alpha_precision_plus_pbit_table[mode];
}
static const int8_t components_in_qword0_table[8] = { 2, -1, 1, 1, 3, 3, 3, 2 };
/* Extract endpoint colors. */
static void ExtractEndpoints(int mode, int nu_subsets, detexBlock128 * DETEX_RESTRICT block,
uint8_t * DETEX_RESTRICT endpoint_array) {
// Optimized version avoiding the use of block_extract_bits().
int components_in_qword0 = components_in_qword0_table[mode];
uint64_t data = block->data0 >> block->index;
uint8_t precision = GetColorComponentPrecision(mode);
uint8_t mask = (1 << precision) - 1;
int total_bits_per_component = nu_subsets * 2 * precision;
for (int i = 0; i < components_in_qword0; i++) // For each color component.
for (int j = 0; j < nu_subsets; j++) // For each subset.
for (int k = 0; k < 2; k++) { // For each endpoint.
endpoint_array[j * 8 + k * 4 + i] = data & mask;
data >>= precision;
}
block->index += components_in_qword0 * total_bits_per_component;
if (components_in_qword0 < 3) {
// Handle the color component that crosses the boundary between data0 and data1
data = block->data0 >> block->index;
data |= block->data1 << (64 - block->index);
int i = components_in_qword0;
for (int j = 0; j < nu_subsets; j++) // For each subset.
for (int k = 0; k < 2; k++) { // For each endpoint.
endpoint_array[j * 8 + k * 4 + i] = data & mask;
data >>= precision;
}
block->index += total_bits_per_component;
}
if (components_in_qword0 < 2) {
// Handle the color component that is wholly in data1.
data = block->data1 >> (block->index - 64);
int i = 2;
for (int j = 0; j < nu_subsets; j++) // For each subset.
for (int k = 0; k < 2; k++) { // For each endpoint.
endpoint_array[j * 8 + k * 4 + i] = data & mask;
data >>= precision;
}
block->index += total_bits_per_component;
}
// Alpha component.
if (GetAlphaComponentPrecision(mode) > 0) {
// For mode 7, the alpha data is wholly in data1.
// For modes 4 and 6, the alpha data is wholly in data0.
// For mode 5, the alpha data is in data0 and data1.
if (mode == 7)
data = block->data1 >> (block->index - 64);
else if (mode == 5)
data = (block->data0 >> block->index) | ((block->data1 & 0x3) << 14);
else
data = block->data0 >> block->index;
uint8_t alpha_precision = GetAlphaComponentPrecision(mode);
uint8_t mask = (1 << alpha_precision) - 1;
for (int j = 0; j < nu_subsets; j++)
for (int k = 0; k < 2; k++) { // For each endpoint.
endpoint_array[j * 8 + k * 4 + 3] = data & mask;
data >>= alpha_precision;
}
block->index += nu_subsets * 2 * alpha_precision;
}
}
static const uint8_t mode_has_p_bits[8] = { 1, 1, 0, 1, 0, 0, 1, 1 };
static void FullyDecodeEndpoints(uint8_t * DETEX_RESTRICT endpoint_array, int nu_subsets,
int mode, detexBlock128 * DETEX_RESTRICT block) {
if (mode_has_p_bits[mode]) {
// Mode 1 (shared P-bits) handled elsewhere.
// Extract end-point P-bits. Take advantage of the fact that they don't cross the
// 64-bit word boundary in any mode.
uint32_t bits;
if (block->index < 64)
bits = block->data0 >> block->index;
else
bits = block->data1 >> (block->index - 64);
for (int i = 0; i < nu_subsets * 2; i++) {
endpoint_array[i * 4 + 0] <<= 1;
endpoint_array[i * 4 + 1] <<= 1;
endpoint_array[i * 4 + 2] <<= 1;
endpoint_array[i * 4 + 3] <<= 1;
endpoint_array[i * 4 + 0] |= (bits & 1);
endpoint_array[i * 4 + 1] |= (bits & 1);
endpoint_array[i * 4 + 2] |= (bits & 1);
endpoint_array[i * 4 + 3] |= (bits & 1);
bits >>= 1;
}
block->index += nu_subsets * 2;
}
int color_prec = GetColorComponentPrecisionPlusPbit(mode);
int alpha_prec = GetAlphaComponentPrecisionPlusPbit(mode);
for (int i = 0; i < nu_subsets * 2; i++) {
// Color_component_precision & alpha_component_precision includes pbit
// left shift endpoint components so that their MSB lies in bit 7
endpoint_array[i * 4 + 0] <<= (8 - color_prec);
endpoint_array[i * 4 + 1] <<= (8 - color_prec);
endpoint_array[i * 4 + 2] <<= (8 - color_prec);
endpoint_array[i * 4 + 3] <<= (8 - alpha_prec);
// Replicate each component's MSB into the LSBs revealed by the left-shift operation above.
endpoint_array[i * 4 + 0] |= (endpoint_array[i * 4 + 0] >> color_prec);
endpoint_array[i * 4 + 1] |= (endpoint_array[i * 4 + 1] >> color_prec);
endpoint_array[i * 4 + 2] |= (endpoint_array[i * 4 + 2] >> color_prec);
endpoint_array[i * 4 + 3] |= (endpoint_array[i * 4 + 3] >> alpha_prec);
}
if (mode <= 3) {
for (int i = 0; i < nu_subsets * 2; i++)
endpoint_array[i * 4 + 3] = 0xFF;
}
}
static uint8_t Interpolate(uint8_t e0, uint8_t e1, uint8_t index, uint8_t indexprecision) {
if (indexprecision == 2)
return (uint8_t) (((64 - detex_bptc_table_aWeight2[index]) * (uint16_t)e0
+ detex_bptc_table_aWeight2[index] * (uint16_t)e1 + 32) >> 6);
else
if (indexprecision == 3)
return (uint8_t) (((64 - detex_bptc_table_aWeight3[index]) * (uint16_t)e0
+ detex_bptc_table_aWeight3[index] * (uint16_t)e1 + 32) >> 6);
else // indexprecision == 4
return (uint8_t) (((64 - detex_bptc_table_aWeight4[index]) * (uint16_t)e0
+ detex_bptc_table_aWeight4[index] * (uint16_t)e1 + 32) >> 6);
}
static const uint8_t bptc_color_index_bitcount[8] = { 3, 3, 2, 2, 2, 2, 4, 2 };
static DETEX_INLINE_ONLY int GetColorIndexBitcount(int mode, int index_selection_bit) {
// If the index selection bit is set for mode 4, return 3, otherwise 2.
return bptc_color_index_bitcount[mode] + index_selection_bit;
}
static uint8_t bptc_alpha_index_bitcount[8] = { 3, 3, 2, 2, 3, 2, 4, 2};
static DETEX_INLINE_ONLY int GetAlphaIndexBitcount(int mode, int index_selection_bit) {
// If the index selection bit is set for mode 4, return 2, otherwise 3.
return bptc_alpha_index_bitcount[mode] - index_selection_bit;
}
static const uint8_t bptc_NS[8] = { 3, 2, 3, 2, 1, 1, 1, 2 };
static DETEX_INLINE_ONLY int GetNumberOfSubsets(int mode) {
return bptc_NS[mode];
}
static const uint8_t PB[8] = { 4, 6, 6, 6, 0, 0, 0, 6 };
static DETEX_INLINE_ONLY int GetNumberOfPartitionBits(int mode) {
return PB[mode];
}
static const uint8_t RB[8] = { 0, 0, 0, 0, 2, 2, 0, 0 };
static DETEX_INLINE_ONLY int GetNumberOfRotationBits(int mode) {
return RB[mode];
}
// Functions to extract parameters. */
static int ExtractMode(detexBlock128 *block) {
for (int i = 0; i < 8; i++)
if (block->data0 & ((uint64_t)1 << i)) {
block->index = i + 1;
return i;
}
// Illegal.
return - 1;
}
static DETEX_INLINE_ONLY int ExtractPartitionSetID(detexBlock128 *block, int mode) {
return detexBlock128ExtractBits(block, GetNumberOfPartitionBits(mode));
}
static DETEX_INLINE_ONLY int GetPartitionIndex(int nu_subsets, int partition_set_id, int i) {
if (nu_subsets == 1)
return 0;
if (nu_subsets == 2)
return detex_bptc_table_P2[partition_set_id * 16 + i];
return detex_bptc_table_P3[partition_set_id * 16 + i];
}
static DETEX_INLINE_ONLY int ExtractRotationBits(detexBlock128 *block, int mode) {
return detexBlock128ExtractBits(block, GetNumberOfRotationBits(mode));
}
static DETEX_INLINE_ONLY int GetAnchorIndex(int partition_set_id, int partition, int nu_subsets) {
if (partition == 0)
return 0;
if (nu_subsets == 2)
return detex_bptc_table_anchor_index_second_subset[partition_set_id];
if (partition == 1)
return detex_bptc_table_anchor_index_second_subset_of_three[partition_set_id];
return detex_bptc_table_anchor_index_third_subset[partition_set_id];
}
static const uint8_t IB[8] = { 3, 3, 2, 2, 2, 2, 4, 2 };
static const uint8_t IB2[8] = { 0, 0, 0, 0, 3, 2, 0, 0 };
static const uint8_t mode_has_partition_bits[8] = { 1, 1, 1, 1, 0, 0, 0, 1 };
/* Decompress a 128-bit 4x4 pixel texture block compressed using BPTC mode 1. */
static bool DecompressBlockBPTCMode1(detexBlock128 * DETEX_RESTRICT block,
uint8_t * DETEX_RESTRICT pixel_buffer) {
uint64_t data0 = block->data0;
uint64_t data1 = block->data1;
int partition_set_id = detexGetBits64(data0, 2, 7);
uint8_t endpoint[2 * 2 * 3]; // 2 subsets.
endpoint[0] = detexGetBits64(data0, 8, 13); // red, subset 0, endpoint 0
endpoint[3] = detexGetBits64(data0, 14, 19); // red, subset 0, endpoint 1
endpoint[6] = detexGetBits64(data0, 20, 25); // red, subset 1, endpoint 0
endpoint[9] = detexGetBits64(data0, 26, 31); // red, subset 1, endpoint 1
endpoint[1] = detexGetBits64(data0, 32, 37); // green, subset 0, endpoint 0
endpoint[4] = detexGetBits64(data0, 38, 43); // green, subset 0, endpoint 1
endpoint[7] = detexGetBits64(data0, 44, 49); // green, subset 1, endpoint 0
endpoint[10] = detexGetBits64(data0, 50, 55); // green, subset 1, endpoint 1
endpoint[2] = detexGetBits64(data0, 56, 61); // blue, subset 0, endpoint 0
endpoint[5] = detexGetBits64(data0, 62, 63) // blue, subset 0, endpoint 1
| (detexGetBits64(data1, 0, 3) << 2);
endpoint[8] = detexGetBits64(data1, 4, 9); // blue, subset 1, endpoint 0
endpoint[11] = detexGetBits64(data1, 10, 15); // blue, subset 1, endpoint 1
// Decode endpoints.
for (int i = 0; i < 2 * 2; i++) {
//component-wise left-shift
endpoint[i * 3 + 0] <<= 2;
endpoint[i * 3 + 1] <<= 2;
endpoint[i * 3 + 2] <<= 2;
}
// P-bit is shared.
uint8_t pbit_zero = detexGetBits64(data1, 16, 16) << 1;
uint8_t pbit_one = detexGetBits64(data1, 17, 17) << 1;
// RGB only pbits for mode 1, one for each subset.
for (int j = 0; j < 3; j++) {
endpoint[0 * 3 + j] |= pbit_zero;
endpoint[1 * 3 + j] |= pbit_zero;
endpoint[2 * 3 + j] |= pbit_one;
endpoint[3 * 3 + j] |= pbit_one;
}
for (int i = 0; i < 2 * 2; i++) {
// Replicate each component's MSB into the LSB.
endpoint[i * 3 + 0] |= endpoint[i * 3 + 0] >> 7;
endpoint[i * 3 + 1] |= endpoint[i * 3 + 1] >> 7;
endpoint[i * 3 + 2] |= endpoint[i * 3 + 2] >> 7;
}
uint8_t subset_index[16];
for (int i = 0; i < 16; i++)
// subset_index[i] is a number from 0 to 1.
subset_index[i] = detex_bptc_table_P2[partition_set_id * 16 + i];
uint8_t anchor_index[2];
anchor_index[0] = 0;
anchor_index[1] = detex_bptc_table_anchor_index_second_subset[partition_set_id];
uint8_t color_index[16];
// Extract primary index bits.
data1 >>= 18;
for (int i = 0; i < 16; i++)
if (i == anchor_index[subset_index[i]]) {
// Highest bit is zero.
color_index[i] = data1 & 3; // Get two bits.
data1 >>= 2;
}
else {
color_index[i] = data1 & 7; // Get three bits.
data1 >>= 3;
}
uint32_t *pixel32_buffer = (uint32_t *)pixel_buffer;
for (int i = 0; i < 16; i++) {
uint8_t endpoint_start[3];
uint8_t endpoint_end[3];
for (int j = 0; j < 3; j++) {
endpoint_start[j] = endpoint[2 * subset_index[i] * 3 + j];
endpoint_end[j] = endpoint[(2 * subset_index[i] + 1) * 3 + j];
}
uint32_t output;
output = detexPack32R8(Interpolate(endpoint_start[0], endpoint_end[0], color_index[i], 3));
output |= detexPack32G8(Interpolate(endpoint_start[1], endpoint_end[1], color_index[i], 3));
output |= detexPack32B8(Interpolate(endpoint_start[2], endpoint_end[2], color_index[i], 3));
output |= detexPack32A8(0xFF);
pixel32_buffer[i] = output;
}
return true;
}
/* Decompress a 128-bit 4x4 pixel texture block compressed using the BPTC */
/* (BC7) format. */
bool detexDecompressBlockBPTC(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask,
uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) {
detexBlock128 block;
block.data0 = *(uint64_t *)&bitstring[0];
block.data1 = *(uint64_t *)&bitstring[8];
block.index = 0;
int mode = ExtractMode(&block);
if (mode == - 1)
return 0;
// Allow compression tied to specific modes (according to mode_mask).
if (!(mode_mask & ((int)1 << mode)))
return 0;
if (mode >= 4 && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY))
return 0;
if (mode < 4 && (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY))
return 0;
if (mode == 1)
return DecompressBlockBPTCMode1(&block, pixel_buffer);
int nu_subsets = 1;
int partition_set_id = 0;
if (mode_has_partition_bits[mode]) {
nu_subsets = GetNumberOfSubsets(mode);
partition_set_id = ExtractPartitionSetID(&block, mode);
}
int rotation = ExtractRotationBits(&block, mode);
int index_selection_bit = 0;
if (mode == 4)
index_selection_bit = detexBlock128ExtractBits(&block, 1);
int alpha_index_bitcount = GetAlphaIndexBitcount(mode, index_selection_bit);
int color_index_bitcount = GetColorIndexBitcount(mode, index_selection_bit);
uint8_t endpoint_array[3 * 2 * 4]; // Max. 3 subsets.
ExtractEndpoints(mode, nu_subsets, &block, endpoint_array);
FullyDecodeEndpoints(endpoint_array, nu_subsets, mode, &block);
uint8_t subset_index[16];
for (int i = 0; i < 16; i++)
// subset_index[i] is a number from 0 to 2, or 0 to 1, or 0 depending on the number of subsets.
subset_index[i] = GetPartitionIndex(nu_subsets, partition_set_id, i);
uint8_t anchor_index[4]; // Only need max. 3 elements.
for (int i = 0; i < nu_subsets; i++)
anchor_index[i] = GetAnchorIndex(partition_set_id, i, nu_subsets);
uint8_t color_index[16];
uint8_t alpha_index[16];
// Extract primary index bits.
uint64_t data1;
if (block.index >= 64) {
// Because the index bits are all in the second 64-bit word, there is no need to use
// block_extract_bits().
// This implies the mode is not 4.
data1 = block.data1 >> (block.index - 64);
uint8_t mask1 = (1 << IB[mode]) - 1;
uint8_t mask2 = (1 << (IB[mode] - 1)) - 1;
for (int i = 0; i < 16; i++)
if (i == anchor_index[subset_index[i]]) {
// Highest bit is zero.
color_index[i] = data1 & mask2;
data1 >>= IB[mode] - 1;
alpha_index[i] = color_index[i];
}
else {
color_index[i] = data1 & mask1;
data1 >>= IB[mode];
alpha_index[i] = color_index[i];
}
}
else { // Implies mode 4.
// Because the bits cross the 64-bit word boundary, we have to be careful.
// Block index is 50 at this point.
uint64_t data = block.data0 >> 50;
data |= block.data1 << 14;
for (int i = 0; i < 16; i++)
if (i == anchor_index[subset_index[i]]) {
// Highest bit is zero.
if (index_selection_bit) { // Implies mode == 4.
alpha_index[i] = data & 0x1;
data >>= 1;
}
else {
color_index[i] = data & 0x1;
data >>= 1;
}
}
else {
if (index_selection_bit) { // Implies mode == 4.
alpha_index[i] = data & 0x3;
data >>= 2;
}
else {
color_index[i] = data & 0x3;
data >>= 2;
}
}
// Block index is 81 at this point.
data1 = block.data1 >> (81 - 64);
}
// Extract secondary index bits.
if (IB2[mode] > 0) {
uint8_t mask1 = (1 << IB2[mode]) - 1;
uint8_t mask2 = (1 << (IB2[mode] - 1)) - 1;
for (int i = 0; i < 16; i++)
if (i == anchor_index[subset_index[i]]) {
// Highest bit is zero.
if (index_selection_bit) {
color_index[i] = data1 & 0x3;
data1 >>= 2;
}
else {
// alpha_index[i] = block_extract_bits(&block, IB2[mode] - 1);
alpha_index[i] = data1 & mask2;
data1 >>= IB2[mode] - 1;
}
}
else {
if (index_selection_bit) {
color_index[i] = data1 & 0x7;
data1 >>= 3;
}
else {
// alpha_index[i] = block_extract_bits(&block, IB2[mode]);
alpha_index[i] = data1 & mask1;
data1 >>= IB2[mode];
}
}
}
uint32_t *pixel32_buffer = (uint32_t *)pixel_buffer;
for (int i = 0; i < 16; i++) {
uint8_t endpoint_start[4];
uint8_t endpoint_end[4];
for (int j = 0; j < 4; j++) {
endpoint_start[j] = endpoint_array[2 * subset_index[i] * 4 + j];
endpoint_end[j] = endpoint_array[(2 * subset_index[i] + 1) * 4 + j];
}
uint32_t output = 0;
output = detexPack32R8(Interpolate(endpoint_start[0], endpoint_end[0], color_index[i], color_index_bitcount));
output |= detexPack32G8(Interpolate(endpoint_start[1], endpoint_end[1], color_index[i], color_index_bitcount));
output |= detexPack32B8(Interpolate(endpoint_start[2], endpoint_end[2], color_index[i], color_index_bitcount));
output |= detexPack32A8(Interpolate(endpoint_start[3], endpoint_end[3], alpha_index[i], alpha_index_bitcount));
if (rotation > 0) {
if (rotation == 1)
output = detexPack32RGBA8(detexPixel32GetA8(output), detexPixel32GetG8(output),
detexPixel32GetB8(output), detexPixel32GetR8(output));
else
if (rotation == 2)
output = detexPack32RGBA8(detexPixel32GetR8(output), detexPixel32GetA8(output),
detexPixel32GetB8(output), detexPixel32GetG8(output));
else // rotation == 3
output = detexPack32RGBA8(detexPixel32GetR8(output), detexPixel32GetG8(output),
detexPixel32GetA8(output), detexPixel32GetB8(output));
}
pixel32_buffer[i] = output;
}
return true;
}
#if 0
/* Modify compressed block to use specific colors. For later use. */
static void SetBlockColors(uint8_t * DETEX_RESTRICT bitstring, uint32_t flags,
uint32_t * DETEX_RESTRICT colors) {
if ((flags & TWO_COLORS) == 0)
return;
uint64_t data0 = *(uint64_t *)&bitstring[0];
uint64_t data1 = *(uint64_t *)&bitstring[8];
if ((flags & BPTC_MODE_ALLOWED_ALL) == (1 << 3)) {
// Mode 3, 7 color bits.
// Color bits at index: 10
// Color bits end before index: 10 + 4 * 3 * 7 = 94
uint32_t r0 = detexPixel32GetR8(colors[0]);
uint32_t g0 = detexPixel32GetG8(colors[0]);
uint32_t b0 = detexPixel32GetB8(colors[0]);
uint32_t r1 = detexPixel32GetR8(colors[1]);
uint32_t g1 = detexPixel32GetG8(colors[1]);
uint32_t b1 = detexPixel32GetB8(colors[1]);
data0 = detexSetBits64(data0, 10, 16, r0 >> 1);
data0 = detexSetBits64(data0, 17, 23, r0 >> 1);
data0 = detexSetBits64(data0, 24, 30, r1 >> 1);
data0 = detexSetBits64(data0, 31, 37, r1 >> 1);
data0 = detexSetBits64(data0, 38, 44, g0 >> 1);
data0 = detexSetBits64(data0, 45, 51, g0 >> 1);
data0 = detexSetBits64(data0, 52, 58, g1 >> 1);
data0 = detexSetBits64(data0, 59, 63, (g1 >> 1) & 0x1F);
data1 = detexSetBits64(data1, 0, 1, ((g1 >> 1) & 0x60) >> 5);
data1 = detexSetBits64(data1, 2, 8, b0 >> 1);
data1 = detexSetBits64(data1, 9, 15, b0 >> 1);
data1 = detexSetBits64(data1, 16, 22, b1 >> 1);
data1 = detexSetBits64(data1, 23, 29, b1 >> 1);
*(uint64_t *)&bitstring[0] = data0;
*(uint64_t *)&bitstring[8] = data1;
// printf("bptc_set_block_colors: Colors set for mode 3.\n");
}
else if ((flags & BPTC_MODE_ALLOWED_ALL) == (1 << 5)) {
// Mode 5, 7 color bits, 8 alpha bits.
// Color bits at index: 6 + 2 = 8
// Alpha bits at index: 8 + 2 * 3 * 7 = 50
// Alpha bits end before index: 50 + 2 * 8 = 66
uint32_t r0 = detexPixel32GetR8(colors[0]);
uint32_t g0 = detexPixel32GetG8(colors[0]);
uint32_t b0 = detexPixel32GetB8(colors[0]);
uint32_t r1 = detexPixel32GetR8(colors[1]);
uint32_t g1 = detexPixel32GetG8(colors[1]);
uint32_t b1 = detexPixel32GetB8(colors[1]);
data0 = detexSetBits64(data0, 8, 14, r0 >> 1);
data0 = detexSetBits64(data0, 15, 21, r1 >> 1);
data0 = detexSetBits64(data0, 22, 28, g0 >> 1);
data0 = detexSetBits64(data0, 29, 35, g0 >> 1);
data0 = detexSetBits64(data0, 36, 42, b0 >> 1);
data0 = detexSetBits64(data0, 43, 49, b1 >> 1);
if (flags & (MODES_ALLOWED_PUNCHTHROUGH_ONLY)) {
data0 = detexSetBits64(data0, 50, 57, 0x00);
data0 = detexSetBits64(data0, 58, 63, 0x3F);
data1 = detexSetBits64(data1, 0, 1, 0x3);
}
*(uint64_t *)&bitstring[0] = data0;
*(uint64_t *)&bitstring[8] = data1;
// printf("bptc_set_block_colors: Colors set for mode 5.\n");
}
else if ((flags & BPTC_MODE_ALLOWED_ALL) == (1 << 6)) {
// Mode 5, 7 color bits, 7 alpha bits.
// Color bits at index 7.
// Alpha bits at index: 7 + 2 * 3 * 7 = 49
// Alpha bits end before index: 49 + 2 * 7 = 63
uint32_t r0 = detexPixel32GetR8(colors[0]);
uint32_t g0 = detexPixel32GetG8(colors[0]);
uint32_t b0 = detexPixel32GetB8(colors[0]);
uint32_t r1 = detexPixel32GetR8(colors[1]);
uint32_t g1 = detexPixel32GetG8(colors[1]);
uint32_t b1 = detexPixel32GetB8(colors[1]);
data0 = detexSetBits64(data0, 7, 13, r0 >> 1);
data0 = detexSetBits64(data0, 14, 20, r1 >> 1);
data0 = detexSetBits64(data0, 21, 27, g0 >> 1);
data0 = detexSetBits64(data0, 28, 34, g1 >> 1);
data0 = detexSetBits64(data0, 35, 41, b0 >> 1);
data0 = detexSetBits64(data0, 42, 48, b1 >> 1);
if (flags & (MODES_ALLOWED_PUNCHTHROUGH_ONLY)) {
data0 = detexSetBits64(data0, 49, 55, 0x00);
data0 = detexSetBits64(data0, 56, 62, 0x7F);
}
*(uint64_t *)&bitstring[0] = data0;
// printf("bptc_set_block_colors: Colors set for mode 6.\n");
}
}
#endif
/* Return the internal mode of the BPTC block. */
uint32_t detexGetModeBPTC(const uint8_t *bitstring) {
detexBlock128 block;
block.data0 = *(uint64_t *)&bitstring[0];
block.data1 = *(uint64_t *)&bitstring[8];
block.index = 0;
int mode = ExtractMode(&block);
return mode;
}
void detexSetModeBPTC(uint8_t *bitstring, uint32_t mode, uint32_t flags,
uint32_t *colors) {
// Mode 0 starts with 1
// Mode 1 starts with 01
// ...
// Mode 7 starts with 00000001
int bit = 0x1 << mode;
bitstring[0] &= ~(bit - 1);
bitstring[0] |= bit;
return;
}

View File

@@ -0,0 +1,148 @@
/*
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "detex.h"
// For each pixel, decode an 8-bit integer and store as follows:
// If shift and offset are zero, store each value in consecutive 8 bit values in pixel_buffer.
// If shift is one, store each value in consecutive 16-bit words in pixel_buffer; if offset
// is zero, store it in the first 8 bits, if offset is one store it in the last 8 bits of each
// 16-bit word.
static DETEX_INLINE_ONLY void DecodeBlockRGTC(const uint8_t * DETEX_RESTRICT bitstring, int shift,
int offset, uint8_t * DETEX_RESTRICT pixel_buffer) {
// LSBFirst byte order only.
uint64_t bits = (*(uint64_t *)&bitstring[0]) >> 16;
int lum0 = bitstring[0];
int lum1 = bitstring[1];
for (int i = 0; i < 16; i++) {
int control_code = bits & 0x7;
uint8_t output;
if (lum0 > lum1)
switch (control_code) {
case 0 : output = lum0; break;
case 1 : output = lum1; break;
case 2 : output = detexDivide0To1791By7(6 * lum0 + lum1); break;
case 3 : output = detexDivide0To1791By7(5 * lum0 + 2 * lum1); break;
case 4 : output = detexDivide0To1791By7(4 * lum0 + 3 * lum1); break;
case 5 : output = detexDivide0To1791By7(3 * lum0 + 4 * lum1); break;
case 6 : output = detexDivide0To1791By7(2 * lum0 + 5 * lum1); break;
case 7 : output = detexDivide0To1791By7(lum0 + 6 * lum1); break;
}
else
switch (control_code) {
case 0 : output = lum0; break;
case 1 : output = lum1; break;
case 2 : output = detexDivide0To1279By5(4 * lum0 + lum1); break;
case 3 : output = detexDivide0To1279By5(3 * lum0 + 2 * lum1); break;
case 4 : output = detexDivide0To1279By5(2 * lum0 + 3 * lum1); break;
case 5 : output = detexDivide0To1279By5(lum0 + 4 * lum1); break;
case 6 : output = 0; break;
case 7 : output = 0xFF; break;
}
pixel_buffer[(i << shift) + offset] = output;
bits >>= 3;
}
}
/* Decompress a 64-bit 4x4 pixel texture block compressed using the */
/* unsigned RGTC1 (BC4) format. */
bool detexDecompressBlockRGTC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask,
uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) {
DecodeBlockRGTC(bitstring, 0, 0, pixel_buffer);
return true;
}
/* Decompress a 128-bit 4x4 pixel texture block compressed using the */
/* unsigned RGTC2 (BC5) format. */
bool detexDecompressBlockRGTC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask,
uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) {
DecodeBlockRGTC(bitstring, 1, 0, pixel_buffer);
DecodeBlockRGTC(&bitstring[8], 1, 1, pixel_buffer);
return true;
}
// For each pixel, decode an 16-bit integer and store as follows:
// If shift and offset are zero, store each value in consecutive 16 bit values in pixel_buffer.
// If shift is one, store each value in consecutive 32-bit words in pixel_buffer; if offset
// is zero, store it in the first 16 bits, if offset is one store it in the last 16 bits of each
// 32-bit word. Returns true if the compressed block is valid.
static DETEX_INLINE_ONLY bool DecodeBlockSignedRGTC(const uint8_t * DETEX_RESTRICT bitstring, int shift,
int offset, uint8_t * DETEX_RESTRICT pixel_buffer) {
// LSBFirst byte order only.
uint64_t bits = (*(uint64_t *)&bitstring[0]) >> 16;
int lum0 = (int8_t)bitstring[0];
int lum1 = (int8_t)bitstring[1];
if (lum0 == - 127 && lum1 == - 128)
// Not allowed.
return false;
if (lum0 == - 128)
lum0 = - 127;
if (lum1 == - 128)
lum1 = - 127;
// Note: values are mapped to a red value of -127 to 127.
uint16_t *pixel16_buffer = (uint16_t *)pixel_buffer;
for (int i = 0; i < 16; i++) {
int control_code = bits & 0x7;
int32_t result;
if (lum0 > lum1)
switch (control_code) {
case 0 : result = lum0; break;
case 1 : result = lum1; break;
case 2 : result = detexDivideMinus895To895By7(6 * lum0 + lum1); break;
case 3 : result = detexDivideMinus895To895By7(5 * lum0 + 2 * lum1); break;
case 4 : result = detexDivideMinus895To895By7(4 * lum0 + 3 * lum1); break;
case 5 : result = detexDivideMinus895To895By7(3 * lum0 + 4 * lum1); break;
case 6 : result = detexDivideMinus895To895By7(2 * lum0 + 5 * lum1); break;
case 7 : result = detexDivideMinus895To895By7(lum0 + 6 * lum1); break;
}
else
switch (control_code) {
case 0 : result = lum0; break;
case 1 : result = lum1; break;
case 2 : result = detexDivideMinus639To639By5(4 * lum0 + lum1); break;
case 3 : result = detexDivideMinus639To639By5(3 * lum0 + 2 * lum1); break;
case 4 : result = detexDivideMinus639To639By5(2 * lum0 + 3 * lum1); break;
case 5 : result = detexDivideMinus639To639By5(lum0 + 4 * lum1); break;
case 6 : result = - 127; break;
case 7 : result = 127; break;
}
// Map from [-127, 127] to [-32768, 32767].
pixel16_buffer[(i << shift) + offset] = (uint16_t)(int16_t)
((result + 127) * 65535 / 254 - 32768);
bits >>= 3;
}
return true;
}
/* Decompress a 64-bit 4x4 pixel texture block compressed using the */
/* signed RGTC1 (signed BC4) format. */
bool detexDecompressBlockSIGNED_RGTC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask,
uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) {
return DecodeBlockSignedRGTC(bitstring, 0, 0, pixel_buffer);
}
/* Decompress a 128-bit 4x4 pixel texture block compressed using the */
/* signed RGTC2 (signed BC5) format. */
bool detexDecompressBlockSIGNED_RGTC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask,
uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) {
bool r = DecodeBlockSignedRGTC(bitstring, 1, 0, pixel_buffer);
if (!r)
return false;
return DecodeBlockSignedRGTC(&bitstring[8], 1, 1, pixel_buffer);
}

View File

@@ -34,7 +34,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define DETEX_HELPER_SHARED_IMPORT __declspec(dllimport)
#define DETEX_HELPER_SHARED_EXPORT __declspec(dllexport)
#define DETEX_HELPER_SHARED_LOCAL
#define DETEX_INLINE_ONLY __forceinline
#else
#if __GNUC__ >= 4
#define DETEX_HELPER_SHARED_IMPORT __attribute__ ((visibility ("default")))
@@ -45,7 +44,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define DETEX_HELPER_SHARED_EXPORT
#define DETEX_HELPER_SHARED_LOCAL
#endif
#define DETEX_INLINE_ONLY __attribute__((always_inline)) inline
#endif
/* Now we use the generic helper definitions above to define DETEX_API and DETEX_LOCAL. */
@@ -74,6 +72,7 @@ __BEGIN_DECLS
#include <stdint.h>
#include <stdbool.h>
#define DETEX_INLINE_ONLY __attribute__((always_inline)) inline
#define DETEX_RESTRICT __restrict
/* Maximum uncompressed block size in bytes. */