<commit_before>// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// --------------------------------------------------------------------------------
//
// Copyright(c) 2016 Playrix LLC
//
// LICENSE: https://mit-license.org

#include <windows.h>
#pragma warning(push)
#pragma warning(disable : 4458)
#include <gdiplus.h>
#pragma warning(pop)

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <smmintrin.h> // SSE4.1
#include <atomic>
#include <chrono>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

#pragma comment(lib, "gdiplus.lib")

#define M128I_I32(mm, index) ((mm).m128i_i32[index])

typedef struct alignas(16) { int Data[8 * 4]; int Count, unused; uint8_t Shift[8]; } Half;
typedef struct alignas(16) { Half A, B; } Elem;

typedef struct alignas(8) { int Error, Color; } Node;

// http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html sRGB
enum { kGreen = 715, kRed = 213, kBlue = 72, kUnknownError = (255 * 255) * 1000 * (4 * 4) + 1 };

static const int g_table[8][2] alignas(16) = { { 2, 8 },{ 5, 17 },{ 9, 29 },{ 13, 42 },{ 18, 60 },{ 24, 80 },{ 33, 106 },{ 47, 183 } };

static const short g_GRB_I16[8] alignas(16) = { kGreen, kRed, kBlue, 0, kGreen, kRed, kBlue, 0 };
static const short g_GR_I16[8] alignas(16) = { kGreen, kRed, kGreen, kRed, kGreen, kRed, kGreen, kRed };

static const int g_colors4[0x10] alignas(16) =
{
	0x00, 0x11, 0x22, 0x33,
	0x44, 0x55, 0x66, 0x77,
	0x88, 0x99, 0xAA, 0xBB,
	0xCC, 0xDD, 0xEE, 0xFF
};

static const int g_colors5[0x20] alignas(16) =
{
	0x00, 0x08, 0x10, 0x18,
	0x21, 0x29, 0x31, 0x39,
	0x42, 0x4A, 0x52, 0x5A,
	0x63, 0x6B, 0x73, 0x7B,
	0x84, 0x8C, 0x94, 0x9C,
	0xA5, 0xAD, 0xB5, 0xBD,
	0xC6, 0xCE, 0xD6, 0xDE,
	0xE7, 0xEF, 0xF7, 0xFF
};

static __m128i g_errors4[8][0x100][0x10 >> 2];
static __m128i g_errors5[8][0x100][0x20 >> 2];

static const double g_ssim_nk1L = (0.01 * 255 * 8) * (0.01 * 255 * 8);
static const double g_ssim_nk2L = (0.03 * 255 * 8) * (0.03 * 255 * 8);

static const int WorkerThreadStackSize = 3 * 1024 * 1024;

static int Stride;

static __forceinline uint32_t BSWAP(uint32_t x)
{
	return _byteswap_ulong(x);
}

static __forceinline uint32_t BROR(uint32_t x)
{
	return _rotr(x, 8);
}

static __forceinline int Min(int x, int y)
{
	return (x < y) ? x : y;
}

static __forceinline int Max(int x, int y)
{
	return (x > y) ? x : y;
}

static __forceinline int ExpandColor5(int c)
{
	return (c << 3) ^ (c >> 2);
}

static __forceinline int ExpandColor4(int c)
{
	return (c << 4) ^ c;
}

static __forceinline __m128i HorizontalMinimum4(__m128i me4)
{
	__m128i me2 = _mm_min_epi32(me4, _mm_shuffle_epi32(me4, _MM_SHUFFLE(2, 3, 0, 1)));
	__m128i me1 = _mm_min_epi32(me2, _mm_shuffle_epi32(me2, _MM_SHUFFLE(0, 1, 2, 3)));
	return me1;
}

static void InitLevelErrors()
{
	for (int q = 0; q < 8; q++)
	{
		int q0 = g_table[q][0];
		int q1 = g_table[q][1];

		for (int i = 0; i < 0x10; i++)
		{
			int c = g_colors4[i];

			int t0 = Min(c + q0, 255);
			int t1 = Min(c + q1, 255);
			int t2 = Max(c - q0, 0);
			int t3 = Max(c - q1, 0);

			for (int x = 0, n = 0x100; x < n; x++)
			{
				int v = Min(Min(abs(x - t0), abs(x - t1)), Min(abs(x - t2), abs(x - t3)));

				((int*)&g_errors4[q][x][0])[i] = v * v;
			}
		}

		for (int i = 0; i < 0x20; i++)
		{
			int c = g_colors5[i];

			int t0 = Min(c + q0, 255);
			int t1 = Min(c + q1, 255);
			int t2 = Max(c - q0, 0);
			int t3 = Max(c - q1, 0);

			for (int x = 0, n = 0x100; x < n; x++)
			{
				int v = Min(Min(abs(x - t0), abs(x - t1)), Min(abs(x - t2), abs(x - t3)));

				((int*)&g_errors5[q][x][0])[i] = v * v;
			}
		}
	}
}

static __forceinline void GuessLevels(const Half& half, size_t offset, Node nodes[0x10 + 1], int weight, int water, int q)
{
#define PROCESS_PIXEL(index) \
	{ \
		const __m128i* p = errors[(size_t)(uint32_t)half.Data[j + index]]; \
		sum0 = _mm_add_epi32(sum0, _mm_load_si128(p + 0)); \
		sum1 = _mm_add_epi32(sum1, _mm_load_si128(p + 1)); \
		sum2 = _mm_add_epi32(sum2, _mm_load_si128(p + 2)); \
		sum3 = _mm_add_epi32(sum3, _mm_load_si128(p + 3)); \
	} \

#define STORE_QUAD(index) \
	if (_mm_movemask_epi8(_mm_cmpgt_epi32(mtop, sum##index)) != 0) \
	{ \
		__m128i sum = _mm_mullo_epi32(_mm_min_epi32(sum##index, mtop), mweight); \
		__m128i mc = _mm_load_si128((__m128i*)&g_colors4[index * 4]); \
	 	level = _mm_min_epi32(level, sum); \
		__m128i mL = _mm_unpacklo_epi32(sum, mc); \
		__m128i mH = _mm_unpackhi_epi32(sum, mc); \
		_mm_store_si128((__m128i*)&nodes[w + 0], mL); \
		_mm_store_si128((__m128i*)&nodes[w + 2], mH); \
		w += 4; \
	} \

	__m128i sum0 = _mm_setzero_si128();
	__m128i sum1 = _mm_setzero_si128();
	__m128i sum2 = _mm_setzero_si128();
	__m128i sum3 = _mm_setzero_si128();

	auto errors = g_errors4[q];

	int k = half.Count; size_t j = offset;
	if (k & 8)
	{
		PROCESS_PIXEL(0);
		PROCESS_PIXEL(4);
		PROCESS_PIXEL(8);
		PROCESS_PIXEL(12);
		PROCESS_PIXEL(16);
		PROCESS_PIXEL(20);
		PROCESS_PIXEL(24);
		PROCESS_PIXEL(28);
	}
	else
	{
		if (k & 4)
		{
			PROCESS_PIXEL(0);
			PROCESS_PIXEL(4);
			PROCESS_PIXEL(8);
			PROCESS_PIXEL(12);

			j += 16;
		}

		if (k & 2)
		{
			PROCESS_PIXEL(0);
			PROCESS_PIXEL(4);

			j += 8;
		}

		if (k & 1)
		{
			PROCESS_PIXEL(0);
		}
	}

	int top = (water + weight - 1) / weight;
	__m128i mweight = _mm_shuffle_epi32(_mm_cvtsi32_si128(weight), 0);
	__m128i mtop = _mm_shuffle_epi32(_mm_cvtsi32_si128(top), 0);
	__m128i level = _mm_mullo_epi32(mtop, mweight);

	size_t w = 0;

	STORE_QUAD(0);
	STORE_QUAD(1);
	STORE_QUAD(2);
	STORE_QUAD(3);

	nodes[0x10].Error = _mm_cvtsi128_si32(HorizontalMinimum4(level));
	nodes[0x10].Color = (int)w;

#undef PROCESS_PIXEL
#undef STORE_QUAD
}

static __forceinline void AdjustLevels(const Half& half, size_t offset, Node nodes[0x20 + 1], int weight, int water, int q)
{
#define PROCESS_PIXEL(index) \
	{ \
		const __m128i* p = errors[(size_t)(uint32_t)half.Data[j + index]]; \
		sum0 = _mm_add_epi32(sum0, _mm_load_si128(p + 0)); \
		sum1 = _mm_add_epi32(sum1, _mm_load_si128(p + 1)); \
		sum2 = _mm_add_epi32(sum2, _mm_load_si128(p + 2)); \
		sum3 = _mm_add_epi32(sum3, _mm_load_si128(p + 3)); \
		sum4 = _mm_add_epi32(sum4, _mm_load_si128(p + 4)); \
		sum5 = _mm_add_epi32(sum5, _mm_load_si128(p + 5)); \
		sum6 = _mm_add_epi32(sum6, _mm_load_si128(p + 6)); \
		sum7 = _mm_add_epi32(sum7, _mm_load_si128(p + 7)); \
	} \

#define STORE_QUAD(index) \
	if (_mm_movemask_epi8(_mm_cmpgt_epi32(mtop, sum##index)) != 0) \
	{ \
		__m128i sum = _mm_mullo_epi32(_mm_min_epi32(sum##index, mtop), mweight); \
		__m128i mc = _mm_load_si128((__m128i*)&g_colors5[index * 4]); \
	 	level = _mm_min_epi32(level, sum); \
		__m128i mL = _mm_unpacklo_epi32(sum, mc); \
		__m128i mH = _mm_unpackhi_epi32(sum, mc); \
		_mm_store_si128((__m128i*)&nodes[w + 0], mL); \
		_mm_store_si128((__m128i*)&nodes[w + 2], mH); \
		w += 4; \
	} \

	__m128i sum0 = _mm_setzero_si128();
	__m128i sum1 = _mm_setzero_si128();
	__m128i sum2 = _mm_setzero_si128();
	__m128i sum3 = _mm_setzero_si128();
	__m128i sum4 = _mm_setzero_si128();
	__m128i sum5 = _mm_setzero_si128();
	__m128i sum6 = _mm_setzero_si128();
	__m128i sum7 = _mm_setzero_si128();

	auto errors = g_errors5[q];

	int k = half.Count; size_t j = offset;
	if (k & 8)
	{
		PROCESS_PIXEL(0);
		PROCESS_PIXEL(4);
		PROCESS_PIXEL(8);
		PROCESS_PIXEL(12);
		PROCESS_PIXEL(16);
		PROCESS_PIXEL(20);
		PROCESS_PIXEL(24);
		PROCESS_PIXEL(28);
	}
	else
	{
		if (k & 4)
		{
			PROCESS_PIXEL(0);
			PROCESS_PIXEL(4);
			PROCESS_PIXEL(8);
			PROCESS_PIXEL(12);

			j += 16;
		}

		if (k & 2)
		{
			PROCESS_PIXEL(0);
			PROCESS_PIXEL(4);

			j += 8;
		}

		if (k & 1)
		{
			PROCESS_PIXEL(0);
		}
	}

	int top = (water + weight - 1) / weight;
	__m128i mweight = _mm_shuffle_epi32(_mm_cvtsi32_si128(weight), 0);
	__m128i mtop = _mm_shuffle_epi32(_mm_cvtsi32_si128(top), 0);
	__m128i level = _mm_mullo_epi32(mtop, mweight);

	size_t w = 0;

	STORE_QUAD(0);
	STORE_QUAD(1);
	STORE_QUAD(2);
	STORE_QUAD(3);
	STORE_QUAD(4);
	STORE_QUAD(5);
	STORE_QUAD(6);
	STORE_QUAD(7);

	nodes[0x20].Error = _mm_cvtsi128_si32(HorizontalMinimum4(level));
	nodes[0x20].Color = (int)w;

#undef PROCESS_PIXEL
#undef STORE_QUAD
}


#define SSIM_INIT() \
	__m128i sa = _mm_setzero_si128(); \
	__m128i sb = _mm_setzero_si128(); \
	__m128i sab = _mm_setzero_si128(); \
	__m128i saa_sbb = _mm_setzero_si128(); \

#define SSIM_UPDATE(a, b) \
	sa = _mm_add_epi32(sa, a); \
	sb = _mm_add_epi32(sb, b); \
	sab = _mm_add_epi32(sab, _mm_mullo_epi16(a, b)); \
	saa_sbb = _mm_add_epi32(saa_sbb, _mm_add_epi32(_mm_mullo_epi16(a, a), _mm_mullo_epi16(b, b))); \

#define SSIM_CLOSE() \
	sab = _mm_slli_epi32(sab, 3 + 1); \
	saa_sbb = _mm_slli_epi32(saa_sbb, 3); \
	__m128i sasb = _mm_mullo_epi32(sa, sb); \
	sasb = _mm_add_epi32(sasb, sasb); \
	__m128i sasa_sbsb = _mm_add_epi32(_mm_mullo_epi32(sa, sa), _mm_mullo_epi32(sb, sb)); \
	sab = _mm_sub_epi32(sab, sasb); \
	saa_sbb = _mm_sub_epi32(saa_sbb, sasa_sbsb); \

#define SSIM_OTHER() \
	sab = _mm_unpackhi_epi64(sab, sab); \
	saa_sbb = _mm_unpackhi_epi64(saa_sbb, saa_sbb); \
	sasb = _mm_unpackhi_epi64(sasb, sasb); \
	sasa_sbsb = _mm_unpackhi_epi64(sasa_sbsb, sasa_sbsb); \

#define SSIM_FINAL(dst) \
	__m128d dst; \
	{ \
		__m128d mc1 = _mm_load1_pd(&g_ssim_nk1L); \
		__m128d mc2 = _mm_load1_pd(&g_ssim_nk2L); \
		dst = _mm_div_pd( \
			_mm_mul_pd(_mm_add_pd(_mm_cvtepi32_pd(sasb), mc1), _mm_add_pd(_mm_cvtepi32_pd(sab), mc2)), \
			_mm_mul_pd(_mm_add_pd(_mm_cvtepi32_pd(sasa_sbsb), mc1), _mm_add_pd(_mm_cvtepi32_pd(saa_sbb), mc2))); \
	} \


static __forceinline void DecompressHalfAlpha(uint8_t pL[4 * 4 - 3], uint8_t pH[4 * 4 - 3], int alpha, int q, uint32_t data, int shift)
{
	static const int g_delta[8][2] alignas(16) =
	{
		{ 2, (8 ^ 2) },
		{ 5, (17 ^ 5) },
		{ 9, (29 ^ 9) },
		{ 13, (42 ^ 13) },
		{ 18, (60 ^ 18) },
		{ 24, (80 ^ 24) },
		{ 33, (106 ^ 33) },
		{ 47, (183 ^ 47) }
	};

	static const int g_mask[16][4] alignas(16) =
	{
		{ 0, 0, 0, 0 },{ -1, 0, 0, 0 },{ 0, -1, 0, 0 },{ -1, -1, 0, 0 },
		{ 0, 0, -1, 0 },{ -1, 0, -1, 0 },{ 0, -1, -1, 0 },{ -1, -1, -1, 0 },
		{ 0, 0, 0, -1 },{ -1, 0, 0, -1 },{ 0, -1, 0, -1 },{ -1, -1, 0, -1 },
		{ 0, 0, -1, -1 },{ -1, 0, -1, -1 },{ 0, -1, -1, -1 },{ -1, -1, -1, -1 }
	};

	__m128i mt0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(g_delta[q][0]), 0);
	__m128i mt10 = _mm_shuffle_epi32(_mm_cvtsi32_si128(g_delta[q][1]), 0);

	__m128i mMaskL = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(shift < 4 ? data << (4 - shift) : data >> (shift - 4)) & 0xF0]);
	__m128i mMaskH = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 4 - 4)) & 0xF0]);

	__m128i mtL = _mm_xor_si128(_mm_and_si128(mMaskL, mt10), mt0);
	__m128i mtH = _mm_xor_si128(_mm_and_si128(mMaskH, mt10), mt0);

	mMaskL = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 16 + 0 - 4)) & 0xF0]);
	mMaskH = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 16 + 4 - 4)) & 0xF0]);

	__m128i mc = _mm_shuffle_epi32(_mm_cvtsi32_si128(alpha), 0);

	__m128i mcL = _mm_or_si128(_mm_and_si128(mMaskL, _mm_subs_epu8(mc, mtL)), _mm_andnot_si128(mMaskL, _mm_adds_epu8(mc, mtL)));
	__m128i mcH = _mm_or_si128(_mm_and_si128(mMaskH, _mm_subs_epu8(mc, mtH)), _mm_andnot_si128(mMaskH, _mm_adds_epu8(mc, mtH)));

	pL[0] = (uint8_t)_mm_extract_epi16(mcL, 0);
	pL[4] = (uint8_t)_mm_extract_epi16(mcL, 2);
	pL[8] = (uint8_t)_mm_extract_epi16(mcL, 4);
	pL[12] = (uint8_t)_mm_extract_epi16(mcL, 6);

	pH[0] = (uint8_t)_mm_extract_epi16(mcH, 0);
	pH[4] = (uint8_t)_mm_extract_epi16(mcH, 2);
	pH[8] = (uint8_t)_mm_extract_epi16(mcH, 4);
	pH[12] = (uint8_t)_mm_extract_epi16(mcH, 6);
}

static __forceinline void DecompressBlockAlpha(const uint8_t input[8], uint8_t* __restrict cell)
{
	cell += 3;

	int a, b;

	uint32_t c = *(const uint32_t*)input;

	if ((c & (2 << 24)) == 0)
	{
		a = c & 0xF0; a |= a >> 4;
		b = c & 0x0F; b |= b << 4;
	}
	else
	{
		a = c & 0xF8;
		b = (((((c & 0x07) ^ 0x24) - 0x04) << 3) + a) & 0xF8;

		a |= (a >> 5) & 0x07;
		b |= (b >> 5) & 0x07;
	}

	uint32_t way = BSWAP(*(const uint32_t*)&input[4]);

	if ((c & (1 << 24)) == 0)
	{
		uint8_t buffer[4 * 4];

		int qa = (c >> (5 + 24)) & 7;
		DecompressHalfAlpha(&buffer[0], &buffer[1], a, qa, way, 0);

		int qb = (c >> (2 + 24)) & 7;
		DecompressHalfAlpha(&buffer[2], &buffer[3], b, qb, way, 8);

		uint8_t* dst = cell;

		dst[0] = buffer[0];
		dst[4] = buffer[1];
		dst[8] = buffer[2];
		dst[12] = buffer[3];

		dst += Stride;

		dst[0] = buffer[4];
		dst[4] = buffer[5];
		dst[8] = buffer[6];
		dst[12] = buffer[7];

		dst += Stride;

		dst[0] = buffer[8];
		dst[4] = buffer[9];
		dst[8] = buffer[10];
		dst[12] = buffer[11];

		dst += Stride;

		dst[0] = buffer[12];
		dst[4] = buffer[13];
		dst[8] = buffer[14];
		dst[12] = buffer[15];
	}
	else
	{
		way =
			((way & 0x00080008u) << 9) ^
			((way & 0x00840084u) << 6) ^
			((way & 0x08420842u) << 3) ^
			((way & 0x84218421u)) ^
			((way & 0x42104210u) >> 3) ^
			((way & 0x21002100u) >> 6) ^
			((way & 0x10001000u) >> 9);

		int qa = (c >> (5 + 24)) & 7;
		DecompressHalfAlpha(cell, cell + Stride, a, qa, way, 0);

		cell += Stride + Stride;

		int qb = (c >> (2 + 24)) & 7;
		DecompressHalfAlpha(cell, cell + Stride, b, qb, way, 8);
	}
}


struct BlockStateAlpha
{
	int a, b, qa, qb, mode;
};

struct GuessStateAlpha
{
	Node node[0x11] alignas(16);

	__forceinline GuessStateAlpha()
	{
	}

	__forceinline int Init(const Half& half, int water, int q)
	{
		GuessLevels(half, 0, node, 1, water, q);

		return node[0x10].Error;
	}

	__forceinline int Find(int error)
	{
		for (int c = 0, n = node[0x10].Color; c < n; c++)
		{
			if (node[c].Error <= error)
			{
				return node[c].Color;
			}
		}

		return 0x10;
	}
};

struct AdjustStateAlpha
{
	Node node[0x21] alignas(16);

	int swap[0x20];

	int stop;

	bool flag_swap;

	__forceinline AdjustStateAlpha()
	{
	}

	__forceinline void Init(const Half& half, int water, int q)
	{
		flag_swap = false;

		AdjustLevels(half, 0, node, 1, water, q);

		stop = node[0x20].Error;
	}

	__forceinline void Index()
	{
		if (flag_swap)
			return;
		flag_swap = true;

		memset(swap, -1, sizeof(swap));

		for (int i = 0, n = node[0x20].Color; i < n; i++)
		{
			int c = node[i].Color >> 3;
			swap[c] = i;
		}
	}
};

struct AdjustStateAlphaGroup
{
	AdjustStateAlpha S[8];

	__forceinline AdjustStateAlphaGroup()
	{
	}

	__forceinline void Init(const Half& half, int water)
	{
		for (int q = 0; q < 8; q++)
		{
			S[q].Init(half, water, q);
		}
	}

	__forceinline int Best(int water) const
	{
		int best = water;

		for (int q = 0; q < 8; q++)
		{
			best = Min(best, S[q].stop);
		}

		return best;
	}
};

static __forceinline double ComputeTableAlpha(const Half& half, int alpha, int q, uint32_t& index, uint32_t order)
{
	__m128i ma = _mm_cvtsi32_si128(alpha);
	ma = _mm_unpacklo_epi32(ma, ma);

	__m128i mt10 = _mm_loadl_epi64((const __m128i*)&g_table[q][0]);

	__m128i mt3210 = _mm_unpacklo_epi64(_mm_adds_epu8(ma, mt10), _mm_subs_epu8(ma, mt10));

	int good = 0xF;
	if (M128I_I32(mt3210, 0) == M128I_I32(mt3210, 1)) good &= ~2;
	if (M128I_I32(mt3210, 2) == M128I_I32(mt3210, 3)) good &= ~8;

	int ways[8];

	__m128i mc = mt3210;

	for (size_t i = 0; i < 8; i++)
	{
		__m128i mb = _mm_shuffle_epi32(_mm_cvtsi32_si128(half.Data[i << 2]), 0);

		__m128i me4 = _mm_abs_epi16(_mm_sub_epi16(mb, mc));

		__m128i me2 = _mm_min_epi16(me4, _mm_shuffle_epi32(me4, _MM_SHUFFLE(2, 3, 0, 1)));
		__m128i me1 = _mm_min_epi16(me2, _mm_shuffle_epi32(me2, _MM_SHUFFLE(0, 1, 2, 3)));

		int way = _mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(me4, me1)));
		ways[i] = (way & good) | (1 << 4);
	}

	int loops[8];

	for (size_t i = 0; i < 8; i++)
	{
		int k = 0;
		while ((ways[i] & (1 << k)) == 0) k++;
		loops[i] = k;
	}

	double best = -1.1;
	uint32_t codes = 0;

	for (;; )
	{
		SSIM_INIT();

		for (size_t i = 0; i < 8; i++)
		{
			__m128i mt = _mm_cvtsi32_si128(M128I_I32(mt3210, (size_t)(uint32_t)loops[i]));

			__m128i mb = _mm_cvtsi32_si128(half.Data[i << 2]);

			SSIM_UPDATE(mt, mb);
		}

		SSIM_CLOSE();

		SSIM_FINAL(mssim);

		double ssim = _mm_cvtsd_f64(mssim);

		if (best < ssim)
		{
			best = ssim;

			uint32_t v = 0;
			for (size_t j = 0; j < 8; j++)
			{
				v |= ((uint32_t)loops[j]) << (j + j);
			}
			codes = v;

			if (best >= 1.0)
				break;
		}

		size_t i = 0;
		for (;; )
		{
			int k = loops[i];
			if (ways[i] != (1 << k))
			{
				do { k++; } while ((ways[i] & (1 << k)) == 0);
				if (k < 4)
				{
					loops[i] = k;
					break;
				}

				k = 0;
				while ((ways[i] & (1 << k)) == 0) k++;
				loops[i] = k;
			}

			i++;
			if (i & 8)
				break;
		}
		if (i & 8)
			break;
	}

	for (int i = 8; --i >= 0;)
	{
		int shift = order & 0xF;

		order >>= 4;

		uint32_t code = ((codes & 2u) << (16 - 1)) | (codes & 1u);

		codes >>= 2;

		index |= code << shift;
	}

	return best;
}

static __forceinline int GuessAlpha4(const Half& half, int& alpha, int water, int& table)
{
	GuessStateAlpha SA;

	for (int q = 0; q < 8; q++)
	{
		int error = SA.Init(half, water, q);

		if (water > error)
		{
			water = error;

			alpha = SA.Find(error);
			table = q;

			if (water <= 0)
				break;
		}
	}

	return water;
}

static int CompressBlockAlpha44(BlockStateAlpha& s, const Elem& elem, int water, int mode)
{
	int a, b, qa, qb;

	int err = GuessAlpha4(elem.A, a, water, qa);
	if (err >= water)
		return water;

	err += GuessAlpha4(elem.B, b, water - err, qb);
	if (err >= water)
		return water;

	s.a = a;
	s.b = b;
	s.qa = qa;
	s.qb = qb;
	s.mode = mode;

	return err;
}

static __forceinline int AdjustAlphas53(int& alpha, int& other, int water, AdjustStateAlpha& SA, AdjustStateAlpha& SB)
{
	SB.Index();

	for (int a0 = 0; a0 < SA.node[0x20].Color; a0++)
	{
		int e0 = SA.node[a0].Error;
		if (e0 + SB.stop >= water)
			continue;

		int a = SA.node[a0].Color;

		int Id = a >> 3;
		int Ld = Max(Id - 4, 0);
		int Hd = Min(Id + 3, 31);

		for (int d0 = Ld; d0 <= Hd; d0++)
		{
			int b0 = SB.swap[d0];
			if (b0 < 0)
				continue;

			int e1 = SB.node[b0].Error + e0;
			if (e1 >= water)
				continue;

			water = e1;

			alpha = a;
			other = SB.node[b0].Color;

			if (water <= e0 + SB.stop)
				break;
		}
	}

	return water;
}

static int CompressBlockAlpha53(BlockStateAlpha& s, const Elem& elem, int water, int mode)
{
	AdjustStateAlphaGroup GB;

	GB.Init(elem.B, water);

	int stopB = GB.Best(water);
	if (stopB >= water)
		return water;

	AdjustStateAlphaGroup GA;

	GA.Init(elem.A, water - stopB);

	for (int qa = 0; qa < 8; qa++)
	{
		int bestA = GA.Best(water - stopB);
		if (bestA + stopB >= water)
			return water;

		AdjustStateAlpha& SA = GA.S[qa];

		for (int qb = 0; qb < 8; qb++)
		{
			AdjustStateAlpha& SB = GB.S[qb];

			if (SA.stop + stopB >= water)
				break;

			if (SA.stop + SB.stop >= water)
				continue;

			int error = AdjustAlphas53(s.a, s.b, water, SA, SB);

			if (water > error)
			{
				water = error;

				s.qa = qa;
				s.qb = qb;
				s.mode = mode;
			}
		}

		SA.stop = water;
	}

	return water;
}

static __forceinline int MeasureHalfAlpha(const int pL[4 * 4], const int pH[4 * 4], int alpha, int q, uint32_t dataL, uint32_t dataH, int slice, int shift)
{
	__m128i ma = _mm_cvtsi32_si128(alpha);
	ma = _mm_unpacklo_epi32(ma, ma);

	__m128i mt10 = _mm_loadl_epi64((const __m128i*)&g_table[q][0]);

	__m128i mt3210 = _mm_unpacklo_epi64(_mm_adds_epu8(ma, mt10), _mm_subs_epu8(ma, mt10));

	__m128i sum = _mm_setzero_si128();

	for (int i = 0; i < 4; i++)
	{
		__m128i m = _mm_cvtsi32_si128(*pL);

		__m128i mt = mt3210;

		if ((dataL & 0x10000u) != 0)
		{
			mt = _mm_shuffle_epi32(mt, _MM_SHUFFLE(1, 0, 3, 2));
		}

		if ((dataL & 1u) != 0)
		{
			mt = _mm_shuffle_epi32(mt, _MM_SHUFFLE(2, 3, 0, 1));
		}

		m = _mm_sub_epi16(m, mt);
		m = _mm_mullo_epi16(m, m);

		sum = _mm_add_epi32(sum, m);

		pL += slice;

		dataL >>= shift;
	}

	for (int i = 0; i < 4; i++)
	{
		__m128i m = _mm_cvtsi32_si128(*pH);

		__m128i mt = mt3210;

		if ((dataH & 0x10000u) != 0)
		{
			mt = _mm_shuffle_epi32(mt, _MM_SHUFFLE(1, 0, 3, 2));
		}

		if ((dataH & 1u) != 0)
		{
			mt = _mm_shuffle_epi32(mt, _MM_SHUFFLE(2, 3, 0, 1));
		}

		m = _mm_sub_epi16(m, mt);
		m = _mm_mullo_epi16(m, m);

		sum = _mm_add_epi32(sum, m);

		pH += slice;

		dataH >>= shift;
	}

	return _mm_cvtsi128_si32(sum);
}

static __m128i CompressBlockAlpha(uint8_t output[8], const uint8_t* __restrict cell)
{
	Elem norm, flip;

	{
		const uint8_t* src = cell;

		int c00 = src[3]; flip.A.Data[0] = c00; norm.A.Data[0] = c00;
		int c01 = src[7]; flip.A.Data[4] = c01; norm.A.Data[4] = c01;
		int c02 = src[11]; flip.A.Data[8] = c02; norm.B.Data[0] = c02;
		int c03 = src[15]; flip.A.Data[12] = c03; norm.B.Data[4] = c03;

		src += Stride;

		int c10 = src[3]; flip.A.Data[16] = c10; norm.A.Data[8] = c10;
		int c11 = src[7]; flip.A.Data[20] = c11; norm.A.Data[12] = c11;
		int c12 = src[11]; flip.A.Data[24] = c12; norm.B.Data[8] = c12;
		int c13 = src[15]; flip.A.Data[28] = c13; norm.B.Data[12] = c13;

		src += Stride;

		int c20 = src[3]; flip.B.Data[0] = c20; norm.A.Data[16] = c20;
		int c21 = src[7]; flip.B.Data[4] = c21; norm.A.Data[20] = c21;
		int c22 = src[11]; flip.B.Data[8] = c22; norm.B.Data[16] = c22;
		int c23 = src[15]; flip.B.Data[12] = c23; norm.B.Data[20] = c23;

		src += Stride;

		int c30 = src[3]; flip.B.Data[16] = c30; norm.A.Data[24] = c30;
		int c31 = src[7]; flip.B.Data[20] = c31; norm.A.Data[28] = c31;
		int c32 = src[11]; flip.B.Data[24] = c32; norm.B.Data[24] = c32;
		int c33 = src[15]; flip.B.Data[28] = c33; norm.B.Data[28] = c33;
	}

	BlockStateAlpha s;

	int err;
	{
		int c0 = output[0];

		int f = output[3];

		s.mode = f & 3;

		if ((f & 2) == 0)
		{
			s.a = (uint8_t)ExpandColor4(c0 >> 4);
			s.b = (uint8_t)ExpandColor4(c0 & 0xF);
		}
		else
		{
			s.a = (uint8_t)ExpandColor5(c0 >> 3);
			s.b = (uint8_t)ExpandColor5((c0 >> 3) + (int(uint32_t(c0) << 29) >> 29));
		}

		s.qa = (f >> 5) & 7;
		s.qb = (f >> 2) & 7;

		uint32_t way = BSWAP(*(const uint32_t*)&output[4]);

		if ((f & 1) == 0)
		{
			err = MeasureHalfAlpha(norm.A.Data, norm.A.Data + 1 * 4, s.a, s.qa, way, way >> 4, 2 * 4, 1);
			err += MeasureHalfAlpha(norm.B.Data, norm.B.Data + 1 * 4, s.b, s.qb, way >> 8, way >> 12, 2 * 4, 1);
		}
		else
		{
			err = MeasureHalfAlpha(flip.A.Data, flip.A.Data + 4 * 4, s.a, s.qa, way, way >> 1, 1 * 4, 4);
			err += MeasureHalfAlpha(flip.B.Data, flip.B.Data + 4 * 4, s.b, s.qb, way >> 2, way >> 3, 1 * 4, 4);
		}
	}

	norm.A.Count = 8;
	norm.B.Count = 8;

	flip.A.Count = 8;
	flip.B.Count = 8;

	if (err > 0)
	{
		int err_norm44 = CompressBlockAlpha44(s, norm, err, 0);
		if (err > err_norm44)
			err = err_norm44;

		if (err > 0)
		{
			int err_flip44 = CompressBlockAlpha44(s, flip, err, 1);
			if (err > err_flip44)
				err = err_flip44;

			if (err > 0)
			{
				int err_norm53 = CompressBlockAlpha53(s, norm, err, 2);
				if (err > err_norm53)
					err = err_norm53;

				if (err > 0)
				{
					int err_flip53 = CompressBlockAlpha53(s, flip, err, 3);
					if (err > err_flip53)
						err = err_flip53;
				}
			}
		}
	}

	double ssim;
	{
		uint32_t index = 0;

		bool f = (s.mode & 1) != 0;
		ssim = ComputeTableAlpha(f ? flip.A : norm.A, s.a, s.qa, index, f ? 0xD951C840u : 0x73625140u);
		ssim += ComputeTableAlpha(f ? flip.B : norm.B, s.b, s.qb, index, f ? 0xD951C840u + 0x22222222u : 0x73625140u + 0x88888888u);

		uint8_t c = (s.mode & 2) ?
			(uint8_t)((s.a & 0xF8) ^ (((s.b >> 3) - (s.a >> 3)) & 7)) :
			(uint8_t)((s.a & 0xF0) ^ (s.b & 0x0F));

		output[0] = c;
		output[1] = c;
		output[2] = c;

		output[3] = (uint8_t)((s.qa << 5) ^ (s.qb << 2) ^ s.mode);

		*(uint32_t*)&output[4] = BSWAP(index);
	}

	return _mm_unpacklo_epi64(_mm_cvtsi32_si128(err), _mm_castpd_si128(_mm_load_sd(&ssim)));
}


static __forceinline void DecompressHalfColor(int pL[4], int pH[4], int color, int q, uint32_t data, int shift)
{
	static const int g_delta[8][2] alignas(16) =
	{
		{ 2 * 0x010101, (8 ^ 2) * 0x010101 },
		{ 5 * 0x010101, (17 ^ 5) * 0x010101 },
		{ 9 * 0x010101, (29 ^ 9) * 0x010101 },
		{ 13 * 0x010101, (42 ^ 13) * 0x010101 },
		{ 18 * 0x010101, (60 ^ 18) * 0x010101 },
		{ 24 * 0x010101, (80 ^ 24) * 0x010101 },
		{ 33 * 0x010101, (106 ^ 33) * 0x010101 },
		{ 47 * 0x010101, (183 ^ 47) * 0x010101 }
	};

	static const int g_mask[16][4] alignas(16) =
	{
		{ 0, 0, 0, 0 },{ -1, 0, 0, 0 },{ 0, -1, 0, 0 },{ -1, -1, 0, 0 },
		{ 0, 0, -1, 0 },{ -1, 0, -1, 0 },{ 0, -1, -1, 0 },{ -1, -1, -1, 0 },
		{ 0, 0, 0, -1 },{ -1, 0, 0, -1 },{ 0, -1, 0, -1 },{ -1, -1, 0, -1 },
		{ 0, 0, -1, -1 },{ -1, 0, -1, -1 },{ 0, -1, -1, -1 },{ -1, -1, -1, -1 }
	};

	__m128i mt0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(g_delta[q][0]), 0);
	__m128i mt10 = _mm_shuffle_epi32(_mm_cvtsi32_si128(g_delta[q][1]), 0);

	__m128i mMaskL = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(shift < 4 ? data << (4 - shift) : data >> (shift - 4)) & 0xF0]);
	__m128i mMaskH = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 4 - 4)) & 0xF0]);

	__m128i mtL = _mm_xor_si128(_mm_and_si128(mMaskL, mt10), mt0);
	__m128i mtH = _mm_xor_si128(_mm_and_si128(mMaskH, mt10), mt0);

	mMaskL = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 16 + 0 - 4)) & 0xF0]);
	mMaskH = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 16 + 4 - 4)) & 0xF0]);

	__m128i mc = _mm_shuffle_epi32(_mm_cvtsi32_si128(color), 0);

	__m128i mcL = _mm_or_si128(_mm_and_si128(mMaskL, _mm_subs_epu8(mc, mtL)), _mm_andnot_si128(mMaskL, _mm_adds_epu8(mc, mtL)));
	__m128i mcH = _mm_or_si128(_mm_and_si128(mMaskH, _mm_subs_epu8(mc, mtH)), _mm_andnot_si128(mMaskH, _mm_adds_epu8(mc, mtH)));

	_mm_storeu_si128((__m128i*)pL, mcL);
	_mm_storeu_si128((__m128i*)pH, mcH);
}

static __forceinline void DecompressBlockColor(const uint8_t input[8], uint8_t* __restrict cell)
{
	int a, b;

	uint32_t c = *(const uint32_t*)input;

	c = BROR(BSWAP(c));

	if ((c & (2 << 24)) == 0)
	{
		a = c & 0xF0F0F0; a |= a >> 4;
		b = c & 0x0F0F0F; b |= b << 4;
	}
	else
	{
		a = c & 0xF8F8F8;
		b = (((((c & 0x070707) ^ 0x242424) - 0x040404) << 3) + a) & 0xF8F8F8;

		a |= (a >> 5) & 0x070707;
		b |= (b >> 5) & 0x070707;
	}

	a |= 0xFFu << 24;
	b |= 0xFFu << 24;

	uint32_t way = BSWAP(*(const uint32_t*)&input[4]);
<commit_msg>Отлов invalid combinations используемых в ETC2<commit_after>// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// --------------------------------------------------------------------------------
//
// Copyright(c) 2016 Playrix LLC
//
// LICENSE: https://mit-license.org

#include <windows.h>
#pragma warning(push)
#pragma warning(disable : 4458)
#include <gdiplus.h>
#pragma warning(pop)

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <smmintrin.h> // SSE4.1
#include <atomic>
#include <chrono>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

#pragma comment(lib, "gdiplus.lib")

#define M128I_I32(mm, index) ((mm).m128i_i32[index])

typedef struct alignas(16) { int Data[8 * 4]; int Count, unused; uint8_t Shift[8]; } Half;
typedef struct alignas(16) { Half A, B; } Elem;

typedef struct alignas(8) { int Error, Color; } Node;

// http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html sRGB
enum { kGreen = 715, kRed = 213, kBlue = 72, kUnknownError = (255 * 255) * 1000 * (4 * 4) + 1 };

static const int g_table[8][2] alignas(16) = { { 2, 8 },{ 5, 17 },{ 9, 29 },{ 13, 42 },{ 18, 60 },{ 24, 80 },{ 33, 106 },{ 47, 183 } };

static const short g_GRB_I16[8] alignas(16) = { kGreen, kRed, kBlue, 0, kGreen, kRed, kBlue, 0 };
static const short g_GR_I16[8] alignas(16) = { kGreen, kRed, kGreen, kRed, kGreen, kRed, kGreen, kRed };

static const int g_colors4[0x10] alignas(16) =
{
	0x00, 0x11, 0x22, 0x33,
	0x44, 0x55, 0x66, 0x77,
	0x88, 0x99, 0xAA, 0xBB,
	0xCC, 0xDD, 0xEE, 0xFF
};

static const int g_colors5[0x20] alignas(16) =
{
	0x00, 0x08, 0x10, 0x18,
	0x21, 0x29, 0x31, 0x39,
	0x42, 0x4A, 0x52, 0x5A,
	0x63, 0x6B, 0x73, 0x7B,
	0x84, 0x8C, 0x94, 0x9C,
	0xA5, 0xAD, 0xB5, 0xBD,
	0xC6, 0xCE, 0xD6, 0xDE,
	0xE7, 0xEF, 0xF7, 0xFF
};

static __m128i g_errors4[8][0x100][0x10 >> 2];
static __m128i g_errors5[8][0x100][0x20 >> 2];

static const double g_ssim_nk1L = (0.01 * 255 * 8) * (0.01 * 255 * 8);
static const double g_ssim_nk2L = (0.03 * 255 * 8) * (0.03 * 255 * 8);

static const int WorkerThreadStackSize = 3 * 1024 * 1024;

static int Stride;

static __forceinline uint32_t BSWAP(uint32_t x)
{
	return _byteswap_ulong(x);
}

static __forceinline uint32_t BROR(uint32_t x)
{
	return _rotr(x, 8);
}

static __forceinline int Min(int x, int y)
{
	return (x < y) ? x : y;
}

static __forceinline int Max(int x, int y)
{
	return (x > y) ? x : y;
}

static __forceinline int ExpandColor5(int c)
{
	return (c << 3) ^ (c >> 2);
}

static __forceinline int ExpandColor4(int c)
{
	return (c << 4) ^ c;
}

static __forceinline __m128i HorizontalMinimum4(__m128i me4)
{
	__m128i me2 = _mm_min_epi32(me4, _mm_shuffle_epi32(me4, _MM_SHUFFLE(2, 3, 0, 1)));
	__m128i me1 = _mm_min_epi32(me2, _mm_shuffle_epi32(me2, _MM_SHUFFLE(0, 1, 2, 3)));
	return me1;
}

static void InitLevelErrors()
{
	for (int q = 0; q < 8; q++)
	{
		int q0 = g_table[q][0];
		int q1 = g_table[q][1];

		for (int i = 0; i < 0x10; i++)
		{
			int c = g_colors4[i];

			int t0 = Min(c + q0, 255);
			int t1 = Min(c + q1, 255);
			int t2 = Max(c - q0, 0);
			int t3 = Max(c - q1, 0);

			for (int x = 0, n = 0x100; x < n; x++)
			{
				int v = Min(Min(abs(x - t0), abs(x - t1)), Min(abs(x - t2), abs(x - t3)));

				((int*)&g_errors4[q][x][0])[i] = v * v;
			}
		}

		for (int i = 0; i < 0x20; i++)
		{
			int c = g_colors5[i];

			int t0 = Min(c + q0, 255);
			int t1 = Min(c + q1, 255);
			int t2 = Max(c - q0, 0);
			int t3 = Max(c - q1, 0);

			for (int x = 0, n = 0x100; x < n; x++)
			{
				int v = Min(Min(abs(x - t0), abs(x - t1)), Min(abs(x - t2), abs(x - t3)));

				((int*)&g_errors5[q][x][0])[i] = v * v;
			}
		}
	}
}

static __forceinline void GuessLevels(const Half& half, size_t offset, Node nodes[0x10 + 1], int weight, int water, int q)
{
#define PROCESS_PIXEL(index) \
	{ \
		const __m128i* p = errors[(size_t)(uint32_t)half.Data[j + index]]; \
		sum0 = _mm_add_epi32(sum0, _mm_load_si128(p + 0)); \
		sum1 = _mm_add_epi32(sum1, _mm_load_si128(p + 1)); \
		sum2 = _mm_add_epi32(sum2, _mm_load_si128(p + 2)); \
		sum3 = _mm_add_epi32(sum3, _mm_load_si128(p + 3)); \
	} \

#define STORE_QUAD(index) \
	if (_mm_movemask_epi8(_mm_cmpgt_epi32(mtop, sum##index)) != 0) \
	{ \
		__m128i sum = _mm_mullo_epi32(_mm_min_epi32(sum##index, mtop), mweight); \
		__m128i mc = _mm_load_si128((__m128i*)&g_colors4[index * 4]); \
	 	level = _mm_min_epi32(level, sum); \
		__m128i mL = _mm_unpacklo_epi32(sum, mc); \
		__m128i mH = _mm_unpackhi_epi32(sum, mc); \
		_mm_store_si128((__m128i*)&nodes[w + 0], mL); \
		_mm_store_si128((__m128i*)&nodes[w + 2], mH); \
		w += 4; \
	} \

	__m128i sum0 = _mm_setzero_si128();
	__m128i sum1 = _mm_setzero_si128();
	__m128i sum2 = _mm_setzero_si128();
	__m128i sum3 = _mm_setzero_si128();

	auto errors = g_errors4[q];

	int k = half.Count; size_t j = offset;
	if (k & 8)
	{
		PROCESS_PIXEL(0);
		PROCESS_PIXEL(4);
		PROCESS_PIXEL(8);
		PROCESS_PIXEL(12);
		PROCESS_PIXEL(16);
		PROCESS_PIXEL(20);
		PROCESS_PIXEL(24);
		PROCESS_PIXEL(28);
	}
	else
	{
		if (k & 4)
		{
			PROCESS_PIXEL(0);
			PROCESS_PIXEL(4);
			PROCESS_PIXEL(8);
			PROCESS_PIXEL(12);

			j += 16;
		}

		if (k & 2)
		{
			PROCESS_PIXEL(0);
			PROCESS_PIXEL(4);

			j += 8;
		}

		if (k & 1)
		{
			PROCESS_PIXEL(0);
		}
	}

	int top = (water + weight - 1) / weight;
	__m128i mweight = _mm_shuffle_epi32(_mm_cvtsi32_si128(weight), 0);
	__m128i mtop = _mm_shuffle_epi32(_mm_cvtsi32_si128(top), 0);
	__m128i level = _mm_mullo_epi32(mtop, mweight);

	size_t w = 0;

	STORE_QUAD(0);
	STORE_QUAD(1);
	STORE_QUAD(2);
	STORE_QUAD(3);

	nodes[0x10].Error = _mm_cvtsi128_si32(HorizontalMinimum4(level));
	nodes[0x10].Color = (int)w;

#undef PROCESS_PIXEL
#undef STORE_QUAD
}

static __forceinline void AdjustLevels(const Half& half, size_t offset, Node nodes[0x20 + 1], int weight, int water, int q)
{
#define PROCESS_PIXEL(index) \
	{ \
		const __m128i* p = errors[(size_t)(uint32_t)half.Data[j + index]]; \
		sum0 = _mm_add_epi32(sum0, _mm_load_si128(p + 0)); \
		sum1 = _mm_add_epi32(sum1, _mm_load_si128(p + 1)); \
		sum2 = _mm_add_epi32(sum2, _mm_load_si128(p + 2)); \
		sum3 = _mm_add_epi32(sum3, _mm_load_si128(p + 3)); \
		sum4 = _mm_add_epi32(sum4, _mm_load_si128(p + 4)); \
		sum5 = _mm_add_epi32(sum5, _mm_load_si128(p + 5)); \
		sum6 = _mm_add_epi32(sum6, _mm_load_si128(p + 6)); \
		sum7 = _mm_add_epi32(sum7, _mm_load_si128(p + 7)); \
	} \

#define STORE_QUAD(index) \
	if (_mm_movemask_epi8(_mm_cmpgt_epi32(mtop, sum##index)) != 0) \
	{ \
		__m128i sum = _mm_mullo_epi32(_mm_min_epi32(sum##index, mtop), mweight); \
		__m128i mc = _mm_load_si128((__m128i*)&g_colors5[index * 4]); \
	 	level = _mm_min_epi32(level, sum); \
		__m128i mL = _mm_unpacklo_epi32(sum, mc); \
		__m128i mH = _mm_unpackhi_epi32(sum, mc); \
		_mm_store_si128((__m128i*)&nodes[w + 0], mL); \
		_mm_store_si128((__m128i*)&nodes[w + 2], mH); \
		w += 4; \
	} \

	__m128i sum0 = _mm_setzero_si128();
	__m128i sum1 = _mm_setzero_si128();
	__m128i sum2 = _mm_setzero_si128();
	__m128i sum3 = _mm_setzero_si128();
	__m128i sum4 = _mm_setzero_si128();
	__m128i sum5 = _mm_setzero_si128();
	__m128i sum6 = _mm_setzero_si128();
	__m128i sum7 = _mm_setzero_si128();

	auto errors = g_errors5[q];

	int k = half.Count; size_t j = offset;
	if (k & 8)
	{
		PROCESS_PIXEL(0);
		PROCESS_PIXEL(4);
		PROCESS_PIXEL(8);
		PROCESS_PIXEL(12);
		PROCESS_PIXEL(16);
		PROCESS_PIXEL(20);
		PROCESS_PIXEL(24);
		PROCESS_PIXEL(28);
	}
	else
	{
		if (k & 4)
		{
			PROCESS_PIXEL(0);
			PROCESS_PIXEL(4);
			PROCESS_PIXEL(8);
			PROCESS_PIXEL(12);

			j += 16;
		}

		if (k & 2)
		{
			PROCESS_PIXEL(0);
			PROCESS_PIXEL(4);

			j += 8;
		}

		if (k & 1)
		{
			PROCESS_PIXEL(0);
		}
	}

	int top = (water + weight - 1) / weight;
	__m128i mweight = _mm_shuffle_epi32(_mm_cvtsi32_si128(weight), 0);
	__m128i mtop = _mm_shuffle_epi32(_mm_cvtsi32_si128(top), 0);
	__m128i level = _mm_mullo_epi32(mtop, mweight);

	size_t w = 0;

	STORE_QUAD(0);
	STORE_QUAD(1);
	STORE_QUAD(2);
	STORE_QUAD(3);
	STORE_QUAD(4);
	STORE_QUAD(5);
	STORE_QUAD(6);
	STORE_QUAD(7);

	nodes[0x20].Error = _mm_cvtsi128_si32(HorizontalMinimum4(level));
	nodes[0x20].Color = (int)w;

#undef PROCESS_PIXEL
#undef STORE_QUAD
}


#define SSIM_INIT() \
	__m128i sa = _mm_setzero_si128(); \
	__m128i sb = _mm_setzero_si128(); \
	__m128i sab = _mm_setzero_si128(); \
	__m128i saa_sbb = _mm_setzero_si128(); \

#define SSIM_UPDATE(a, b) \
	sa = _mm_add_epi32(sa, a); \
	sb = _mm_add_epi32(sb, b); \
	sab = _mm_add_epi32(sab, _mm_mullo_epi16(a, b)); \
	saa_sbb = _mm_add_epi32(saa_sbb, _mm_add_epi32(_mm_mullo_epi16(a, a), _mm_mullo_epi16(b, b))); \

#define SSIM_CLOSE() \
	sab = _mm_slli_epi32(sab, 3 + 1); \
	saa_sbb = _mm_slli_epi32(saa_sbb, 3); \
	__m128i sasb = _mm_mullo_epi32(sa, sb); \
	sasb = _mm_add_epi32(sasb, sasb); \
	__m128i sasa_sbsb = _mm_add_epi32(_mm_mullo_epi32(sa, sa), _mm_mullo_epi32(sb, sb)); \
	sab = _mm_sub_epi32(sab, sasb); \
	saa_sbb = _mm_sub_epi32(saa_sbb, sasa_sbsb); \

#define SSIM_OTHER() \
	sab = _mm_unpackhi_epi64(sab, sab); \
	saa_sbb = _mm_unpackhi_epi64(saa_sbb, saa_sbb); \
	sasb = _mm_unpackhi_epi64(sasb, sasb); \
	sasa_sbsb = _mm_unpackhi_epi64(sasa_sbsb, sasa_sbsb); \

#define SSIM_FINAL(dst) \
	__m128d dst; \
	{ \
		__m128d mc1 = _mm_load1_pd(&g_ssim_nk1L); \
		__m128d mc2 = _mm_load1_pd(&g_ssim_nk2L); \
		dst = _mm_div_pd( \
			_mm_mul_pd(_mm_add_pd(_mm_cvtepi32_pd(sasb), mc1), _mm_add_pd(_mm_cvtepi32_pd(sab), mc2)), \
			_mm_mul_pd(_mm_add_pd(_mm_cvtepi32_pd(sasa_sbsb), mc1), _mm_add_pd(_mm_cvtepi32_pd(saa_sbb), mc2))); \
	} \


static __forceinline void DecompressHalfAlpha(uint8_t pL[4 * 4 - 3], uint8_t pH[4 * 4 - 3], int alpha, int q, uint32_t data, int shift)
{
	static const int g_delta[8][2] alignas(16) =
	{
		{ 2, (8 ^ 2) },
		{ 5, (17 ^ 5) },
		{ 9, (29 ^ 9) },
		{ 13, (42 ^ 13) },
		{ 18, (60 ^ 18) },
		{ 24, (80 ^ 24) },
		{ 33, (106 ^ 33) },
		{ 47, (183 ^ 47) }
	};

	static const int g_mask[16][4] alignas(16) =
	{
		{ 0, 0, 0, 0 },{ -1, 0, 0, 0 },{ 0, -1, 0, 0 },{ -1, -1, 0, 0 },
		{ 0, 0, -1, 0 },{ -1, 0, -1, 0 },{ 0, -1, -1, 0 },{ -1, -1, -1, 0 },
		{ 0, 0, 0, -1 },{ -1, 0, 0, -1 },{ 0, -1, 0, -1 },{ -1, -1, 0, -1 },
		{ 0, 0, -1, -1 },{ -1, 0, -1, -1 },{ 0, -1, -1, -1 },{ -1, -1, -1, -1 }
	};

	__m128i mt0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(g_delta[q][0]), 0);
	__m128i mt10 = _mm_shuffle_epi32(_mm_cvtsi32_si128(g_delta[q][1]), 0);

	__m128i mMaskL = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(shift < 4 ? data << (4 - shift) : data >> (shift - 4)) & 0xF0]);
	__m128i mMaskH = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 4 - 4)) & 0xF0]);

	__m128i mtL = _mm_xor_si128(_mm_and_si128(mMaskL, mt10), mt0);
	__m128i mtH = _mm_xor_si128(_mm_and_si128(mMaskH, mt10), mt0);

	mMaskL = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 16 + 0 - 4)) & 0xF0]);
	mMaskH = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 16 + 4 - 4)) & 0xF0]);

	__m128i mc = _mm_shuffle_epi32(_mm_cvtsi32_si128(alpha), 0);

	__m128i mcL = _mm_or_si128(_mm_and_si128(mMaskL, _mm_subs_epu8(mc, mtL)), _mm_andnot_si128(mMaskL, _mm_adds_epu8(mc, mtL)));
	__m128i mcH = _mm_or_si128(_mm_and_si128(mMaskH, _mm_subs_epu8(mc, mtH)), _mm_andnot_si128(mMaskH, _mm_adds_epu8(mc, mtH)));

	pL[0] = (uint8_t)_mm_extract_epi16(mcL, 0);
	pL[4] = (uint8_t)_mm_extract_epi16(mcL, 2);
	pL[8] = (uint8_t)_mm_extract_epi16(mcL, 4);
	pL[12] = (uint8_t)_mm_extract_epi16(mcL, 6);

	pH[0] = (uint8_t)_mm_extract_epi16(mcH, 0);
	pH[4] = (uint8_t)_mm_extract_epi16(mcH, 2);
	pH[8] = (uint8_t)_mm_extract_epi16(mcH, 4);
	pH[12] = (uint8_t)_mm_extract_epi16(mcH, 6);
}

static __forceinline void DecompressBlockAlpha(const uint8_t input[8], uint8_t* __restrict cell)
{
	cell += 3;

	int a, b;

	uint32_t c = *(const uint32_t*)input;

	if ((c & (2 << 24)) == 0)
	{
		a = c & 0xF0; a |= a >> 4;
		b = c & 0x0F; b |= b << 4;
	}
	else
	{
		a = c & 0xF8;
		b = ((((c & 0x07) ^ 0x44) - 0x04) << 3) + a;
		if (b & 0x0100)
		{
			__debugbreak();
			return;
		}
		b &= 0xF8;

		a |= (a >> 5) & 0x07;
		b |= (b >> 5) & 0x07;
	}

	uint32_t way = BSWAP(*(const uint32_t*)&input[4]);

	if ((c & (1 << 24)) == 0)
	{
		uint8_t buffer[4 * 4];

		int qa = (c >> (5 + 24)) & 7;
		DecompressHalfAlpha(&buffer[0], &buffer[1], a, qa, way, 0);

		int qb = (c >> (2 + 24)) & 7;
		DecompressHalfAlpha(&buffer[2], &buffer[3], b, qb, way, 8);

		uint8_t* dst = cell;

		dst[0] = buffer[0];
		dst[4] = buffer[1];
		dst[8] = buffer[2];
		dst[12] = buffer[3];

		dst += Stride;

		dst[0] = buffer[4];
		dst[4] = buffer[5];
		dst[8] = buffer[6];
		dst[12] = buffer[7];

		dst += Stride;

		dst[0] = buffer[8];
		dst[4] = buffer[9];
		dst[8] = buffer[10];
		dst[12] = buffer[11];

		dst += Stride;

		dst[0] = buffer[12];
		dst[4] = buffer[13];
		dst[8] = buffer[14];
		dst[12] = buffer[15];
	}
	else
	{
		way =
			((way & 0x00080008u) << 9) ^
			((way & 0x00840084u) << 6) ^
			((way & 0x08420842u) << 3) ^
			((way & 0x84218421u)) ^
			((way & 0x42104210u) >> 3) ^
			((way & 0x21002100u) >> 6) ^
			((way & 0x10001000u) >> 9);

		int qa = (c >> (5 + 24)) & 7;
		DecompressHalfAlpha(cell, cell + Stride, a, qa, way, 0);

		cell += Stride + Stride;

		int qb = (c >> (2 + 24)) & 7;
		DecompressHalfAlpha(cell, cell + Stride, b, qb, way, 8);
	}
}


struct BlockStateAlpha
{
	int a, b, qa, qb, mode;
};

struct GuessStateAlpha
{
	Node node[0x11] alignas(16);

	__forceinline GuessStateAlpha()
	{
	}

	__forceinline int Init(const Half& half, int water, int q)
	{
		GuessLevels(half, 0, node, 1, water, q);

		return node[0x10].Error;
	}

	__forceinline int Find(int error)
	{
		for (int c = 0, n = node[0x10].Color; c < n; c++)
		{
			if (node[c].Error <= error)
			{
				return node[c].Color;
			}
		}

		return 0x10;
	}
};

struct AdjustStateAlpha
{
	Node node[0x21] alignas(16);

	int swap[0x20];

	int stop;

	bool flag_swap;

	__forceinline AdjustStateAlpha()
	{
	}

	__forceinline void Init(const Half& half, int water, int q)
	{
		flag_swap = false;

		AdjustLevels(half, 0, node, 1, water, q);

		stop = node[0x20].Error;
	}

	__forceinline void Index()
	{
		if (flag_swap)
			return;
		flag_swap = true;

		memset(swap, -1, sizeof(swap));

		for (int i = 0, n = node[0x20].Color; i < n; i++)
		{
			int c = node[i].Color >> 3;
			swap[c] = i;
		}
	}
};

struct AdjustStateAlphaGroup
{
	AdjustStateAlpha S[8];

	__forceinline AdjustStateAlphaGroup()
	{
	}

	__forceinline void Init(const Half& half, int water)
	{
		for (int q = 0; q < 8; q++)
		{
			S[q].Init(half, water, q);
		}
	}

	__forceinline int Best(int water) const
	{
		int best = water;

		for (int q = 0; q < 8; q++)
		{
			best = Min(best, S[q].stop);
		}

		return best;
	}
};

static __forceinline double ComputeTableAlpha(const Half& half, int alpha, int q, uint32_t& index, uint32_t order)
{
	__m128i ma = _mm_cvtsi32_si128(alpha);
	ma = _mm_unpacklo_epi32(ma, ma);

	__m128i mt10 = _mm_loadl_epi64((const __m128i*)&g_table[q][0]);

	__m128i mt3210 = _mm_unpacklo_epi64(_mm_adds_epu8(ma, mt10), _mm_subs_epu8(ma, mt10));

	int good = 0xF;
	if (M128I_I32(mt3210, 0) == M128I_I32(mt3210, 1)) good &= ~2;
	if (M128I_I32(mt3210, 2) == M128I_I32(mt3210, 3)) good &= ~8;

	int ways[8];

	__m128i mc = mt3210;

	for (size_t i = 0; i < 8; i++)
	{
		__m128i mb = _mm_shuffle_epi32(_mm_cvtsi32_si128(half.Data[i << 2]), 0);

		__m128i me4 = _mm_abs_epi16(_mm_sub_epi16(mb, mc));

		__m128i me2 = _mm_min_epi16(me4, _mm_shuffle_epi32(me4, _MM_SHUFFLE(2, 3, 0, 1)));
		__m128i me1 = _mm_min_epi16(me2, _mm_shuffle_epi32(me2, _MM_SHUFFLE(0, 1, 2, 3)));

		int way = _mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(me4, me1)));
		ways[i] = (way & good) | (1 << 4);
	}

	int loops[8];

	for (size_t i = 0; i < 8; i++)
	{
		int k = 0;
		while ((ways[i] & (1 << k)) == 0) k++;
		loops[i] = k;
	}

	double best = -1.1;
	uint32_t codes = 0;

	for (;; )
	{
		SSIM_INIT();

		for (size_t i = 0; i < 8; i++)
		{
			__m128i mt = _mm_cvtsi32_si128(M128I_I32(mt3210, (size_t)(uint32_t)loops[i]));

			__m128i mb = _mm_cvtsi32_si128(half.Data[i << 2]);

			SSIM_UPDATE(mt, mb);
		}

		SSIM_CLOSE();

		SSIM_FINAL(mssim);

		double ssim = _mm_cvtsd_f64(mssim);

		if (best < ssim)
		{
			best = ssim;

			uint32_t v = 0;
			for (size_t j = 0; j < 8; j++)
			{
				v |= ((uint32_t)loops[j]) << (j + j);
			}
			codes = v;

			if (best >= 1.0)
				break;
		}

		size_t i = 0;
		for (;; )
		{
			int k = loops[i];
			if (ways[i] != (1 << k))
			{
				do { k++; } while ((ways[i] & (1 << k)) == 0);
				if (k < 4)
				{
					loops[i] = k;
					break;
				}

				k = 0;
				while ((ways[i] & (1 << k)) == 0) k++;
				loops[i] = k;
			}

			i++;
			if (i & 8)
				break;
		}
		if (i & 8)
			break;
	}

	for (int i = 8; --i >= 0;)
	{
		int shift = order & 0xF;

		order >>= 4;

		uint32_t code = ((codes & 2u) << (16 - 1)) | (codes & 1u);

		codes >>= 2;

		index |= code << shift;
	}

	return best;
}

static __forceinline int GuessAlpha4(const Half& half, int& alpha, int water, int& table)
{
	GuessStateAlpha SA;

	for (int q = 0; q < 8; q++)
	{
		int error = SA.Init(half, water, q);

		if (water > error)
		{
			water = error;

			alpha = SA.Find(error);
			table = q;

			if (water <= 0)
				break;
		}
	}

	return water;
}

static int CompressBlockAlpha44(BlockStateAlpha& s, const Elem& elem, int water, int mode)
{
	int a, b, qa, qb;

	int err = GuessAlpha4(elem.A, a, water, qa);
	if (err >= water)
		return water;

	err += GuessAlpha4(elem.B, b, water - err, qb);
	if (err >= water)
		return water;

	s.a = a;
	s.b = b;
	s.qa = qa;
	s.qb = qb;
	s.mode = mode;

	return err;
}

static __forceinline int AdjustAlphas53(int& alpha, int& other, int water, AdjustStateAlpha& SA, AdjustStateAlpha& SB)
{
	SB.Index();

	for (int a0 = 0; a0 < SA.node[0x20].Color; a0++)
	{
		int e0 = SA.node[a0].Error;
		if (e0 + SB.stop >= water)
			continue;

		int a = SA.node[a0].Color;

		int Id = a >> 3;
		int Ld = Max(Id - 4, 0);
		int Hd = Min(Id + 3, 31);

		for (int d0 = Ld; d0 <= Hd; d0++)
		{
			int b0 = SB.swap[d0];
			if (b0 < 0)
				continue;

			int e1 = SB.node[b0].Error + e0;
			if (e1 >= water)
				continue;

			water = e1;

			alpha = a;
			other = SB.node[b0].Color;

			if (water <= e0 + SB.stop)
				break;
		}
	}

	return water;
}

static int CompressBlockAlpha53(BlockStateAlpha& s, const Elem& elem, int water, int mode)
{
	AdjustStateAlphaGroup GB;

	GB.Init(elem.B, water);

	int stopB = GB.Best(water);
	if (stopB >= water)
		return water;

	AdjustStateAlphaGroup GA;

	GA.Init(elem.A, water - stopB);

	for (int qa = 0; qa < 8; qa++)
	{
		int bestA = GA.Best(water - stopB);
		if (bestA + stopB >= water)
			return water;

		AdjustStateAlpha& SA = GA.S[qa];

		for (int qb = 0; qb < 8; qb++)
		{
			AdjustStateAlpha& SB = GB.S[qb];

			if (SA.stop + stopB >= water)
				break;

			if (SA.stop + SB.stop >= water)
				continue;

			int error = AdjustAlphas53(s.a, s.b, water, SA, SB);

			if (water > error)
			{
				water = error;

				s.qa = qa;
				s.qb = qb;
				s.mode = mode;
			}
		}

		SA.stop = water;
	}

	return water;
}

static __forceinline int MeasureHalfAlpha(const int pL[4 * 4], const int pH[4 * 4], int alpha, int q, uint32_t dataL, uint32_t dataH, int slice, int shift)
{
	__m128i ma = _mm_cvtsi32_si128(alpha);
	ma = _mm_unpacklo_epi32(ma, ma);

	__m128i mt10 = _mm_loadl_epi64((const __m128i*)&g_table[q][0]);

	__m128i mt3210 = _mm_unpacklo_epi64(_mm_adds_epu8(ma, mt10), _mm_subs_epu8(ma, mt10));

	__m128i sum = _mm_setzero_si128();

	for (int i = 0; i < 4; i++)
	{
		__m128i m = _mm_cvtsi32_si128(*pL);

		__m128i mt = mt3210;

		if ((dataL & 0x10000u) != 0)
		{
			mt = _mm_shuffle_epi32(mt, _MM_SHUFFLE(1, 0, 3, 2));
		}

		if ((dataL & 1u) != 0)
		{
			mt = _mm_shuffle_epi32(mt, _MM_SHUFFLE(2, 3, 0, 1));
		}

		m = _mm_sub_epi16(m, mt);
		m = _mm_mullo_epi16(m, m);

		sum = _mm_add_epi32(sum, m);

		pL += slice;

		dataL >>= shift;
	}

	for (int i = 0; i < 4; i++)
	{
		__m128i m = _mm_cvtsi32_si128(*pH);

		__m128i mt = mt3210;

		if ((dataH & 0x10000u) != 0)
		{
			mt = _mm_shuffle_epi32(mt, _MM_SHUFFLE(1, 0, 3, 2));
		}

		if ((dataH & 1u) != 0)
		{
			mt = _mm_shuffle_epi32(mt, _MM_SHUFFLE(2, 3, 0, 1));
		}

		m = _mm_sub_epi16(m, mt);
		m = _mm_mullo_epi16(m, m);

		sum = _mm_add_epi32(sum, m);

		pH += slice;

		dataH >>= shift;
	}

	return _mm_cvtsi128_si32(sum);
}

static __m128i CompressBlockAlpha(uint8_t output[8], const uint8_t* __restrict cell)
{
	Elem norm, flip;

	{
		const uint8_t* src = cell;

		int c00 = src[3]; flip.A.Data[0] = c00; norm.A.Data[0] = c00;
		int c01 = src[7]; flip.A.Data[4] = c01; norm.A.Data[4] = c01;
		int c02 = src[11]; flip.A.Data[8] = c02; norm.B.Data[0] = c02;
		int c03 = src[15]; flip.A.Data[12] = c03; norm.B.Data[4] = c03;

		src += Stride;

		int c10 = src[3]; flip.A.Data[16] = c10; norm.A.Data[8] = c10;
		int c11 = src[7]; flip.A.Data[20] = c11; norm.A.Data[12] = c11;
		int c12 = src[11]; flip.A.Data[24] = c12; norm.B.Data[8] = c12;
		int c13 = src[15]; flip.A.Data[28] = c13; norm.B.Data[12] = c13;

		src += Stride;

		int c20 = src[3]; flip.B.Data[0] = c20; norm.A.Data[16] = c20;
		int c21 = src[7]; flip.B.Data[4] = c21; norm.A.Data[20] = c21;
		int c22 = src[11]; flip.B.Data[8] = c22; norm.B.Data[16] = c22;
		int c23 = src[15]; flip.B.Data[12] = c23; norm.B.Data[20] = c23;

		src += Stride;

		int c30 = src[3]; flip.B.Data[16] = c30; norm.A.Data[24] = c30;
		int c31 = src[7]; flip.B.Data[20] = c31; norm.A.Data[28] = c31;
		int c32 = src[11]; flip.B.Data[24] = c32; norm.B.Data[24] = c32;
		int c33 = src[15]; flip.B.Data[28] = c33; norm.B.Data[28] = c33;
	}

	BlockStateAlpha s;

	int err;
	{
		int c0 = output[0];

		int f = output[3];

		s.mode = f & 3;

		if ((f & 2) == 0)
		{
			s.a = (uint8_t)ExpandColor4(c0 >> 4);
			s.b = (uint8_t)ExpandColor4(c0 & 0xF);
		}
		else
		{
			s.a = (uint8_t)ExpandColor5(c0 >> 3);
			s.b = (uint8_t)ExpandColor5((c0 >> 3) + (int(uint32_t(c0) << 29) >> 29));
		}

		s.qa = (f >> 5) & 7;
		s.qb = (f >> 2) & 7;

		uint32_t way = BSWAP(*(const uint32_t*)&output[4]);

		if ((f & 1) == 0)
		{
			err = MeasureHalfAlpha(norm.A.Data, norm.A.Data + 1 * 4, s.a, s.qa, way, way >> 4, 2 * 4, 1);
			err += MeasureHalfAlpha(norm.B.Data, norm.B.Data + 1 * 4, s.b, s.qb, way >> 8, way >> 12, 2 * 4, 1);
		}
		else
		{
			err = MeasureHalfAlpha(flip.A.Data, flip.A.Data + 4 * 4, s.a, s.qa, way, way >> 1, 1 * 4, 4);
			err += MeasureHalfAlpha(flip.B.Data, flip.B.Data + 4 * 4, s.b, s.qb, way >> 2, way >> 3, 1 * 4, 4);
		}
	}

	norm.A.Count = 8;
	norm.B.Count = 8;

	flip.A.Count = 8;
	flip.B.Count = 8;

	if (err > 0)
	{
		int err_norm44 = CompressBlockAlpha44(s, norm, err, 0);
		if (err > err_norm44)
			err = err_norm44;

		if (err > 0)
		{
			int err_flip44 = CompressBlockAlpha44(s, flip, err, 1);
			if (err > err_flip44)
				err = err_flip44;

			if (err > 0)
			{
				int err_norm53 = CompressBlockAlpha53(s, norm, err, 2);
				if (err > err_norm53)
					err = err_norm53;

				if (err > 0)
				{
					int err_flip53 = CompressBlockAlpha53(s, flip, err, 3);
					if (err > err_flip53)
						err = err_flip53;
				}
			}
		}
	}

	double ssim;
	{
		uint32_t index = 0;

		bool f = (s.mode & 1) != 0;
		ssim = ComputeTableAlpha(f ? flip.A : norm.A, s.a, s.qa, index, f ? 0xD951C840u : 0x73625140u);
		ssim += ComputeTableAlpha(f ? flip.B : norm.B, s.b, s.qb, index, f ? 0xD951C840u + 0x22222222u : 0x73625140u + 0x88888888u);

		uint8_t c = (s.mode & 2) ?
			(uint8_t)((s.a & 0xF8) ^ (((s.b >> 3) - (s.a >> 3)) & 7)) :
			(uint8_t)((s.a & 0xF0) ^ (s.b & 0x0F));

		output[0] = c;
		output[1] = c;
		output[2] = c;

		output[3] = (uint8_t)((s.qa << 5) ^ (s.qb << 2) ^ s.mode);

		*(uint32_t*)&output[4] = BSWAP(index);
	}

	return _mm_unpacklo_epi64(_mm_cvtsi32_si128(err), _mm_castpd_si128(_mm_load_sd(&ssim)));
}


static __forceinline void DecompressHalfColor(int pL[4], int pH[4], int color, int q, uint32_t data, int shift)
{
	static const int g_delta[8][2] alignas(16) =
	{
		{ 2 * 0x010101, (8 ^ 2) * 0x010101 },
		{ 5 * 0x010101, (17 ^ 5) * 0x010101 },
		{ 9 * 0x010101, (29 ^ 9) * 0x010101 },
		{ 13 * 0x010101, (42 ^ 13) * 0x010101 },
		{ 18 * 0x010101, (60 ^ 18) * 0x010101 },
		{ 24 * 0x010101, (80 ^ 24) * 0x010101 },
		{ 33 * 0x010101, (106 ^ 33) * 0x010101 },
		{ 47 * 0x010101, (183 ^ 47) * 0x010101 }
	};

	static const int g_mask[16][4] alignas(16) =
	{
		{ 0, 0, 0, 0 },{ -1, 0, 0, 0 },{ 0, -1, 0, 0 },{ -1, -1, 0, 0 },
		{ 0, 0, -1, 0 },{ -1, 0, -1, 0 },{ 0, -1, -1, 0 },{ -1, -1, -1, 0 },
		{ 0, 0, 0, -1 },{ -1, 0, 0, -1 },{ 0, -1, 0, -1 },{ -1, -1, 0, -1 },
		{ 0, 0, -1, -1 },{ -1, 0, -1, -1 },{ 0, -1, -1, -1 },{ -1, -1, -1, -1 }
	};

	__m128i mt0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(g_delta[q][0]), 0);
	__m128i mt10 = _mm_shuffle_epi32(_mm_cvtsi32_si128(g_delta[q][1]), 0);

	__m128i mMaskL = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(shift < 4 ? data << (4 - shift) : data >> (shift - 4)) & 0xF0]);
	__m128i mMaskH = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 4 - 4)) & 0xF0]);

	__m128i mtL = _mm_xor_si128(_mm_and_si128(mMaskL, mt10), mt0);
	__m128i mtH = _mm_xor_si128(_mm_and_si128(mMaskH, mt10), mt0);

	mMaskL = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 16 + 0 - 4)) & 0xF0]);
	mMaskH = _mm_load_si128((const __m128i*)&((const uint8_t*)g_mask)[(data >> (shift + 16 + 4 - 4)) & 0xF0]);

	__m128i mc = _mm_shuffle_epi32(_mm_cvtsi32_si128(color), 0);

	__m128i mcL = _mm_or_si128(_mm_and_si128(mMaskL, _mm_subs_epu8(mc, mtL)), _mm_andnot_si128(mMaskL, _mm_adds_epu8(mc, mtL)));
	__m128i mcH = _mm_or_si128(_mm_and_si128(mMaskH, _mm_subs_epu8(mc, mtH)), _mm_andnot_si128(mMaskH, _mm_adds_epu8(mc, mtH)));

	_mm_storeu_si128((__m128i*)pL, mcL);
	_mm_storeu_si128((__m128i*)pH, mcH);
}

static __forceinline void DecompressBlockColor(const uint8_t input[8], uint8_t* __restrict cell)
{
	int a, b;

	uint32_t c = *(const uint32_t*)input;

	c = BROR(BSWAP(c));

	if ((c & (2 << 24)) == 0)
	{
		a = c & 0xF0F0F0; a |= a >> 4;
		b = c & 0x0F0F0F; b |= b << 4;
	}
	else
	{
		a = c & 0xF8F8F8;
		b = ((((c & 0x070707) ^ 0x444444) - 0x040404) << 3) + a;
		if (b & 0x01010100)
		{
			__debugbreak();
			return;
		}
		b &= 0xF8F8F8;

		a |= (a >> 5) & 0x070707;
		b |= (b >> 5) & 0x070707;
	}

	a |= 0xFFu << 24;
	b |= 0xFFu << 24;

	uint32_t way = BSWAP(*(const uint32_t*)&input[4]);

{'fraction_non_alphanumeric': 0.1871125518967184, 'fraction_numerical': 0.10481715293180914, 'mean_word_length': 3.3258979826144004, 'pattern_counts': {'":': 0, '<': 203, '<?xml version=': 0, '>': 247, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6314674', 'n_tokens_mistral': 30903, 'n_tokens_neox': 25639, 'n_words': 5487}