Files
UnrealEngine/Engine/Source/ThirdParty/Android/detex/AndroidETC.cpp
2025-05-18 13:04:45 +08:00

3537 lines
138 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 "AndroidETC.h"
#include "CoreMinimal.h"
#include "GenericPlatform/GenericPlatformMath.h"
#include "AndroidETC.h"
#include "AndroidETCInternal.h"
#include "RHI.h"
IMPLEMENT_MODULE( Fdetex, detex );
Fdetex::Fdetex()
{
}
Fdetex::~Fdetex()
{
}
void Fdetex::StartupModule()
{
}
void Fdetex::ShutdownModule()
{
}
/* Maximum uncompressed block size in bytes. */
#define DETEX_MAX_BLOCK_SIZE 256
/* Compressed texture format definitions for general texture decompression */
/* functions. */
#define DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(n) ((uint32_t)n << 24)
/* Mode mask flags. */
enum
{
DETEX_MODE_MASK_ETC_INDIVIDUAL = 0x1,
DETEX_MODE_MASK_ETC_DIFFERENTIAL = 0x2,
DETEX_MODE_MASK_ETC_T = 0x4,
DETEX_MODE_MASK_ETC_H = 0x8,
DETEX_MODE_MASK_ETC_PLANAR = 0x10,
DETEX_MODE_MASK_ALL_MODES_ETC1 = 0x3,
DETEX_MODE_MASK_ALL_MODES_ETC2 = 0x1F,
DETEX_MODE_MASK_ALL_MODES_ETC2_PUNCHTHROUGH = 0X1E,
DETEX_MODE_MASK_ALL_MODES_BPTC = 0xFF,
DETEX_MODE_MASK_ALL_MODES_BPTC_FLOAT = 0x3FFF,
DETEX_MODE_MASK_ALL = 0XFFFFFFFF,
};
/* Decompression function flags. */
enum
{
/* Function returns false (invalid block) when the compressed block */
/* is in a format not allowed to be generated by an encoder. */
DETEX_DECOMPRESS_FLAG_ENCODE = 0x1,
/* For compression formats that have opaque and non-opaque modes, */
/* return false (invalid block) when the compressed block is encoded */
/* using a non-opaque mode. */
DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY = 0x2,
/* For compression formats that have opaque and non-opaque modes, */
/* return false (invalid block) when the compressed block is encoded */
/* using an opaque mode. */
DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY = 0x4,
};
enum
{
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_UNCOMPRESSED = 0,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1 = 1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT1 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_S3TC = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1A,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT1A = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1A,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT3 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC3,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT5 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC3,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC4_UNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC4_SNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC5_UNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC5_SNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_FLOAT,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC6H_UF16 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_FLOAT,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_SIGNED_FLOAT,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC6H_SF16 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_SIGNED_FLOAT,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC7 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_PUNCHTHROUGH,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_EAC,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_R11,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_R11,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_RG11,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_RG11,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ASTC_4X4,
};
typedef struct
{
uint32_t texture_format;
int ktx_support;
int dds_support;
const char *text1;
const char *text2;
int block_width; // The block width (1 for uncompressed textures).
int block_height; // The block height (1 for uncompressed textures).
int gl_internal_format;
uint32_t gl_format;
uint32_t gl_type;
const char *dx_four_cc;
int dx10_format;
} detexTextureFileInfo;
enum
{
DETEX_TEXTURE_FORMAT_PIXEL_FORMAT_MASK = 0x0000FFFF,
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT = 0x00800000,
DETEX_TEXTURE_FORMAT_BC1 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1) |
DETEX_PIXEL_FORMAT_RGBX8
),
DETEX_TEXTURE_FORMAT_BC1A = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1A) |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_BC2 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC2) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_BC3 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC3) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_RGTC1 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC1) |
DETEX_PIXEL_FORMAT_R8
),
DETEX_TEXTURE_FORMAT_SIGNED_RGTC1 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC1) |
DETEX_PIXEL_FORMAT_SIGNED_R16
),
DETEX_TEXTURE_FORMAT_RGTC2 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC2) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RG8
),
DETEX_TEXTURE_FORMAT_SIGNED_RGTC2 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC2) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_SIGNED_RG16
),
DETEX_TEXTURE_FORMAT_BPTC_FLOAT = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_FLOAT) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_FLOAT_RGBX16
),
DETEX_TEXTURE_FORMAT_BPTC_SIGNED_FLOAT = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_SIGNED_FLOAT) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_SIGNED_FLOAT_RGBX16
),
DETEX_TEXTURE_FORMAT_BPTC = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_ETC1 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC1) |
DETEX_PIXEL_FORMAT_RGBX8
),
DETEX_TEXTURE_FORMAT_ETC2 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2) |
DETEX_PIXEL_FORMAT_RGBX8
),
DETEX_TEXTURE_FORMAT_ETC2_PUNCHTHROUGH = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_PUNCHTHROUGH) |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_ETC2_EAC = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_EAC) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_EAC_R11 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_R11) |
DETEX_PIXEL_FORMAT_R16
),
DETEX_TEXTURE_FORMAT_EAC_SIGNED_R11 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_R11) |
DETEX_PIXEL_FORMAT_SIGNED_R16
),
DETEX_TEXTURE_FORMAT_EAC_RG11 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_RG11) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RG16
),
DETEX_TEXTURE_FORMAT_EAC_SIGNED_RG11 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_RG11) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_SIGNED_RG16
),
DETEX_TEXTURE_FORMAT_ASTC_4X4 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ASTC_4X4) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
};
static const detexTextureFileInfo texture_info[] =
{
// Texture format KTX/DDS Textual representations Block
// support size OpenGL ID in KTX files DDS file IDs
// internalFormat, format, type FourCC, DX10 format
// Compressed formats.
{ DETEX_TEXTURE_FORMAT_BC1, 1, 1, "BC1", "DXT1", 4, 4, 0x83F0, 0, 0, "DXT1", 0 },
{ DETEX_TEXTURE_FORMAT_BC1A, 1, 1, "BC1A", "DXT1A", 4, 4, 0x83F1, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_BC2, 1, 1, "BC2", "DXT3", 4, 4, 0x83F2, 0, 0, "DXT3", 0 },
{ DETEX_TEXTURE_FORMAT_BC3, 1, 1, "BC3", "DXT5", 4, 4, 0x83F3, 0, 0, "DXT5", 0 },
{ DETEX_TEXTURE_FORMAT_RGTC1, 1, 1, "RGTC1", "BC4_UNORM", 4, 4, 0x8DBB, 0, 0, "DX10", 80 },
{ DETEX_TEXTURE_FORMAT_SIGNED_RGTC1, 1, 1, "SIGNED_RGTC1", "BC4_SNORM", 4, 4, 0x8DBC, 0, 0, "DX10", 81 },
{ DETEX_TEXTURE_FORMAT_RGTC2, 1, 1, "RGTC2", "BC5_UNORM", 4, 4, 0x8DBD, 0, 0, "DX10", 83 },
{ DETEX_TEXTURE_FORMAT_SIGNED_RGTC2, 1, 1, "SIGNED_RGTC2", "BC5_SNORM", 4, 4, 0x8DBE, 0, 0, "DX10", 84 },
{ DETEX_TEXTURE_FORMAT_BPTC_FLOAT, 1, 1, "BPTC_FLOAT", "BC6H_UF16", 4, 4, 0x8E8F, 0, 0, "DX10", 95 },
{ DETEX_TEXTURE_FORMAT_BPTC_SIGNED_FLOAT, 1, 1, "BPTC_SIGNED_FLOAT", "BC6H_SF16", 4, 4, 0x8E8E, 0, 0, "DX10", 96 },
{ DETEX_TEXTURE_FORMAT_BPTC, 1, 1, "BPTC", "BC7", 4, 4, 0x8E8C, 0, 0, "DX10", 98 },
{ DETEX_TEXTURE_FORMAT_ETC1, 1, 0, "ETC1", "", 4, 4, 0x8D64, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_ETC2, 1, 0, "ETC2", "ETC2_RGB8", 4, 4, 0x9274, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_ETC2_PUNCHTHROUGH, 1, 0, "ETC2_PUNCHTHROUGH", "", 4, 4, 0x9275, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_ETC2_EAC, 1, 0, "ETC2_EAC", "EAC", 4, 4, 0x9278, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_EAC_R11, 1, 0, "EAC_R11", "", 4, 4, 0x9270, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_EAC_SIGNED_R11, 1, 0, "EAC_SIGNED_R11", "", 4, 4, 0x9271, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_EAC_RG11, 1, 0, "EAC_RG11", "", 4, 4, 0x9272, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_EAC_SIGNED_RG11, 1, 0, "EAC_SIGNED_RG11", "", 4, 4, 0x9273, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_ASTC_4X4, 1, 0, "ASTC_4x4", "", 4, 4, 0x93B0, 0, 0, "DX10", 134 }
};
#define DETEX_NU_TEXTURE_INFO_ENTRIES (sizeof(texture_info) / sizeof(texture_info[0]))
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
};
static const int8_t map_mode_table[32] = {
0, 1, 2, 10, -1, -1, 3, 11, -1, -1, 4, 12, -1, -1, 5, 13,
-1, -1, 6, -1, -1, -1, 7, -1, -1, -1, 8, -1, -1, -1, 9, -1
};
static const uint8_t bptc_float_EPB[14] = { 10, 7, 11, 11, 11, 9, 8, 8, 8, 6, 10, 11, 12, 16 };
static const int complement3bitshifted_table[8] = { 0, 8, 16, 24, -32, -24, -16, -8 };
static const int modifier_table[8][4] = {
{ 2, 8, -2, -8 },
{ 5, 17, -5, -17 },
{ 9, 29, -9, -29 },
{ 13, 42, -13, -42 },
{ 18, 60, -18, -60 },
{ 24, 80, -24, -80 },
{ 33, 106, -33, -106 },
{ 47, 183, -47, -183 }
};
const uint8_t detex_division_by_3_table[768] =
{
0, 0, 0, 1, 1, 1, 2, 2,
2, 3, 3, 3, 4, 4, 4, 5,
5, 5, 6, 6, 6, 7, 7, 7,
8, 8, 8, 9, 9, 9, 10, 10,
10, 11, 11, 11, 12, 12, 12, 13,
13, 13, 14, 14, 14, 15, 15, 15,
16, 16, 16, 17, 17, 17, 18, 18,
18, 19, 19, 19, 20, 20, 20, 21,
21, 21, 22, 22, 22, 23, 23, 23,
24, 24, 24, 25, 25, 25, 26, 26,
26, 27, 27, 27, 28, 28, 28, 29,
29, 29, 30, 30, 30, 31, 31, 31,
32, 32, 32, 33, 33, 33, 34, 34,
34, 35, 35, 35, 36, 36, 36, 37,
37, 37, 38, 38, 38, 39, 39, 39,
40, 40, 40, 41, 41, 41, 42, 42,
42, 43, 43, 43, 44, 44, 44, 45,
45, 45, 46, 46, 46, 47, 47, 47,
48, 48, 48, 49, 49, 49, 50, 50,
50, 51, 51, 51, 52, 52, 52, 53,
53, 53, 54, 54, 54, 55, 55, 55,
56, 56, 56, 57, 57, 57, 58, 58,
58, 59, 59, 59, 60, 60, 60, 61,
61, 61, 62, 62, 62, 63, 63, 63,
64, 64, 64, 65, 65, 65, 66, 66,
66, 67, 67, 67, 68, 68, 68, 69,
69, 69, 70, 70, 70, 71, 71, 71,
72, 72, 72, 73, 73, 73, 74, 74,
74, 75, 75, 75, 76, 76, 76, 77,
77, 77, 78, 78, 78, 79, 79, 79,
80, 80, 80, 81, 81, 81, 82, 82,
82, 83, 83, 83, 84, 84, 84, 85,
85, 85, 86, 86, 86, 87, 87, 87,
88, 88, 88, 89, 89, 89, 90, 90,
90, 91, 91, 91, 92, 92, 92, 93,
93, 93, 94, 94, 94, 95, 95, 95,
96, 96, 96, 97, 97, 97, 98, 98,
98, 99, 99, 99, 100, 100, 100, 101,
101, 101, 102, 102, 102, 103, 103, 103,
104, 104, 104, 105, 105, 105, 106, 106,
106, 107, 107, 107, 108, 108, 108, 109,
109, 109, 110, 110, 110, 111, 111, 111,
112, 112, 112, 113, 113, 113, 114, 114,
114, 115, 115, 115, 116, 116, 116, 117,
117, 117, 118, 118, 118, 119, 119, 119,
120, 120, 120, 121, 121, 121, 122, 122,
122, 123, 123, 123, 124, 124, 124, 125,
125, 125, 126, 126, 126, 127, 127, 127,
128, 128, 128, 129, 129, 129, 130, 130,
130, 131, 131, 131, 132, 132, 132, 133,
133, 133, 134, 134, 134, 135, 135, 135,
136, 136, 136, 137, 137, 137, 138, 138,
138, 139, 139, 139, 140, 140, 140, 141,
141, 141, 142, 142, 142, 143, 143, 143,
144, 144, 144, 145, 145, 145, 146, 146,
146, 147, 147, 147, 148, 148, 148, 149,
149, 149, 150, 150, 150, 151, 151, 151,
152, 152, 152, 153, 153, 153, 154, 154,
154, 155, 155, 155, 156, 156, 156, 157,
157, 157, 158, 158, 158, 159, 159, 159,
160, 160, 160, 161, 161, 161, 162, 162,
162, 163, 163, 163, 164, 164, 164, 165,
165, 165, 166, 166, 166, 167, 167, 167,
168, 168, 168, 169, 169, 169, 170, 170,
170, 171, 171, 171, 172, 172, 172, 173,
173, 173, 174, 174, 174, 175, 175, 175,
176, 176, 176, 177, 177, 177, 178, 178,
178, 179, 179, 179, 180, 180, 180, 181,
181, 181, 182, 182, 182, 183, 183, 183,
184, 184, 184, 185, 185, 185, 186, 186,
186, 187, 187, 187, 188, 188, 188, 189,
189, 189, 190, 190, 190, 191, 191, 191,
192, 192, 192, 193, 193, 193, 194, 194,
194, 195, 195, 195, 196, 196, 196, 197,
197, 197, 198, 198, 198, 199, 199, 199,
200, 200, 200, 201, 201, 201, 202, 202,
202, 203, 203, 203, 204, 204, 204, 205,
205, 205, 206, 206, 206, 207, 207, 207,
208, 208, 208, 209, 209, 209, 210, 210,
210, 211, 211, 211, 212, 212, 212, 213,
213, 213, 214, 214, 214, 215, 215, 215,
216, 216, 216, 217, 217, 217, 218, 218,
218, 219, 219, 219, 220, 220, 220, 221,
221, 221, 222, 222, 222, 223, 223, 223,
224, 224, 224, 225, 225, 225, 226, 226,
226, 227, 227, 227, 228, 228, 228, 229,
229, 229, 230, 230, 230, 231, 231, 231,
232, 232, 232, 233, 233, 233, 234, 234,
234, 235, 235, 235, 236, 236, 236, 237,
237, 237, 238, 238, 238, 239, 239, 239,
240, 240, 240, 241, 241, 241, 242, 242,
242, 243, 243, 243, 244, 244, 244, 245,
245, 245, 246, 246, 246, 247, 247, 247,
248, 248, 248, 249, 249, 249, 250, 250,
250, 251, 251, 251, 252, 252, 252, 253,
253, 253, 254, 254, 254, 255, 255, 255,
};
const uint8_t detex_division_by_7_table[1792] =
{
0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 2, 2,
2, 2, 2, 2, 2, 3, 3, 3,
3, 3, 3, 3, 4, 4, 4, 4,
4, 4, 4, 5, 5, 5, 5, 5,
5, 5, 6, 6, 6, 6, 6, 6,
6, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 9,
9, 9, 9, 9, 9, 9, 10, 10,
10, 10, 10, 10, 10, 11, 11, 11,
11, 11, 11, 11, 12, 12, 12, 12,
12, 12, 12, 13, 13, 13, 13, 13,
13, 13, 14, 14, 14, 14, 14, 14,
14, 15, 15, 15, 15, 15, 15, 15,
16, 16, 16, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18,
18, 18, 18, 18, 18, 19, 19, 19,
19, 19, 19, 19, 20, 20, 20, 20,
20, 20, 20, 21, 21, 21, 21, 21,
21, 21, 22, 22, 22, 22, 22, 22,
22, 23, 23, 23, 23, 23, 23, 23,
24, 24, 24, 24, 24, 24, 24, 25,
25, 25, 25, 25, 25, 25, 26, 26,
26, 26, 26, 26, 26, 27, 27, 27,
27, 27, 27, 27, 28, 28, 28, 28,
28, 28, 28, 29, 29, 29, 29, 29,
29, 29, 30, 30, 30, 30, 30, 30,
30, 31, 31, 31, 31, 31, 31, 31,
32, 32, 32, 32, 32, 32, 32, 33,
33, 33, 33, 33, 33, 33, 34, 34,
34, 34, 34, 34, 34, 35, 35, 35,
35, 35, 35, 35, 36, 36, 36, 36,
36, 36, 36, 37, 37, 37, 37, 37,
37, 37, 38, 38, 38, 38, 38, 38,
38, 39, 39, 39, 39, 39, 39, 39,
40, 40, 40, 40, 40, 40, 40, 41,
41, 41, 41, 41, 41, 41, 42, 42,
42, 42, 42, 42, 42, 43, 43, 43,
43, 43, 43, 43, 44, 44, 44, 44,
44, 44, 44, 45, 45, 45, 45, 45,
45, 45, 46, 46, 46, 46, 46, 46,
46, 47, 47, 47, 47, 47, 47, 47,
48, 48, 48, 48, 48, 48, 48, 49,
49, 49, 49, 49, 49, 49, 50, 50,
50, 50, 50, 50, 50, 51, 51, 51,
51, 51, 51, 51, 52, 52, 52, 52,
52, 52, 52, 53, 53, 53, 53, 53,
53, 53, 54, 54, 54, 54, 54, 54,
54, 55, 55, 55, 55, 55, 55, 55,
56, 56, 56, 56, 56, 56, 56, 57,
57, 57, 57, 57, 57, 57, 58, 58,
58, 58, 58, 58, 58, 59, 59, 59,
59, 59, 59, 59, 60, 60, 60, 60,
60, 60, 60, 61, 61, 61, 61, 61,
61, 61, 62, 62, 62, 62, 62, 62,
62, 63, 63, 63, 63, 63, 63, 63,
64, 64, 64, 64, 64, 64, 64, 65,
65, 65, 65, 65, 65, 65, 66, 66,
66, 66, 66, 66, 66, 67, 67, 67,
67, 67, 67, 67, 68, 68, 68, 68,
68, 68, 68, 69, 69, 69, 69, 69,
69, 69, 70, 70, 70, 70, 70, 70,
70, 71, 71, 71, 71, 71, 71, 71,
72, 72, 72, 72, 72, 72, 72, 73,
73, 73, 73, 73, 73, 73, 74, 74,
74, 74, 74, 74, 74, 75, 75, 75,
75, 75, 75, 75, 76, 76, 76, 76,
76, 76, 76, 77, 77, 77, 77, 77,
77, 77, 78, 78, 78, 78, 78, 78,
78, 79, 79, 79, 79, 79, 79, 79,
80, 80, 80, 80, 80, 80, 80, 81,
81, 81, 81, 81, 81, 81, 82, 82,
82, 82, 82, 82, 82, 83, 83, 83,
83, 83, 83, 83, 84, 84, 84, 84,
84, 84, 84, 85, 85, 85, 85, 85,
85, 85, 86, 86, 86, 86, 86, 86,
86, 87, 87, 87, 87, 87, 87, 87,
88, 88, 88, 88, 88, 88, 88, 89,
89, 89, 89, 89, 89, 89, 90, 90,
90, 90, 90, 90, 90, 91, 91, 91,
91, 91, 91, 91, 92, 92, 92, 92,
92, 92, 92, 93, 93, 93, 93, 93,
93, 93, 94, 94, 94, 94, 94, 94,
94, 95, 95, 95, 95, 95, 95, 95,
96, 96, 96, 96, 96, 96, 96, 97,
97, 97, 97, 97, 97, 97, 98, 98,
98, 98, 98, 98, 98, 99, 99, 99,
99, 99, 99, 99, 100, 100, 100, 100,
100, 100, 100, 101, 101, 101, 101, 101,
101, 101, 102, 102, 102, 102, 102, 102,
102, 103, 103, 103, 103, 103, 103, 103,
104, 104, 104, 104, 104, 104, 104, 105,
105, 105, 105, 105, 105, 105, 106, 106,
106, 106, 106, 106, 106, 107, 107, 107,
107, 107, 107, 107, 108, 108, 108, 108,
108, 108, 108, 109, 109, 109, 109, 109,
109, 109, 110, 110, 110, 110, 110, 110,
110, 111, 111, 111, 111, 111, 111, 111,
112, 112, 112, 112, 112, 112, 112, 113,
113, 113, 113, 113, 113, 113, 114, 114,
114, 114, 114, 114, 114, 115, 115, 115,
115, 115, 115, 115, 116, 116, 116, 116,
116, 116, 116, 117, 117, 117, 117, 117,
117, 117, 118, 118, 118, 118, 118, 118,
118, 119, 119, 119, 119, 119, 119, 119,
120, 120, 120, 120, 120, 120, 120, 121,
121, 121, 121, 121, 121, 121, 122, 122,
122, 122, 122, 122, 122, 123, 123, 123,
123, 123, 123, 123, 124, 124, 124, 124,
124, 124, 124, 125, 125, 125, 125, 125,
125, 125, 126, 126, 126, 126, 126, 126,
126, 127, 127, 127, 127, 127, 127, 127,
128, 128, 128, 128, 128, 128, 128, 129,
129, 129, 129, 129, 129, 129, 130, 130,
130, 130, 130, 130, 130, 131, 131, 131,
131, 131, 131, 131, 132, 132, 132, 132,
132, 132, 132, 133, 133, 133, 133, 133,
133, 133, 134, 134, 134, 134, 134, 134,
134, 135, 135, 135, 135, 135, 135, 135,
136, 136, 136, 136, 136, 136, 136, 137,
137, 137, 137, 137, 137, 137, 138, 138,
138, 138, 138, 138, 138, 139, 139, 139,
139, 139, 139, 139, 140, 140, 140, 140,
140, 140, 140, 141, 141, 141, 141, 141,
141, 141, 142, 142, 142, 142, 142, 142,
142, 143, 143, 143, 143, 143, 143, 143,
144, 144, 144, 144, 144, 144, 144, 145,
145, 145, 145, 145, 145, 145, 146, 146,
146, 146, 146, 146, 146, 147, 147, 147,
147, 147, 147, 147, 148, 148, 148, 148,
148, 148, 148, 149, 149, 149, 149, 149,
149, 149, 150, 150, 150, 150, 150, 150,
150, 151, 151, 151, 151, 151, 151, 151,
152, 152, 152, 152, 152, 152, 152, 153,
153, 153, 153, 153, 153, 153, 154, 154,
154, 154, 154, 154, 154, 155, 155, 155,
155, 155, 155, 155, 156, 156, 156, 156,
156, 156, 156, 157, 157, 157, 157, 157,
157, 157, 158, 158, 158, 158, 158, 158,
158, 159, 159, 159, 159, 159, 159, 159,
160, 160, 160, 160, 160, 160, 160, 161,
161, 161, 161, 161, 161, 161, 162, 162,
162, 162, 162, 162, 162, 163, 163, 163,
163, 163, 163, 163, 164, 164, 164, 164,
164, 164, 164, 165, 165, 165, 165, 165,
165, 165, 166, 166, 166, 166, 166, 166,
166, 167, 167, 167, 167, 167, 167, 167,
168, 168, 168, 168, 168, 168, 168, 169,
169, 169, 169, 169, 169, 169, 170, 170,
170, 170, 170, 170, 170, 171, 171, 171,
171, 171, 171, 171, 172, 172, 172, 172,
172, 172, 172, 173, 173, 173, 173, 173,
173, 173, 174, 174, 174, 174, 174, 174,
174, 175, 175, 175, 175, 175, 175, 175,
176, 176, 176, 176, 176, 176, 176, 177,
177, 177, 177, 177, 177, 177, 178, 178,
178, 178, 178, 178, 178, 179, 179, 179,
179, 179, 179, 179, 180, 180, 180, 180,
180, 180, 180, 181, 181, 181, 181, 181,
181, 181, 182, 182, 182, 182, 182, 182,
182, 183, 183, 183, 183, 183, 183, 183,
184, 184, 184, 184, 184, 184, 184, 185,
185, 185, 185, 185, 185, 185, 186, 186,
186, 186, 186, 186, 186, 187, 187, 187,
187, 187, 187, 187, 188, 188, 188, 188,
188, 188, 188, 189, 189, 189, 189, 189,
189, 189, 190, 190, 190, 190, 190, 190,
190, 191, 191, 191, 191, 191, 191, 191,
192, 192, 192, 192, 192, 192, 192, 193,
193, 193, 193, 193, 193, 193, 194, 194,
194, 194, 194, 194, 194, 195, 195, 195,
195, 195, 195, 195, 196, 196, 196, 196,
196, 196, 196, 197, 197, 197, 197, 197,
197, 197, 198, 198, 198, 198, 198, 198,
198, 199, 199, 199, 199, 199, 199, 199,
200, 200, 200, 200, 200, 200, 200, 201,
201, 201, 201, 201, 201, 201, 202, 202,
202, 202, 202, 202, 202, 203, 203, 203,
203, 203, 203, 203, 204, 204, 204, 204,
204, 204, 204, 205, 205, 205, 205, 205,
205, 205, 206, 206, 206, 206, 206, 206,
206, 207, 207, 207, 207, 207, 207, 207,
208, 208, 208, 208, 208, 208, 208, 209,
209, 209, 209, 209, 209, 209, 210, 210,
210, 210, 210, 210, 210, 211, 211, 211,
211, 211, 211, 211, 212, 212, 212, 212,
212, 212, 212, 213, 213, 213, 213, 213,
213, 213, 214, 214, 214, 214, 214, 214,
214, 215, 215, 215, 215, 215, 215, 215,
216, 216, 216, 216, 216, 216, 216, 217,
217, 217, 217, 217, 217, 217, 218, 218,
218, 218, 218, 218, 218, 219, 219, 219,
219, 219, 219, 219, 220, 220, 220, 220,
220, 220, 220, 221, 221, 221, 221, 221,
221, 221, 222, 222, 222, 222, 222, 222,
222, 223, 223, 223, 223, 223, 223, 223,
224, 224, 224, 224, 224, 224, 224, 225,
225, 225, 225, 225, 225, 225, 226, 226,
226, 226, 226, 226, 226, 227, 227, 227,
227, 227, 227, 227, 228, 228, 228, 228,
228, 228, 228, 229, 229, 229, 229, 229,
229, 229, 230, 230, 230, 230, 230, 230,
230, 231, 231, 231, 231, 231, 231, 231,
232, 232, 232, 232, 232, 232, 232, 233,
233, 233, 233, 233, 233, 233, 234, 234,
234, 234, 234, 234, 234, 235, 235, 235,
235, 235, 235, 235, 236, 236, 236, 236,
236, 236, 236, 237, 237, 237, 237, 237,
237, 237, 238, 238, 238, 238, 238, 238,
238, 239, 239, 239, 239, 239, 239, 239,
240, 240, 240, 240, 240, 240, 240, 241,
241, 241, 241, 241, 241, 241, 242, 242,
242, 242, 242, 242, 242, 243, 243, 243,
243, 243, 243, 243, 244, 244, 244, 244,
244, 244, 244, 245, 245, 245, 245, 245,
245, 245, 246, 246, 246, 246, 246, 246,
246, 247, 247, 247, 247, 247, 247, 247,
248, 248, 248, 248, 248, 248, 248, 249,
249, 249, 249, 249, 249, 249, 250, 250,
250, 250, 250, 250, 250, 251, 251, 251,
251, 251, 251, 251, 252, 252, 252, 252,
252, 252, 252, 253, 253, 253, 253, 253,
253, 253, 254, 254, 254, 254, 254, 254,
254, 255, 255, 255, 255, 255, 255, 255,
};
const uint8_t detex_division_by_5_table[1280] =
{
0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 3,
3, 3, 3, 3, 4, 4, 4, 4,
4, 5, 5, 5, 5, 5, 6, 6,
6, 6, 6, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 9, 9, 9,
9, 9, 10, 10, 10, 10, 10, 11,
11, 11, 11, 11, 12, 12, 12, 12,
12, 13, 13, 13, 13, 13, 14, 14,
14, 14, 14, 15, 15, 15, 15, 15,
16, 16, 16, 16, 16, 17, 17, 17,
17, 17, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 20, 20, 20, 20,
20, 21, 21, 21, 21, 21, 22, 22,
22, 22, 22, 23, 23, 23, 23, 23,
24, 24, 24, 24, 24, 25, 25, 25,
25, 25, 26, 26, 26, 26, 26, 27,
27, 27, 27, 27, 28, 28, 28, 28,
28, 29, 29, 29, 29, 29, 30, 30,
30, 30, 30, 31, 31, 31, 31, 31,
32, 32, 32, 32, 32, 33, 33, 33,
33, 33, 34, 34, 34, 34, 34, 35,
35, 35, 35, 35, 36, 36, 36, 36,
36, 37, 37, 37, 37, 37, 38, 38,
38, 38, 38, 39, 39, 39, 39, 39,
40, 40, 40, 40, 40, 41, 41, 41,
41, 41, 42, 42, 42, 42, 42, 43,
43, 43, 43, 43, 44, 44, 44, 44,
44, 45, 45, 45, 45, 45, 46, 46,
46, 46, 46, 47, 47, 47, 47, 47,
48, 48, 48, 48, 48, 49, 49, 49,
49, 49, 50, 50, 50, 50, 50, 51,
51, 51, 51, 51, 52, 52, 52, 52,
52, 53, 53, 53, 53, 53, 54, 54,
54, 54, 54, 55, 55, 55, 55, 55,
56, 56, 56, 56, 56, 57, 57, 57,
57, 57, 58, 58, 58, 58, 58, 59,
59, 59, 59, 59, 60, 60, 60, 60,
60, 61, 61, 61, 61, 61, 62, 62,
62, 62, 62, 63, 63, 63, 63, 63,
64, 64, 64, 64, 64, 65, 65, 65,
65, 65, 66, 66, 66, 66, 66, 67,
67, 67, 67, 67, 68, 68, 68, 68,
68, 69, 69, 69, 69, 69, 70, 70,
70, 70, 70, 71, 71, 71, 71, 71,
72, 72, 72, 72, 72, 73, 73, 73,
73, 73, 74, 74, 74, 74, 74, 75,
75, 75, 75, 75, 76, 76, 76, 76,
76, 77, 77, 77, 77, 77, 78, 78,
78, 78, 78, 79, 79, 79, 79, 79,
80, 80, 80, 80, 80, 81, 81, 81,
81, 81, 82, 82, 82, 82, 82, 83,
83, 83, 83, 83, 84, 84, 84, 84,
84, 85, 85, 85, 85, 85, 86, 86,
86, 86, 86, 87, 87, 87, 87, 87,
88, 88, 88, 88, 88, 89, 89, 89,
89, 89, 90, 90, 90, 90, 90, 91,
91, 91, 91, 91, 92, 92, 92, 92,
92, 93, 93, 93, 93, 93, 94, 94,
94, 94, 94, 95, 95, 95, 95, 95,
96, 96, 96, 96, 96, 97, 97, 97,
97, 97, 98, 98, 98, 98, 98, 99,
99, 99, 99, 99, 100, 100, 100, 100,
100, 101, 101, 101, 101, 101, 102, 102,
102, 102, 102, 103, 103, 103, 103, 103,
104, 104, 104, 104, 104, 105, 105, 105,
105, 105, 106, 106, 106, 106, 106, 107,
107, 107, 107, 107, 108, 108, 108, 108,
108, 109, 109, 109, 109, 109, 110, 110,
110, 110, 110, 111, 111, 111, 111, 111,
112, 112, 112, 112, 112, 113, 113, 113,
113, 113, 114, 114, 114, 114, 114, 115,
115, 115, 115, 115, 116, 116, 116, 116,
116, 117, 117, 117, 117, 117, 118, 118,
118, 118, 118, 119, 119, 119, 119, 119,
120, 120, 120, 120, 120, 121, 121, 121,
121, 121, 122, 122, 122, 122, 122, 123,
123, 123, 123, 123, 124, 124, 124, 124,
124, 125, 125, 125, 125, 125, 126, 126,
126, 126, 126, 127, 127, 127, 127, 127,
128, 128, 128, 128, 128, 129, 129, 129,
129, 129, 130, 130, 130, 130, 130, 131,
131, 131, 131, 131, 132, 132, 132, 132,
132, 133, 133, 133, 133, 133, 134, 134,
134, 134, 134, 135, 135, 135, 135, 135,
136, 136, 136, 136, 136, 137, 137, 137,
137, 137, 138, 138, 138, 138, 138, 139,
139, 139, 139, 139, 140, 140, 140, 140,
140, 141, 141, 141, 141, 141, 142, 142,
142, 142, 142, 143, 143, 143, 143, 143,
144, 144, 144, 144, 144, 145, 145, 145,
145, 145, 146, 146, 146, 146, 146, 147,
147, 147, 147, 147, 148, 148, 148, 148,
148, 149, 149, 149, 149, 149, 150, 150,
150, 150, 150, 151, 151, 151, 151, 151,
152, 152, 152, 152, 152, 153, 153, 153,
153, 153, 154, 154, 154, 154, 154, 155,
155, 155, 155, 155, 156, 156, 156, 156,
156, 157, 157, 157, 157, 157, 158, 158,
158, 158, 158, 159, 159, 159, 159, 159,
160, 160, 160, 160, 160, 161, 161, 161,
161, 161, 162, 162, 162, 162, 162, 163,
163, 163, 163, 163, 164, 164, 164, 164,
164, 165, 165, 165, 165, 165, 166, 166,
166, 166, 166, 167, 167, 167, 167, 167,
168, 168, 168, 168, 168, 169, 169, 169,
169, 169, 170, 170, 170, 170, 170, 171,
171, 171, 171, 171, 172, 172, 172, 172,
172, 173, 173, 173, 173, 173, 174, 174,
174, 174, 174, 175, 175, 175, 175, 175,
176, 176, 176, 176, 176, 177, 177, 177,
177, 177, 178, 178, 178, 178, 178, 179,
179, 179, 179, 179, 180, 180, 180, 180,
180, 181, 181, 181, 181, 181, 182, 182,
182, 182, 182, 183, 183, 183, 183, 183,
184, 184, 184, 184, 184, 185, 185, 185,
185, 185, 186, 186, 186, 186, 186, 187,
187, 187, 187, 187, 188, 188, 188, 188,
188, 189, 189, 189, 189, 189, 190, 190,
190, 190, 190, 191, 191, 191, 191, 191,
192, 192, 192, 192, 192, 193, 193, 193,
193, 193, 194, 194, 194, 194, 194, 195,
195, 195, 195, 195, 196, 196, 196, 196,
196, 197, 197, 197, 197, 197, 198, 198,
198, 198, 198, 199, 199, 199, 199, 199,
200, 200, 200, 200, 200, 201, 201, 201,
201, 201, 202, 202, 202, 202, 202, 203,
203, 203, 203, 203, 204, 204, 204, 204,
204, 205, 205, 205, 205, 205, 206, 206,
206, 206, 206, 207, 207, 207, 207, 207,
208, 208, 208, 208, 208, 209, 209, 209,
209, 209, 210, 210, 210, 210, 210, 211,
211, 211, 211, 211, 212, 212, 212, 212,
212, 213, 213, 213, 213, 213, 214, 214,
214, 214, 214, 215, 215, 215, 215, 215,
216, 216, 216, 216, 216, 217, 217, 217,
217, 217, 218, 218, 218, 218, 218, 219,
219, 219, 219, 219, 220, 220, 220, 220,
220, 221, 221, 221, 221, 221, 222, 222,
222, 222, 222, 223, 223, 223, 223, 223,
224, 224, 224, 224, 224, 225, 225, 225,
225, 225, 226, 226, 226, 226, 226, 227,
227, 227, 227, 227, 228, 228, 228, 228,
228, 229, 229, 229, 229, 229, 230, 230,
230, 230, 230, 231, 231, 231, 231, 231,
232, 232, 232, 232, 232, 233, 233, 233,
233, 233, 234, 234, 234, 234, 234, 235,
235, 235, 235, 235, 236, 236, 236, 236,
236, 237, 237, 237, 237, 237, 238, 238,
238, 238, 238, 239, 239, 239, 239, 239,
240, 240, 240, 240, 240, 241, 241, 241,
241, 241, 242, 242, 242, 242, 242, 243,
243, 243, 243, 243, 244, 244, 244, 244,
244, 245, 245, 245, 245, 245, 246, 246,
246, 246, 246, 247, 247, 247, 247, 247,
248, 248, 248, 248, 248, 249, 249, 249,
249, 249, 250, 250, 250, 250, 250, 251,
251, 251, 251, 251, 252, 252, 252, 252,
252, 253, 253, 253, 253, 253, 254, 254,
254, 254, 254, 255, 255, 255, 255, 255,
};
const uint8_t detex_clamp0to255_table[255 + 256 + 256] =
{
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,
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,
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,
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,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
};
typedef bool (*detexDecompressBlockFuncType)(const uint8_t *bitstring, uint32_t mode_mask, uint32_t flags, uint8_t *pixel_buffer);
/**
*/
typedef struct
{
uint32_t format;
uint8_t *data;
int width;
int height;
int width_in_blocks;
int height_in_blocks;
} FDetexTexture;
/** Data structure used to extract bits from 128-bit bitstring. */
typedef struct
{
uint64_t data0;
uint64_t data1;
int index;
} FDetexBlock128;
static int detexMatchConversion(uint32_t source_pixel_format, uint32_t target_pixel_format, uint32_t *conversion);
uint32_t detexBlock128ExtractBits(FDetexBlock128 *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;
}
/** Return the compressed texture type index of a texture format. */
static DETEX_INLINE_ONLY uint32_t detexGetCompressedFormat(uint32_t texture_format)
{
return texture_format >> 24;
}
/** Return the block size of a compressed texture format in bytes. */
static DETEX_INLINE_ONLY uint32_t detexGetCompressedBlockSize(uint32_t texture_format)
{
return 8 + ((texture_format & DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT) >> 20);
}
/* Return the pixel format of a texture format. */
static DETEX_INLINE_ONLY uint32_t detexGetPixelFormat(uint32_t texture_format)
{
return texture_format & DETEX_TEXTURE_FORMAT_PIXEL_FORMAT_MASK;
}
/* Integer division using look-up tables, used by BC1/2/3 and RGTC (BC4/5) */
/* decompression. */
static DETEX_INLINE_ONLY uint32_t detexDivide0To767By3(uint32_t value)
{
return detex_division_by_3_table[value];
}
static DETEX_INLINE_ONLY uint32_t detexDivide0To1791By7(uint32_t value)
{
return detex_division_by_7_table[value];
}
static DETEX_INLINE_ONLY int8_t detexSignInt32(int v)
{
return (int8_t)((v >> 31) | -(-v >> 31));
}
static DETEX_INLINE_ONLY int detexDivideMinus895To895By7(int value)
{
return (int8_t)detex_division_by_7_table[abs(value)] * detexSignInt32(value);
}
static DETEX_INLINE_ONLY uint32_t detexDivide0To1279By5(uint32_t value)
{
return detex_division_by_5_table[value];
}
static DETEX_INLINE_ONLY int detexDivideMinus639To639By5(int value)
{
return (int8_t)detex_division_by_5_table[abs(value)] * detexSignInt32(value);
}
/** 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;
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the BC1 format. */
bool detexDecompressBlockBC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__)
uint32_t colors = *(uint32_t *)&bitstring[0];
#else
uint32_t colors = ((uint32_t)bitstring[0] << 24) |
((uint32_t)bitstring[1] << 16) |
((uint32_t)bitstring[2] << 8) | bitstring[3];
#endif
// Decode the two 5-6-5 RGB colors.
int color_r[4], color_g[4], color_b[4];
color_b[0] = (colors & 0x0000001F) << 3;
color_g[0] = (colors & 0x000007E0) >> (5 - 2);
color_r[0] = (colors & 0x0000F800) >> (11 - 3);
color_b[1] = (colors & 0x001F0000) >> (16 - 3);
color_g[1] = (colors & 0x07E00000) >> (21 - 2);
color_r[1] = (colors & 0xF8000000) >> (27 - 3);
if ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16))
{
color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]);
color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]);
color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]);
color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]);
color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]);
color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]);
}
else
{
color_r[2] = (color_r[0] + color_r[1]) / 2;
color_g[2] = (color_g[0] + color_g[1]) / 2;
color_b[2] = (color_b[0] + color_b[1]) / 2;
color_r[3] = color_g[3] = color_b[3] = 0;
}
uint32_t pixels = *(uint32_t *)&bitstring[4];
for (int i = 0; i < 16; i++)
{
int pixel = (pixels >> (i * 2)) & 0x3;
*(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGB8Alpha0xFF(color_r[pixel], color_g[pixel], color_b[pixel]);
}
return true;
}
uint32_t detexGetModeBC1(const uint8_t *bitstring)
{
uint32_t colors = *(uint32_t *)bitstring;
if ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16))
return 0;
else
return 1;
}
void detexSetModeBC1(uint8_t *bitstring, uint32_t mode, uint32_t flags, uint32_t *colors)
{
uint32_t colorbits = *(uint32_t *)bitstring;
uint32_t current_mode;
if ((colorbits & 0xFFFF) > ((colorbits & 0xFFFF0000) >> 16))
current_mode = 0;
else
current_mode = 1;
if (current_mode != mode)
{
colorbits = ((colorbits & 0xFFFF) << 16) | (colorbits >> 16);
*(uint32_t *)bitstring = colorbits;
}
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the BC1A format. */
bool detexDecompressBlockBC1A(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__)
uint32_t colors = *(uint32_t *)&bitstring[0];
#else
uint32_t colors = ((uint32_t)bitstring[0] << 24) |
((uint32_t)bitstring[1] << 16) |
((uint32_t)bitstring[2] << 8) | bitstring[3];
#endif
bool opaque = ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16));
if (opaque && (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY))
return false;
if (!opaque && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY))
return false;
// Decode the two 5-6-5 RGB colors.
int color_r[4], color_g[4], color_b[4], color_a[4];
color_b[0] = (colors & 0x0000001F) << 3;
color_g[0] = (colors & 0x000007E0) >> (5 - 2);
color_r[0] = (colors & 0x0000F800) >> (11 - 3);
color_b[1] = (colors & 0x001F0000) >> (16 - 3);
color_g[1] = (colors & 0x07E00000) >> (21 - 2);
color_r[1] = (colors & 0xF8000000) >> (27 - 3);
color_a[0] = color_a[1] = color_a[2] = color_a[3] = 0xFF;
if (opaque)
{
color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]);
color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]);
color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]);
color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]);
color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]);
color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]);
}
else
{
color_r[2] = (color_r[0] + color_r[1]) / 2;
color_g[2] = (color_g[0] + color_g[1]) / 2;
color_b[2] = (color_b[0] + color_b[1]) / 2;
color_r[3] = color_g[3] = color_b[3] = color_a[3] = 0;
}
uint32_t pixels = *(uint32_t *)&bitstring[4];
for (int i = 0; i < 16; i++)
{
int pixel = (pixels >> (i * 2)) & 0x3;
*(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8(color_r[pixel], color_g[pixel], color_b[pixel], color_a[pixel]);
}
return true;
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the BC2 format. */
bool detexDecompressBlockBC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__)
uint32_t colors = *(uint32_t *)&bitstring[8];
#else
uint32_t colors = ((uint32_t)bitstring[8] << 24) |
((uint32_t)bitstring[9] << 16) |
((uint32_t)bitstring[10] << 8) | bitstring[11];
#endif
if ((colors & 0xFFFF) <= ((colors & 0xFFFF0000) >> 16) &&
(flags & DETEX_DECOMPRESS_FLAG_ENCODE))
// GeForce 6 and 7 series produce wrong result in this case.
return false;
int color_r[4], color_g[4], color_b[4];
color_b[0] = (colors & 0x0000001F) << 3;
color_g[0] = (colors & 0x000007E0) >> (5 - 2);
color_r[0] = (colors & 0x0000F800) >> (11 - 3);
color_b[1] = (colors & 0x001F0000) >> (16 - 3);
color_g[1] = (colors & 0x07E00000) >> (21 - 2);
color_r[1] = (colors & 0xF8000000) >> (27 - 3);
color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]);
color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]);
color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]);
color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]);
color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]);
color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]);
uint32_t pixels = *(uint32_t *)&bitstring[12];
uint64_t alpha_pixels = *(uint64_t *)&bitstring[0];
for (int i = 0; i < 16; i++)
{
int pixel = (pixels >> (i * 2)) & 0x3;
int alpha = ((alpha_pixels >> (i * 4)) & 0xF) * 255 / 15;
*(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8(color_r[pixel], color_g[pixel], color_b[pixel], alpha);
}
return true;
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the BC3 format. */
bool detexDecompressBlockBC3(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int alpha0 = bitstring[0];
int alpha1 = bitstring[1];
if (alpha0 > alpha1 && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY))
return false;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__)
uint32_t colors = *(uint32_t *)&bitstring[8];
#else
uint32_t colors = ((uint32_t)bitstring[8] << 24) |
((uint32_t)bitstring[9] << 16) |
((uint32_t)bitstring[10] << 8) | bitstring[11];
#endif
if ((colors & 0xFFFF) <= ((colors & 0xFFFF0000) >> 16) &&
(flags & DETEX_DECOMPRESS_FLAG_ENCODE))
// GeForce 6 and 7 series produce wrong result in this case.
return false;
int color_r[4], color_g[4], color_b[4];
// color_x[] has a value between 0 and 248 with the lower three bits zero.
color_b[0] = (colors & 0x0000001F) << 3;
color_g[0] = (colors & 0x000007E0) >> (5 - 2);
color_r[0] = (colors & 0x0000F800) >> (11 - 3);
color_b[1] = (colors & 0x001F0000) >> (16 - 3);
color_g[1] = (colors & 0x07E00000) >> (21 - 2);
color_r[1] = (colors & 0xF8000000) >> (27 - 3);
color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]);
color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]);
color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]);
color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]);
color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]);
color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]);
uint32_t pixels = *(uint32_t *)&bitstring[12];
uint64_t alpha_bits = (uint32_t)bitstring[2] | ((uint32_t)bitstring[3] << 8) | ((uint64_t)*(uint32_t *)&bitstring[4] << 16);
for (int i = 0; i < 16; i++)
{
int pixel = (pixels >> (i * 2)) & 0x3;
int code = (alpha_bits >> (i * 3)) & 0x7;
int alpha;
if (alpha0 > alpha1)
{
switch (code)
{
case 0 : alpha = alpha0; break;
case 1 : alpha = alpha1; break;
case 2 : alpha = detexDivide0To1791By7(6 * alpha0 + 1 * alpha1); break;
case 3 : alpha = detexDivide0To1791By7(5 * alpha0 + 2 * alpha1); break;
case 4 : alpha = detexDivide0To1791By7(4 * alpha0 + 3 * alpha1); break;
case 5 : alpha = detexDivide0To1791By7(3 * alpha0 + 4 * alpha1); break;
case 6 : alpha = detexDivide0To1791By7(2 * alpha0 + 5 * alpha1); break;
case 7 : alpha = detexDivide0To1791By7(1 * alpha0 + 6 * alpha1); break;
}
}
else
{
switch (code)
{
case 0 : alpha = alpha0; break;
case 1 : alpha = alpha1; break;
case 2 : alpha = detexDivide0To1279By5(4 * alpha0 + 1 * alpha1); break;
case 3 : alpha = detexDivide0To1279By5(3 * alpha0 + 2 * alpha1); break;
case 4 : alpha = detexDivide0To1279By5(2 * alpha0 + 3 * alpha1); break;
case 5 : alpha = detexDivide0To1279By5(1 * alpha0 + 4 * alpha1); break;
case 6 : alpha = 0; break;
case 7 : alpha = 0xFF; break;
}
}
*(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8(color_r[pixel], color_g[pixel], color_b[pixel], alpha);
}
return true;
}
/**
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);
}
////////////////////////////////////////////////////////////////////////////////////////////////
static int ExtractMode(FDetexBlock128 *block)
{
uint32_t mode = detexBlock128ExtractBits(block, 2);
if (mode < 2)
return mode;
return map_mode_table[mode | (detexBlock128ExtractBits(block, 3) << 2)];
}
static int GetPartitionIndex(int nu_subsets, int partition_set_id, int i)
{
if (nu_subsets == 1)
return 0;
// nu_subset == 2
return detex_bptc_table_P2[partition_set_id * 16 + i];
}
static DETEX_INLINE_ONLY int GetAnchorIndex(int partition_set_id, int partition, int nu_subsets)
{
if (partition == 0)
return 0;
// nu_subsets = 2, partition = 1.
return detex_bptc_table_anchor_index_second_subset[partition_set_id];
}
static uint32_t Unquantize(uint16_t x, int mode)
{
int32_t unq;
if (mode == 13)
unq = x;
else if (x == 0)
unq = 0;
else if (x == (((int32_t)1 << bptc_float_EPB[mode]) - 1))
unq = 0xFFFF;
else
unq = (((int32_t)x << 15) + 0x4000) >> (bptc_float_EPB[mode] - 1);
return unq;
}
static int32_t UnquantizeSigned(int16_t x, int mode)
{
int s = 0;
int32_t unq;
if (bptc_float_EPB[mode] >= 16)
unq = x;
else
{
if (x < 0) {
s = 1;
x = -x;
}
if (x == 0)
unq = 0;
else
if (x >= (((int32_t)1 << (bptc_float_EPB[mode] - 1)) - 1))
unq = 0x7FFF;
else
unq = (((int32_t)x << 15) + 0x4000) >> (bptc_float_EPB[mode] - 1);
if (s)
unq = -unq;
}
return unq;
}
static int SignExtend(int value, int source_nu_bits, int target_nu_bits)
{
uint32_t sign_bit = value & (1 << (source_nu_bits - 1));
if (!sign_bit)
return value;
uint32_t sign_extend_bits = 0xFFFFFFFF ^ ((1 << source_nu_bits) - 1);
sign_extend_bits &= ((uint64_t)1 << target_nu_bits) - 1;
return value | sign_extend_bits;
}
static int32_t InterpolateFloat(int32_t e0, int32_t e1, int16_t index, uint8_t indexprecision)
{
if (indexprecision == 2)
return (((64 - detex_bptc_table_aWeight2[index]) * e0 + detex_bptc_table_aWeight2[index] * e1 + 32) >> 6);
else if (indexprecision == 3)
return (((64 - detex_bptc_table_aWeight3[index]) * e0 + detex_bptc_table_aWeight3[index] * e1 + 32) >> 6);
else // indexprecision == 4
return (((64 - detex_bptc_table_aWeight4[index]) * e0 + detex_bptc_table_aWeight4[index] * e1 + 32) >> 6);
}
static bool DecompressBlockBPTCFloatShared(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, bool signed_flag, const uint8_t * DETEX_RESTRICT pixel_buffer)
{
FDetexBlock128 block;
block.data0 = *(uint64_t *)&bitstring[0];
block.data1 = *(uint64_t *)&bitstring[8];
block.index = 0;
uint32_t mode = ExtractMode(&block);
if (mode == - 1)
return false;
// Allow compression tied to specific modes (according to mode_mask).
if (!(mode_mask & ((int)1 << mode)))
return false;
int32_t r[4], g[4], b[4];
int partition_set_id = 0;
int delta_bits_r, delta_bits_g, delta_bits_b;
uint64_t data0 = block.data0;
uint64_t data1 = block.data1;
switch (mode)
{
case 0 :
// m[1:0],g2[4],b2[4],b3[4],r0[9:0],g0[9:0],b0[9:0],r1[4:0],g3[4],g2[3:0],
// g1[4:0],b3[0],g3[3:0],b1[4:0],b3[1],b2[3:0],r2[4:0],b3[2],r3[4:0],b3[3]
g[2] = detexGetBits64(data0, 2, 2) << 4;
b[2] = detexGetBits64(data0, 3, 3) << 4;
b[3] = detexGetBits64(data0, 4, 4) << 4;
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 39);
g[3] = detexGetBits64(data0, 40, 40) << 4;
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
b[3] |= detexGetBits64(data0, 50, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = delta_bits_b = 5;
break;
case 1 :
// m[1:0],g2[5],g3[4],g3[5],r0[6:0],b3[0],b3[1],b2[4],g0[6:0],b2[5],b3[2],
// g2[4],b0[6:0],b3[3],b3[5],b3[4],r1[5:0],g2[3:0],g1[5:0],g3[3:0],b1[5:0],
// b2[3:0],r2[5:0],r3[5:0]
g[2] = detexGetBits64(data0, 2, 2) << 5;
g[3] = detexGetBits64(data0, 3, 3) << 4;
g[3] |= detexGetBits64(data0, 4, 4) << 5;
r[0] = detexGetBits64(data0, 5, 11);
b[3] = detexGetBits64(data0, 12, 12);
b[3] |= detexGetBits64(data0, 13, 13) << 1;
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 21);
b[2] |= detexGetBits64(data0, 22, 22) << 5;
b[3] |= detexGetBits64(data0, 23, 23) << 2;
g[2] |= detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 31);
b[3] |= detexGetBits64(data0, 32, 32) << 3;
b[3] |= detexGetBits64(data0, 33, 33) << 5;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 40);
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 60);
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 6);
r[3] = detexGetBits64(data1, 7, 12);
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = delta_bits_b = 6;
break;
case 2 :
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[4:0],r0[10],g2[3:0],g1[3:0],g0[10],
// b3[0],g3[3:0],b1[3:0],b0[10],b3[1],b2[3:0],r2[4:0],b3[2],r3[4:0],b3[3]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 39);
r[0] |= detexGetBits64(data0, 40, 40) << 10;
g[2] = detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 48);
g[0] |= detexGetBits64(data0, 49, 49) << 10;
b[3] = detexGetBits64(data0, 50, 50);
g[3] = detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 58);
b[0] |= detexGetBits64(data0, 59, 59) << 10;
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] = detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = 5;
delta_bits_g = delta_bits_b = 4;
break;
case 3 : // Original mode 6.
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[3:0],r0[10],g3[4],g2[3:0],g1[4:0],
// g0[10],g3[3:0],b1[3:0],b0[10],b3[1],b2[3:0],r2[3:0],b3[0],b3[2],r3[3:0],
// g2[4],b3[3]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 38);
r[0] |= detexGetBits64(data0, 39, 39) << 10;
g[3] = detexGetBits64(data0, 40, 40) << 4;
g[2] = detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
g[0] |= detexGetBits64(data0, 50, 50) << 10;
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 58);
b[0] |= detexGetBits64(data0, 59, 59) << 10;
b[3] = detexGetBits64(data0, 60, 60) << 1;
b[2] = detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 4);
b[3] |= detexGetBits64(data1, 5, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 10);
g[2] |= detexGetBits64(data1, 11, 11) << 4;
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_b = 4;
delta_bits_g = 5;
break;
case 4 : // Original mode 10.
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[3:0],r0[10],b2[4],g2[3:0],g1[3:0],
// g0[10],b3[0],g3[3:0],b1[4:0],b0[10],b2[3:0],r2[3:0],b3[1],b3[2],r3[3:0],
// b3[4],b3[3]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 38);
r[0] |= detexGetBits64(data0, 39, 39) << 10;
b[2] = detexGetBits64(data0, 40, 40) << 4;
g[2] = detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 48);
g[0] |= detexGetBits64(data0, 49, 49) << 10;
b[3] = detexGetBits64(data0, 50, 50);
g[3] = detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[0] |= detexGetBits64(data0, 60, 60) << 10;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 4);
b[3] |= detexGetBits64(data1, 5, 5) << 1;
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 10);
b[3] |= detexGetBits64(data1, 11, 11) << 4;
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = 4;
delta_bits_b = 5;
break;
case 5 : // Original mode 14
// m[4:0],r0[8:0],b2[4],g0[8:0],g2[4],b0[8:0],b3[4],r1[4:0],g3[4],g2[3:0],
// g1[4:0],b3[0],g3[3:0],b1[4:0],b3[1],b2[3:0],r2[4:0],b3[2],r3[4:0],b3[3]
r[0] = detexGetBits64(data0, 5, 13);
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 23);
g[2] = detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 33);
b[3] = detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 39);
g[3] = detexGetBits64(data0, 40, 40) << 4;
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
b[3] |= detexGetBits64(data0, 50, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = delta_bits_b = 5;
break;
case 6 : // Original mode 18
// m[4:0],r0[7:0],g3[4],b2[4],g0[7:0],b3[2],g2[4],b0[7:0],b3[3],b3[4],
// r1[5:0],g2[3:0],g1[4:0],b3[0],g3[3:0],b1[4:0],b3[1],b2[3:0],r2[5:0],r3[5:0]
r[0] = detexGetBits64(data0, 5, 12);
g[3] = detexGetBits64(data0, 13, 13) << 4;
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 22);
b[3] = detexGetBits64(data0, 23, 23) << 2;
g[2] = detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 32);
b[3] |= detexGetBits64(data0, 33, 33) << 3;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 40);
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
b[3] |= detexGetBits64(data0, 50, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 6);
r[3] = detexGetBits64(data1, 7, 12);
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = 6;
delta_bits_g = delta_bits_b = 5;
break;
case 7 : // Original mode 22
// m[4:0],r0[7:0],b3[0],b2[4],g0[7:0],g2[5],g2[4],b0[7:0],g3[5],b3[4],
// r1[4:0],g3[4],g2[3:0],g1[5:0],g3[3:0],b1[4:0],b3[1],b2[3:0],r2[4:0],
// b3[2],r3[4:0],b3[3]
r[0] = detexGetBits64(data0, 5, 12);
b[3] = detexGetBits64(data0, 13, 13);
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 22);
g[2] = detexGetBits64(data0, 23, 23) << 5;
g[2] |= detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 32);
g[3] = detexGetBits64(data0, 33, 33) << 5;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 39);
g[3] |= detexGetBits64(data0, 40, 40) << 4;
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_b = 5;
delta_bits_g = 6;
break;
case 8 : // Original mode 26
// m[4:0],r0[7:0],b3[1],b2[4],g0[7:0],b2[5],g2[4],b0[7:0],b3[5],b3[4],
// r1[4:0],g3[4],g2[3:0],g1[4:0],b3[0],g3[3:0],b1[5:0],b2[3:0],r2[4:0],
// b3[2],r3[4:0],b3[3]
r[0] = detexGetBits64(data0, 5, 12);
b[3] = detexGetBits64(data0, 13, 13) << 1;
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 22);
b[2] |= detexGetBits64(data0, 23, 23) << 5;
g[2] = detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 32);
b[3] |= detexGetBits64(data0, 33, 33) << 5;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 39);
g[3] = detexGetBits64(data0, 40, 40) << 4;
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
b[3] |= detexGetBits64(data0, 50, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 60);
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = 5;
delta_bits_b = 6;
break;
case 9 : // Original mode 30
// m[4:0],r0[5:0],g3[4],b3[0],b3[1],b2[4],g0[5:0],g2[5],b2[5],b3[2],
// g2[4],b0[5:0],g3[5],b3[3],b3[5],b3[4],r1[5:0],g2[3:0],g1[5:0],g3[3:0],
// b1[5:0],b2[3:0],r2[5:0],r3[5:0]
r[0] = detexGetBits64(data0, 5, 10);
g[3] = detexGetBits64(data0, 11, 11) << 4;
b[3] = detexGetBits64(data0, 12, 13);
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 20);
g[2] = detexGetBits64(data0, 21, 21) << 5;
b[2] |= detexGetBits64(data0, 22, 22) << 5;
b[3] |= detexGetBits64(data0, 23, 23) << 2;
g[2] |= detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 30);
g[3] |= detexGetBits64(data0, 31, 31) << 5;
b[3] |= detexGetBits64(data0, 32, 32) << 3;
b[3] |= detexGetBits64(data0, 33, 33) << 5;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 40);
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 60);
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 6);
r[3] = detexGetBits64(data1, 7, 12);
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
// delta_bits_r = delta_bits_g = delta_bits_b = 6;
break;
case 10 : // Original mode 3
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[9:0],g1[9:0],b1[9:0]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 44);
g[1] = detexGetBits64(data0, 45, 54);
b[1] = detexGetBits64(data0, 55, 63);
b[1] |= detexGetBits64(data1, 0, 0) << 9;
partition_set_id = 0;
block.index = 65;
// delta_bits_r = delta_bits_g = delta_bits_b = 10;
break;
case 11 : // Original mode 7
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[8:0],r0[10],g1[8:0],g0[10],b1[8:0],b0[10]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 43);
r[0] |= detexGetBits64(data0, 44, 44) << 10;
g[1] = detexGetBits64(data0, 45, 53);
g[0] |= detexGetBits64(data0, 54, 54) << 10;
b[1] = detexGetBits64(data0, 55, 63);
b[0] |= detexGetBits64(data1, 0, 0) << 10;
partition_set_id = 0;
block.index = 65;
delta_bits_r = delta_bits_g = delta_bits_b = 9;
break;
case 12 : // Original mode 11
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[7:0],r0[10:11],g1[7:0],g0[10:11],
// b1[7:0],b0[10:11]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 42);
r[0] |= detexGetBits64Reversed(data0, 44, 43) << 10; // Reversed.
g[1] = detexGetBits64(data0, 45, 52);
g[0] |= detexGetBits64Reversed(data0, 54, 53) << 10; // Reversed.
b[1] = detexGetBits64(data0, 55, 62);
b[0] |= detexGetBits64(data0, 63, 63) << 11; // MSB
b[0] |= detexGetBits64(data1, 0, 0) << 10; // LSB
partition_set_id = 0;
block.index = 65;
delta_bits_r = delta_bits_g = delta_bits_b = 8;
break;
case 13 : // Original mode 15
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[3:0],r0[10:15],g1[3:0],g0[10:15],
// b1[3:0],b0[10:15]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 38);
r[0] |= detexGetBits64Reversed(data0, 44, 39) << 10; // Reversed.
g[1] = detexGetBits64(data0, 45, 48);
g[0] |= detexGetBits64Reversed(data0, 54, 49) << 10; // Reversed.
b[1] = detexGetBits64(data0, 55, 58);
b[0] |= detexGetBits64Reversed(data0, 63, 59) << 11; // Reversed.
b[0] |= detexGetBits64(data1, 0, 0) << 10;
partition_set_id = 0;
block.index = 65;
delta_bits_r = delta_bits_g = delta_bits_b = 4;
break;
}
int nu_subsets;
if (mode >= 10)
nu_subsets = 1;
else
nu_subsets = 2;
if (signed_flag)
{
r[0] = SignExtend(r[0], bptc_float_EPB[mode], 32);
g[0] = SignExtend(g[0], bptc_float_EPB[mode], 32);
b[0] = SignExtend(b[0], bptc_float_EPB[mode], 32);
}
if (mode != 9 && mode != 10)
{
// Transformed endpoints.
for (int i = 1; i < nu_subsets * 2; i++)
{
r[i] = SignExtend(r[i], delta_bits_r, 32);
r[i] = (r[0] + r[i]) & (((uint32_t)1 << bptc_float_EPB[mode]) - 1);
g[i] = SignExtend(g[i], delta_bits_g, 32);
g[i] = (g[0] + g[i]) & (((uint32_t)1 << bptc_float_EPB[mode]) - 1);
b[i] = SignExtend(b[i], delta_bits_b, 32);
b[i] = (b[0] + b[i]) & (((uint32_t)1 << bptc_float_EPB[mode]) - 1);
if (signed_flag)
{
r[i] = SignExtend(r[i], bptc_float_EPB[mode], 32);
g[i] = SignExtend(g[i], bptc_float_EPB[mode], 32);
b[i] = SignExtend(b[i], bptc_float_EPB[mode], 32);
}
}
}
else // Mode 9 or 10, no transformed endpoints.
{
if (signed_flag)
{
for (int i = 1; i < nu_subsets * 2; i++)
{
r[i] = SignExtend(r[i], bptc_float_EPB[mode], 32);
g[i] = SignExtend(g[i], bptc_float_EPB[mode], 32);
b[i] = SignExtend(b[i], bptc_float_EPB[mode], 32);
}
}
}
// Unquantize endpoints.
if (signed_flag)
{
for (int i = 0; i < 2 * nu_subsets; i++)
{
r[i] = UnquantizeSigned(r[i], mode);
g[i] = UnquantizeSigned(g[i], mode);
b[i] = UnquantizeSigned(b[i], mode);
}
}
else
{
for (int i = 0; i < 2 * nu_subsets; i++)
{
r[i] = Unquantize(r[i], mode);
g[i] = Unquantize(g[i], mode);
b[i] = Unquantize(b[i], mode);
}
}
uint8_t subset_index[16];
for (int i = 0; i < 16; i++)
{
// subset_index[i] is a number from 0 to 1, depending on the number of subsets.
subset_index[i] = GetPartitionIndex(nu_subsets, partition_set_id, i);
}
uint8_t anchor_index[4]; // Only need max. 2 elements
for (int i = 0; i < nu_subsets; i++)
{
anchor_index[i] = GetAnchorIndex(partition_set_id, i, nu_subsets);
}
uint8_t color_index[16];
// Extract index bits.
int color_index_bit_count = 3;
if ((bitstring[0] & 3) == 3) // This defines original modes 3, 7, 11, 15
color_index_bit_count = 4;
// Because the index bits are all in the second 64-bit word, there is no need to use
// block_extract_bits().
data1 >>= (block.index - 64);
uint8_t mask1 = (1 << color_index_bit_count) - 1;
uint8_t mask2 = (1 << (color_index_bit_count - 1)) - 1;
for (int i = 0; i < 16; i++)
{
if (i == anchor_index[subset_index[i]])
{
// Highest bit is zero.
// color_index[i] = block_extract_bits(&block, color_index_bit_count - 1);
color_index[i] = data1 & mask2;
data1 >>= color_index_bit_count - 1;
}
else
{
// color_index[i] = block_extract_bits(&block, color_index_bit_count);
color_index[i] = data1 & mask1;
data1 >>= color_index_bit_count;
}
}
for (int i = 0; i < 16; i++)
{
int32_t endpoint_start_r, endpoint_start_g, endpoint_start_b;
int32_t endpoint_end_r, endpoint_end_g, endpoint_end_b;
endpoint_start_r = r[2 * subset_index[i]];
endpoint_end_r = r[2 * subset_index[i] + 1];
endpoint_start_g = g[2 * subset_index[i]];
endpoint_end_g = g[2 * subset_index[i] + 1];
endpoint_start_b = b[2 * subset_index[i]];
endpoint_end_b = b[2 * subset_index[i] + 1];
uint64_t output;
if (signed_flag)
{
int32_t r16 = InterpolateFloat(endpoint_start_r, endpoint_end_r, color_index[i], color_index_bit_count);
if (r16 < 0)
r16 = - (((- r16) * 31) >> 5);
else
r16 = (r16 * 31) >> 5;
int s = 0;
if (r16 < 0)
{
s = 0x8000;
r16 = - r16;
}
r16 |= s;
int32_t g16 = InterpolateFloat(endpoint_start_g, endpoint_end_g, color_index[i], color_index_bit_count);
if (g16 < 0)
g16 = - (((- g16) * 31) >> 5);
else
g16 = (g16 * 31) >> 5;
s = 0;
if (g16 < 0)
{
s = 0x8000;
g16 = - g16;
}
g16 |= s;
int32_t b16 = InterpolateFloat(endpoint_start_b, endpoint_end_b, color_index[i], color_index_bit_count);
if (b16 < 0)
b16 = - (((- b16) * 31) >> 5);
else
b16 = (b16 * 31) >> 5;
s = 0;
if (b16 < 0)
{
s = 0x8000;
b16 = - b16;
}
b16 |= s;
output = detexPack64RGB16(r16, g16, b16);
}
else
{
output = detexPack64R16(InterpolateFloat(endpoint_start_r, endpoint_end_r, color_index[i], color_index_bit_count) * 31 / 64);
output |= detexPack64G16(InterpolateFloat(endpoint_start_g, endpoint_end_g, color_index[i], color_index_bit_count) * 31 / 64);
output |= detexPack64B16(InterpolateFloat(endpoint_start_b, endpoint_end_b, color_index[i], color_index_bit_count) * 31 / 64);
}
*(uint64_t *)&pixel_buffer[i * 8] = output;
}
return true;
}
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 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 };
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];
}
static DETEX_INLINE_ONLY int ExtractPartitionSetID(FDetexBlock128 *block, int mode)
{
return detexBlock128ExtractBits(block, GetNumberOfPartitionBits(mode));
}
static DETEX_INLINE_ONLY int ExtractRotationBits(FDetexBlock128 *block, int mode)
{
return detexBlock128ExtractBits(block, GetNumberOfRotationBits(mode));
}
static const int8_t components_in_qword0_table[8] = { 2, -1, 1, 1, 3, 3, 3, 2 };
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];
}
/* Extract endpoint colors. */
static void ExtractEndpoints(int mode, int nu_subsets, FDetexBlock128 * 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 amask = (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 & amask;
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, FDetexBlock128 * 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;
}
}
/* Decompress a 128-bit 4x4 pixel texture block compressed using BPTC mode 1. */
static bool DecompressBlockBPTCMode1(FDetexBlock128 * 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)
{
FDetexBlock128 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;
}
/**
Decompress a 128-bit 4x4 pixel texture block compressed using the
BPTC_FLOAT (BC6H) format. The output format is
DETEX_PIXEL_FORMAT_FLOAT_RGBX16.
*/
bool detexDecompressBlockBPTC_FLOAT(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
return DecompressBlockBPTCFloatShared(bitstring, mode_mask, flags, false, pixel_buffer);
}
/**
Decompress a 128-bit 4x4 pixel texture block compressed using the
BPTC_FLOAT (BC6H_FLOAT) format. The output format is
DETEX_PIXEL_FORMAT_SIGNED_FLOAT_RGBX16.
*/
bool detexDecompressBlockBPTC_SIGNED_FLOAT(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
return DecompressBlockBPTCFloatShared(bitstring, mode_mask, flags, true, pixel_buffer);
}
//////////////////////////////////////////////////////////////////////////////////
static DETEX_INLINE_ONLY int clamp2047(int x)
{
if (x < 0)
return 0;
if (x > 2047)
return 2047;
return x;
}
static DETEX_INLINE_ONLY int clamp1023_signed(int x)
{
if (x < -1023)
return -1023;
if (x > 1023)
return 1023;
return x;
}
/** Clamp an integer value in the range -255 to 511 to the the range 0 to 255. */
static DETEX_INLINE_ONLY uint8_t detexClamp0To255(int x)
{
return detex_clamp0to255_table[x + 255];
}
// This function calculates the 3-bit complement value in the range -4 to 3 of a three bit
// representation. The result is arithmetically shifted 3 places to the left before returning.
static DETEX_INLINE_ONLY int complement3bitshifted(int x)
{
return complement3bitshifted_table[x];
}
static DETEX_INLINE_ONLY int complement3bitshifted_slow(int x)
{
if (x & 4)
return ((x & 3) - 4) << 3; // Note: shift is arithmetic.
return x << 3;
}
static DETEX_INLINE_ONLY int complement3bit(int x)
{
if (x & 4)
return ((x & 3) - 4);
return x;
}
// Define inline function to speed up ETC1 decoding.
static DETEX_INLINE_ONLY void ProcessPixelETC1(uint8_t i, uint32_t pixel_index_word, uint32_t table_codeword, int * DETEX_RESTRICT base_color_subblock, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int pixel_index = ((pixel_index_word & (1 << i)) >> i) | ((pixel_index_word & (0x10000 << i)) >> (16 + i - 1));
int r, g, b;
int modifier = modifier_table[table_codeword][pixel_index];
r = detexClamp0To255(base_color_subblock[0] + modifier);
g = detexClamp0To255(base_color_subblock[1] + modifier);
b = detexClamp0To255(base_color_subblock[2] + modifier);
uint32_t *buffer = (uint32_t *)pixel_buffer;
buffer[(i & 3) * 4 + ((i & 12) >> 2)] = detexPack32RGB8Alpha0xFF(r, g, b);
}
/* Decompress a 64-bit 4x4 pixel texture block compressed using the ETC1 */
/* format. */
bool detexDecompressBlockETC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int differential_mode = bitstring[3] & 2;
if (differential_mode)
{
if ((mode_mask & DETEX_MODE_MASK_ETC_DIFFERENTIAL) == 0)
return false;
}
else
{
if ((mode_mask & DETEX_MODE_MASK_ETC_INDIVIDUAL) == 0)
return false;
}
int flipbit = bitstring[3] & 1;
int base_color_subblock1[3];
int base_color_subblock2[3];
if (differential_mode)
{
base_color_subblock1[0] = (bitstring[0] & 0xF8);
base_color_subblock1[0] |= ((base_color_subblock1[0] & 224) >> 5);
base_color_subblock1[1] = (bitstring[1] & 0xF8);
base_color_subblock1[1] |= (base_color_subblock1[1] & 224) >> 5;
base_color_subblock1[2] = (bitstring[2] & 0xF8);
base_color_subblock1[2] |= (base_color_subblock1[2] & 224) >> 5;
base_color_subblock2[0] = (bitstring[0] & 0xF8); // 5 highest order bits.
base_color_subblock2[0] += complement3bitshifted(bitstring[0] & 7); // Add difference.
if (base_color_subblock2[0] & 0xFF07) // Check for overflow.
return false;
base_color_subblock2[0] |= (base_color_subblock2[0] & 224) >> 5; // Replicate.
base_color_subblock2[1] = (bitstring[1] & 0xF8);
base_color_subblock2[1] += complement3bitshifted(bitstring[1] & 7);
if (base_color_subblock2[1] & 0xFF07)
return false;
base_color_subblock2[1] |= (base_color_subblock2[1] & 224) >> 5;
base_color_subblock2[2] = (bitstring[2] & 0xF8);
base_color_subblock2[2] += complement3bitshifted(bitstring[2] & 7);
if (base_color_subblock2[2] & 0xFF07)
return false;
base_color_subblock2[2] |= (base_color_subblock2[2] & 224) >> 5;
}
else
{
base_color_subblock1[0] = (bitstring[0] & 0xF0);
base_color_subblock1[0] |= base_color_subblock1[0] >> 4;
base_color_subblock1[1] = (bitstring[1] & 0xF0);
base_color_subblock1[1] |= base_color_subblock1[1] >> 4;
base_color_subblock1[2] = (bitstring[2] & 0xF0);
base_color_subblock1[2] |= base_color_subblock1[2] >> 4;
base_color_subblock2[0] = (bitstring[0] & 0x0F);
base_color_subblock2[0] |= base_color_subblock2[0] << 4;
base_color_subblock2[1] = (bitstring[1] & 0x0F);
base_color_subblock2[1] |= base_color_subblock2[1] << 4;
base_color_subblock2[2] = (bitstring[2] & 0x0F);
base_color_subblock2[2] |= base_color_subblock2[2] << 4;
}
uint32_t table_codeword1 = (bitstring[3] & 224) >> 5;
uint32_t table_codeword2 = (bitstring[3] & 28) >> 2;
uint32_t pixel_index_word = ((uint32_t)bitstring[4] << 24) | ((uint32_t)bitstring[5] << 16) | ((uint32_t)bitstring[6] << 8) | bitstring[7];
if (flipbit == 0)
{
ProcessPixelETC1(0, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(1, pixel_index_word, table_codeword1,base_color_subblock1, pixel_buffer);
ProcessPixelETC1(2, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(3, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(4, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(5, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(6, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(7, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(8, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(9, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(10, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(11, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(12, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(13, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(14, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(15, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
}
else
{
ProcessPixelETC1(0, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(1, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(2, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(3, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(4, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(5, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(6, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(7, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(8, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(9, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(10, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(11, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(12, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(13, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(14, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(15, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
}
return true;
}
static const int etc2_distance_table[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
static void ProcessBlockETC2TOrHMode(const uint8_t * DETEX_RESTRICT bitstring, int mode, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int base_color1_R, base_color1_G, base_color1_B;
int base_color2_R, base_color2_G, base_color2_B;
int paint_color_R[4], paint_color_G[4], paint_color_B[4];
int distance;
if (mode == DETEX_MODE_MASK_ETC_T)
{
// T mode.
base_color1_R = ((bitstring[0] & 0x18) >> 1) | (bitstring[0] & 0x3);
base_color1_R |= base_color1_R << 4;
base_color1_G = bitstring[1] & 0xF0;
base_color1_G |= base_color1_G >> 4;
base_color1_B = bitstring[1] & 0x0F;
base_color1_B |= base_color1_B << 4;
base_color2_R = bitstring[2] & 0xF0;
base_color2_R |= base_color2_R >> 4;
base_color2_G = bitstring[2] & 0x0F;
base_color2_G |= base_color2_G << 4;
base_color2_B = bitstring[3] & 0xF0;
base_color2_B |= base_color2_B >> 4;
// index = (da << 1) | db
distance = etc2_distance_table[((bitstring[3] & 0x0C) >> 1) | (bitstring[3] & 0x1)];
paint_color_R[0] = base_color1_R;
paint_color_G[0] = base_color1_G;
paint_color_B[0] = base_color1_B;
paint_color_R[2] = base_color2_R;
paint_color_G[2] = base_color2_G;
paint_color_B[2] = base_color2_B;
paint_color_R[1] = detexClamp0To255(base_color2_R + distance);
paint_color_G[1] = detexClamp0To255(base_color2_G + distance);
paint_color_B[1] = detexClamp0To255(base_color2_B + distance);
paint_color_R[3] = detexClamp0To255(base_color2_R - distance);
paint_color_G[3] = detexClamp0To255(base_color2_G - distance);
paint_color_B[3] = detexClamp0To255(base_color2_B - distance);
}
else
{
// H mode.
base_color1_R = (bitstring[0] & 0x78) >> 3;
base_color1_R |= base_color1_R << 4;
base_color1_G = ((bitstring[0] & 0x07) << 1) | ((bitstring[1] & 0x10) >> 4);
base_color1_G |= base_color1_G << 4;
base_color1_B = (bitstring[1] & 0x08) | ((bitstring[1] & 0x03) << 1) | ((bitstring[2] & 0x80) >> 7);
base_color1_B |= base_color1_B << 4;
base_color2_R = (bitstring[2] & 0x78) >> 3;
base_color2_R |= base_color2_R << 4;
base_color2_G = ((bitstring[2] & 0x07) << 1) | ((bitstring[3] & 0x80) >> 7);
base_color2_G |= base_color2_G << 4;
base_color2_B = (bitstring[3] & 0x78) >> 3;
base_color2_B |= base_color2_B << 4;
// da is most significant bit, db is middle bit, least significant bit is
// (base_color1 value >= base_color2 value).
int base_color1_value = (base_color1_R << 16) + (base_color1_G << 8) + base_color1_B;
int base_color2_value = (base_color2_R << 16) + (base_color2_G << 8) + base_color2_B;
int bit;
if (base_color1_value >= base_color2_value)
bit = 1;
else
bit = 0;
distance = etc2_distance_table[(bitstring[3] & 0x04) | ((bitstring[3] & 0x01) << 1) | bit];
paint_color_R[0] = detexClamp0To255(base_color1_R + distance);
paint_color_G[0] = detexClamp0To255(base_color1_G + distance);
paint_color_B[0] = detexClamp0To255(base_color1_B + distance);
paint_color_R[1] = detexClamp0To255(base_color1_R - distance);
paint_color_G[1] = detexClamp0To255(base_color1_G - distance);
paint_color_B[1] = detexClamp0To255(base_color1_B - distance);
paint_color_R[2] = detexClamp0To255(base_color2_R + distance);
paint_color_G[2] = detexClamp0To255(base_color2_G + distance);
paint_color_B[2] = detexClamp0To255(base_color2_B + distance);
paint_color_R[3] = detexClamp0To255(base_color2_R - distance);
paint_color_G[3] = detexClamp0To255(base_color2_G - distance);
paint_color_B[3] = detexClamp0To255(base_color2_B - distance);
}
uint32_t pixel_index_word = ((uint32_t)bitstring[4] << 24) | ((uint32_t)bitstring[5] << 16) | ((uint32_t)bitstring[6] << 8) | bitstring[7];
uint32_t *buffer = (uint32_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
int pixel_index = ((pixel_index_word & (1 << i)) >> i) | ((pixel_index_word & (0x10000 << i)) >> (16 + i - 1));
int r = paint_color_R[pixel_index];
int g = paint_color_G[pixel_index];
int b = paint_color_B[pixel_index];
buffer[(i & 3) * 4 + ((i & 12) >> 2)] = detexPack32RGB8Alpha0xFF(r, g, b);
}
}
static void ProcessBlockETC2PlanarMode(const uint8_t * DETEX_RESTRICT bitstring, uint8_t * DETEX_RESTRICT pixel_buffer)
{
// Each color O, H and V is in 6-7-6 format.
int RO = (bitstring[0] & 0x7E) >> 1;
int GO = ((bitstring[0] & 0x1) << 6) | ((bitstring[1] & 0x7E) >> 1);
int BO = ((bitstring[1] & 0x1) << 5) | (bitstring[2] & 0x18) | ((bitstring[2] & 0x03) << 1) | ((bitstring[3] & 0x80) >> 7);
int RH = ((bitstring[3] & 0x7C) >> 1) | (bitstring[3] & 0x1);
int GH = (bitstring[4] & 0xFE) >> 1;
int BH = ((bitstring[4] & 0x1) << 5) | ((bitstring[5] & 0xF8) >> 3);
int RV = ((bitstring[5] & 0x7) << 3) | ((bitstring[6] & 0xE0) >> 5);
int GV = ((bitstring[6] & 0x1F) << 2) | ((bitstring[7] & 0xC0) >> 6);
int BV = bitstring[7] & 0x3F;
RO = (RO << 2) | ((RO & 0x30) >> 4); // Replicate bits.
GO = (GO << 1) | ((GO & 0x40) >> 6);
BO = (BO << 2) | ((BO & 0x30) >> 4);
RH = (RH << 2) | ((RH & 0x30) >> 4);
GH = (GH << 1) | ((GH & 0x40) >> 6);
BH = (BH << 2) | ((BH & 0x30) >> 4);
RV = (RV << 2) | ((RV & 0x30) >> 4);
GV = (GV << 1) | ((GV & 0x40) >> 6);
BV = (BV << 2) | ((BV & 0x30) >> 4);
uint32_t *buffer = (uint32_t *)pixel_buffer;
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
int r = detexClamp0To255((x * (RH - RO) + y * (RV - RO) + 4 * RO + 2) >> 2);
int g = detexClamp0To255((x * (GH - GO) + y * (GV - GO) + 4 * GO + 2) >> 2);
int b = detexClamp0To255((x * (BH - BO) + y * (BV - BO) + 4 * BO + 2) >> 2);
buffer[y * 4 + x] = detexPack32RGB8Alpha0xFF(r, g, b);
}
}
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the ETC2 format. */
bool detexDecompressBlockETC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
// Figure out the mode.
if ((bitstring[3] & 2) == 0)
{
// Individual mode.
return detexDecompressBlockETC1(bitstring, mode_mask, flags, pixel_buffer);
}
if ((mode_mask & (~DETEX_MODE_MASK_ETC_INDIVIDUAL)) == 0)
return false;
int R = (bitstring[0] & 0xF8);
R += complement3bitshifted(bitstring[0] & 7);
int G = (bitstring[1] & 0xF8);
G += complement3bitshifted(bitstring[1] & 7);
int B = (bitstring[2] & 0xF8);
B += complement3bitshifted(bitstring[2] & 7);
if (R & 0xFF07)
{
// T mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_T) == 0)
return false;
ProcessBlockETC2TOrHMode(bitstring, DETEX_MODE_MASK_ETC_T, pixel_buffer);
return true;
}
else if (G & 0xFF07)
{
// H mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_H) == 0)
return false;
ProcessBlockETC2TOrHMode(bitstring, DETEX_MODE_MASK_ETC_H,
pixel_buffer);
return true;
}
else if (B & 0xFF07)
{
// Planar mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_PLANAR) == 0)
return false;
ProcessBlockETC2PlanarMode(bitstring, pixel_buffer);
return true;
}
else
{
// Differential mode.
return detexDecompressBlockETC1(bitstring, mode_mask, flags, pixel_buffer);
}
}
static const int punchthrough_modifier_table[8][4] = {
{ 0, 8, 0, -8 },
{ 0, 17, 0, -17 },
{ 0, 29, 0, -29 },
{ 0, 42, 0, -42 },
{ 0, 60, 0, -60 },
{ 0, 80, 0, -80 },
{ 0, 106, 0, -106 },
{ 0, 183, 0, -183 }
};
static const uint32_t punchthrough_mask_table[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF };
static DETEX_INLINE_ONLY void ProcessPixelETC2Punchthrough(uint8_t i, uint32_t pixel_index_word, uint32_t table_codeword, int * DETEX_RESTRICT base_color_subblock, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int pixel_index = ((pixel_index_word & (1 << i)) >> i) | ((pixel_index_word & (0x10000 << i)) >> (16 + i - 1));
int r, g, b;
int modifier = punchthrough_modifier_table[table_codeword][pixel_index];
r = detexClamp0To255(base_color_subblock[0] + modifier);
g = detexClamp0To255(base_color_subblock[1] + modifier);
b = detexClamp0To255(base_color_subblock[2] + modifier);
uint32_t mask = punchthrough_mask_table[pixel_index];
uint32_t *buffer = (uint32_t *)pixel_buffer;
buffer[(i & 3) * 4 + ((i & 12) >> 2)] = detexPack32RGB8Alpha0xFF(r, g, b) & mask;
}
void ProcessBlockETC2PunchthroughDifferentialMode(const uint8_t * DETEX_RESTRICT bitstring, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int flipbit = bitstring[3] & 1;
int base_color_subblock1[3];
int base_color_subblock2[3];
base_color_subblock1[0] = (bitstring[0] & 0xF8);
base_color_subblock1[0] |= ((base_color_subblock1[0] & 224) >> 5);
base_color_subblock1[1] = (bitstring[1] & 0xF8);
base_color_subblock1[1] |= (base_color_subblock1[1] & 224) >> 5;
base_color_subblock1[2] = (bitstring[2] & 0xF8);
base_color_subblock1[2] |= (base_color_subblock1[2] & 224) >> 5;
base_color_subblock2[0] = (bitstring[0] & 0xF8); // 5 highest order bits.
base_color_subblock2[0] += complement3bitshifted(bitstring[0] & 7); // Add difference.
base_color_subblock2[0] |= (base_color_subblock2[0] & 224) >> 5; // Replicate.
base_color_subblock2[1] = (bitstring[1] & 0xF8);
base_color_subblock2[1] += complement3bitshifted(bitstring[1] & 7);
base_color_subblock2[1] |= (base_color_subblock2[1] & 224) >> 5;
base_color_subblock2[2] = (bitstring[2] & 0xF8);
base_color_subblock2[2] += complement3bitshifted(bitstring[2] & 7);
base_color_subblock2[2] |= (base_color_subblock2[2] & 224) >> 5;
uint32_t table_codeword1 = (bitstring[3] & 224) >> 5;
uint32_t table_codeword2 = (bitstring[3] & 28) >> 2;
uint32_t pixel_index_word = ((uint32_t)bitstring[4] << 24) | ((uint32_t)bitstring[5] << 16) | ((uint32_t)bitstring[6] << 8) | bitstring[7];
if (flipbit == 0)
{
ProcessPixelETC2Punchthrough(0, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(1, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(2, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(3, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(4, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(5, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(6, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(7, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(8, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(9, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(10, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(11, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(12, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(13, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(14, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(15, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
}
else
{
ProcessPixelETC2Punchthrough(0, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(1, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(2, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(3, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(4, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(5, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(6, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(7, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(8, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(9, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(10, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(11, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(12, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(13, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(14, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(15, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
}
}
static void ProcessBlockETC2PunchthroughTOrHMode(const uint8_t * DETEX_RESTRICT bitstring, int mode, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int base_color1_R, base_color1_G, base_color1_B;
int base_color2_R, base_color2_G, base_color2_B;
int paint_color_R[4], paint_color_G[4], paint_color_B[4];
int distance;
if (mode == DETEX_MODE_MASK_ETC_T)
{
// T mode.
base_color1_R = ((bitstring[0] & 0x18) >> 1) | (bitstring[0] & 0x3);
base_color1_R |= base_color1_R << 4;
base_color1_G = bitstring[1] & 0xF0;
base_color1_G |= base_color1_G >> 4;
base_color1_B = bitstring[1] & 0x0F;
base_color1_B |= base_color1_B << 4;
base_color2_R = bitstring[2] & 0xF0;
base_color2_R |= base_color2_R >> 4;
base_color2_G = bitstring[2] & 0x0F;
base_color2_G |= base_color2_G << 4;
base_color2_B = bitstring[3] & 0xF0;
base_color2_B |= base_color2_B >> 4;
// index = (da << 1) | db
distance = etc2_distance_table[((bitstring[3] & 0x0C) >> 1) | (bitstring[3] & 0x1)];
paint_color_R[0] = base_color1_R;
paint_color_G[0] = base_color1_G;
paint_color_B[0] = base_color1_B;
paint_color_R[2] = base_color2_R;
paint_color_G[2] = base_color2_G;
paint_color_B[2] = base_color2_B;
paint_color_R[1] = detexClamp0To255(base_color2_R + distance);
paint_color_G[1] = detexClamp0To255(base_color2_G + distance);
paint_color_B[1] = detexClamp0To255(base_color2_B + distance);
paint_color_R[3] = detexClamp0To255(base_color2_R - distance);
paint_color_G[3] = detexClamp0To255(base_color2_G - distance);
paint_color_B[3] = detexClamp0To255(base_color2_B - distance);
}
else
{
// H mode.
base_color1_R = (bitstring[0] & 0x78) >> 3;
base_color1_R |= base_color1_R << 4;
base_color1_G = ((bitstring[0] & 0x07) << 1) | ((bitstring[1] & 0x10) >> 4);
base_color1_G |= base_color1_G << 4;
base_color1_B = (bitstring[1] & 0x08) | ((bitstring[1] & 0x03) << 1) | ((bitstring[2] & 0x80) >> 7);
base_color1_B |= base_color1_B << 4;
base_color2_R = (bitstring[2] & 0x78) >> 3;
base_color2_R |= base_color2_R << 4;
base_color2_G = ((bitstring[2] & 0x07) << 1) | ((bitstring[3] & 0x80) >> 7);
base_color2_G |= base_color2_G << 4;
base_color2_B = (bitstring[3] & 0x78) >> 3;
base_color2_B |= base_color2_B << 4;
// da is most significant bit, db is middle bit, least significant bit is
// (base_color1 value >= base_color2 value).
int base_color1_value = (base_color1_R << 16) + (base_color1_G << 8) + base_color1_B;
int base_color2_value = (base_color2_R << 16) + (base_color2_G << 8) + base_color2_B;
int bit;
if (base_color1_value >= base_color2_value)
bit = 1;
else
bit = 0;
distance = etc2_distance_table[(bitstring[3] & 0x04) | ((bitstring[3] & 0x01) << 1) | bit];
paint_color_R[0] = detexClamp0To255(base_color1_R + distance);
paint_color_G[0] = detexClamp0To255(base_color1_G + distance);
paint_color_B[0] = detexClamp0To255(base_color1_B + distance);
paint_color_R[1] = detexClamp0To255(base_color1_R - distance);
paint_color_G[1] = detexClamp0To255(base_color1_G - distance);
paint_color_B[1] = detexClamp0To255(base_color1_B - distance);
paint_color_R[2] = detexClamp0To255(base_color2_R + distance);
paint_color_G[2] = detexClamp0To255(base_color2_G + distance);
paint_color_B[2] = detexClamp0To255(base_color2_B + distance);
paint_color_R[3] = detexClamp0To255(base_color2_R - distance);
paint_color_G[3] = detexClamp0To255(base_color2_G - distance);
paint_color_B[3] = detexClamp0To255(base_color2_B - distance);
}
uint32_t pixel_index_word = ((uint32_t)bitstring[4] << 24) | ((uint32_t)bitstring[5] << 16) | ((uint32_t)bitstring[6] << 8) | bitstring[7];
uint32_t *buffer = (uint32_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
int pixel_index = ((pixel_index_word & (1 << i)) >> i) | ((pixel_index_word & (0x10000 << i)) >> (16 + i - 1));
int r = paint_color_R[pixel_index];
int g = paint_color_G[pixel_index];
int b = paint_color_B[pixel_index];
uint32_t mask = punchthrough_mask_table[pixel_index];
buffer[(i & 3) * 4 + ((i & 12) >> 2)] = (detexPack32RGB8Alpha0xFF(r, g, b)) & mask;
}
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the ETC2_PUNCHTROUGH format. */
bool detexDecompressBlockETC2_PUNCHTHROUGH(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int R = (bitstring[0] & 0xF8);
R += complement3bitshifted(bitstring[0] & 7);
int G = (bitstring[1] & 0xF8);
G += complement3bitshifted(bitstring[1] & 7);
int B = (bitstring[2] & 0xF8);
B += complement3bitshifted(bitstring[2] & 7);
int opaque = bitstring[3] & 2;
if (opaque && (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY))
return false;
if (!opaque && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY))
return false;
if (R & 0xFF07)
{
// T mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_T) == 0)
return false;
if (opaque)
{
ProcessBlockETC2TOrHMode(bitstring, DETEX_MODE_MASK_ETC_T, pixel_buffer);
return true;
}
// T mode with punchthrough alpha.
ProcessBlockETC2PunchthroughTOrHMode(bitstring, DETEX_MODE_MASK_ETC_T, pixel_buffer);
return true;
}
else if (G & 0xFF07)
{
// H mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_H) == 0)
return false;
if (opaque)
{
ProcessBlockETC2TOrHMode(bitstring, DETEX_MODE_MASK_ETC_H, pixel_buffer);
return true;
}
// H mode with punchthrough alpha.
ProcessBlockETC2PunchthroughTOrHMode(bitstring, DETEX_MODE_MASK_ETC_H, pixel_buffer);
return true;
}
else if (B & 0xFF07)
{
// Planar mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_PLANAR) == 0)
return false;
// Opaque always set.
if (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY)
return false;
ProcessBlockETC2PlanarMode(bitstring, pixel_buffer);
return true;
}
else
{
// Differential mode.
if (opaque)
return detexDecompressBlockETC1(bitstring, mode_mask, flags, pixel_buffer);
// Differential mode with punchthrough alpha.
if ((mode_mask & DETEX_MODE_MASK_ETC_DIFFERENTIAL) == 0)
return false;
ProcessBlockETC2PunchthroughDifferentialMode(bitstring, pixel_buffer);
return true;
}
}
static const int8_t eac_modifier_table[16][8] = {
{ -3, -6, -9, -15, 2, 5, 8, 14 },
{ -3, -7, -10, -13, 2, 6, 9, 12 },
{ -2, -5, -8, -13, 1, 4, 7, 12 },
{ -2, -4, -6, -13, 1, 3, 5, 12 },
{ -3, -6, -8, -12, 2, 5, 7, 11 },
{ -3, -7, -9, -11, 2, 6, 8, 10 },
{ -4, -7, -8, -11, 3, 6, 7, 10 },
{ -3, -5, -8, -11, 2, 4, 7, 10 },
{ -2, -6, -8, -10, 1, 5, 7, 9 },
{ -2, -5, -8, -10, 1, 4, 7, 9 },
{ -2, -4, -8, -10, 1, 3, 7, 9 },
{ -2, -5, -7, -10, 1, 4, 6, 9 },
{ -3, -4, -7, -10, 2, 3, 6, 9 },
{ -1, -2, -3, -10, 0, 1, 2, 9 },
{ -4, -6, -8, -9, 3, 5, 7, 8 },
{ -3, -5, -7, -9, 2, 4, 6, 8 }
};
static DETEX_INLINE_ONLY int modifier_times_multiplier(int modifier, int multiplier)
{
return modifier * multiplier;
}
static DETEX_INLINE_ONLY void ProcessPixelEAC(uint8_t i, uint64_t pixels, const int8_t * DETEX_RESTRICT _modifier_table, int base_codeword, int multiplier, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int modifier = _modifier_table[(pixels >> (45 - i * 3)) & 7];
pixel_buffer[((i & 3) * 4 + ((i & 12) >> 2)) * 4 + DETEX_PIXEL32_ALPHA_BYTE_OFFSET] = detexClamp0To255(base_codeword + modifier_times_multiplier(modifier, multiplier));
}
/** Decompress a 128-bit 4x4 pixel texture block compressed using the ETC2_EAC format. */
bool detexDecompressBlockETC2_EAC(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
bool r = detexDecompressBlockETC2(&bitstring[8], mode_mask, flags, pixel_buffer);
if (!r)
return false;
// Decode the alpha part.
int base_codeword = bitstring[0];
const int8_t *_modifier_table = eac_modifier_table[(bitstring[1] & 0x0F)];
int multiplier = (bitstring[1] & 0xF0) >> 4;
if (multiplier == 0 && (flags & DETEX_DECOMPRESS_FLAG_ENCODE))
// Not allowed in encoding. Decoder should handle it.
return false;
uint64_t pixels = ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
ProcessPixelEAC(0, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(1, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(2, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(3, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(4, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(5, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(6, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(7, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(8, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(9, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(10, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(11, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(12, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(13, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(14, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(15, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
return true;
}
/**
For each pixel, decode an 11-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.
*/
static DETEX_INLINE_ONLY void DecodeBlockEAC11Bit(uint64_t qword, int shift, int offset, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int base_codeword_times_8_plus_4 = ((qword & 0xFF00000000000000) >> (56 - 3)) | 0x4;
int modifier_index = (qword & 0x000F000000000000) >> 48;
const int8_t *_modifier_table = eac_modifier_table[modifier_index];
int multiplier_times_8 = (qword & 0x00F0000000000000) >> (52 - 3);
if (multiplier_times_8 == 0)
multiplier_times_8 = 1;
uint16_t *buffer = (uint16_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
int pixel_index = (qword & (0x0000E00000000000 >> (i * 3))) >> (45 - i * 3);
int modifier = _modifier_table[pixel_index];
uint32_t value = clamp2047(base_codeword_times_8_plus_4 + modifier * multiplier_times_8);
buffer[(((i & 3) * 4 + ((i & 12) >> 2)) << shift) + offset] = (value << 5) | (value >> 6); // Replicate bits to 16-bit.
}
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using theEAC_R11 format. */
bool detexDecompressBlockEAC_R11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
uint64_t qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
DecodeBlockEAC11Bit(qword, 0, 0, pixel_buffer);
return true;
}
/** Decompress a 128-bit 4x4 pixel texture block compressed using the EAC_RG11 format. */
bool detexDecompressBlockEAC_RG11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
uint64_t red_qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
DecodeBlockEAC11Bit(red_qword, 1, 0, pixel_buffer);
uint64_t green_qword = ((uint64_t)bitstring[8] << 56) | ((uint64_t)bitstring[9] << 48) | ((uint64_t)bitstring[10] << 40) | ((uint64_t)bitstring[11] << 32) | ((uint64_t)bitstring[12] << 24) | ((uint64_t)bitstring[13] << 16) | ((uint64_t)bitstring[14] << 8) | bitstring[15];
DecodeBlockEAC11Bit(green_qword, 1, 1, pixel_buffer);
return true;
}
static DETEX_INLINE_ONLY uint32_t ReplicateSigned11BitsTo16Bits(int value)
{
if (value >= 0)
return (value << 5) | (value >> 5);
value = - value;
value = (value << 5) | (value >> 5);
return - value;
}
/**
For each pixel, decode an 11-bit signed 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.
*/
static DETEX_INLINE_ONLY bool DecodeBlockEACSigned11Bit(uint64_t qword, int shift, int offset, uint8_t *pixel_buffer)
{
int base_codeword = (int8_t)((qword & 0xFF00000000000000) >> 56); // Signed 8 bits.
if (base_codeword == - 128)
// Not allowed in encoding. Decoder should handle it but we don't do that yet.
return false;
int base_codeword_times_8 = base_codeword << 3; // Arithmetic shift.
int modifier_index = (qword & 0x000F000000000000) >> 48;
const int8_t *_modifier_table = eac_modifier_table[modifier_index];
int multiplier_times_8 = (qword & 0x00F0000000000000) >> (52 - 3);
if (multiplier_times_8 == 0)
multiplier_times_8 = 1;
uint16_t *buffer = (uint16_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
int pixel_index = (qword & (0x0000E00000000000 >> (i * 3))) >> (45 - i * 3);
int modifier = _modifier_table[pixel_index];
int value = clamp1023_signed(base_codeword_times_8 + modifier * multiplier_times_8);
uint32_t bits = ReplicateSigned11BitsTo16Bits(value);
buffer[(((i & 3) * 4 + ((i & 12) >> 2)) << shift) + offset] = bits;
}
return true;
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the EAC_SIGNED_R11 format. */
bool detexDecompressBlockEAC_SIGNED_R11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
uint64_t qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
return DecodeBlockEACSigned11Bit(qword, 0, 0, pixel_buffer);
}
/** Decompress a 128-bit 4x4 pixel texture block compressed using the EAC_SIGNED_RG11 format. */
bool detexDecompressBlockEAC_SIGNED_RG11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
uint64_t red_qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
int r = DecodeBlockEACSigned11Bit(red_qword, 1, 0, pixel_buffer);
if (!r)
return false;
uint64_t green_qword = ((uint64_t)bitstring[8] << 56) | ((uint64_t)bitstring[9] << 48) | ((uint64_t)bitstring[10] << 40) | ((uint64_t)bitstring[11] << 32) | ((uint64_t)bitstring[12] << 24) | ((uint64_t)bitstring[13] << 16) | ((uint64_t)bitstring[14] << 8) | bitstring[15];
return DecodeBlockEACSigned11Bit(green_qword, 1, 1, pixel_buffer);
}
static detexDecompressBlockFuncType decompress_function[] =
{
NULL,
detexDecompressBlockBC1,
detexDecompressBlockBC1A,
detexDecompressBlockBC2,
detexDecompressBlockBC3,
detexDecompressBlockRGTC1,
detexDecompressBlockSIGNED_RGTC1,
detexDecompressBlockRGTC2,
detexDecompressBlockSIGNED_RGTC2,
detexDecompressBlockBPTC_FLOAT,
detexDecompressBlockBPTC_SIGNED_FLOAT,
detexDecompressBlockBPTC,
detexDecompressBlockETC1,
detexDecompressBlockETC2,
detexDecompressBlockETC2_PUNCHTHROUGH,
detexDecompressBlockETC2_EAC,
detexDecompressBlockEAC_R11,
detexDecompressBlockEAC_SIGNED_R11,
detexDecompressBlockEAC_RG11,
detexDecompressBlockEAC_SIGNED_RG11,
};
/**
General block decompression function. Block is decompressed using the given
compressed format, and stored in the given pixel format. Returns true if
succesful.
*/
bool detexDecompressBlock(const uint8_t * DETEX_RESTRICT bitstring, uint32_t texture_format, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer, uint32_t pixel_format)
{
uint8_t block_buffer[DETEX_MAX_BLOCK_SIZE];
uint32_t compressed_format = detexGetCompressedFormat(texture_format);
bool r = decompress_function[compressed_format](bitstring, mode_mask, flags,
block_buffer);
if (!r)
{
detexSetErrorMessage("detexDecompressBlock: Decompress function for format returned error");
return false;
}
/* Convert into desired pixel format. */
return detexConvertPixels(block_buffer, 16, detexGetPixelFormat(texture_format), pixel_buffer, pixel_format);
}
// Look-up texture file info for KTX file format based on GL format parameters.
const detexTextureFileInfo *detexLookupKTXFileInfo(int gl_internal_format)
{
for (int i = 0; i < DETEX_NU_TEXTURE_INFO_ENTRIES; i++)
{
if (texture_info[i].gl_internal_format == gl_internal_format)
{
return &texture_info[i];
}
}
return NULL;
}
/*
* Decode texture function (linear). Decode an entire texture into a single
* image buffer, with pixels stored row-by-row, converting into the given pixel
* format.
*/
bool detexDecompressTextureLinear(const FDetexTexture *texture, uint8_t *pixel_buffer, uint32_t pixel_format)
{
uint8_t block_buffer[DETEX_MAX_BLOCK_SIZE];
const uint8_t *data = texture->data;
int pixel_size = detexGetPixelSize(pixel_format);
bool result = true;
for (int y = 0; y < texture->height_in_blocks; y++)
{
int nu_rows;
if (y * 4 + 3 >= texture->height)
{
nu_rows = texture->height - y * 4;
}
else
{
nu_rows = 4;
}
for (int x = 0; x < texture->width_in_blocks; x++)
{
bool r = detexDecompressBlock(data, texture->format, DETEX_MODE_MASK_ALL, 0, block_buffer, pixel_format);
uint32_t block_size = detexGetPixelSize(pixel_format) * 16;
if (!r)
{
result = false;
memset(block_buffer, 0, block_size);
}
uint8_t *pixelp = pixel_buffer + y * 4 * texture->width * pixel_size + x * 4 * pixel_size;
int nu_columns;
if (x * 4 + 3 >= texture->width)
{
nu_columns = texture->width - x * 4;
}
else
{
nu_columns = 4;
}
for (int row = 0; row < nu_rows; row++)
{
memcpy(pixelp + row * texture->width * pixel_size, block_buffer + row * 4 * pixel_size, nu_columns * pixel_size);
}
data += detexGetCompressedBlockSize(texture->format);
}
}
return result;
}
bool DecompressTexture(uint8_t *data, const uint32_t SizeX, const uint32_t SizeY, uint32_t InternalFormat, uint8_t **decompressedData)
{
FDetexTexture dexTexture;
dexTexture.data = data;
dexTexture.width = SizeX;
dexTexture.height = SizeY;
const int32 BlockSizeX = 4;
const int32 BlockSizeY = 4;
dexTexture.width_in_blocks = FMath::Max(SizeX / BlockSizeX, (uint32_t)1);
dexTexture.height_in_blocks = FMath::Max(SizeY / BlockSizeY, (uint32_t)1);
const detexTextureFileInfo *DetexTFI = detexLookupKTXFileInfo(InternalFormat);
uint32_t pixel_format = detexGetPixelFormat(DetexTFI->texture_format);
dexTexture.format = DetexTFI->texture_format;
uint32_t decompressSize = SizeX * SizeY * detexGetPixelSize(pixel_format);
(*decompressedData) = (uint8_t *)malloc(decompressSize);
return detexDecompressTextureLinear(&dexTexture, *decompressedData, pixel_format);
}