From 26c308cc1996c945d2316ba7ec76a29784b66a0e Mon Sep 17 00:00:00 2001 From: Michael Carlberg <c@rlberg.se> Date: Mon, 31 Oct 2016 01:21:24 +0100 Subject: [PATCH] feat(color_util): Utility functions for color handling --- include/utils/color.hpp | 97 ++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/unit_tests/utils/color.cpp | 29 ++++++++++ 3 files changed, 127 insertions(+) create mode 100644 include/utils/color.hpp create mode 100644 tests/unit_tests/utils/color.cpp 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 <iomanip> + +#include "common.hpp" +#include "utils/string.hpp" + +LEMONBUDDY_NS + +namespace color_util { + template <typename ChannelType = uint8_t, typename ValueType = uint32_t> + struct color { + using type = color<ChannelType, ValueType>; + union { + struct { + ChannelType red; + ChannelType green; + ChannelType blue; + ChannelType alpha; + } bits; + + ValueType value = 0U; + } colorspace; + + explicit color(ValueType v) { + colorspace.value = v; + } + }; + + template <typename T> + auto make_24bit(T&& value) { + return color<uint8_t, uint32_t>(forward<T>(value)); + } + + template <typename T> + auto make_32bit(T&& value) { + return color<uint16_t, uint32_t>(forward<T>(value)); + } + + template <typename ValueType = uint32_t> + uint8_t alpha(const color<ValueType> c) { + return ((c.colorspace.value >> 24) << 8) | ((c.colorspace.value >> 24)); + } + + template <typename T = uint8_t, typename ValueType = uint32_t> + T red(const color<ValueType> c) { + uint8_t r = c.colorspace.value >> 16; + if (std::is_same<T, uint8_t>::value) + return r << 8 / 0xFF; + if (std::is_same<T, uint16_t>::value) + return r << 8 | r << 8 / 0xFF; + } + + template <typename T = uint8_t, typename ValueType = uint32_t> + T green(const color<ValueType> c) { + uint8_t g = c.colorspace.value >> 8; + if (std::is_same<T, uint8_t>::value) + return g << 8 / 0xFF; + if (std::is_same<T, uint16_t>::value) + return g << 8 | g << 8 / 0xFF; + } + + template <typename T = uint8_t, typename ValueType = uint32_t> + T blue(const color<ValueType> c) { + uint8_t b = c.colorspace.value; + if (std::is_same<T, uint8_t>::value) + return b << 8 / 0xFF; + if (std::is_same<T, uint16_t>::value) + return b << 8 | b << 8 / 0xFF; + } + + string hex(const color<uint8_t, uint32_t> 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<uint16_t, uint32_t> 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<uint8_t>(color) == 0x12); + expect(color_util::green<uint8_t>(color) == 0x34); + expect(color_util::blue<uint8_t>(color) == 0x56); + }; + + "rgba"_test = []{ + auto color = color_util::make_32bit(0xCC123456); + expect(color_util::alpha(color) == 0xCC); + expect(color_util::red<uint16_t>(color) == 0x1212); + expect(color_util::green<uint16_t>(color) == 0x3434); + expect(color_util::blue<uint16_t>(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"); + }; +}