|
1 | 1 | #include "Color.h"
|
2 | 2 | #include <algorithm>
|
3 |
| -#include <cmath> |
4 | 3 | #include <cassert>
|
| 4 | +#include <cmath> |
5 | 5 |
|
6 | 6 | namespace {
|
7 | 7 |
|
8 | 8 | // Int -> fixed point
|
9 |
| -int up( int x ) { return x * 255; } |
| 9 | +int up(int x) { return x * 255; } |
10 | 10 |
|
11 | 11 | } // namespace
|
12 | 12 |
|
13 |
| -int iRgbSqrt( int num ) { |
| 13 | +int iRgbSqrt(int num) { |
14 | 14 | // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
|
15 |
| - assert( "sqrt input should be non-negative" && num >= 0 ); |
16 |
| - assert( "sqrt input should no exceed 16 bits" && num <= 0xFFFF ); |
| 15 | + assert("sqrt input should be non-negative" && num >= 0); |
| 16 | + assert("sqrt input should no exceed 16 bits" && num <= 0xFFFF); |
17 | 17 | int res = 0;
|
18 | 18 | int bit = 1 << 16;
|
19 |
| - while ( bit > num ) |
| 19 | + while (bit > num) |
20 | 20 | bit >>= 2;
|
21 |
| - while ( bit != 0 ) { |
22 |
| - if ( num >= res + bit ) { |
| 21 | + while (bit != 0) { |
| 22 | + if (num >= res + bit) { |
23 | 23 | num -= res + bit;
|
24 |
| - res = ( res >> 1 ) + bit; |
| 24 | + res = (res >> 1) + bit; |
25 | 25 | } else
|
26 | 26 | res >>= 1;
|
27 | 27 | bit >>= 2;
|
28 | 28 | }
|
29 | 29 | return res;
|
30 | 30 | }
|
31 | 31 |
|
32 |
| -Rgb::Rgb( Hsv y ) { |
| 32 | +Rgb::Rgb(const Hsv& y) { |
33 | 33 | // https://stackoverflow.com/questions/24152553/hsv-to-rgb-and-back-without-floating-point-math-in-python
|
34 | 34 | // greyscale
|
35 |
| - if( y.s == 0 ) { |
| 35 | + if (y.s == 0) { |
36 | 36 | r = g = b = y.v;
|
37 | 37 | return;
|
38 | 38 | }
|
39 | 39 |
|
40 | 40 | const int region = y.h / 43;
|
41 |
| - const int remainder = ( y.h - ( region * 43 ) ) * 6; |
42 |
| - |
43 |
| - const int p = ( y.v * ( 255 - y.s ) ) >> 8; |
44 |
| - const int q = ( y.v * ( 255 - ( ( y.s * remainder ) >> 8 ) ) ) >> 8; |
45 |
| - const int t = ( y.v * ( 255 - ( ( y.s * (255 -remainder ) ) >> 8 ) ) ) >> 8; |
46 |
| - |
47 |
| - switch( region ) { |
48 |
| - case 0: r = y.v; g = t; b = p; break; |
49 |
| - case 1: r = q; g = y.v; b = p; break; |
50 |
| - case 2: r = p; g = y.v; b = t; break; |
51 |
| - case 3: r = p; g = q; b = y.v; break; |
52 |
| - case 4: r = t; g = p; b = y.v; break; |
53 |
| - case 5: r = y.v; g = p; b = q; break; |
54 |
| - default: __builtin_trap(); |
| 41 | + const int remainder = (y.h - (region * 43)) * 6; |
| 42 | + |
| 43 | + const int p = (y.v * (255 - y.s)) >> 8; |
| 44 | + const int q = (y.v * (255 - ((y.s * remainder) >> 8))) >> 8; |
| 45 | + const int t = (y.v * (255 - ((y.s * (255 - remainder)) >> 8))) >> 8; |
| 46 | + |
| 47 | + switch (region) { |
| 48 | + case 0: |
| 49 | + r = y.v; |
| 50 | + g = t; |
| 51 | + b = p; |
| 52 | + break; |
| 53 | + case 1: |
| 54 | + r = q; |
| 55 | + g = y.v; |
| 56 | + b = p; |
| 57 | + break; |
| 58 | + case 2: |
| 59 | + r = p; |
| 60 | + g = y.v; |
| 61 | + b = t; |
| 62 | + break; |
| 63 | + case 3: |
| 64 | + r = p; |
| 65 | + g = q; |
| 66 | + b = y.v; |
| 67 | + break; |
| 68 | + case 4: |
| 69 | + r = t; |
| 70 | + g = p; |
| 71 | + b = y.v; |
| 72 | + break; |
| 73 | + case 5: |
| 74 | + r = y.v; |
| 75 | + g = p; |
| 76 | + b = q; |
| 77 | + break; |
| 78 | + default: |
| 79 | + __builtin_trap(); |
55 | 80 | }
|
56 | 81 |
|
57 | 82 | a = y.a;
|
58 | 83 | }
|
59 | 84 |
|
60 |
| -Rgb& Rgb::operator=( Hsv hsv ) { |
61 |
| - Rgb r{ hsv }; |
62 |
| - swap( r ); |
| 85 | +Rgb& Rgb::operator=(const Hsv& hsv) { |
| 86 | + Rgb r { hsv }; |
| 87 | + swap(r); |
63 | 88 | return *this;
|
64 | 89 | }
|
65 | 90 |
|
66 |
| -Rgb Rgb::operator+( Rgb in ) const { |
| 91 | +Rgb Rgb::operator+(const Rgb& in) const { |
67 | 92 | auto copy = *this;
|
68 | 93 | copy += in;
|
69 | 94 | return copy;
|
70 | 95 | }
|
71 | 96 |
|
72 |
| -Rgb& Rgb::operator+=( Rgb in ) { |
| 97 | +Rgb& Rgb::operator+=(const Rgb& in) { |
73 | 98 | unsigned int red = r + in.r;
|
74 |
| - r = ( red < 255 ) ? red : 255; |
| 99 | + r = (red < 255) ? red : 255; |
75 | 100 | unsigned int green = g + in.g;
|
76 |
| - g = ( green < 255 ) ? green : 255; |
| 101 | + g = (green < 255) ? green : 255; |
77 | 102 | unsigned int blue = b + in.b;
|
78 |
| - b = ( blue < 255 ) ? blue : 255; |
| 103 | + b = (blue < 255) ? blue : 255; |
79 | 104 | return *this;
|
80 | 105 | }
|
81 | 106 |
|
82 |
| -Rgb& Rgb::blend( Rgb in ) { |
83 |
| - unsigned int inAlpha = in.a * ( 255 - a ); |
84 |
| - unsigned int alpha = a + inAlpha; |
85 |
| - r = iRgbSqrt( ( ( r * r * a ) + ( in.r * in.r * inAlpha ) ) / alpha ); |
86 |
| - g = iRgbSqrt( ( ( g * g * a ) + ( in.g * in.g * inAlpha ) ) / alpha ); |
87 |
| - b = iRgbSqrt( ( ( b * b * a ) + ( in.b * in.b * inAlpha ) ) / alpha ); |
88 |
| - a = alpha; |
| 107 | +Rgb Rgb::operator-(const Rgb& in) const { |
| 108 | + auto copy = *this; |
| 109 | + copy -= in; |
| 110 | + return copy; |
| 111 | +} |
| 112 | + |
| 113 | +Rgb& Rgb::operator-=(const Rgb& in) { |
| 114 | + r = (in.r > r) ? 0 : r - in.r; |
| 115 | + g = (in.g > g) ? 0 : g - in.g; |
| 116 | + b = (in.b > b) ? 0 : b - in.b; |
89 | 117 | return *this;
|
90 | 118 | }
|
91 | 119 |
|
92 |
| -uint8_t IRAM_ATTR Rgb::getGrb( int idx ) { |
93 |
| - switch ( idx ) { |
94 |
| - case 0: return g; |
95 |
| - case 1: return r; |
96 |
| - case 2: return b; |
97 |
| - } |
98 |
| - __builtin_unreachable(); |
| 120 | +Rgb& Rgb::blend(const Rgb& in) { |
| 121 | + unsigned int inAlpha = in.a * (255 - a); |
| 122 | + unsigned int alpha = a + inAlpha; |
| 123 | + r = iRgbSqrt(((r * r * a) + (in.r * in.r * inAlpha)) / alpha); |
| 124 | + g = iRgbSqrt(((g * g * a) + (in.g * in.g * inAlpha)) / alpha); |
| 125 | + b = iRgbSqrt(((b * b * a) + (in.b * in.b * inAlpha)) / alpha); |
| 126 | + a = alpha; |
| 127 | + return *this; |
99 | 128 | }
|
100 | 129 |
|
101 |
| -Hsv::Hsv( Rgb r ) { |
102 |
| - int min = std::min( r.r, std::min( r.g, r.b ) ); |
103 |
| - int max = std::max( r.r, std::max( r.g, r.b ) ); |
| 130 | +Hsv::Hsv(const Rgb& r) { |
| 131 | + int min = std::min(r.r, std::min(r.g, r.b)); |
| 132 | + int max = std::max(r.r, std::max(r.g, r.b)); |
104 | 133 | int chroma = max - min;
|
105 | 134 |
|
106 | 135 | v = max;
|
107 |
| - if ( chroma == 0 ) { |
| 136 | + if (chroma == 0) { |
108 | 137 | h = s = 0;
|
109 | 138 | return;
|
110 | 139 | }
|
111 | 140 |
|
112 |
| - s = up( chroma ) / max; |
| 141 | + s = up(chroma) / max; |
113 | 142 | int hh;
|
114 |
| - if ( max == r.r ) |
115 |
| - hh = ( up( int( r.g ) - int( r.b ) ) ) / chroma / 6; |
116 |
| - else if ( max == r.g ) |
117 |
| - hh = 255 / 3 + ( up( int( r.b ) - int( r.r ) ) ) / chroma / 6; |
| 143 | + if (max == r.r) |
| 144 | + hh = (up(int(r.g) - int(r.b))) / chroma / 6; |
| 145 | + else if (max == r.g) |
| 146 | + hh = 255 / 3 + (up(int(r.b) - int(r.r))) / chroma / 6; |
118 | 147 | else
|
119 |
| - hh = 2 * 255 / 3 + ( up( int( r.r ) - int( r.g ) ) ) / chroma / 6; |
| 148 | + hh = 2 * 255 / 3 + (up(int(r.r) - int(r.g))) / chroma / 6; |
120 | 149 |
|
121 |
| - if ( hh < 0 ) |
| 150 | + if (hh < 0) |
122 | 151 | hh += 255;
|
123 | 152 | h = hh;
|
124 | 153 |
|
125 | 154 | a = r.a;
|
126 | 155 | }
|
127 | 156 |
|
128 |
| -Hsv& Hsv::operator=( Rgb rgb ) { |
129 |
| - Hsv h{ rgb }; |
130 |
| - swap( h ); |
| 157 | +Hsv& Hsv::operator=(const Rgb& rgb) { |
| 158 | + Hsv h { rgb }; |
| 159 | + swap(h); |
131 | 160 | return *this;
|
132 | 161 | }
|
0 commit comments