diff --git a/include/utils/color.hpp b/include/utils/color.hpp new file mode 100644 index 00000000..1f116b9e --- /dev/null +++ b/include/utils/color.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include + +#include "common.hpp" +#include "utils/string.hpp" + +LEMONBUDDY_NS + +namespace color_util { + template + struct color { + using type = color; + union { + struct { + ChannelType red; + ChannelType green; + ChannelType blue; + ChannelType alpha; + } bits; + + ValueType value = 0U; + } colorspace; + + explicit color(ValueType v) { + colorspace.value = v; + } + }; + + template + auto make_24bit(T&& value) { + return color(forward(value)); + } + + template + auto make_32bit(T&& value) { + return color(forward(value)); + } + + template + uint8_t alpha(const color c) { + return ((c.colorspace.value >> 24) << 8) | ((c.colorspace.value >> 24)); + } + + template + T red(const color c) { + uint8_t r = c.colorspace.value >> 16; + if (std::is_same::value) + return r << 8 / 0xFF; + if (std::is_same::value) + return r << 8 | r << 8 / 0xFF; + } + + template + T green(const color c) { + uint8_t g = c.colorspace.value >> 8; + if (std::is_same::value) + return g << 8 / 0xFF; + if (std::is_same::value) + return g << 8 | g << 8 / 0xFF; + } + + template + T blue(const color c) { + uint8_t b = c.colorspace.value; + if (std::is_same::value) + return b << 8 / 0xFF; + if (std::is_same::value) + return b << 8 | b << 8 / 0xFF; + } + + string hex(const color value) { + // clang-format off + return string_util::from_stream(stringstream() + << "#" + << std::setw(6) + << std::setfill('0') + << std::hex + << std::uppercase + << (value.colorspace.value & 0x00FFFFFF)); + // clang-format on + } + + string hex(const color value) { + // clang-format off + return string_util::from_stream(stringstream() + << "#" + << std::setw(8) + << std::setfill('0') + << std::hex + << std::uppercase + << value.colorspace.value); + // clang-format on + } +} + +LEMONBUDDY_NS_END diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e6317366..f98b5845 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,6 +12,7 @@ function(unit_test file) add_test(unit_test.${testname} unit_test.${testname}) endfunction() +unit_test("utils/color") unit_test("utils/math") unit_test("utils/memory") unit_test("utils/string") diff --git a/tests/unit_tests/utils/color.cpp b/tests/unit_tests/utils/color.cpp new file mode 100644 index 00000000..c1fea25b --- /dev/null +++ b/tests/unit_tests/utils/color.cpp @@ -0,0 +1,29 @@ +#include "common/test.hpp" +#include "utils/color.hpp" + +int main() { + using namespace lemonbuddy; + + "rgb"_test = []{ + auto color = color_util::make_24bit(0x123456); + expect(color_util::alpha(color) == 0); + expect(color_util::red(color) == 0x12); + expect(color_util::green(color) == 0x34); + expect(color_util::blue(color) == 0x56); + }; + + "rgba"_test = []{ + auto color = color_util::make_32bit(0xCC123456); + expect(color_util::alpha(color) == 0xCC); + expect(color_util::red(color) == 0x1212); + expect(color_util::green(color) == 0x3434); + expect(color_util::blue(color) == 0x5656); + }; + + "hex"_test = [] { + auto colorA = color_util::make_24bit(0x123456); + expect(color_util::hex(colorA) == "#123456"); + auto colorB = color_util::make_32bit(0xCC123456); + expect(color_util::hex(colorB) == "#CC123456"); + }; +}