#include <psemek/gfx/dither.hpp>
#include <psemek/util/exception.hpp>

namespace psemek::gfx
{

	static std::uint8_t interleave_with_zeros(std::uint8_t input) {
		std::uint8_t word = input;
		word = (word ^ (word << 4 )) & 0x0f0f;
		word = (word ^ (word << 2 )) & 0x3333;
		word = (word ^ (word << 1 )) & 0x5555;
		return word;
	}

	static std::uint8_t bit_interleave(std::uint8_t a, std::uint8_t b) {
		return interleave_with_zeros(a) | (interleave_with_zeros(b) << 1);
	}

	static std::uint8_t bit_reverse(std::uint8_t b) {
		b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
		b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
		b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
		return b;
	}

	basic_pixmap<std::uint8_t> ordered_dither(std::size_t size)
	{
		if (size > 16)
			throw util::exception("8-bit dither map cannot be larger than 16x16");

		basic_pixmap<std::uint8_t> result({size, size});

		for (auto idx : result.indices())
		{
			result(idx) = bit_reverse(bit_interleave(idx[0] ^ idx[1], idx[0]));
		}

		return result;
	}

}
