From 0bddeaf865e67e841ad0fd7845580496373e03c3 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sat, 18 Jun 2022 17:35:50 +0300 Subject: [PATCH] Add ordered dither mask generation to gfx --- libs/gfx/include/psemek/gfx/dither.hpp | 10 +++++++ libs/gfx/source/dither.cpp | 40 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 libs/gfx/include/psemek/gfx/dither.hpp create mode 100644 libs/gfx/source/dither.cpp diff --git a/libs/gfx/include/psemek/gfx/dither.hpp b/libs/gfx/include/psemek/gfx/dither.hpp new file mode 100644 index 00000000..338c3719 --- /dev/null +++ b/libs/gfx/include/psemek/gfx/dither.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace psemek::gfx +{ + + basic_pixmap ordered_dither(std::size_t size); + +} diff --git a/libs/gfx/source/dither.cpp b/libs/gfx/source/dither.cpp new file mode 100644 index 00000000..30681233 --- /dev/null +++ b/libs/gfx/source/dither.cpp @@ -0,0 +1,40 @@ +#include + +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 ordered_dither(std::size_t size) + { + if (size > 16) + throw std::runtime_error("8-bit dither map cannot be larger than 16x16"); + + basic_pixmap result({size, size}); + + for (auto idx : result.indices()) + { + result(idx) = bit_reverse(bit_interleave(idx[0] ^ idx[1], idx[0])); + } + + return result; + } + +}