Skip to content

Instantly share code, notes, and snippets.

@averne
Created April 10, 2019 17:39
Show Gist options
  • Save averne/d72f94cc4585f46baf296187246cc854 to your computer and use it in GitHub Desktop.
Save averne/d72f94cc4585f46baf296187246cc854 to your computer and use it in GitHub Desktop.
C++ templates for pixel data
#pragma once
#include <cstdint>
#include <utility>
#include <type_traits>
#define ASSERT_SIZE(x, sz) static_assert(sizeof(x) == sz, "Wrong size in " #x)
#define ASSERT_STANDARD_LAYOUT(x) static_assert(std::is_standard_layout_v<x>, #x "is not standard layout")
struct rgb565_t {
union {
struct {
uint16_t r: 5, g: 6, b: 5;
} __attribute__((packed));
uint16_t rgb;
};
inline rgb565_t(uint16_t raw): rgb(raw) { }
inline rgb565_t(uint8_t r, uint8_t g, uint8_t b): r(r), g(g), b(b) { }
};
ASSERT_SIZE(rgb565_t, 2);
ASSERT_STANDARD_LAYOUT(rgb565_t);
struct rgba4444_t {
union {
struct {
uint16_t r: 4, g: 4, b: 4, a: 4;
} __attribute__((packed));
uint16_t rgba;
};
inline rgba4444_t(uint16_t raw): rgba(raw) { }
inline rgba4444_t(uint8_t r, uint8_t g, uint8_t b, uint8_t a): r(r), g(g), b(b), a(a) { }
};
ASSERT_SIZE(rgba4444_t, 2);
ASSERT_STANDARD_LAYOUT(rgba4444_t);
template<typename T, typename=void>
struct has_alpha : std::false_type { };
template<typename T>
struct has_alpha<T, decltype(std::declval<T>().a, void())> : std::true_type { };
template<typename T>
inline constexpr bool has_alpha_v = has_alpha<T>::value;
template<typename T>
struct col_underlying_type { typedef decltype(T::r) type; };
template<typename T>
using col_underlying_type_t = typename col_underlying_type<T>::type;
template<typename T>
inline T MakeColor(col_underlying_type_t<T> raw) {
return T(raw);
}
template<typename T>
typename std::enable_if_t<!has_alpha_v<T>, T>
inline MakeColor(decltype(T::r) r, decltype(T::g) g, decltype(T::b) b) {
return T(r, g, b);
}
template<typename T>
typename std::enable_if_t<has_alpha_v<T>, T>
inline MakeColor(decltype(T::r) r, decltype(T::g) g, decltype(T::b) b, decltype(T::a) a=-1) {
return T(r, g, b, a);
}
template<typename T>
typename std::enable_if_t<!has_alpha_v<T>, T>
inline make_color_min_alpha() {
return MakeColor<T>(0, 0, 0);
}
template<typename T>
typename std::enable_if_t<has_alpha_v<T>, T>
inline make_color_min_alpha() {
return MakeColor<T>(0, 0, 0, 0);
}
template<typename T>
inline T make_color_max_alpha(decltype(T::r) r, decltype(T::g) g, decltype(T::b) b) {
return MakeColor<T>(r, g, b);
}
template<typename T>
inline T make_color_max_all() {
return MakeColor<T>(-1, -1, -1);
}
#define BLEND_CHANNEL(x, y, a) (((a) * (x) + ((0xff - (a)) * (y))) / 0xff)
template<typename T>
typename std::enable_if_t<!has_alpha_v<T>, T>
inline Blend(T x, T y, uint8_t alpha) {
return MakeColor<T>(
BLEND_CHANNEL(x.r, y.r, alpha),
BLEND_CHANNEL(x.g, y.g, alpha),
BLEND_CHANNEL(x.b, y.b, alpha)
);
}
template<typename T>
typename std::enable_if_t<has_alpha_v<T>, T>
inline Blend(T x, T y, uint8_t alpha) {
return MakeColor<T>(
BLEND_CHANNEL(x.r, y.r, alpha),
BLEND_CHANNEL(x.g, y.g, alpha),
BLEND_CHANNEL(x.b, y.b, alpha),
BLEND_CHANNEL(1, y.a, alpha)
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment