Color.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /********************************************************************************
  2. * https://github.com/RoboticsBrno/SmartLeds
  3. *
  4. * MIT License
  5. *
  6. * Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in all
  16. * copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. * SOFTWARE.
  25. *******************************************************************************/
  26. #pragma once
  27. #include "esp_attr.h"
  28. #include <cstdint>
  29. union Hsv;
  30. union Rgb {
  31. struct __attribute__((packed)) {
  32. uint8_t g, r, b, a;
  33. };
  34. uint32_t value;
  35. Rgb(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, uint8_t a = 255)
  36. : g(g)
  37. , r(r)
  38. , b(b)
  39. , a(a) {}
  40. Rgb(const Hsv& c);
  41. Rgb(const Rgb&) = default;
  42. Rgb& operator=(const Rgb& rgb) {
  43. swap(rgb);
  44. return *this;
  45. }
  46. Rgb& operator=(const Hsv& hsv);
  47. Rgb operator+(const Rgb& in) const;
  48. Rgb& operator+=(const Rgb& in);
  49. Rgb operator-(const Rgb& in) const;
  50. Rgb& operator-=(const Rgb& in);
  51. bool operator==(const Rgb& in) const { return in.value == value; }
  52. Rgb& blend(const Rgb& in);
  53. void swap(const Rgb& o) { value = o.value; }
  54. void linearize() {
  55. r = channelGamma(r);
  56. g = channelGamma(g);
  57. b = channelGamma(b);
  58. }
  59. inline uint8_t IRAM_ATTR getGrb(int idx) {
  60. switch (idx) {
  61. case 0:
  62. return g;
  63. case 1:
  64. return r;
  65. case 2:
  66. return b;
  67. }
  68. __builtin_unreachable();
  69. }
  70. void stretchChannels(uint8_t maxR, uint8_t maxG, uint8_t maxB) {
  71. r = stretch(r, maxR);
  72. g = stretch(g, maxG);
  73. b = stretch(b, maxB);
  74. }
  75. void stretchChannelsEvenly(uint8_t max) { stretchChannels(max, max, max); }
  76. private:
  77. uint8_t stretch(int value, uint8_t max) { return (value * max) >> 8; }
  78. uint8_t channelGamma(int channel) {
  79. /* The optimal gamma correction is x^2.8. However, this is expensive to
  80. * compute. Therefore, we use x^3 for gamma correction. Also, we add a
  81. * bias as the WS2812 LEDs do not turn on for values less than 4. */
  82. if (channel == 0)
  83. return channel;
  84. channel = channel * channel * channel * 251;
  85. channel >>= 24;
  86. return static_cast<uint8_t>(4 + channel);
  87. }
  88. };
  89. union Hsv {
  90. struct __attribute__((packed)) {
  91. uint8_t h, s, v, a;
  92. };
  93. uint32_t value;
  94. Hsv(uint8_t h, uint8_t s = 0, uint8_t v = 0, uint8_t a = 255)
  95. : h(h)
  96. , s(s)
  97. , v(v)
  98. , a(a) {}
  99. Hsv(const Rgb& r);
  100. Hsv& operator=(const Hsv& h) {
  101. swap(h);
  102. return *this;
  103. }
  104. Hsv& operator=(const Rgb& rgb);
  105. bool operator==(const Hsv& in) const { return in.value == value; }
  106. void swap(const Hsv& o) { value = o.value; }
  107. };