Color.cpp 3.2 KB

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