624 lines
23 KiB
C++
624 lines
23 KiB
C++
/*
|
|
|
|
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;
|
|
}
|
|
|