godot/thirdparty/basis_universal/transcoder/basisu_transcoder.cpp

// basisu_transcoder.cpp
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "basisu_transcoder.h"
#include <limits.h>
#include "basisu_containers_impl.h"

#ifndef BASISD_IS_BIG_ENDIAN
// TODO: This doesn't work on OSX. How can this be so difficult?
//#if defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) || defined(BIG_ENDIAN)
//	#define BASISD_IS_BIG_ENDIAN (1)
//#else
	#define BASISD_IS_BIG_ENDIAN
//#endif
#endif

#ifndef BASISD_USE_UNALIGNED_WORD_READS
	#ifdef __EMSCRIPTEN__
		// Can't use unaligned loads/stores with WebAssembly.
		#define BASISD_USE_UNALIGNED_WORD_READS
	#elif defined(_M_AMD64) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)
		#define BASISD_USE_UNALIGNED_WORD_READS
	#else
		#define BASISD_USE_UNALIGNED_WORD_READS
	#endif
#endif

// Using unaligned loads and stores causes errors when using UBSan. Jam it off.
#if defined(__has_feature)
#if __has_feature(undefined_behavior_sanitizer)
#undef BASISD_USE_UNALIGNED_WORD_READS
#define BASISD_USE_UNALIGNED_WORD_READS
#endif
#endif

#define BASISD_SUPPORTED_BASIS_VERSION

#ifndef BASISD_SUPPORT_KTX2
	#error Must have defined BASISD_SUPPORT_KTX2
#endif

#ifndef BASISD_SUPPORT_KTX2_ZSTD
#error Must have defined BASISD_SUPPORT_KTX2_ZSTD
#endif

// Set to 1 for fuzz testing. This will disable all CRC16 checks on headers and compressed data.
#ifndef BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS
	#define BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS
#endif

#ifndef BASISD_SUPPORT_DXT1
	#define BASISD_SUPPORT_DXT1
#endif

#ifndef BASISD_SUPPORT_DXT5A
	#define BASISD_SUPPORT_DXT5A
#endif

// Disable all BC7 transcoders if necessary (useful when cross compiling to Javascript)
#if defined(BASISD_SUPPORT_BC7) && !BASISD_SUPPORT_BC7
	#ifndef BASISD_SUPPORT_BC7_MODE5
		#define BASISD_SUPPORT_BC7_MODE5
	#endif
#endif // !BASISD_SUPPORT_BC7

// BC7 mode 5 supports both opaque and opaque+alpha textures, and uses less memory BC1.
#ifndef BASISD_SUPPORT_BC7_MODE5
	#define BASISD_SUPPORT_BC7_MODE5
#endif

#ifndef BASISD_SUPPORT_PVRTC1
	#define BASISD_SUPPORT_PVRTC1
#endif

#ifndef BASISD_SUPPORT_ETC2_EAC_A8
	#define BASISD_SUPPORT_ETC2_EAC_A8
#endif

// Set BASISD_SUPPORT_UASTC to 0 to completely disable support for transcoding UASTC files.
#ifndef BASISD_SUPPORT_UASTC
	#define BASISD_SUPPORT_UASTC
#endif

#ifndef BASISD_SUPPORT_ASTC
	#define BASISD_SUPPORT_ASTC
#endif

// Note that if BASISD_SUPPORT_ATC is enabled, BASISD_SUPPORT_DXT5A should also be enabled for alpha support.
#ifndef BASISD_SUPPORT_ATC
	#define BASISD_SUPPORT_ATC
#endif

// Support for ETC2 EAC R11 and ETC2 EAC RG11
#ifndef BASISD_SUPPORT_ETC2_EAC_RG11
	#define BASISD_SUPPORT_ETC2_EAC_RG11
#endif

// If BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY is 1, opaque blocks will be transcoded to ASTC at slightly higher quality (higher than BC1), but the transcoder tables will be 2x as large.
// This impacts grayscale and grayscale+alpha textures the most.
#ifndef BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY
	#ifdef __EMSCRIPTEN__
		// Let's assume size matters more than quality when compiling with emscripten.
		#define BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY
	#else
		// Compiling native, so an extra 64K lookup table is probably acceptable.
		#define BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY
	#endif
#endif

#ifndef BASISD_SUPPORT_FXT1
	#define BASISD_SUPPORT_FXT1
#endif

#ifndef BASISD_SUPPORT_PVRTC2
	#define BASISD_SUPPORT_PVRTC2
#endif

#if BASISD_SUPPORT_PVRTC2
	#if !BASISD_SUPPORT_ATC
		#error BASISD_SUPPORT_ATC must be 1 if BASISD_SUPPORT_PVRTC2 is 1
	#endif
#endif

#if BASISD_SUPPORT_ATC
	#if !BASISD_SUPPORT_DXT5A
		#error BASISD_SUPPORT_DXT5A must be 1 if BASISD_SUPPORT_ATC is 1
	#endif
#endif

#define BASISD_WRITE_NEW_BC7_MODE5_TABLES
#define BASISD_WRITE_NEW_DXT1_TABLES
#define BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES
#define BASISD_WRITE_NEW_ASTC_TABLES
#define BASISD_WRITE_NEW_ATC_TABLES
#define BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES

#ifndef BASISD_ENABLE_DEBUG_FLAGS
	#define BASISD_ENABLE_DEBUG_FLAGS
#endif

// If KTX2 support is enabled, we may need Zstd for decompression of supercompressed UASTC files. Include this header.
#if BASISD_SUPPORT_KTX2
   // If BASISD_SUPPORT_KTX2_ZSTD is 0, UASTC files compressed with Zstd cannot be loaded.
	#if BASISD_SUPPORT_KTX2_ZSTD
		// We only use two Zstd API's: ZSTD_decompress() and ZSTD_isError()
		#include <zstd.h>
	#endif
#endif

namespace basisu
{
	bool g_debug_printf;

	void enable_debug_printf(bool enabled)
	{}

	void debug_printf(const char* pFmt, ...)
	{}
} // namespace basisu

namespace basist
{

#if BASISD_ENABLE_DEBUG_FLAGS
	static uint32_t g_debug_flags = 0;
#endif

	uint32_t get_debug_flags()
	{}

	void set_debug_flags(uint32_t f)
	{}

	inline uint16_t byteswap_uint16(uint16_t v)
	{}

	static inline int32_t clampi(int32_t value, int32_t low, int32_t high) {}
	static inline float clampf(float value, float low, float high) {}
	static inline float saturate(float value) {}

	static inline uint8_t mul_8(uint32_t v, uint32_t q) {}

	uint16_t crc16(const void* r, size_t size, uint16_t crc)
	{}
		
	enum etc_constants
	{};

#define DECLARE_ETC1_INTEN_TABLE(name, N)

	DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables, 1);
	DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables16, 16);
	DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables48, 3 * 16);

	//const uint8_t g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };
	const uint8_t g_selector_index_to_etc1[cETC1SelectorValues] =;
	
	static const uint8_t g_etc_5_to_8[32] =;

	struct decoder_etc_block
	{};

	enum dxt_constants
	{};

	static const uint8_t g_etc1_x_selector_unpack[4][256] =;

	struct dxt1_block
	{};

	struct dxt_selector_range
	{};

	struct etc1_to_dxt1_56_solution
	{};

#if BASISD_SUPPORT_DXT1
	static dxt_selector_range g_etc1_to_dxt1_selector_ranges[] =;

	const uint32_t NUM_ETC1_TO_DXT1_SELECTOR_RANGES =;

	static uint32_t g_etc1_to_dxt1_selector_range_index[4][4];

	const uint32_t NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS =;
	static const uint8_t g_etc1_to_dxt1_selector_mappings[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][4] =;
	
	static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256];
	static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_inv_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256];

	static const etc1_to_dxt1_56_solution g_etc1_to_dxt_6[32 * 8 * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS * NUM_ETC1_TO_DXT1_SELECTOR_RANGES] =;

	static const etc1_to_dxt1_56_solution g_etc1_to_dxt_5[32 * 8 * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS * NUM_ETC1_TO_DXT1_SELECTOR_RANGES] =;
#endif // BASISD_SUPPORT_DXT1

#if BASISD_SUPPORT_DXT1 || BASISD_SUPPORT_UASTC
	// First saw the idea for optimal BC1 single-color block encoding using lookup tables in ryg_dxt.
	struct bc1_match_entry
	{};
	static bc1_match_entry g_bc1_match5_equals_1[256], g_bc1_match6_equals_1[256]; // selector 1, allow equals hi/lo
	static bc1_match_entry g_bc1_match5_equals_0[256], g_bc1_match6_equals_0[256]; // selector 0, allow equals hi/lo

	static void prepare_bc1_single_color_table(bc1_match_entry* pTable, const uint8_t* pExpand, int size0, int size1, int sel)
	{}
#endif

#if BASISD_WRITE_NEW_DXT1_TABLES
	static void create_etc1_to_dxt1_5_conversion_table()
	{
		FILE* pFile = nullptr;
		fopen_s(&pFile, "basisu_transcoder_tables_dxt1_5.inc", "w");

		uint32_t n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1_TO_DXT1_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1_to_dxt1_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1_to_dxt1_selector_ranges[sr].m_high;

					for (uint32_t m = 0; m < NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 31; hi++)
						{
							for (uint32_t lo = 0; lo <= 31; lo++)
							{
								//if (lo == hi) continue;

								uint32_t colors[4];

								colors[0] = (lo << 3) | (lo >> 2);
								colors[3] = (hi << 3) | (hi >> 2);

								colors[1] = (colors[0] * 2 + colors[3]) / 3;
								colors[2] = (colors[3] * 2 + colors[0]) / 3;

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1_to_dxt1_selector_mappings[m][s]];

									total_err += err * err;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						assert(best_err <= 0xFFFF);

						//table[g + inten * 32].m_solutions[sr][m].m_lo = static_cast<uint8_t>(best_lo);
						//table[g + inten * 32].m_solutions[sr][m].m_hi = static_cast<uint8_t>(best_hi);
						//table[g + inten * 32].m_solutions[sr][m].m_err = static_cast<uint16_t>(best_err);

						//assert(best_lo != best_hi);
						fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m
				} // sr
			} // g
		} // inten

		fclose(pFile);
	}

	static void create_etc1_to_dxt1_6_conversion_table()
	{
		FILE* pFile = nullptr;
		fopen_s(&pFile, "basisu_transcoder_tables_dxt1_6.inc", "w");

		uint32_t n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1_TO_DXT1_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1_to_dxt1_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1_to_dxt1_selector_ranges[sr].m_high;

					for (uint32_t m = 0; m < NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 63; hi++)
						{
							for (uint32_t lo = 0; lo <= 63; lo++)
							{
								//if (lo == hi) continue;

								uint32_t colors[4];

								colors[0] = (lo << 2) | (lo >> 4);
								colors[3] = (hi << 2) | (hi >> 4);

								colors[1] = (colors[0] * 2 + colors[3]) / 3;
								colors[2] = (colors[3] * 2 + colors[0]) / 3;

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1_to_dxt1_selector_mappings[m][s]];

									total_err += err * err;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						assert(best_err <= 0xFFFF);

						//table[g + inten * 32].m_solutions[sr][m].m_lo = static_cast<uint8_t>(best_lo);
						//table[g + inten * 32].m_solutions[sr][m].m_hi = static_cast<uint8_t>(best_hi);
						//table[g + inten * 32].m_solutions[sr][m].m_err = static_cast<uint16_t>(best_err);

						//assert(best_lo != best_hi);
						fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");

					} // m
				} // sr
			} // g
		} // inten

		fclose(pFile);
	}
#endif


#if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11
	static const int8_t g_eac_modifier_table[16][8] =;

	// Used by ETC2 EAC A8 and ETC2 EAC R11/RG11.
	struct eac_block
	{};

#endif // #if BASISD_SUPPORT_UASTC BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11

#if BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11
	static const dxt_selector_range s_etc2_eac_selector_ranges[] =;

	const uint32_t NUM_ETC2_EAC_SELECTOR_RANGES =;

	struct etc1_g_to_eac_conversion
	{};
#endif // BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11

#if BASISD_SUPPORT_ETC2_EAC_A8

#if BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES
	struct pack_eac_a8_results
	{
		uint32_t m_base;
		uint32_t m_table;
		uint32_t m_multiplier;
		basisu::vector<uint8_t> m_selectors;
		basisu::vector<uint8_t> m_selectors_temp;
	};

	static uint64_t pack_eac_a8_exhaustive(pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels)
	{
		results.m_selectors.resize(num_pixels);
		results.m_selectors_temp.resize(num_pixels);

		uint64_t best_err = UINT64_MAX;

		for (uint32_t base_color = 0; base_color < 256; base_color++)
		{
			for (uint32_t multiplier = 1; multiplier < 16; multiplier++)
			{
				for (uint32_t table = 0; table < 16; table++)
				{
					uint64_t total_err = 0;

					for (uint32_t i = 0; i < num_pixels; i++)
					{
						const int a = pPixels[i];

						uint32_t best_s_err = UINT32_MAX;
						uint32_t best_s = 0;
						for (uint32_t s = 0; s < 8; s++)
						{
							int v = (int)multiplier * g_eac_modifier_table[table][s] + (int)base_color;
							if (v < 0)
								v = 0;
							else if (v > 255)
								v = 255;

							uint32_t err = abs(a - v);
							if (err < best_s_err)
							{
								best_s_err = err;
								best_s = s;
							}
						}

						results.m_selectors_temp[i] = static_cast<uint8_t>(best_s);

						total_err += best_s_err * best_s_err;
						if (total_err >= best_err)
							break;
					}

					if (total_err < best_err)
					{
						best_err = total_err;
						results.m_base = base_color;
						results.m_multiplier = multiplier;
						results.m_table = table;
						results.m_selectors.swap(results.m_selectors_temp);
					}

				} // table

			} // multiplier

		} // base_color

		return best_err;
	}
#endif // BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES
		
	static
#if !BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES		
		const
#endif
		etc1_g_to_eac_conversion s_etc1_g_to_etc2_a8[32 * 8][NUM_ETC2_EAC_SELECTOR_RANGES] =;
#endif // BASISD_SUPPORT_ETC2_EAC_A8

#if BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES
	static void create_etc2_eac_a8_conversion_table()
	{
		FILE* pFile = fopen("basisu_decoder_tables_etc2_eac_a8.inc", "w");

		for (uint32_t inten = 0; inten < 8; inten++)
		{
			for (uint32_t base = 0; base < 32; base++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(base, base, base, 255), false), inten);

				fprintf(pFile, "{");

				for (uint32_t sel_range = 0; sel_range < NUM_ETC2_EAC_SELECTOR_RANGES; sel_range++)
				{
					const uint32_t low_selector = s_etc2_eac_selector_ranges[sel_range].m_low;
					const uint32_t high_selector = s_etc2_eac_selector_ranges[sel_range].m_high;

					// We have a ETC1 base color and intensity, and a used selector range from low_selector-high_selector.
					// Now find the best ETC2 EAC A8 base/table/multiplier that fits these colors.

					uint8_t pixels[4];
					uint32_t num_pixels = 0;
					for (uint32_t s = low_selector; s <= high_selector; s++)
						pixels[num_pixels++] = block_colors[s].g;

					pack_eac_a8_results pack_results;
					pack_eac_a8_exhaustive(pack_results, pixels, num_pixels);

					etc1_g_to_eac_conversion& c = s_etc1_g_to_etc2_a8[base + inten * 32][sel_range];

					c.m_base = pack_results.m_base;
					c.m_table_mul = pack_results.m_table * 16 + pack_results.m_multiplier;
					c.m_trans = 0;

					for (uint32_t s = 0; s < 4; s++)
					{
						if ((s < low_selector) || (s > high_selector))
							continue;

						uint32_t etc2_selector = pack_results.m_selectors[s - low_selector];

						c.m_trans |= (etc2_selector << (s * 3));
					}

					fprintf(pFile, "{%u,%u,%u}", c.m_base, c.m_table_mul, c.m_trans);
					if (sel_range < (NUM_ETC2_EAC_SELECTOR_RANGES - 1))
						fprintf(pFile, ",");
				}

				fprintf(pFile, "},\n");
			}
		}

		fclose(pFile);
	}
#endif

#if BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES
	struct pack_eac_r11_results
	{
		uint32_t m_base;
		uint32_t m_table;
		uint32_t m_multiplier;
		basisu::vector<uint8_t> m_selectors;
		basisu::vector<uint8_t> m_selectors_temp;
	};

	static uint64_t pack_eac_r11_exhaustive(pack_eac_r11_results& results, const uint8_t* pPixels, uint32_t num_pixels)
	{
		results.m_selectors.resize(num_pixels);
		results.m_selectors_temp.resize(num_pixels);

		uint64_t best_err = UINT64_MAX;

		for (uint32_t base_color = 0; base_color < 256; base_color++)
		{
			for (uint32_t multiplier = 0; multiplier < 16; multiplier++)
			{
				for (uint32_t table = 0; table < 16; table++)
				{
					uint64_t total_err = 0;

					for (uint32_t i = 0; i < num_pixels; i++)
					{
						// Convert 8-bit input to 11-bits
						const int a = (pPixels[i] * 2047 + 128) / 255;

						uint32_t best_s_err = UINT32_MAX;
						uint32_t best_s = 0;
						for (uint32_t s = 0; s < 8; s++)
						{
							int v = (int)(multiplier ? (multiplier * 8) : 1) * g_eac_modifier_table[table][s] + (int)base_color * 8 + 4;
							if (v < 0)
								v = 0;
							else if (v > 2047)
								v = 2047;

							uint32_t err = abs(a - v);
							if (err < best_s_err)
							{
								best_s_err = err;
								best_s = s;
							}
						}

						results.m_selectors_temp[i] = static_cast<uint8_t>(best_s);

						total_err += best_s_err * best_s_err;
						if (total_err >= best_err)
							break;
					}

					if (total_err < best_err)
					{
						best_err = total_err;
						results.m_base = base_color;
						results.m_multiplier = multiplier;
						results.m_table = table;
						results.m_selectors.swap(results.m_selectors_temp);
					}

				} // table

			} // multiplier

		} // base_color

		return best_err;
	}

	static void create_etc2_eac_r11_conversion_table()
	{
		FILE* pFile = nullptr;
		fopen_s(&pFile, "basisu_decoder_tables_etc2_eac_r11.inc", "w");

		for (uint32_t inten = 0; inten < 8; inten++)
		{
			for (uint32_t base = 0; base < 32; base++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(base, base, base, 255), false), inten);

				fprintf(pFile, "{");

				for (uint32_t sel_range = 0; sel_range < NUM_ETC2_EAC_SELECTOR_RANGES; sel_range++)
				{
					const uint32_t low_selector = s_etc2_eac_selector_ranges[sel_range].m_low;
					const uint32_t high_selector = s_etc2_eac_selector_ranges[sel_range].m_high;

					// We have a ETC1 base color and intensity, and a used selector range from low_selector-high_selector.
					// Now find the best ETC2 EAC R11 base/table/multiplier that fits these colors.

					uint8_t pixels[4];
					uint32_t num_pixels = 0;
					for (uint32_t s = low_selector; s <= high_selector; s++)
						pixels[num_pixels++] = block_colors[s].g;

					pack_eac_r11_results pack_results;
					pack_eac_r11_exhaustive(pack_results, pixels, num_pixels);

					etc1_g_to_eac_conversion c;

					c.m_base = (uint8_t)pack_results.m_base;
					c.m_table_mul = (uint8_t)(pack_results.m_table * 16 + pack_results.m_multiplier);
					c.m_trans = 0;

					for (uint32_t s = 0; s < 4; s++)
					{
						if ((s < low_selector) || (s > high_selector))
							continue;

						uint32_t etc2_selector = pack_results.m_selectors[s - low_selector];

						c.m_trans |= (etc2_selector << (s * 3));
					}

					fprintf(pFile, "{%u,%u,%u}", c.m_base, c.m_table_mul, c.m_trans);
					if (sel_range < (NUM_ETC2_EAC_SELECTOR_RANGES - 1))
						fprintf(pFile, ",");
				}

				fprintf(pFile, "},\n");
			}
		}

		fclose(pFile);
	}
#endif // BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES

#if BASISD_WRITE_NEW_ASTC_TABLES
	static void create_etc1_to_astc_conversion_table_0_47();
	static void create_etc1_to_astc_conversion_table_0_255();
#endif

#if BASISD_SUPPORT_ASTC
	static void transcoder_init_astc();
#endif

#if BASISD_WRITE_NEW_BC7_MODE5_TABLES
	static void create_etc1_to_bc7_m5_color_conversion_table();
	static void create_etc1_to_bc7_m5_alpha_conversion_table();
#endif

#if BASISD_SUPPORT_BC7_MODE5
	static void transcoder_init_bc7_mode5();
#endif

#if BASISD_WRITE_NEW_ATC_TABLES
	static void create_etc1s_to_atc_conversion_tables();
#endif

#if BASISD_SUPPORT_ATC
	static void transcoder_init_atc();
#endif

#if BASISD_SUPPORT_PVRTC2
	static void transcoder_init_pvrtc2();
#endif

#if BASISD_SUPPORT_UASTC
	void uastc_init();
#endif

	static bool g_transcoder_initialized;
		
	// Library global initialization. Requires ~9 milliseconds when compiled and executed natively on a Core i7 2.2 GHz.
	// If this is too slow, these computed tables can easilky be moved to be compiled in.
	void basisu_transcoder_init()
	{}

#if BASISD_SUPPORT_DXT1
	static void convert_etc1s_to_dxt1(dxt1_block* pDst_block, const endpoint *pEndpoints, const selector* pSelector, bool use_threecolor_blocks)
	{}

#if BASISD_ENABLE_DEBUG_FLAGS
	static void convert_etc1s_to_dxt1_vis(dxt1_block* pDst_block, const endpoint* pEndpoints, const selector* pSelector, bool use_threecolor_blocks)
	{
		convert_etc1s_to_dxt1(pDst_block, pEndpoints, pSelector, use_threecolor_blocks);

		if (g_debug_flags & cDebugFlagVisBC1Sels)
		{
			uint32_t l = dxt1_block::pack_unscaled_color(31, 63, 31);
			uint32_t h = dxt1_block::pack_unscaled_color(0, 0, 0);
			pDst_block->set_low_color(static_cast<uint16_t>(l));
			pDst_block->set_high_color(static_cast<uint16_t>(h));
		}
		else if (g_debug_flags & cDebugFlagVisBC1Endpoints)
		{
			for (uint32_t y = 0; y < 4; y++)
				for (uint32_t x = 0; x < 4; x++)
					pDst_block->set_selector(x, y, (y < 2) ? 0 : 1);
		}
	}
#endif
#endif

#if BASISD_SUPPORT_FXT1
	struct fxt1_block
	{};

	static uint8_t conv_dxt1_to_fxt1_sels(uint32_t sels)
	{}

	static void convert_etc1s_to_fxt1(void *pDst, const endpoint *pEndpoints, const selector *pSelectors, uint32_t fxt1_subblock)
	{}
#endif // BASISD_SUPPORT_FXT1
#if BASISD_SUPPORT_DXT5A
	static dxt_selector_range s_dxt5a_selector_ranges[] =;

	const uint32_t NUM_DXT5A_SELECTOR_RANGES =;

	struct etc1_g_to_dxt5a_conversion
	{};

	static etc1_g_to_dxt5a_conversion g_etc1_g_to_dxt5a[32 * 8][NUM_DXT5A_SELECTOR_RANGES] =;

	struct dxt5a_block
	{};

	static void convert_etc1s_to_dxt5a(dxt5a_block* pDst_block, const endpoint* pEndpoints, const selector* pSelector)
	{}
#endif //BASISD_SUPPORT_DXT5A

	// PVRTC

#if BASISD_SUPPORT_PVRTC1 || BASISD_SUPPORT_UASTC
	static const  uint16_t g_pvrtc_swizzle_table[256] =;

	// Note we can't use simple calculations to convert PVRTC1 encoded endpoint components to/from 8-bits, due to hardware approximations.
	static const uint8_t g_pvrtc_5[32] =;
	static const uint8_t g_pvrtc_4[16] =;
	static const uint8_t g_pvrtc_3[8] =;
	static const uint8_t g_pvrtc_alpha[9] =;
		
	static const uint8_t g_pvrtc_5_floor[256] =;

	static const uint8_t g_pvrtc_5_ceil[256] =;
		
	static const uint8_t g_pvrtc_4_floor[256] =;

	static const uint8_t g_pvrtc_4_ceil[256] =;
		
	static const uint8_t g_pvrtc_3_floor[256] =;

	static const uint8_t g_pvrtc_3_ceil[256] =;
		
	static const uint8_t g_pvrtc_alpha_floor[256] =;

	static const uint8_t g_pvrtc_alpha_ceil[256] =;

	struct pvrtc4_block
	{};

#if 0
	static const uint8_t g_pvrtc_bilinear_weights[16][4] =
	{
		{ 4, 4, 4, 4 }, { 2, 6, 2, 6 }, { 8, 0, 8, 0 }, { 6, 2, 6, 2 },
		{ 2, 2, 6, 6 }, { 1, 3, 3, 9 }, { 4, 0, 12, 0 }, { 3, 1, 9, 3 },
		{ 8, 8, 0, 0 }, { 4, 12, 0, 0 }, { 16, 0, 0, 0 }, { 12, 4, 0, 0 },
		{ 6, 6, 2, 2 }, { 3, 9, 1, 3 }, { 12, 0, 4, 0 }, { 9, 3, 3, 1 },
	};
#endif

	struct pvrtc1_temp_block
	{};

	static inline uint32_t get_opaque_endpoint_l0(uint32_t endpoints)
	{}

	static inline uint32_t get_opaque_endpoint_l1(uint32_t endpoints)
	{}

	static color32 get_endpoint_8888(uint32_t endpoints, uint32_t endpoint_index)
	{}

	static uint32_t get_endpoint_l8(uint32_t endpoints, uint32_t endpoint_index)
	{}
#endif

#if BASISD_SUPPORT_PVRTC1
	// TODO: Support decoding a non-pow2 ETC1S texture into the next larger pow2 PVRTC texture.
	static void fixup_pvrtc1_4_modulation_rgb(const decoder_etc_block* pETC_Blocks, const uint32_t* pPVRTC_endpoints, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y)
	{}

	static void fixup_pvrtc1_4_modulation_rgba(
		const decoder_etc_block* pETC_Blocks, 
		const uint32_t* pPVRTC_endpoints, 
		void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, void *pAlpha_blocks,
		const endpoint* pEndpoints, const selector* pSelectors)
	{}
#endif // BASISD_SUPPORT_PVRTC1

#if BASISD_SUPPORT_BC7_MODE5
	static dxt_selector_range g_etc1_to_bc7_m5_selector_ranges[] =;

	const uint32_t NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES =;

	static uint32_t g_etc1_to_bc7_m5_selector_range_index[4][4];
	
	const uint32_t NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS =;
	static const uint8_t g_etc1_to_bc7_m5_selector_mappings[NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS][4] =;

	struct etc1_to_bc7_m5_solution
	{};
		
	static const etc1_to_bc7_m5_solution g_etc1_to_bc7_m5_color[32 * 8 * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS * NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES] =;
	
	static dxt_selector_range g_etc1_to_bc7_m5a_selector_ranges[] =;

	const uint32_t NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES =;

	static uint32_t g_etc1_to_bc7_m5a_selector_range_index[4][4];

	struct etc1_g_to_bc7_m5a_conversion
	{};

	static etc1_g_to_bc7_m5a_conversion g_etc1_g_to_bc7_m5a[8 * 32 * NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES] =;
	
	static inline uint32_t set_block_bits(uint8_t* pBytes, uint32_t val, uint32_t num_bits, uint32_t cur_ofs)
	{}

	struct bc7_mode_5
	{};

#if BASISD_WRITE_NEW_BC7_MODE5_TABLES
	static void create_etc1_to_bc7_m5_color_conversion_table()
	{
		FILE* pFile = nullptr;
		fopen_s(&pFile, "basisu_transcoder_tables_bc7_m5_color.inc", "w");

		uint32_t n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1_to_bc7_m5_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1_to_bc7_m5_selector_ranges[sr].m_high;

					for (uint32_t m = 0; m < NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 127; hi++)
						{
							for (uint32_t lo = 0; lo <= 127; lo++)
							{
								uint32_t colors[4];

								colors[0] = (lo << 1) | (lo >> 6);
								colors[3] = (hi << 1) | (hi >> 6);

								colors[1] = (colors[0] * (64 - 21) + colors[3] * 21 + 32) / 64;
								colors[2] = (colors[0] * (64 - 43) + colors[3] * 43 + 32) / 64;

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1_to_bc7_m5_selector_mappings[m][s]];

									int err_scale = 1;
									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										err_scale = 5;

									total_err += (err * err) * err_scale;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);

						fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m
				} // sr
			} // g
		} // inten

		fclose(pFile);
	}

	static void create_etc1_to_bc7_m5_alpha_conversion_table()
	{
		FILE* pFile = nullptr;
		fopen_s(&pFile, "basisu_transcoder_tables_bc7_m5_alpha.inc", "w");

		uint32_t n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1_to_bc7_m5a_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1_to_bc7_m5a_selector_ranges[sr].m_high;

					uint32_t best_lo = 0;
					uint32_t best_hi = 0;
					uint64_t best_err = UINT64_MAX;
					uint32_t best_output_selectors = 0;

					for (uint32_t hi = 0; hi <= 255; hi++)
					{
						for (uint32_t lo = 0; lo <= 255; lo++)
						{
							uint32_t colors[4];

							colors[0] = lo;
							colors[3] = hi;

							colors[1] = (colors[0] * (64 - 21) + colors[3] * 21 + 32) / 64;
							colors[2] = (colors[0] * (64 - 43) + colors[3] * 43 + 32) / 64;

							uint64_t total_err = 0;
							uint32_t output_selectors = 0;

							for (uint32_t s = low_selector; s <= high_selector; s++)
							{
								int best_mapping_err = INT_MAX;
								int best_k = 0;
								for (int k = 0; k < 4; k++)
								{
									int mapping_err = block_colors[s].g - colors[k];
									mapping_err *= mapping_err;

									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										mapping_err *= 5;

									if (mapping_err < best_mapping_err)
									{
										best_mapping_err = mapping_err;
										best_k = k;
									}
								} // k
								
								total_err += best_mapping_err;
								output_selectors |= (best_k << (s * 2));
							} // s

							if (total_err < best_err)
							{
								best_err = total_err;
								best_lo = lo;
								best_hi = hi;
								best_output_selectors = output_selectors;
							}

						} // lo
					} // hi
										
					fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, best_output_selectors);
					n++;
					if ((n & 31) == 31)
						fprintf(pFile, "\n");

				} // sr
			} // g
		} // inten

		fclose(pFile);
	}
#endif // BASISD_WRITE_NEW_BC7_MODE5_TABLES

	struct bc7_m5_match_entry
	{};

	static bc7_m5_match_entry g_bc7_m5_equals_1[256] =;
	
	static void transcoder_init_bc7_mode5()
	{}

	static void convert_etc1s_to_bc7_m5_color(void* pDst, const endpoint* pEndpoints, const selector* pSelector)
	{}

	static void convert_etc1s_to_bc7_m5_alpha(void* pDst, const endpoint* pEndpoints, const selector* pSelector)
	{}
#endif // BASISD_SUPPORT_BC7_MODE5

#if BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_UASTC
	static const uint8_t g_etc2_eac_a8_sel4[6] =;
#endif

#if BASISD_SUPPORT_ETC2_EAC_A8
	static void convert_etc1s_to_etc2_eac_a8(eac_block* pDst_block, const endpoint* pEndpoints, const selector* pSelector)
	{}
#endif // BASISD_SUPPORT_ETC2_EAC_A8

#if BASISD_SUPPORT_ETC2_EAC_RG11
	static const etc1_g_to_eac_conversion s_etc1_g_to_etc2_r11[32 * 8][NUM_ETC2_EAC_SELECTOR_RANGES] =;

	static void convert_etc1s_to_etc2_eac_r11(eac_block* pDst_block, const endpoint* pEndpoints, const selector* pSelector)
	{}
#endif // BASISD_SUPPORT_ETC2_EAC_RG11

// ASTC
	struct etc1_to_astc_solution
	{};

#if BASISD_SUPPORT_ASTC
	static dxt_selector_range g_etc1_to_astc_selector_ranges[] =;

	const uint32_t NUM_ETC1_TO_ASTC_SELECTOR_RANGES =;

	static uint32_t g_etc1_to_astc_selector_range_index[4][4];

	const uint32_t NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS =;
	static const uint8_t g_etc1_to_astc_selector_mappings[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS][4] =;

	static const etc1_to_astc_solution g_etc1_to_astc[32 * 8 * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS * NUM_ETC1_TO_ASTC_SELECTOR_RANGES] =;

	// The best selector mapping to use given a base base+inten table and used selector range for converting grayscale data.
	static uint8_t g_etc1_to_astc_best_grayscale_mapping[32][8][NUM_ETC1_TO_ASTC_SELECTOR_RANGES];
	
#if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY
	static const etc1_to_astc_solution g_etc1_to_astc_0_255[32 * 8 * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS * NUM_ETC1_TO_ASTC_SELECTOR_RANGES] =;
	static uint8_t g_etc1_to_astc_best_grayscale_mapping_0_255[32][8][NUM_ETC1_TO_ASTC_SELECTOR_RANGES];
#endif

	static uint32_t g_ise_to_unquant[48];

#if BASISD_WRITE_NEW_ASTC_TABLES
	static void create_etc1_to_astc_conversion_table_0_47()
	{
		FILE* pFile = nullptr;
		fopen_s(&pFile, "basisu_transcoder_tables_astc.inc", "w");

		uint32_t n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1_TO_ASTC_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1_to_astc_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1_to_astc_selector_ranges[sr].m_high;

					uint32_t mapping_best_low[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];
					uint32_t mapping_best_high[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];
					uint64_t mapping_best_err[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];
					uint64_t highest_best_err = 0;

					for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 47; hi++)
						{
							for (uint32_t lo = 0; lo <= 47; lo++)
							{
								uint32_t colors[4];

								for (uint32_t s = 0; s < 4; s++)
								{
									uint32_t s_scaled = s | (s << 2) | (s << 4);
									if (s_scaled > 32)
										s_scaled++;

									uint32_t c0 = g_ise_to_unquant[lo] | (g_ise_to_unquant[lo] << 8);
									uint32_t c1 = g_ise_to_unquant[hi] | (g_ise_to_unquant[hi] << 8);
									colors[s] = ((c0 * (64 - s_scaled) + c1 * s_scaled + 32) / 64) >> 8;
								}

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1_to_astc_selector_mappings[m][s]];

									int err_scale = 1;
									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										err_scale = 8;

									total_err += (err * err) * err_scale;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						mapping_best_low[m] = best_lo;
						mapping_best_high[m] = best_hi;
						mapping_best_err[m] = best_err;
						highest_best_err = basisu::maximum(highest_best_err, best_err);
												
					} // m

					for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++)
					{
						uint64_t err = mapping_best_err[m];

						err = basisu::minimum<uint64_t>(err, 0xFFFF);

						fprintf(pFile, "{%u,%u,%u},", mapping_best_low[m], mapping_best_high[m], (uint32_t)err);

						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m

				} // sr
			} // g
		} // inten

		fclose(pFile);
	}

	static void create_etc1_to_astc_conversion_table_0_255()
	{
		FILE* pFile = nullptr;
		fopen_s(&pFile, "basisu_transcoder_tables_astc_0_255.inc", "w");

		uint32_t n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1_TO_ASTC_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1_to_astc_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1_to_astc_selector_ranges[sr].m_high;

					uint32_t mapping_best_low[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];
					uint32_t mapping_best_high[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];
					uint64_t mapping_best_err[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];
					uint64_t highest_best_err = 0;

					for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 255; hi++)
						{
							for (uint32_t lo = 0; lo <= 255; lo++)
							{
								uint32_t colors[4];

								for (uint32_t s = 0; s < 4; s++)
								{
									uint32_t s_scaled = s | (s << 2) | (s << 4);
									if (s_scaled > 32)
										s_scaled++;

									uint32_t c0 = lo | (lo << 8);
									uint32_t c1 = hi | (hi << 8);
									colors[s] = ((c0 * (64 - s_scaled) + c1 * s_scaled + 32) / 64) >> 8;
								}

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1_to_astc_selector_mappings[m][s]];

									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									int err_scale = 1;
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										err_scale = 8;

									total_err += (err * err) * err_scale;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						mapping_best_low[m] = best_lo;
						mapping_best_high[m] = best_hi;
						mapping_best_err[m] = best_err;
						highest_best_err = basisu::maximum(highest_best_err, best_err);
					} // m

					for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++)
					{
						uint64_t err = mapping_best_err[m];

						err = basisu::minimum<uint64_t>(err, 0xFFFF);
						
						fprintf(pFile, "{%u,%u,%u},", mapping_best_low[m], mapping_best_high[m], (uint32_t)err);
						
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m

				} // sr
			} // g
		} // inten

		fclose(pFile);
	}
#endif

#endif

#if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ASTC
	// Table encodes 5 trits to 8 output bits. 3^5 entries.
	// Inverse of the trit bit manipulation process in https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-integer-sequence-encoding
	static const uint8_t g_astc_trit_encode[243] =;

	// Extracts bits [low,high]
	static inline uint32_t astc_extract_bits(uint32_t bits, int low, int high)
	{}

	// Writes bits to output in an endian safe way
	static inline void astc_set_bits(uint32_t* pOutput, int& bit_pos, uint32_t value, uint32_t total_bits)
	{}

	// Encodes 5 values to output, usable for any range that uses trits and bits
	static void astc_encode_trits(uint32_t* pOutput, const uint8_t* pValues, int& bit_pos, int n)
	{}
#endif // #if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ASTC

#if BASISD_SUPPORT_ASTC
	struct astc_block_params
	{};
	
	// Packs a single format ASTC block using Color Endpoint Mode 12 (LDR RGBA direct), endpoint BISE range 13, 2-bit weights (range 2). 
	// We're always going to output blocks containing alpha, even if the input doesn't have alpha, for simplicity.
	// Each block always has 4x4 weights, uses range 13 BISE encoding on the endpoints (0-47), and each weight ranges from 0-3. This encoding should be roughly equal in quality vs. BC1 for color.
	// 8 total endpoints, stored as RGBA LH LH LH LH order, each ranging from 0-47. 
	// Note the input [0,47] endpoint values are not linear - they are encoded as outlined in the ASTC spec:
	// https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-endpoint-unquantization
	// 32 total weights, stored as 16 CA CA, each ranging from 0-3.
	static void astc_pack_block_cem_12_weight_range2(uint32_t *pOutput, const astc_block_params* pBlock)
	{}

	// CEM mode 12 (LDR RGBA Direct), 8-bit endpoints, 1-bit weights 
	// This ASTC mode is basically block truncation coding (BTC) using 1-bit weights and 8-bit/component endpoints - very convenient.
	static void astc_pack_block_cem_12_weight_range0(uint32_t* pOutput, const astc_block_params* pBlock)
	{}

#if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY
	// Optional 8-bit endpoint packing functions.

	// CEM mode 4 (LDR Luminance+Alpha Direct), 8-bit endpoints, 2 bit weights
	static void astc_pack_block_cem_4_weight_range2(uint32_t* pOutput, const astc_block_params* pBlock)
	{}

	// CEM mode 8 (LDR RGB Direct), 8-bit endpoints, 2 bit weights
	static void astc_pack_block_cem_8_weight_range2(uint32_t* pOutput, const astc_block_params* pBlock)
	{}
#endif

	// Optimal quantized [0,47] entry to use given [0,255] input
	static uint8_t g_astc_single_color_encoding_0[256];

	// Optimal quantized [0,47] low/high values given [0,255] input assuming a selector of 1
	static struct
	{} g_astc_single_color_encoding_1[256];
		
	static void transcoder_init_astc()
	{}

	// Converts opaque or color+alpha ETC1S block to ASTC 4x4.
	// This function tries to use the best ASTC mode given the block's actual contents.
	static void convert_etc1s_to_astc_4x4(void* pDst_block, const endpoint* pEndpoints, const selector* pSelector, 
		bool transcode_alpha, const endpoint *pEndpoint_codebook, const selector *pSelector_codebook)
	{}
#endif

#if BASISD_SUPPORT_ATC
	// ATC and PVRTC2 both use these tables.
	struct etc1s_to_atc_solution
	{};

	static dxt_selector_range g_etc1s_to_atc_selector_ranges[] =;

	const uint32_t NUM_ETC1S_TO_ATC_SELECTOR_RANGES =;

	static uint32_t g_etc1s_to_atc_selector_range_index[4][4];

	const uint32_t NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS =;
	static const uint8_t g_etc1s_to_atc_selector_mappings[NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS][4] =;
	const uint32_t ATC_IDENTITY_SELECTOR_MAPPING_INDEX =;

#if BASISD_SUPPORT_PVRTC2
	static const etc1s_to_atc_solution g_etc1s_to_pvrtc2_45[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] =;

#if 0
	static const etc1s_to_atc_solution g_etc1s_to_pvrtc2_alpha_33[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] = {
#include "basisu_transcoder_tables_pvrtc2_alpha_33.inc"
	};
#endif

#endif

	static const etc1s_to_atc_solution g_etc1s_to_atc_55[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] =;

	static const etc1s_to_atc_solution g_etc1s_to_atc_56[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] =;

	struct atc_match_entry
	{};
	static atc_match_entry g_pvrtc2_match45_equals_1[256], g_atc_match55_equals_1[256], g_atc_match56_equals_1[256]; // selector 1
	static atc_match_entry g_pvrtc2_match4[256], g_atc_match5[256], g_atc_match6[256];

	static void prepare_atc_single_color_table(atc_match_entry* pTable, int size0, int size1, int sel)
	{}

	static void transcoder_init_atc()
	{}

	struct atc_block
	{};

	static void convert_etc1s_to_atc(void* pDst, const endpoint* pEndpoints, const selector* pSelector)
	{}

#if BASISD_WRITE_NEW_ATC_TABLES
	static void create_etc1s_to_atc_conversion_tables()
	{
		// ATC 55
		FILE* pFile = nullptr;
		fopen_s(&pFile, "basisu_transcoder_tables_atc_55.inc", "w");

		uint32_t n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;

					for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 31; hi++)
						{
							for (uint32_t lo = 0; lo <= 31; lo++)
							{
								uint32_t colors[4];

								colors[0] = (lo << 3) | (lo >> 2);
								colors[3] = (hi << 3) | (hi >> 2);

								colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;
								colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];

									int err_scale = 1;
									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										err_scale = 5;

									total_err += (err * err) * err_scale;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						//assert(best_err <= 0xFFFF);
						best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);

						fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m
				} // sr
			} // g
		} // inten

		fclose(pFile);
		pFile = nullptr;

		// ATC 56
		fopen_s(&pFile, "basisu_transcoder_tables_atc_56.inc", "w");

		n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;

					for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 63; hi++)
						{
							for (uint32_t lo = 0; lo <= 31; lo++)
							{
								uint32_t colors[4];

								colors[0] = (lo << 3) | (lo >> 2);
								colors[3] = (hi << 2) | (hi >> 4);

								colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;
								colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];

									int err_scale = 1;
									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										err_scale = 5;

									total_err += (err * err) * err_scale;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						//assert(best_err <= 0xFFFF);
						best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);

						fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m
				} // sr
			} // g
		} // inten

		fclose(pFile);
		
		// PVRTC2 45
		fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_45.inc", "w");

		n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;

					for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 31; hi++)
						{
							for (uint32_t lo = 0; lo <= 15; lo++)
							{
								uint32_t colors[4];

								colors[0] = (lo << 1) | (lo >> 3);
								colors[0] = (colors[0] << 3) | (colors[0] >> 2);

								colors[3] = (hi << 3) | (hi >> 2);

								colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;
								colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];

									int err_scale = 1;
									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										err_scale = 5;

									total_err += (err * err) * err_scale;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						//assert(best_err <= 0xFFFF);
						best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);

						fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m
				} // sr
			} // g
		} // inten

		fclose(pFile);

#if 0
		// PVRTC2 34
		fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_34.inc", "w");

		n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;

					for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 15; hi++)
						{
							for (uint32_t lo = 0; lo <= 7; lo++)
							{
								uint32_t colors[4];

								colors[0] = (lo << 2) | (lo >> 1);
								colors[0] = (colors[0] << 3) | (colors[0] >> 2);

								colors[3] = (hi << 1) | (hi >> 3);
								colors[3] = (colors[3] << 3) | (colors[3] >> 2);

								colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;
								colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];

									int err_scale = 1;
									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										err_scale = 5;

									total_err += (err * err) * err_scale;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						//assert(best_err <= 0xFFFF);
						best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);

						fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m
				} // sr
			} // g
		} // inten

		fclose(pFile);
#endif
#if 0
		// PVRTC2 44
		fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_44.inc", "w");

		n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;

					for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 15; hi++)
						{
							for (uint32_t lo = 0; lo <= 15; lo++)
							{
								uint32_t colors[4];

								colors[0] = (lo << 1) | (lo >> 3);
								colors[0] = (colors[0] << 3) | (colors[0] >> 2);

								colors[3] = (hi << 1) | (hi >> 3);
								colors[3] = (colors[3] << 3) | (colors[3] >> 2);

								colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;
								colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];

									int err_scale = 1;
									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										err_scale = 5;

									total_err += (err * err) * err_scale;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						//assert(best_err <= 0xFFFF);
						best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);

						fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m
				} // sr
			} // g
		} // inten

		fclose(pFile);
#endif

		// PVRTC2 alpha 33
		fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_alpha_33.inc", "w");

		n = 0;

		for (int inten = 0; inten < 8; inten++)
		{
			for (uint32_t g = 0; g < 32; g++)
			{
				color32 block_colors[4];
				decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);

				for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)
				{
					const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;
					const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;

					for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)
					{
						uint32_t best_lo = 0;
						uint32_t best_hi = 0;
						uint64_t best_err = UINT64_MAX;

						for (uint32_t hi = 0; hi <= 7; hi++)
						{
							for (uint32_t lo = 0; lo <= 7; lo++)
							{
								uint32_t colors[4];

								colors[0] = (lo << 1);
								colors[0] = (colors[0] << 4) | colors[0];

								colors[3] = (hi << 1) | 1;
								colors[3] = (colors[3] << 4) | colors[3];

								colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;
								colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;

								uint64_t total_err = 0;

								for (uint32_t s = low_selector; s <= high_selector; s++)
								{
									int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];

									int err_scale = 1;
									// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor 
									// the low/high selectors which are clamping to either 0 or 255.
									if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))
										err_scale = 5;

									total_err += (err * err) * err_scale;
								}

								if (total_err < best_err)
								{
									best_err = total_err;
									best_lo = lo;
									best_hi = hi;
								}
							}
						}

						//assert(best_err <= 0xFFFF);
						best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);

						fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);
						n++;
						if ((n & 31) == 31)
							fprintf(pFile, "\n");
					} // m
				} // sr
			} // g
		} // inten

		fclose(pFile);
	}
#endif // BASISD_WRITE_NEW_ATC_TABLES

#endif // BASISD_SUPPORT_ATC

#if BASISD_SUPPORT_PVRTC2
	struct pvrtc2_block
	{};

	static struct
	{} g_pvrtc2_trans_match34[256];

	static struct
	{} g_pvrtc2_trans_match44[256];
		
	static struct
	{} g_pvrtc2_alpha_match33[256];
	
	static struct
	{} g_pvrtc2_alpha_match33_0[256];

	static struct
	{} g_pvrtc2_alpha_match33_3[256];
		
	// PVRTC2 can be forced to look like a slightly weaker variant of ATC/BC1, so that's what we do here for simplicity.
	static void convert_etc1s_to_pvrtc2_rgb(void* pDst, const endpoint* pEndpoints, const selector* pSelector)
	{}

	vec4F;
		
	static inline vec4F* vec4F_set_scalar(vec4F* pV, float x) {}
	static inline vec4F* vec4F_set(vec4F* pV, float x, float y, float z, float w) {}
	static inline vec4F* vec4F_saturate_in_place(vec4F* pV) {}
	static inline vec4F vec4F_saturate(const vec4F* pV) {}
	static inline vec4F vec4F_from_color(const color32* pC) {}
	static inline vec4F vec4F_add(const vec4F* pLHS, const vec4F* pRHS) {}
	static inline vec4F vec4F_sub(const vec4F* pLHS, const vec4F* pRHS) {}
	static inline float vec4F_dot(const vec4F* pLHS, const vec4F* pRHS) {}
	static inline vec4F vec4F_mul(const vec4F* pLHS, float s) {}
	static inline vec4F* vec4F_normalize_in_place(vec4F* pV) {}

	static color32 convert_rgba_5554_to_8888(const color32& col)
	{}

	static inline int sq(int x) {}
						
	// PVRTC2 is a slightly borked format for alpha: In Non-Interpolated mode, the way AlphaB8 is exanded from 4 to 8 bits means it can never be 0. 
	// This is actually very bad, because on 100% transparent blocks which have non-trivial color pixels, part of the color channel will leak into alpha! 
	// And there's nothing straightforward we can do because using the other modes is too expensive/complex. I can see why Apple didn't adopt it.
	static void convert_etc1s_to_pvrtc2_rgba(void* pDst, const endpoint* pEndpoints, const selector* pSelector, const endpoint* pEndpoint_codebook, const selector* pSelector_codebook)
	{}
		
	static void transcoder_init_pvrtc2()
	{}
#endif // BASISD_SUPPORT_PVRTC2

	basisu_lowlevel_etc1s_transcoder::basisu_lowlevel_etc1s_transcoder() :{}

	bool basisu_lowlevel_etc1s_transcoder::decode_palettes(
		uint32_t num_endpoints, const uint8_t* pEndpoints_data, uint32_t endpoints_data_size,
		uint32_t num_selectors, const uint8_t* pSelectors_data, uint32_t selectors_data_size)
	{}

	bool basisu_lowlevel_etc1s_transcoder::decode_tables(const uint8_t* pTable_data, uint32_t table_data_size)
	{}

	bool basisu_lowlevel_etc1s_transcoder::transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
		uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const bool is_video, const bool is_alpha_slice, const uint32_t level_index, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels,
		basisu_transcoder_state* pState, bool transcode_alpha, void *pAlpha_blocks, uint32_t output_rows_in_pixels)
	{}

	bool basis_validate_output_buffer_size(transcoder_texture_format target_format,
		uint32_t output_blocks_buf_size_in_blocks_or_pixels,
		uint32_t orig_width, uint32_t orig_height,
		uint32_t output_row_pitch_in_blocks_or_pixels,
		uint32_t output_rows_in_pixels,
		uint32_t total_slice_blocks)
	{}

	bool basisu_lowlevel_etc1s_transcoder::transcode_image(
			transcoder_texture_format target_format,
			void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
			const uint8_t* pCompressed_data, uint32_t compressed_data_length,
			uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
			uint32_t rgb_offset, uint32_t rgb_length, uint32_t alpha_offset, uint32_t alpha_length,
			uint32_t decode_flags,
			bool basis_file_has_alpha_slices,
			bool is_video,
			uint32_t output_row_pitch_in_blocks_or_pixels,
			basisu_transcoder_state* pState,
			uint32_t output_rows_in_pixels)
	{}
	
	basisu_lowlevel_uastc_transcoder::basisu_lowlevel_uastc_transcoder()
	{}

	bool basisu_lowlevel_uastc_transcoder::transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
        uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels,
		basisu_transcoder_state* pState, uint32_t output_rows_in_pixels, int channel0, int channel1, uint32_t decode_flags)
	{}
		
	bool basisu_lowlevel_uastc_transcoder::transcode_image(
		transcoder_texture_format target_format,
		void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
		const uint8_t* pCompressed_data, uint32_t compressed_data_length,
		uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
		uint32_t slice_offset, uint32_t slice_length,
		uint32_t decode_flags,
		bool has_alpha,
		bool is_video,
		uint32_t output_row_pitch_in_blocks_or_pixels,
		basisu_transcoder_state* pState,
		uint32_t output_rows_in_pixels,
		int channel0, int channel1)
	{}
	
	basisu_transcoder::basisu_transcoder() :{}

	bool basisu_transcoder::validate_file_checksums(const void* pData, uint32_t data_size, bool full_validation) const
	{}

	bool basisu_transcoder::validate_header_quick(const void* pData, uint32_t data_size) const
	{}

	bool basisu_transcoder::validate_header(const void* pData, uint32_t data_size) const
	{}

	basis_texture_type basisu_transcoder::get_texture_type(const void* pData, uint32_t data_size) const
	{}

	bool basisu_transcoder::get_userdata(const void* pData, uint32_t data_size, uint32_t& userdata0, uint32_t& userdata1) const
	{}

	uint32_t basisu_transcoder::get_total_images(const void* pData, uint32_t data_size) const
	{}

	basis_tex_format basisu_transcoder::get_tex_format(const void* pData, uint32_t data_size) const
	{}

	bool basisu_transcoder::get_image_info(const void* pData, uint32_t data_size, basisu_image_info& image_info, uint32_t image_index) const
	{}

	uint32_t basisu_transcoder::get_total_image_levels(const void* pData, uint32_t data_size, uint32_t image_index) const
	{}

	bool basisu_transcoder::get_image_level_desc(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, uint32_t& orig_width, uint32_t& orig_height, uint32_t& total_blocks) const
	{}

	bool basisu_transcoder::get_image_level_info(const void* pData, uint32_t data_size, basisu_image_level_info& image_info, uint32_t image_index, uint32_t level_index) const
	{}

	bool basisu_transcoder::get_file_info(const void* pData, uint32_t data_size, basisu_file_info& file_info) const
	{}
		
	bool basisu_transcoder::start_transcoding(const void* pData, uint32_t data_size)
	{}

	bool basisu_transcoder::stop_transcoding()
	{}

	bool basisu_transcoder::transcode_slice(const void* pData, uint32_t data_size, uint32_t slice_index, void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels, block_format fmt,
		uint32_t output_block_or_pixel_stride_in_bytes, uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state* pState, void *pAlpha_blocks, uint32_t output_rows_in_pixels, int channel0, int channel1) const
	{}

	int basisu_transcoder::find_first_slice_index(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index) const
	{}

	int basisu_transcoder::find_slice(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, bool alpha_data) const
	{}

	void basisu_transcoder::write_opaque_alpha_blocks(
		uint32_t num_blocks_x, uint32_t num_blocks_y,
		void* pOutput_blocks, block_format fmt,
		uint32_t block_stride_in_bytes, uint32_t output_row_pitch_in_blocks_or_pixels)
	{}

	bool basisu_transcoder::transcode_image_level(
		const void* pData, uint32_t data_size,
		uint32_t image_index, uint32_t level_index,
		void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
		transcoder_texture_format fmt,
		uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state *pState, uint32_t output_rows_in_pixels) const
	{}

	uint32_t basis_get_bytes_per_block_or_pixel(transcoder_texture_format fmt)
	{}

	const char* basis_get_format_name(transcoder_texture_format fmt)
	{}

	const char* basis_get_block_format_name(block_format fmt)
	{}

	const char* basis_get_texture_type_name(basis_texture_type tex_type)
	{}

	bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt)
	{}

	basisu::texture_format basis_get_basisu_texture_format(transcoder_texture_format fmt)
	{}

	bool basis_transcoder_format_is_uncompressed(transcoder_texture_format tex_type)
	{}

	bool basis_block_format_is_uncompressed(block_format blk_fmt)
	{}
	
	uint32_t basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format fmt)
	{}
	
	uint32_t basis_get_block_width(transcoder_texture_format tex_type)
	{}

	uint32_t basis_get_block_height(transcoder_texture_format tex_type)
	{}
	
	bool basis_is_format_supported(transcoder_texture_format tex_type, basis_tex_format fmt)
	{}

	// ------------------------------------------------------------------------------------------------------ 
	// UASTC
	// ------------------------------------------------------------------------------------------------------ 

#if BASISD_SUPPORT_UASTC
	const astc_bc7_common_partition2_desc g_astc_bc7_common_partitions2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2] =;

	const bc73_astc2_common_partition_desc g_bc7_3_astc2_common_partitions[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS] =;

	const astc_bc7_common_partition3_desc g_astc_bc7_common_partitions3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3] =;

	const uint8_t g_astc_to_bc7_partition_index_perm_tables[6][3] =;

	const uint8_t g_bc7_to_astc_partition_index_perm_tables[6][3] =;

	uint32_t bc7_convert_partition_index_3_to_2(uint32_t p, uint32_t k)
	{}

	static const uint8_t g_zero_pattern[16] =;

	const uint8_t g_astc_bc7_patterns2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][16] =;

	const uint8_t g_astc_bc7_patterns3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][16] =;

	const uint8_t g_bc7_3_astc2_patterns2[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][16] =;

	const uint8_t g_astc_bc7_pattern2_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][3] =;

	const uint8_t g_astc_bc7_pattern3_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][3] =;

	const uint8_t g_bc7_3_astc2_patterns2_anchors[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][3] =;

	const uint32_t g_uastc_mode_huff_codes[TOTAL_UASTC_MODES + 1][2] =;

	// If g_uastc_mode_huff_codes[] changes this table must be updated!
	static const uint8_t g_uastc_huff_modes[128] =;

	const uint8_t g_uastc_mode_weight_bits[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_weight_ranges[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_endpoint_ranges[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_subsets[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_planes[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_comps[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_has_etc1_bias[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_has_bc1_hint0[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_has_bc1_hint1[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_cem[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_has_alpha[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_is_la[TOTAL_UASTC_MODES] =;
	const uint8_t g_uastc_mode_total_hint_bits[TOTAL_UASTC_MODES] =;

	// bits, trits, quints
	const int g_astc_bise_range_table[TOTAL_ASTC_RANGES][3] =;

	int astc_get_levels(int range)
	{}

	// g_astc_unquant[] is the inverse of g_astc_sorted_order_unquant[]
	astc_quant_bin g_astc_unquant[BC7ENC_TOTAL_ASTC_RANGES][256]; // [ASTC encoded endpoint index]

	// Taken right from the ASTC spec.
	static struct
	{} g_astc_endpoint_unquant_params[BC7ENC_TOTAL_ASTC_RANGES] =;

	bool astc_is_valid_endpoint_range(uint32_t range)
	{}

	uint32_t unquant_astc_endpoint(uint32_t packed_bits, uint32_t packed_trits, uint32_t packed_quints, uint32_t range)
	{}

	uint32_t unquant_astc_endpoint_val(uint32_t packed_val, uint32_t range)
	{}

	// BC7 - Various BC7 tables/helpers
	const uint32_t g_bc7_weights1[2] =;
	const uint32_t g_bc7_weights2[4] =;
	const uint32_t g_bc7_weights3[8] =;
	const uint32_t g_bc7_weights4[16] =;
	const uint32_t g_astc_weights4[16] =;
	const uint32_t g_astc_weights5[32] =;
	const uint32_t g_astc_weights_3levels[3] =;

	const uint8_t g_bc7_partition1[16] =;

	const uint8_t g_bc7_partition2[64 * 16] =;

	const uint8_t g_bc7_partition3[64 * 16] =;

	const uint8_t g_bc7_table_anchor_index_second_subset[64] =;

	const uint8_t g_bc7_table_anchor_index_third_subset_1[64] =;

	const uint8_t g_bc7_table_anchor_index_third_subset_2[64] =;

	const uint8_t g_bc7_num_subsets[8] =;
	const uint8_t g_bc7_partition_bits[8] =;
	const uint8_t g_bc7_color_index_bitcount[8] =;

	const uint8_t g_bc7_mode_has_p_bits[8] =;
	const uint8_t g_bc7_mode_has_shared_p_bits[8] =;
	const uint8_t g_bc7_color_precision_table[8] =;
	const int8_t g_bc7_alpha_precision_table[8] =;

	const uint8_t g_bc7_alpha_index_bitcount[8] =;

	endpoint_err g_bc7_mode_6_optimal_endpoints[256][2]; // [c][pbit]
	endpoint_err g_bc7_mode_5_optimal_endpoints[256]; // [c]

	static inline void bc7_set_block_bits(uint8_t* pBytes, uint32_t val, uint32_t num_bits, uint32_t* pCur_ofs)
	{}

	// TODO: Optimize this.
	void encode_bc7_block(void* pBlock, const bc7_optimization_results* pResults)
	{}

	// ASTC
	static inline void astc_set_bits_1_to_9(uint32_t* pDst, int& bit_offset, uint32_t code, uint32_t codesize)
	{}

	void pack_astc_solid_block(void* pDst_block, const color32& color)
	{}

	// See 23.21 https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.inline.html#_partition_pattern_generation
#ifdef _DEBUG
	static inline uint32_t astc_hash52(uint32_t v)
	{
		uint32_t p = v;
		p ^= p >> 15;	p -= p << 17;	p += p << 7;	p += p << 4;
		p ^= p >> 5;	p += p << 16;	p ^= p >> 7;	p ^= p >> 3;
		p ^= p << 6;	p ^= p >> 17;
		return p;
	}

	int astc_compute_texel_partition(int seed, int x, int y, int z, int partitioncount, bool small_block)
	{
		if (small_block)
		{
			x <<= 1; y <<= 1; z <<= 1;
		}
		seed += (partitioncount - 1) * 1024;
		uint32_t rnum = astc_hash52(seed);
		uint8_t seed1 = rnum & 0xF;
		uint8_t seed2 = (rnum >> 4) & 0xF;
		uint8_t seed3 = (rnum >> 8) & 0xF;
		uint8_t seed4 = (rnum >> 12) & 0xF;
		uint8_t seed5 = (rnum >> 16) & 0xF;
		uint8_t seed6 = (rnum >> 20) & 0xF;
		uint8_t seed7 = (rnum >> 24) & 0xF;
		uint8_t seed8 = (rnum >> 28) & 0xF;
		uint8_t seed9 = (rnum >> 18) & 0xF;
		uint8_t seed10 = (rnum >> 22) & 0xF;
		uint8_t seed11 = (rnum >> 26) & 0xF;
		uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF;

		seed1 *= seed1;    seed2 *= seed2;
		seed3 *= seed3;    seed4 *= seed4;
		seed5 *= seed5;    seed6 *= seed6;
		seed7 *= seed7;    seed8 *= seed8;
		seed9 *= seed9;    seed10 *= seed10;
		seed11 *= seed11;   seed12 *= seed12;

		int sh1, sh2, sh3;
		if (seed & 1)
		{
			sh1 = (seed & 2 ? 4 : 5); sh2 = (partitioncount == 3 ? 6 : 5);
		}
		else
		{
			sh1 = (partitioncount == 3 ? 6 : 5); sh2 = (seed & 2 ? 4 : 5);
		}
		sh3 = (seed & 0x10) ? sh1 : sh2;

		seed1 >>= sh1; seed2 >>= sh2; seed3 >>= sh1; seed4 >>= sh2;
		seed5 >>= sh1; seed6 >>= sh2; seed7 >>= sh1; seed8 >>= sh2;
		seed9 >>= sh3; seed10 >>= sh3; seed11 >>= sh3; seed12 >>= sh3;

		int a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
		int b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
		int c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
		int d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);

		a &= 0x3F; b &= 0x3F; c &= 0x3F; d &= 0x3F;

		if (partitioncount < 4) d = 0;
		if (partitioncount < 3) c = 0;

		if (a >= b && a >= c && a >= d)
			return 0;
		else if (b >= c && b >= d)
			return 1;
		else if (c >= d)
			return 2;
		else
			return 3;
	}
#endif

	static const uint8_t g_astc_quint_encode[125] =;

	// Encodes 3 values to output, usable for any range that uses quints and bits
	static inline void astc_encode_quints(uint32_t* pOutput, const uint8_t* pValues, int& bit_pos, int n)
	{}

	// Packs values using ASTC's BISE to output buffer.
	static void astc_pack_bise(uint32_t* pDst, const uint8_t* pSrc_vals, int bit_pos, int num_vals, int range)
	{}

	const uint32_t ASTC_BLOCK_MODE_BITS =;
	const uint32_t ASTC_PART_BITS =;
	const uint32_t ASTC_CEM_BITS =;
	const uint32_t ASTC_PARTITION_INDEX_BITS =;
	const uint32_t ASTC_CCS_BITS =;

	const uint32_t g_uastc_mode_astc_block_mode[TOTAL_UASTC_MODES] =;

	bool pack_astc_block(uint32_t* pDst, const astc_block_desc* pBlock, uint32_t uastc_mode)
	{}

	const uint8_t* get_anchor_indices(uint32_t subsets, uint32_t mode, uint32_t common_pattern, const uint8_t*& pPartition_pattern)
	{}

	static inline uint32_t read_bit(const uint8_t* pBuf, uint32_t& bit_offset)
	{}

	static inline uint32_t read_bits1_to_9(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)
	{}

	inline uint64_t read_bits64(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)
	{}

	static inline uint32_t read_bits1_to_9_fst(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)
	{}

	bool unpack_uastc(const uastc_block& blk, unpacked_uastc_block& unpacked, bool blue_contract_check, bool read_hints)
	{}

	static const uint32_t* g_astc_weight_tables[6] =;

	bool unpack_uastc(uint32_t mode, uint32_t common_pattern, const color32& solid_color, const astc_block_desc& astc, color32* pPixels, bool srgb)
	{}

	bool unpack_uastc(const unpacked_uastc_block& unpacked_blk, color32* pPixels, bool srgb)
	{}

	bool unpack_uastc(const uastc_block& blk, color32* pPixels, bool srgb)
	{}

	// Determines the best shared pbits to use to encode xl/xh
	static void determine_shared_pbits(
		uint32_t total_comps, uint32_t comp_bits, float xl[4], float xh[4],
		color_quad_u8& bestMinColor, color_quad_u8& bestMaxColor, uint32_t best_pbits[2])
	{}

	// Determines the best unique pbits to use to encode xl/xh
	static void determine_unique_pbits(
		uint32_t total_comps, uint32_t comp_bits, float xl[4], float xh[4],
		color_quad_u8& bestMinColor, color_quad_u8& bestMaxColor, uint32_t best_pbits[2])
	{}

	bool transcode_uastc_to_astc(const uastc_block& src_blk, void* pDst)
	{}

	bool transcode_uastc_to_bc7(const unpacked_uastc_block& unpacked_src_blk, bc7_optimization_results& dst_blk)
	{}

	bool transcode_uastc_to_bc7(const uastc_block& src_blk, bc7_optimization_results& dst_blk)
	{}

	bool transcode_uastc_to_bc7(const uastc_block& src_blk, void* pDst)
	{}

	color32 apply_etc1_bias(const color32 &block_color, uint32_t bias, uint32_t limit, uint32_t subblock)
	{}

	static void etc1_determine_selectors(decoder_etc_block& dst_blk, const color32* pSource_pixels, uint32_t first_subblock, uint32_t last_subblock)
	{}

	static const uint8_t s_etc1_solid_selectors[4][4] =;

	struct etc_coord2
	{};

	// [flip][subblock][pixel_index]
	const etc_coord2 g_etc1_pixel_coords[2][2][8] =;

	void transcode_uastc_to_etc1(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst)
	{}

	bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst)
	{}

	static inline int gray_distance2(const uint8_t c, int y)
	{}

	static bool pack_etc1_y_estimate_flipped(const uint8_t* pSrc_pixels,
		int& upper_avg, int& lower_avg, int& left_avg, int& right_avg)
	{}

	// Base  Sel Table
	// XXXXX XX  XXX
	static const uint16_t g_etc1_y_solid_block_configs[256] =;

	// individual
	// table base sel0 sel1 sel2 sel3
	static const uint16_t g_etc1_y_solid_block_4i_configs[256] =;

	static const uint16_t g_etc1_y_solid_block_2i_configs[256] =;

	static const uint16_t g_etc1_y_solid_block_1i_configs[256] =;

	// We don't have any useful hints to accelerate single channel ETC1, so we need to real-time encode from scratch.
	bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst, uint32_t channel)
	{}

	const uint32_t ETC2_EAC_MIN_VALUE_SELECTOR =, ETC2_EAC_MAX_VALUE_SELECTOR =;

	void transcode_uastc_to_etc2_eac_a8(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst)
	{}

	bool transcode_uastc_to_etc2_rgba(const uastc_block& src_blk, void* pDst)
	{}

	static const uint8_t s_uastc5_to_bc1[32] =;
	static const uint8_t s_uastc4_to_bc1[16] =;
	static const uint8_t s_uastc3_to_bc1[8] =;
	static const uint8_t s_uastc2_to_bc1[4] =;
	static const uint8_t s_uastc1_to_bc1[2] =;
	const uint8_t* s_uastc_to_bc1_weights[6] =;
				
	void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride)
	{}

	static void bc1_find_sels(const color32 *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16])
	{}

	static inline void bc1_find_sels_2(const color32* pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16])
	{}

	struct vec3F {};
		
	static bool compute_least_squares_endpoints_rgb(const color32* pColors, const uint8_t* pSelectors, vec3F* pXl, vec3F* pXh)
	{}

	void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb) 
	{}

	static inline uint8_t to_5(uint32_t v) {}
	static inline uint8_t to_6(uint32_t v) {}

	// Good references: squish library, stb_dxt.
	void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags)
	{}
		
	void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags)
	{}

	// Scale the UASTC first subset endpoints and first plane's weight indices directly to BC1's - fastest.
	void transcode_uastc_to_bc1_hint0(const unpacked_uastc_block& unpacked_src_blk, void* pDst)
	{}

	// Scale the UASTC first plane's weight indices to BC1, use 1 or 2 least squares passes to compute endpoints - no PCA needed.
	void transcode_uastc_to_bc1_hint1(const unpacked_uastc_block& unpacked_src_blk, const color32 block_pixels[4][4], void* pDst, bool high_quality)
	{}

	bool transcode_uastc_to_bc1(const uastc_block& src_blk, void* pDst, bool high_quality)
	{}

	static void write_bc4_solid_block(uint8_t* pDst, uint32_t a)
	{}

	bool transcode_uastc_to_bc3(const uastc_block& src_blk, void* pDst, bool high_quality)
	{}

	bool transcode_uastc_to_bc4(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0)
	{}

	bool transcode_uastc_to_bc5(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1)
	{}

	static const uint8_t s_etc2_eac_bit_ofs[16] =;

	static void pack_eac_solid_block(eac_block& blk, uint32_t a)
	{}

	// Only checks 4 tables.
	static void pack_eac(eac_block& blk, const uint8_t* pPixels, uint32_t stride)
	{}

	// Checks all 16 tables. Around ~2 dB better vs. pack_eac(), ~1.2 dB less than near-optimal.
	static void pack_eac_high_quality(eac_block& blk, const uint8_t* pPixels, uint32_t stride)
	{}

	bool transcode_uastc_to_etc2_eac_r11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0)
	{}

	bool transcode_uastc_to_etc2_eac_rg11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1)
	{}

	// PVRTC1
	static void fixup_pvrtc1_4_modulation_rgb(
		const uastc_block* pSrc_blocks,
		const uint32_t* pPVRTC_endpoints,
		void* pDst_blocks,
		uint32_t num_blocks_x, uint32_t num_blocks_y, bool from_alpha)
	{}

	static void fixup_pvrtc1_4_modulation_rgba(
		const uastc_block* pSrc_blocks,
		const uint32_t* pPVRTC_endpoints,
		void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y)
	{}

	bool transcode_uastc_to_pvrtc1_4_rgb(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality, bool from_alpha)
	{}

	bool transcode_uastc_to_pvrtc1_4_rgba(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality)
	{}

	void uastc_init()
	{}

#endif // #if BASISD_SUPPORT_UASTC

// ------------------------------------------------------------------------------------------------------ 
// KTX2
// ------------------------------------------------------------------------------------------------------ 

#if BASISD_SUPPORT_KTX2
	const uint8_t g_ktx2_file_identifier[12] =;

	ktx2_transcoder::ktx2_transcoder() :{}

	void ktx2_transcoder::clear()
	{}

	bool ktx2_transcoder::init(const void* pData, uint32_t data_size)
	{}

	uint32_t ktx2_transcoder::get_etc1s_image_descs_image_flags(uint32_t level_index, uint32_t layer_index, uint32_t face_index) const
	{}

	const basisu::uint8_vec* ktx2_transcoder::find_key(const std::string& key_name) const
	{}
	
	bool ktx2_transcoder::start_transcoding()
	{}

	bool ktx2_transcoder::get_image_level_info(ktx2_image_level_info& level_info, uint32_t level_index, uint32_t layer_index, uint32_t face_index) const
	{}
		
	bool ktx2_transcoder::transcode_image_level(
		uint32_t level_index, uint32_t layer_index, uint32_t face_index, 
		void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
		basist::transcoder_texture_format fmt,
		uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, uint32_t output_rows_in_pixels, int channel0, int channel1,
		ktx2_transcoder_state* pState)
	{}
		
	bool ktx2_transcoder::decompress_level_data(uint32_t level_index, basisu::uint8_vec& uncomp_data)
	{}
		
	bool ktx2_transcoder::decompress_etc1s_global_data()
	{}

	bool ktx2_transcoder::read_key_values()
	{}
		
#endif // BASISD_SUPPORT_KTX2

	bool basisu_transcoder_supports_ktx2()
	{}

	bool basisu_transcoder_supports_ktx2_zstd()
	{}

} // namespace basist