2020-02-13 22:56:04 -08:00
#ifndef __INC_PIXELSET_H
#define __INC_PIXELSET_H
#include "FastLED.h"
#ifndef abs
#include <stdlib.h>
#endif
2020-07-18 19:22:02 -07:00
///// Represents a set of CRGB led objects. Provides the [] array operator, and works like a normal array in that case.
///// This should be kept in sync with the set of functions provided by CRGB as well as functions in colorutils. Note
///// that a pixel set is a window into another set of led data, it is not its own set of led data.
2020-02-13 22:56:04 -08:00
template < class PIXEL_TYPE >
class CPixelView {
public :
const int8_t dir ;
const int len ;
PIXEL_TYPE * const leds ;
PIXEL_TYPE * const end_pos ;
public :
/// PixelSet copy constructor
inline CPixelView ( const CPixelView & other ) : dir ( other . dir ), len ( other . len ), leds ( other . leds ), end_pos ( other . end_pos ) {}
/// pixelset constructor for a pixel set starting at the given PIXEL_TYPE* and going for _len leds. Note that the length
/// can be backwards, creating a PixelSet that walks backwards over the data
/// @param leds point to the raw led data
/// @param len how many leds in this set
inline CPixelView ( PIXEL_TYPE * _leds , int _len ) : dir ( _len < 0 ? - 1 : 1 ), len ( _len ), leds ( _leds ), end_pos ( _leds + _len ) {}
/// PixelSet constructor for the given set of leds, with start and end boundaries. Note that start can be after
/// end, resulting in a set that will iterate backwards
/// @param leds point to the raw led data
/// @param start the start index of the leds for this array
/// @param end the end index of the leds for this array
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 ) {}
/// Get the size of this set
/// @return the size of the set
int size () { return abs ( len ); }
/// Whether or not this set goes backwards
/// @return whether or not the set is backwards
bool reversed () { return len < 0 ; }
/// do these sets point to the same thing (note, this is different from the contents of the set being the same)
bool operator == ( const CPixelView & rhs ) const { return leds == rhs . leds && len == rhs . len && dir == rhs . dir ; }
/// do these sets point to the different things (note, this is different from the contents of the set being the same)
bool operator != ( const CPixelView & rhs ) const { return leds != rhs . leds || len != rhs . len || dir != rhs . dir ; }
/// access a single element in this set, just like an array operator
inline PIXEL_TYPE & operator []( int x ) const { if ( dir & 0x80 ) { return leds [ - x ]; } else { return leds [ x ]; } }
/// Access an inclusive subset of the leds in this set. Note that start can be greater than end, which will
/// result in a reverse ordering for many functions (useful for mirroring)
/// @param start the first element from this set for the new subset
/// @param end the last element for the new subset
inline CPixelView operator ()( int start , int end ) { return CPixelView ( leds , start , end ); }
/// Access an inclusive subset of the leds in this set, starting from the first.
/// @param end the last element for the new subset
/// Not sure i want this? inline CPixelView operator()(int end) { return CPixelView(leds, 0, end); }
/// Return the reverse ordering of this set
inline CPixelView operator - () { return CPixelView ( leds , len - dir , 0 ); }
/// Return a pointer to the first element in this set
inline operator PIXEL_TYPE * () const { return leds ; }
/// Assign the passed in color to all elements in this set
/// @param color the new color for the elements in the set
inline CPixelView & operator = ( const PIXEL_TYPE & color ) {
for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) = color ; }
return * this ;
}
void dump () const {
/**
Serial.print("len: "); Serial.print(len); Serial.print(", dir:"); Serial.print((int)dir);
Serial.print(", range:"); Serial.print((uint32_t)leds); Serial.print("-"); Serial.print((uint32_t)end_pos);
Serial.print(", diff:"); Serial.print((int32_t)(end_pos - leds));
Serial.println("");
**/
}
/// Copy the contents of the passed in set to our set. Note if one set is smaller than the other, only the
/// smallest number of items will be copied over.
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 ;
}
/// @name modification/scaling operators
//@{
/// Add the passed in value to r,g, b for all the pixels in this set
inline CPixelView & addToRGB ( uint8_t inc ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) += inc ; } return * this ; }
/// Add every pixel in the other set to this set
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 ; }
/// Subtract the passed in value from r,g,b for all pixels in this set
inline CPixelView & subFromRGB ( uint8_t inc ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) -= inc ; } return * this ; }
/// Subtract every pixel in the other set from this set
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 ; }
/// Increment every pixel value in this set
inline CPixelView & operator ++ () { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) ++ ; } return * this ; }
/// Increment every pixel value in this set
inline CPixelView & operator ++ ( int DUMMY_ARG ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) ++ ; } return * this ; }
/// Decrement every pixel value in this set
inline CPixelView & operator -- () { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) -- ; } return * this ; }
/// Decrement every pixel value in this set
inline CPixelView & operator -- ( int DUMMY_ARG ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) -- ; } return * this ; }
/// Divide every led by the given value
inline CPixelView & operator /= ( uint8_t d ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) /= d ; } return * this ; }
/// Shift every led in this set right by the given number of bits
inline CPixelView & operator >>= ( uint8_t d ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) >>= d ; } return * this ; }
/// Multiply every led in this set by the given value
inline CPixelView & operator *= ( uint8_t d ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) *= d ; } return * this ; }
/// Scale every led by the given scale
inline CPixelView & nscale8_video ( uint8_t scaledown ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ). nscale8_video ( scaledown ); } return * this ;}
/// Scale down every led by the given scale
inline CPixelView & operator %= ( uint8_t scaledown ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ). nscale8_video ( scaledown ); } return * this ; }
/// Fade every led down by the given scale
inline CPixelView & fadeLightBy ( uint8_t fadefactor ) { return nscale8_video ( 255 - fadefactor ); }
/// Scale every led by the given scale
inline CPixelView & nscale8 ( uint8_t scaledown ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ). nscale8 ( scaledown ); } return * this ; }
/// Scale every led by the given scale
inline CPixelView & nscale8 ( PIXEL_TYPE & scaledown ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ). nscale8 ( scaledown ); } return * this ; }
/// Scale every led in this set by every led in the other set
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 ; }
/// Fade every led down by the given scale
inline CPixelView & fadeToBlackBy ( uint8_t fade ) { return nscale8 ( 255 - fade ); }
/// 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)
inline CPixelView & operator |= ( const PIXEL_TYPE & rhs ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) |= rhs ; } return * this ; }
/// Apply the PIXEL_TYPE |= operator to every pixel in this set with every pixel in the passed in set
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 ; }
/// Apply the PIXEL_TYPE |= operator to every pixel in this set
inline CPixelView & operator |= ( uint8_t d ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) |= d ; } return * this ; }
/// 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)
inline CPixelView & operator &= ( const PIXEL_TYPE & rhs ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) &= rhs ; } return * this ; }
/// Apply the PIXEL_TYPE &= operator to every pixel in this set with every pixel in the passed in set
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 ; }
/// APply the PIXEL_TYPE &= operator to every pixel in this set with the passed in value
inline CPixelView & operator &= ( uint8_t d ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { ( * pixel ) &= d ; } return * this ; }
//@}
/// Returns whether or not any leds in this set are non-zero
inline operator bool () { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { if (( * pixel )) return true ; } return false ; }
// Color util functions
inline CPixelView & fill_solid ( const PIXEL_TYPE & color ) { * this = color ; return * this ; }
inline CPixelView & fill_solid ( const CHSV & color ) { if ( dir > 0 ) { * this = color ; return * this ; } }
inline CPixelView & fill_rainbow ( uint8_t initialhue , uint8_t deltahue = 5 ) {
if ( dir >= 0 ) {
:: fill_rainbow ( leds , len , initialhue , deltahue );
} else {
:: fill_rainbow ( leds + len + 1 , - len , initialhue , deltahue );
}
return * this ;
}
inline CPixelView & fill_gradient ( const CHSV & startcolor , const CHSV & endcolor , TGradientDirectionCode directionCode = SHORTEST_HUES ) {
if ( dir >= 0 ) {
:: fill_gradient ( leds , len , startcolor , endcolor , directionCode );
} else {
:: fill_gradient ( leds + len + 1 , ( - len ), endcolor , startcolor , directionCode );
}
return * this ;
}
inline CPixelView & fill_gradient ( const CHSV & c1 , const CHSV & c2 , const CHSV & c3 , TGradientDirectionCode directionCode = SHORTEST_HUES ) {
if ( dir >= 0 ) {
:: fill_gradient ( leds , len , c1 , c2 , c3 , directionCode );
} else {
:: fill_gradient ( leds + len + 1 , - len , c3 , c2 , c1 , directionCode );
}
return * this ;
}
inline CPixelView & fill_gradient ( const CHSV & c1 , const CHSV & c2 , const CHSV & c3 , const CHSV & c4 , TGradientDirectionCode directionCode = SHORTEST_HUES ) {
if ( dir >= 0 ) {
:: fill_gradient ( leds , len , c1 , c2 , c3 , c4 , directionCode );
} else {
:: fill_gradient ( leds + len + 1 , - len , c4 , c3 , c2 , c1 , directionCode );
}
return * this ;
}
inline CPixelView & fill_gradient_RGB ( const PIXEL_TYPE & startcolor , const PIXEL_TYPE & endcolor , TGradientDirectionCode directionCode = SHORTEST_HUES ) {
if ( dir >= 0 ) {
:: fill_gradient_RGB ( leds , len , startcolor , endcolor );
} else {
:: fill_gradient_RGB ( leds + len + 1 , ( - len ), endcolor , startcolor );
}
return * this ;
}
inline CPixelView & fill_gradient_RGB ( const PIXEL_TYPE & c1 , const PIXEL_TYPE & c2 , const PIXEL_TYPE & c3 ) {
if ( dir >= 0 ) {
:: fill_gradient_RGB ( leds , len , c1 , c2 , c3 );
} else {
:: fill_gradient_RGB ( leds + len + 1 , - len , c3 , c2 , c1 );
}
return * this ;
}
inline CPixelView & fill_gradient_RGB ( const PIXEL_TYPE & c1 , const PIXEL_TYPE & c2 , const PIXEL_TYPE & c3 , const PIXEL_TYPE & c4 ) {
if ( dir >= 0 ) {
:: fill_gradient_RGB ( leds , len , c1 , c2 , c3 , c4 );
} else {
:: fill_gradient_RGB ( leds + len + 1 , - len , c4 , c3 , c2 , c1 );
}
return * this ;
}
inline CPixelView & nblend ( const PIXEL_TYPE & overlay , fract8 amountOfOverlay ) { for ( iterator pixel = begin (), _end = end (); pixel != _end ; ++ pixel ) { :: nblend (( * pixel ), overlay , amountOfOverlay ); } return * this ; }
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 ; }
// Note: only bringing in a 1d blur, not sure 2d blur makes sense when looking at sub arrays
inline CPixelView & blur1d ( fract8 blur_amount ) {
if ( dir >= 0 ) {
:: blur1d ( leds , len , blur_amount );
} else {
:: blur1d ( leds + len + 1 , - len , blur_amount );
}
return * this ;
}
inline CPixelView & napplyGamma_video ( float gamma ) {
if ( dir >= 0 ) {
:: napplyGamma_video ( leds , len , gamma );
} else {
:: napplyGamma_video ( leds + len + 1 , - len , gamma );
}
return * this ;
}
inline CPixelView & napplyGamma_video ( float gammaR , float gammaG , float gammaB ) {
if ( dir >= 0 ) {
:: napplyGamma_video ( leds , len , gammaR , gammaG , gammaB );
} else {
:: napplyGamma_video ( leds + len + 1 , - len , gammaR , gammaG , gammaB );
}
return * this ;
}
// TODO: Make this a fully specified/proper iterator
template < class T >
class pixelset_iterator_base {
T * leds ;
const int8_t dir ;
public :
__attribute__ (( always_inline )) inline pixelset_iterator_base ( const pixelset_iterator_base & rhs ) : leds ( rhs . leds ), dir ( rhs . dir ) {}
__attribute__ (( always_inline )) inline pixelset_iterator_base ( T * _leds , const char _dir ) : leds ( _leds ), dir ( _dir ) {}
__attribute__ (( always_inline )) inline pixelset_iterator_base & operator ++ () { leds += dir ; return * this ; }
__attribute__ (( always_inline )) inline pixelset_iterator_base operator ++ ( int ) { pixelset_iterator_base tmp ( * this ); leds += dir ; return tmp ; }
__attribute__ (( always_inline )) inline bool operator == ( pixelset_iterator_base & other ) const { return leds == other . leds ; } // && set==other.set; }
__attribute__ (( always_inline )) inline bool operator != ( pixelset_iterator_base & other ) const { return leds != other . leds ; } // || set != other.set; }
__attribute__ (( always_inline )) inline PIXEL_TYPE & operator * () const { return * leds ; }
};
typedef pixelset_iterator_base < PIXEL_TYPE > iterator ;
typedef pixelset_iterator_base < const PIXEL_TYPE > const_iterator ;
iterator begin () { return iterator ( leds , dir ); }
iterator end () { return iterator ( end_pos , dir ); }
iterator begin () const { return iterator ( leds , dir ); }
iterator end () const { return iterator ( end_pos , dir ); }
const_iterator cbegin () const { return const_iterator ( leds , dir ); }
const_iterator cend () const { return const_iterator ( end_pos , dir ); }
};
typedef CPixelView < CRGB > CRGBSet ;
__attribute__ (( always_inline ))
inline CRGB * operator + ( const CRGBSet & pixels , int offset ) { return ( CRGB * ) pixels + offset ; }
template < int SIZE >
class CRGBArray : public CPixelView < CRGB > {
CRGB rawleds [ SIZE ];
public :
CRGBArray () : CPixelView < CRGB > ( rawleds , SIZE ) {}
using CPixelView :: operator = ;
};
#endif