PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pixelset.h 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. #ifndef __INC_PIXELSET_H
  2. #define __INC_PIXELSET_H
  3. #include "FastLED.h"
  4. #ifndef abs
  5. #include <stdlib.h>
  6. #endif
  7. ///// Represents a set of CRGB led objects. Provides the [] array operator, and works like a normal array in that case.
  8. ///// This should be kept in sync with the set of functions provided by CRGB as well as functions in colorutils. Note
  9. ///// that a pixel set is a window into another set of led data, it is not its own set of led data.
  10. template<class PIXEL_TYPE>
  11. class CPixelView {
  12. public:
  13. const int8_t dir;
  14. const int len;
  15. PIXEL_TYPE * const leds;
  16. PIXEL_TYPE * const end_pos;
  17. public:
  18. /// PixelSet copy constructor
  19. inline CPixelView(const CPixelView & other) : dir(other.dir), len(other.len), leds(other.leds), end_pos(other.end_pos) {}
  20. /// pixelset constructor for a pixel set starting at the given PIXEL_TYPE* and going for _len leds. Note that the length
  21. /// can be backwards, creating a PixelSet that walks backwards over the data
  22. /// @param leds point to the raw led data
  23. /// @param len how many leds in this set
  24. inline CPixelView(PIXEL_TYPE *_leds, int _len) : dir(_len < 0 ? -1 : 1), len(_len), leds(_leds), end_pos(_leds + _len) {}
  25. /// PixelSet constructor for the given set of leds, with start and end boundaries. Note that start can be after
  26. /// end, resulting in a set that will iterate backwards
  27. /// @param leds point to the raw led data
  28. /// @param start the start index of the leds for this array
  29. /// @param end the end index of the leds for this array
  30. inline CPixelView(PIXEL_TYPE *_leds, int _start, int _end) : dir(((_end-_start)<0) ? -1 : 1), len((_end - _start) + dir), leds(_leds + _start), end_pos(_leds + _start + len) {}
  31. /// Get the size of this set
  32. /// @return the size of the set
  33. int size() { return abs(len); }
  34. /// Whether or not this set goes backwards
  35. /// @return whether or not the set is backwards
  36. bool reversed() { return len < 0; }
  37. /// do these sets point to the same thing (note, this is different from the contents of the set being the same)
  38. bool operator==(const CPixelView & rhs) const { return leds == rhs.leds && len == rhs.len && dir == rhs.dir; }
  39. /// do these sets point to the different things (note, this is different from the contents of the set being the same)
  40. bool operator!=(const CPixelView & rhs) const { return leds != rhs.leds || len != rhs.len || dir != rhs.dir; }
  41. /// access a single element in this set, just like an array operator
  42. inline PIXEL_TYPE & operator[](int x) const { if(dir & 0x80) { return leds[-x]; } else { return leds[x]; } }
  43. /// Access an inclusive subset of the leds in this set. Note that start can be greater than end, which will
  44. /// result in a reverse ordering for many functions (useful for mirroring)
  45. /// @param start the first element from this set for the new subset
  46. /// @param end the last element for the new subset
  47. inline CPixelView operator()(int start, int end) { return CPixelView(leds, start, end); }
  48. /// Access an inclusive subset of the leds in this set, starting from the first.
  49. /// @param end the last element for the new subset
  50. /// Not sure i want this? inline CPixelView operator()(int end) { return CPixelView(leds, 0, end); }
  51. /// Return the reverse ordering of this set
  52. inline CPixelView operator-() { return CPixelView(leds, len - dir, 0); }
  53. /// Return a pointer to the first element in this set
  54. inline operator PIXEL_TYPE* () const { return leds; }
  55. /// Assign the passed in color to all elements in this set
  56. /// @param color the new color for the elements in the set
  57. inline CPixelView & operator=(const PIXEL_TYPE & color) {
  58. for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) = color; }
  59. return *this;
  60. }
  61. void dump() const {
  62. /**
  63. Serial.print("len: "); Serial.print(len); Serial.print(", dir:"); Serial.print((int)dir);
  64. Serial.print(", range:"); Serial.print((uint32_t)leds); Serial.print("-"); Serial.print((uint32_t)end_pos);
  65. Serial.print(", diff:"); Serial.print((int32_t)(end_pos - leds));
  66. Serial.println("");
  67. **/
  68. }
  69. /// Copy the contents of the passed in set to our set. Note if one set is smaller than the other, only the
  70. /// smallest number of items will be copied over.
  71. inline CPixelView & operator=(const CPixelView & rhs) {
  72. for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) {
  73. (*pixel) = (*rhspixel);
  74. }
  75. return *this;
  76. }
  77. /// @name modification/scaling operators
  78. //@{
  79. /// Add the passed in value to r,g, b for all the pixels in this set
  80. inline CPixelView & addToRGB(uint8_t inc) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) += inc; } return *this; }
  81. /// Add every pixel in the other set to this set
  82. inline CPixelView & operator+=(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) += (*rhspixel); } return *this; }
  83. /// Subtract the passed in value from r,g,b for all pixels in this set
  84. inline CPixelView & subFromRGB(uint8_t inc) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) -= inc; } return *this; }
  85. /// Subtract every pixel in the other set from this set
  86. inline CPixelView & operator-=(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) -= (*rhspixel); } return *this; }
  87. /// Increment every pixel value in this set
  88. inline CPixelView & operator++() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)++; } return *this; }
  89. /// Increment every pixel value in this set
  90. inline CPixelView & operator++(int DUMMY_ARG) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)++; } return *this; }
  91. /// Decrement every pixel value in this set
  92. inline CPixelView & operator--() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)--; } return *this; }
  93. /// Decrement every pixel value in this set
  94. inline CPixelView & operator--(int DUMMY_ARG) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)--; } return *this; }
  95. /// Divide every led by the given value
  96. inline CPixelView & operator/=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) /= d; } return *this; }
  97. /// Shift every led in this set right by the given number of bits
  98. inline CPixelView & operator>>=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) >>= d; } return *this; }
  99. /// Multiply every led in this set by the given value
  100. inline CPixelView & operator*=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) *= d; } return *this; }
  101. /// Scale every led by the given scale
  102. inline CPixelView & nscale8_video(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8_video(scaledown); } return *this;}
  103. /// Scale down every led by the given scale
  104. inline CPixelView & operator%=(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8_video(scaledown); } return *this; }
  105. /// Fade every led down by the given scale
  106. inline CPixelView & fadeLightBy(uint8_t fadefactor) { return nscale8_video(255 - fadefactor); }
  107. /// Scale every led by the given scale
  108. inline CPixelView & nscale8(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8(scaledown); } return *this; }
  109. /// Scale every led by the given scale
  110. inline CPixelView & nscale8(PIXEL_TYPE & scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8(scaledown); } return *this; }
  111. /// Scale every led in this set by every led in the other set
  112. inline CPixelView & nscale8(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel).nscale8((*rhspixel)); } return *this; }
  113. /// Fade every led down by the given scale
  114. inline CPixelView & fadeToBlackBy(uint8_t fade) { return nscale8(255 - fade); }
  115. /// Apply the PIXEL_TYPE |= operator to every pixel in this set with the given PIXEL_TYPE value (bringing each channel to the higher of the two values)
  116. inline CPixelView & operator|=(const PIXEL_TYPE & rhs) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) |= rhs; } return *this; }
  117. /// Apply the PIXEL_TYPE |= operator to every pixel in this set with every pixel in the passed in set
  118. inline CPixelView & operator|=(const CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) |= (*rhspixel); } return *this; }
  119. /// Apply the PIXEL_TYPE |= operator to every pixel in this set
  120. inline CPixelView & operator|=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) |= d; } return *this; }
  121. /// Apply the PIXEL_TYPE &= operator to every pixel in this set with the given PIXEL_TYPE value (bringing each channel down to the lower of the two values)
  122. inline CPixelView & operator&=(const PIXEL_TYPE & rhs) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) &= rhs; } return *this; }
  123. /// Apply the PIXEL_TYPE &= operator to every pixel in this set with every pixel in the passed in set
  124. inline CPixelView & operator&=(const CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) &= (*rhspixel); } return *this; }
  125. /// APply the PIXEL_TYPE &= operator to every pixel in this set with the passed in value
  126. inline CPixelView & operator&=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) &= d; } return *this; }
  127. //@}
  128. /// Returns whether or not any leds in this set are non-zero
  129. inline operator bool() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { if((*pixel)) return true; } return false; }
  130. // Color util functions
  131. inline CPixelView & fill_solid(const PIXEL_TYPE & color) { *this = color; return *this; }
  132. inline CPixelView & fill_solid(const CHSV & color) { if(dir>0) { *this = color; return *this; } }
  133. inline CPixelView & fill_rainbow(uint8_t initialhue, uint8_t deltahue=5) {
  134. if(dir >= 0) {
  135. ::fill_rainbow(leds,len,initialhue,deltahue);
  136. } else {
  137. ::fill_rainbow(leds+len+1,-len,initialhue,deltahue);
  138. }
  139. return *this;
  140. }
  141. inline CPixelView & fill_gradient(const CHSV & startcolor, const CHSV & endcolor, TGradientDirectionCode directionCode = SHORTEST_HUES) {
  142. if(dir >= 0) {
  143. ::fill_gradient(leds,len,startcolor, endcolor, directionCode);
  144. } else {
  145. ::fill_gradient(leds + len + 1, (-len), endcolor, startcolor, directionCode);
  146. }
  147. return *this;
  148. }
  149. inline CPixelView & fill_gradient(const CHSV & c1, const CHSV & c2, const CHSV & c3, TGradientDirectionCode directionCode = SHORTEST_HUES) {
  150. if(dir >= 0) {
  151. ::fill_gradient(leds, len, c1, c2, c3, directionCode);
  152. } else {
  153. ::fill_gradient(leds + len + 1, -len, c3, c2, c1, directionCode);
  154. }
  155. return *this;
  156. }
  157. inline CPixelView & fill_gradient(const CHSV & c1, const CHSV & c2, const CHSV & c3, const CHSV & c4, TGradientDirectionCode directionCode = SHORTEST_HUES) {
  158. if(dir >= 0) {
  159. ::fill_gradient(leds, len, c1, c2, c3, c4, directionCode);
  160. } else {
  161. ::fill_gradient(leds + len + 1, -len, c4, c3, c2, c1, directionCode);
  162. }
  163. return *this;
  164. }
  165. inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & startcolor, const PIXEL_TYPE & endcolor, TGradientDirectionCode directionCode = SHORTEST_HUES) {
  166. if(dir >= 0) {
  167. ::fill_gradient_RGB(leds,len,startcolor, endcolor);
  168. } else {
  169. ::fill_gradient_RGB(leds + len + 1, (-len), endcolor, startcolor);
  170. }
  171. return *this;
  172. }
  173. inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & c1, const PIXEL_TYPE & c2, const PIXEL_TYPE & c3) {
  174. if(dir >= 0) {
  175. ::fill_gradient_RGB(leds, len, c1, c2, c3);
  176. } else {
  177. ::fill_gradient_RGB(leds + len + 1, -len, c3, c2, c1);
  178. }
  179. return *this;
  180. }
  181. inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & c1, const PIXEL_TYPE & c2, const PIXEL_TYPE & c3, const PIXEL_TYPE & c4) {
  182. if(dir >= 0) {
  183. ::fill_gradient_RGB(leds, len, c1, c2, c3, c4);
  184. } else {
  185. ::fill_gradient_RGB(leds + len + 1, -len, c4, c3, c2, c1);
  186. }
  187. return *this;
  188. }
  189. inline CPixelView & nblend(const PIXEL_TYPE & overlay, fract8 amountOfOverlay) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { ::nblend((*pixel), overlay, amountOfOverlay); } return *this; }
  190. inline CPixelView & nblend(const CPixelView & rhs, fract8 amountOfOverlay) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { ::nblend((*pixel), (*rhspixel), amountOfOverlay); } return *this; }
  191. // Note: only bringing in a 1d blur, not sure 2d blur makes sense when looking at sub arrays
  192. inline CPixelView & blur1d(fract8 blur_amount) {
  193. if(dir >= 0) {
  194. ::blur1d(leds, len, blur_amount);
  195. } else {
  196. ::blur1d(leds + len + 1, -len, blur_amount);
  197. }
  198. return *this;
  199. }
  200. inline CPixelView & napplyGamma_video(float gamma) {
  201. if(dir >= 0) {
  202. ::napplyGamma_video(leds, len, gamma);
  203. } else {
  204. ::napplyGamma_video(leds + len + 1, -len, gamma);
  205. }
  206. return *this;
  207. }
  208. inline CPixelView & napplyGamma_video(float gammaR, float gammaG, float gammaB) {
  209. if(dir >= 0) {
  210. ::napplyGamma_video(leds, len, gammaR, gammaG, gammaB);
  211. } else {
  212. ::napplyGamma_video(leds + len + 1, -len, gammaR, gammaG, gammaB);
  213. }
  214. return *this;
  215. }
  216. // TODO: Make this a fully specified/proper iterator
  217. template <class T>
  218. class pixelset_iterator_base {
  219. T * leds;
  220. const int8_t dir;
  221. public:
  222. __attribute__((always_inline)) inline pixelset_iterator_base(const pixelset_iterator_base & rhs) : leds(rhs.leds), dir(rhs.dir) {}
  223. __attribute__((always_inline)) inline pixelset_iterator_base(T * _leds, const char _dir) : leds(_leds), dir(_dir) {}
  224. __attribute__((always_inline)) inline pixelset_iterator_base& operator++() { leds += dir; return *this; }
  225. __attribute__((always_inline)) inline pixelset_iterator_base operator++(int) { pixelset_iterator_base tmp(*this); leds += dir; return tmp; }
  226. __attribute__((always_inline)) inline bool operator==(pixelset_iterator_base & other) const { return leds == other.leds; } // && set==other.set; }
  227. __attribute__((always_inline)) inline bool operator!=(pixelset_iterator_base & other) const { return leds != other.leds; } // || set != other.set; }
  228. __attribute__((always_inline)) inline PIXEL_TYPE& operator*() const { return *leds; }
  229. };
  230. typedef pixelset_iterator_base<PIXEL_TYPE> iterator;
  231. typedef pixelset_iterator_base<const PIXEL_TYPE> const_iterator;
  232. iterator begin() { return iterator(leds, dir); }
  233. iterator end() { return iterator(end_pos, dir); }
  234. iterator begin() const { return iterator(leds, dir); }
  235. iterator end() const { return iterator(end_pos, dir); }
  236. const_iterator cbegin() const { return const_iterator(leds, dir); }
  237. const_iterator cend() const { return const_iterator(end_pos, dir); }
  238. };
  239. typedef CPixelView<CRGB> CRGBSet;
  240. __attribute__((always_inline))
  241. inline CRGB *operator+(const CRGBSet & pixels, int offset) { return (CRGB*)pixels + offset; }
  242. template<int SIZE>
  243. class CRGBArray : public CPixelView<CRGB> {
  244. CRGB rawleds[SIZE];
  245. public:
  246. CRGBArray() : CPixelView<CRGB>(rawleds, SIZE) {}
  247. using CPixelView::operator=;
  248. };
  249. #endif