Last active
April 27, 2017 19:41
-
-
Save JohnnyonFlame/21f6230e518c680dcec1a2803be43dda to your computer and use it in GitHub Desktop.
Color conversion C++14 stuff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <ios> | |
#include <iomanip> | |
#include <stdint.h> | |
using u8 = uint8_t; | |
using u16 = uint16_t; | |
using u32 = uint32_t; | |
template <typename T, T Mask> | |
struct Channel | |
{ | |
public: | |
static constexpr u32 get_shift() | |
{ | |
T msk = mask; | |
u32 r = 0; | |
for (; !(msk & 1); r++) | |
msk >>= 1; | |
return r; | |
} | |
static constexpr u32 get_count() | |
{ | |
T msk = mask >> shift; | |
u32 r = 0; | |
for (; msk & 1; r++) | |
msk >>= 1; | |
return r; | |
} | |
Channel operator=(u32 val) | |
{ | |
data = (data & ~mask) | (val << shift); | |
} | |
Channel operator=(Channel other) | |
{ | |
data = (data & ~mask) | (other.data & other.mask); | |
} | |
template <typename T_, T_ m> | |
Channel operator=(Channel<T_, m> other) | |
{ | |
T nmask = mask; | |
//If left channel is bigger than right channel, it makes sense to filter out garbage from the lower channels. | |
if (count > other.count) | |
nmask &= ~((1 << (count - other.count + shift)) - 1); | |
//Calculate displacement | |
int nshift = other.shift - shift + (other.count - count); | |
//Use previous values to displace & mask the desired value | |
T masked; | |
if (nshift > 0) | |
masked = (other.data >> nshift) & nmask; | |
else | |
masked = (other.data << (-nshift)) & nmask; | |
//Set value. | |
data = (data & ~mask) | masked; | |
} | |
T get() | |
{ | |
return (data & mask) >> shift; | |
} | |
static const T mask = Mask; | |
static const u32 shift = get_shift(); | |
static const u32 count = get_count(); | |
T data; | |
}; | |
template <typename T, T Rmask, T Gmask, T Bmask> | |
struct Color | |
{ | |
public: | |
Color operator=(const u8 (&arr)[3]) | |
{ | |
r = arr[2]; | |
g = arr[1]; | |
b = arr[0]; | |
} | |
//Same type | |
Color operator=(Color other) | |
{ | |
data = other.data; | |
} | |
//Different encodings | |
template <typename T_, T_ rm_, T_ gm_, T_ bm_> | |
Color operator=(Color<T_, rm_, gm_, bm_> other) | |
{ | |
r = other.r; | |
g = other.g; | |
b = other.b; | |
} | |
union | |
{ | |
T data; | |
Channel<T, Rmask> r; | |
Channel<T, Gmask> g; | |
Channel<T, Bmask> b; | |
}; | |
}; | |
__attribute__((noinline)) auto builda(u8 r, u8 g, u8 b) | |
{ | |
Color<u32, 0xff << 16, 0xff << 8, 0xff> c1; | |
c1 = {r, g, b}; | |
return c1; | |
} | |
template <typename T> | |
__attribute__((noinline)) auto builda2(T color) | |
{ | |
Color<u32, 0xff << 16, 0xff << 8, 0xff> c; | |
c = color; | |
return c; | |
} | |
template <typename T> | |
__attribute__((noinline)) auto buildb(T color) | |
{ | |
Color<u16, 0x1f << 11, 0x3f << 5, 0x1f> c2; | |
c2 = color; | |
return c2; | |
} | |
template <typename T> | |
__attribute__((noinline)) auto buildman(T color) | |
{ | |
Color<u16, 0x1f << 11, 0x3f << 5, 0x1f> c2; | |
c2.data = ((color.data >> 8) & c2.r.mask); | |
c2.data |= ((color.data >> 5) & c2.g.mask); | |
c2.data |= ((color.data >> 3) & c2.b.mask); | |
return c2; | |
} | |
void print(auto t) | |
{ | |
int n = sizeof(t); | |
for (int i = 0; i < n; i++) | |
{ | |
std::cout << std::setfill('0') << std::setw(2) << ((t >> (((n-1)-i) * 8)) & 0xff); | |
std::cout << ((i == n-1) ? '\n' : ' '); | |
} | |
} | |
int main() | |
{ | |
u32 r, g, b; | |
std::cin >> r >> g >> b; | |
auto c1 = builda((u8)r, (u8)g, (u8)b); | |
auto c2 = buildb(c1); | |
auto c3 = buildman(c1); | |
std::cout << std::hex; | |
std::cout << c1.r.get() << ' ' | |
<< c1.g.get() << ' ' | |
<< c1.b.get() << '\n'; | |
std::cout << c2.r.get() << ' ' | |
<< c2.g.get() << ' ' | |
<< c2.b.get() << '\n'; | |
std::cout << c3.r.get() << ' ' | |
<< c3.g.get() << ' ' | |
<< c3.b.get() << '\n'; | |
auto c4 = builda2(c2); | |
std::cout << c4.r.get() << ' ' | |
<< c4.g.get() << ' ' | |
<< c4.b.get() << '\n'; | |
} |
Create 32bpp color from u8 array:
builda(unsigned char, unsigned char, unsigned char):
movzx eax, dl
movzx esi, sil
movzx edi, dil
sal eax, 16
sal esi, 8
or eax, esi
or eax, edi
ret
Convert 16bpp to 32bpp:
auto builda2<Color<unsigned short, (unsigned short)63488, (unsigned short)2016, (unsigned short)31> >(Color<unsigned short, (unsigned short)63488, (unsigned short)2016, (unsigned short)31>):
movzx edi, di
mov eax, edi
mov edx, edi
sal edi, 3
sal eax, 8
sal edx, 5
and eax, 16252928
and edx, 64512
or edx, eax
movzx eax, dil
or eax, edx
ret
mips32-r2 mipsel-linux-g++ version 6.2.1:
Dump of assembler code for function buildb<Color<unsigned int, 16711680u, 65280u, 255u> >(Color<unsigned int, 16711680u, 65280u, 255u>):
0x00400e20 <+0>: srl v1,a1,0x8
0x00400e24 <+4>: srl a2,a1,0x5
0x00400e28 <+8>: li v0,-2048
0x00400e2c <+12>: andi a2,a2,0x7e0
0x00400e30 <+16>: and v1,v1,v0
0x00400e34 <+20>: ext a1,a1,0x3,0x5
0x00400e38 <+24>: or v1,v1,a2
0x00400e3c <+28>: or v1,v1,a1
0x00400e40 <+32>: move v0,a0
0x00400e44 <+36>: jr ra
0x00400e48 <+40>: sh v1,0(a0)
Dump of assembler code for function buildman<Color<unsigned int, 16711680u, 65280u, 255u> >(Color<unsigned int, 16711680u, 65280u, 255u>):
0x00400e4c <+0>: srl v1,a1,0x8
0x00400e50 <+4>: srl a2,a1,0x5
0x00400e54 <+8>: li v0,-2048
0x00400e58 <+12>: andi a2,a2,0x7e0
0x00400e5c <+16>: and v1,v1,v0
0x00400e60 <+20>: ext a1,a1,0x3,0x5
0x00400e64 <+24>: or v1,v1,a2
0x00400e68 <+28>: or v1,v1,a1
0x00400e6c <+32>: move v0,a0
0x00400e70 <+36>: jr ra
0x00400e74 <+40>: sh v1,0(a0)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
x86-64 g++ 6.3, opts -O2 -std=c++17