kopia lustrzana https://github.com/Aircoookie/WLED
				
				
				
			First working multisegment transitions
							rodzic
							
								
									0df6826c91
								
							
						
					
					
						commit
						9551519a35
					
				
							
								
								
									
										155
									
								
								wled00/FX.h
								
								
								
								
							
							
						
						
									
										155
									
								
								wled00/FX.h
								
								
								
								
							| 
						 | 
				
			
			@ -62,16 +62,15 @@
 | 
			
		|||
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
 | 
			
		||||
  insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
 | 
			
		||||
#ifdef ESP8266
 | 
			
		||||
  #define MAX_NUM_SEGMENTS 12
 | 
			
		||||
  #define MAX_NUM_SEGMENTS    12
 | 
			
		||||
  /* How many color transitions can run at once */
 | 
			
		||||
  #define MAX_NUM_TRANSITIONS  8
 | 
			
		||||
  /* How much data bytes all segments combined may allocate */
 | 
			
		||||
  #define MAX_SEGMENT_DATA  2048
 | 
			
		||||
#else
 | 
			
		||||
  #define MAX_NUM_SEGMENTS 16
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* How much data bytes all segments combined may allocate */
 | 
			
		||||
#ifdef ESP8266
 | 
			
		||||
#define MAX_SEGMENT_DATA 2048
 | 
			
		||||
#else
 | 
			
		||||
#define MAX_SEGMENT_DATA 8192
 | 
			
		||||
  #define MAX_NUM_SEGMENTS    16
 | 
			
		||||
  #define MAX_NUM_TRANSITIONS 16
 | 
			
		||||
  #define MAX_SEGMENT_DATA  8192
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define LED_SKIP_AMOUNT  1
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +78,7 @@
 | 
			
		|||
 | 
			
		||||
#define NUM_COLORS       3 /* number of colors per segment */
 | 
			
		||||
#define SEGMENT          _segments[_segment_index]
 | 
			
		||||
#define SEGCOLOR(x)      gamma32(_segments[_segment_index].colors[x])
 | 
			
		||||
#define SEGCOLOR(x)      _colors_t[x]
 | 
			
		||||
#define SEGENV           _segment_runtimes[_segment_index]
 | 
			
		||||
#define SEGLEN           _virtualSegmentLength
 | 
			
		||||
#define SEGACT           SEGMENT.stop
 | 
			
		||||
| 
						 | 
				
			
			@ -240,11 +239,14 @@
 | 
			
		|||
#define FX_MODE_TV_SIMULATOR           116
 | 
			
		||||
#define FX_MODE_DYNAMIC_SMOOTH         117
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class WS2812FX {
 | 
			
		||||
  typedef uint16_t (WS2812FX::*mode_ptr)(void);
 | 
			
		||||
 | 
			
		||||
  // pre show callback
 | 
			
		||||
  typedef void (*show_callback) (void);
 | 
			
		||||
 | 
			
		||||
  static WS2812FX* instance;
 | 
			
		||||
  
 | 
			
		||||
  // segment parameters
 | 
			
		||||
  public:
 | 
			
		||||
| 
						 | 
				
			
			@ -259,14 +261,39 @@ class WS2812FX {
 | 
			
		|||
      uint8_t grouping, spacing;
 | 
			
		||||
      uint8_t opacity;
 | 
			
		||||
      uint32_t colors[NUM_COLORS];
 | 
			
		||||
      void setOption(uint8_t n, bool val)
 | 
			
		||||
      bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
 | 
			
		||||
        if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
 | 
			
		||||
        if (c == colors[slot]) return false;
 | 
			
		||||
        ColorTransition::startTransition(opacity, colors[slot], instance->_transitionDur, segn, slot);
 | 
			
		||||
        colors[slot] = c; return true;
 | 
			
		||||
      }
 | 
			
		||||
      void setOpacity(uint8_t o, uint8_t segn) {
 | 
			
		||||
        if (segn >= MAX_NUM_SEGMENTS) return;
 | 
			
		||||
        if (opacity == o) return;
 | 
			
		||||
        ColorTransition::startTransition(o, colors[0], instance->_transitionDur, segn, 0);
 | 
			
		||||
        opacity = o;
 | 
			
		||||
      }
 | 
			
		||||
      uint8_t actualOpacity() { //respects On/Off state
 | 
			
		||||
        if (!getOption(SEG_OPTION_ON)) return 0;
 | 
			
		||||
        return opacity;
 | 
			
		||||
      }
 | 
			
		||||
      void setOption(uint8_t n, bool val, uint8_t segn = 255)
 | 
			
		||||
      {
 | 
			
		||||
        bool prevOn = false;
 | 
			
		||||
        if (n == SEG_OPTION_ON) prevOn = getOption(SEG_OPTION_ON);
 | 
			
		||||
        if (val) {
 | 
			
		||||
          options |= 0x01 << n;
 | 
			
		||||
        } else
 | 
			
		||||
        {
 | 
			
		||||
          options &= ~(0x01 << n);
 | 
			
		||||
        }
 | 
			
		||||
        if (n == SEG_OPTION_ON && segn < MAX_NUM_SEGMENTS && getOption(SEG_OPTION_ON) != prevOn) {
 | 
			
		||||
          if (getOption(SEG_OPTION_ON)) {
 | 
			
		||||
            ColorTransition::startTransition(0, colors[0], instance->_transitionDur, segn, 0);
 | 
			
		||||
          } else {
 | 
			
		||||
            ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      bool getOption(uint8_t n)
 | 
			
		||||
      {
 | 
			
		||||
| 
						 | 
				
			
			@ -309,10 +336,10 @@ class WS2812FX {
 | 
			
		|||
      bool allocateData(uint16_t len){
 | 
			
		||||
        if (data && _dataLen == len) return true; //already allocated
 | 
			
		||||
        deallocateData();
 | 
			
		||||
        if (WS2812FX::_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
 | 
			
		||||
        if (WS2812FX::instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
 | 
			
		||||
        data = new (std::nothrow) byte[len];
 | 
			
		||||
        if (!data) return false; //allocation failed
 | 
			
		||||
        WS2812FX::_usedSegmentData += len;
 | 
			
		||||
        WS2812FX::instance->_usedSegmentData += len;
 | 
			
		||||
        _dataLen = len;
 | 
			
		||||
        memset(data, 0, len);
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -320,7 +347,7 @@ class WS2812FX {
 | 
			
		|||
      void deallocateData(){
 | 
			
		||||
        delete[] data;
 | 
			
		||||
        data = nullptr;
 | 
			
		||||
        WS2812FX::_usedSegmentData -= _dataLen;
 | 
			
		||||
        WS2812FX::instance->_usedSegmentData -= _dataLen;
 | 
			
		||||
        _dataLen = 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -350,7 +377,86 @@ class WS2812FX {
 | 
			
		|||
        bool _requiresReset = false;
 | 
			
		||||
    } segment_runtime;
 | 
			
		||||
 | 
			
		||||
    typedef struct ColorTransition { // 12 bytes
 | 
			
		||||
      uint32_t colorOld = 0;
 | 
			
		||||
      uint32_t transitionStart;
 | 
			
		||||
      uint16_t transitionDur;
 | 
			
		||||
      uint8_t segment = 0xFF; //lower 6 bits: the segment this transition is for (255 indicates transition not in use/available) upper 2 bits: color channel
 | 
			
		||||
      uint8_t briOld = 0;
 | 
			
		||||
      static void startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot) {
 | 
			
		||||
        Serial.printf("Starting t: Bri %u Col %u Dur %u Seg %u Slot %u\n", oldBri, oldCol, dur, segn, slot);
 | 
			
		||||
        if (segn >= MAX_NUM_SEGMENTS || slot >= NUM_COLORS || dur == 0) return; 
 | 
			
		||||
        uint8_t tIndex = 0xFF; //none found
 | 
			
		||||
        uint16_t tProgression = 0;
 | 
			
		||||
        uint8_t s = segn + (slot << 6); //merge slot and segment into one byte
 | 
			
		||||
 | 
			
		||||
        for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
 | 
			
		||||
          uint8_t tSeg = instance->transitions[i].segment;
 | 
			
		||||
          //see if this segment + color already has a running transition
 | 
			
		||||
          if (tSeg == s) {
 | 
			
		||||
            tIndex = i; break;
 | 
			
		||||
          }
 | 
			
		||||
          if (tSeg == 0xFF) { //free transition
 | 
			
		||||
            tIndex = i; tProgression = 0xFFFF;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (tIndex == 0xFF) { //no slot found yet
 | 
			
		||||
          for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
 | 
			
		||||
            //find most progressed transition to overwrite
 | 
			
		||||
            uint16_t prog = instance->transitions[i].progress();
 | 
			
		||||
            if (prog > tProgression) {
 | 
			
		||||
              tIndex = i; tProgression = prog;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ColorTransition& t = instance->transitions[tIndex];
 | 
			
		||||
        if (t.segment == s) //this is an active transition on the same segment+color
 | 
			
		||||
        {
 | 
			
		||||
          t.briOld = t.currentBri();
 | 
			
		||||
          t.colorOld = t.currentColor(oldCol);
 | 
			
		||||
        } else {
 | 
			
		||||
          t.briOld = oldBri;
 | 
			
		||||
          t.colorOld = oldCol;
 | 
			
		||||
          uint8_t prevSeg = t.segment & 0x3F;
 | 
			
		||||
          if (prevSeg < MAX_NUM_SEGMENTS) instance->_segments[prevSeg].setOption(SEG_OPTION_TRANSITIONAL, false);
 | 
			
		||||
        }
 | 
			
		||||
        t.transitionDur = dur;
 | 
			
		||||
        t.transitionStart = millis();
 | 
			
		||||
        t.segment = s;
 | 
			
		||||
        instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, true);
 | 
			
		||||
        //Serial.printf("S: %u, TNr: %u, St: %u\n", s, tIndex, t.transitionStart);
 | 
			
		||||
        //instance->transitions[tIndex] = t;
 | 
			
		||||
      }
 | 
			
		||||
      uint16_t progress(bool allowEnd = false) { //transition progression between 0-65535
 | 
			
		||||
        uint32_t timeNow = millis();
 | 
			
		||||
        //Serial.printf("ProgressR %u, St: %u, S: %u\n",timeNow - transitionStart, transitionStart, segment);
 | 
			
		||||
        if (timeNow - transitionStart > transitionDur) return 0xFFFF;
 | 
			
		||||
        uint32_t elapsed = timeNow - transitionStart;
 | 
			
		||||
        uint32_t prog = elapsed * 0xFFFF / transitionDur;
 | 
			
		||||
        //Serial.printf("Progress %u\n",prog);
 | 
			
		||||
        if (prog > 0xFFFF && allowEnd) {
 | 
			
		||||
          uint8_t segn = segment & 0x3F;
 | 
			
		||||
          if (segn < MAX_NUM_SEGMENTS) instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, false);
 | 
			
		||||
          segment = 0xFF;
 | 
			
		||||
        } 
 | 
			
		||||
        return (prog > 0xFFFF) ? 0xFFFF : prog;
 | 
			
		||||
      }
 | 
			
		||||
      uint32_t currentColor(uint32_t colorNew) {
 | 
			
		||||
        return instance->color_blend(colorOld, colorNew, progress(true), true);
 | 
			
		||||
      }
 | 
			
		||||
      uint8_t currentBri() {
 | 
			
		||||
        uint8_t segn = segment & 0x3F;
 | 
			
		||||
        if (segn >= MAX_NUM_SEGMENTS) return 0;
 | 
			
		||||
        uint8_t briNew = instance->_segments[segn].actualOpacity();
 | 
			
		||||
        uint32_t prog = progress();
 | 
			
		||||
        return ((briNew * prog) + (briOld * (0xFFFF - prog))) >> 16;
 | 
			
		||||
      }
 | 
			
		||||
    } color_transition;
 | 
			
		||||
 | 
			
		||||
    WS2812FX() {
 | 
			
		||||
      WS2812FX::instance = this;
 | 
			
		||||
      //assign each member of the _mode[] array to its respective function reference 
 | 
			
		||||
      _mode[FX_MODE_STATIC]                  = &WS2812FX::mode_static;
 | 
			
		||||
      _mode[FX_MODE_BLINK]                   = &WS2812FX::mode_blink;
 | 
			
		||||
| 
						 | 
				
			
			@ -493,6 +599,7 @@ class WS2812FX {
 | 
			
		|||
      setBrightness(uint8_t b),
 | 
			
		||||
      setRange(uint16_t i, uint16_t i2, uint32_t col),
 | 
			
		||||
      setShowCallback(show_callback cb),
 | 
			
		||||
      setTransition(uint16_t t),
 | 
			
		||||
      setTransitionMode(bool t),
 | 
			
		||||
      calcGammaTable(float),
 | 
			
		||||
      trigger(void),
 | 
			
		||||
| 
						 | 
				
			
			@ -547,7 +654,8 @@ class WS2812FX {
 | 
			
		|||
      timebase,
 | 
			
		||||
      color_wheel(uint8_t),
 | 
			
		||||
      color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255),
 | 
			
		||||
      color_blend(uint32_t,uint32_t,uint8_t),
 | 
			
		||||
      color_blend(uint32_t,uint32_t,uint16_t,bool b16=false),
 | 
			
		||||
      currentColor(uint32_t colorNew, uint8_t tNr),
 | 
			
		||||
      gamma32(uint32_t),
 | 
			
		||||
      getLastShow(void),
 | 
			
		||||
      getPixelColor(uint16_t),
 | 
			
		||||
| 
						 | 
				
			
			@ -695,7 +803,8 @@ class WS2812FX {
 | 
			
		|||
    uint16_t _length, _lengthRaw, _virtualSegmentLength;
 | 
			
		||||
    uint16_t _rand16seed;
 | 
			
		||||
    uint8_t _brightness;
 | 
			
		||||
    static uint16_t _usedSegmentData;
 | 
			
		||||
    uint16_t _usedSegmentData = 0;
 | 
			
		||||
    uint16_t _transitionDur = 750;
 | 
			
		||||
 | 
			
		||||
    void load_gradient_palette(uint8_t);
 | 
			
		||||
    void handle_palette(void);
 | 
			
		||||
| 
						 | 
				
			
			@ -735,10 +844,15 @@ class WS2812FX {
 | 
			
		|||
    CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
 | 
			
		||||
    CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff);
 | 
			
		||||
 | 
			
		||||
    void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend);
 | 
			
		||||
    void
 | 
			
		||||
      blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
 | 
			
		||||
      startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot);
 | 
			
		||||
    
 | 
			
		||||
    uint32_t _lastPaletteChange = 0;
 | 
			
		||||
    uint32_t _lastShow = 0;
 | 
			
		||||
 | 
			
		||||
    uint32_t _colors_t[3];
 | 
			
		||||
    uint8_t _bri_t;
 | 
			
		||||
    
 | 
			
		||||
    #ifdef WLED_USE_ANALOG_LEDS
 | 
			
		||||
    uint32_t _analogLastShow = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -755,7 +869,12 @@ class WS2812FX {
 | 
			
		|||
    segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
 | 
			
		||||
    friend class Segment_runtime;
 | 
			
		||||
 | 
			
		||||
    uint16_t realPixelIndex(uint16_t i);
 | 
			
		||||
    ColorTransition transitions[MAX_NUM_TRANSITIONS]; //12 bytes per element
 | 
			
		||||
    friend class ColorTransition;
 | 
			
		||||
 | 
			
		||||
    uint16_t
 | 
			
		||||
      realPixelIndex(uint16_t i),
 | 
			
		||||
      transitionProgress(uint8_t tNr);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//10 names per line
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,23 +85,31 @@ void WS2812FX::service() {
 | 
			
		|||
    // segment's buffers are cleared
 | 
			
		||||
    SEGENV.resetIfRequired();
 | 
			
		||||
 | 
			
		||||
    if (SEGMENT.isActive())
 | 
			
		||||
    if (!SEGMENT.isActive()) continue;
 | 
			
		||||
 | 
			
		||||
    if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
 | 
			
		||||
    {
 | 
			
		||||
      if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
 | 
			
		||||
      {
 | 
			
		||||
        if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
 | 
			
		||||
        doShow = true;
 | 
			
		||||
        uint16_t delay = FRAMETIME;
 | 
			
		||||
      if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
 | 
			
		||||
      doShow = true;
 | 
			
		||||
      uint16_t delay = FRAMETIME;
 | 
			
		||||
 | 
			
		||||
        if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
 | 
			
		||||
          _virtualSegmentLength = SEGMENT.virtualLength();
 | 
			
		||||
          handle_palette();
 | 
			
		||||
          delay = (this->*_mode[SEGMENT.mode])(); //effect function
 | 
			
		||||
          if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
 | 
			
		||||
      if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
 | 
			
		||||
        _virtualSegmentLength = SEGMENT.virtualLength();
 | 
			
		||||
        _bri_t = SEGMENT.opacity; _colors_t[0] = SEGMENT.colors[0]; _colors_t[1] = SEGMENT.colors[1]; _colors_t[2] = SEGMENT.colors[2];
 | 
			
		||||
        if (!IS_SEGMENT_ON) _bri_t = 0;
 | 
			
		||||
        for (uint8_t t = 0; t < MAX_NUM_TRANSITIONS; t++) {
 | 
			
		||||
          if ((transitions[t].segment & 0x3F) != i) continue;
 | 
			
		||||
          uint8_t slot = transitions[t].segment >> 6;
 | 
			
		||||
          if (slot == 0) _bri_t = transitions[t].currentBri();
 | 
			
		||||
          _colors_t[slot] = transitions[t].currentColor(SEGMENT.colors[slot]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SEGENV.next_time = nowUp + delay;
 | 
			
		||||
        for (uint8_t c = 0; c < 3; c++) _colors_t[c] = gamma32(_colors_t[c]);
 | 
			
		||||
        handle_palette();
 | 
			
		||||
        delay = (this->*_mode[SEGMENT.mode])(); //effect function
 | 
			
		||||
        if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      SEGENV.next_time = nowUp + delay;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  _virtualSegmentLength = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -165,17 +173,12 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
 | 
			
		|||
  uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
 | 
			
		||||
  if (SEGLEN) {//from segment
 | 
			
		||||
 | 
			
		||||
    //color_blend(getpixel, col, SEGMENT.opacity); (pseudocode for future blending of segments)
 | 
			
		||||
    if (IS_SEGMENT_ON)
 | 
			
		||||
    {
 | 
			
		||||
      if (SEGMENT.opacity < 255) {  
 | 
			
		||||
        col.R = scale8(col.R, SEGMENT.opacity);
 | 
			
		||||
        col.G = scale8(col.G, SEGMENT.opacity);
 | 
			
		||||
        col.B = scale8(col.B, SEGMENT.opacity);
 | 
			
		||||
        col.W = scale8(col.W, SEGMENT.opacity);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      col = BLACK;
 | 
			
		||||
    //color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
 | 
			
		||||
    if (_bri_t < 255) {  
 | 
			
		||||
      col.R = scale8(col.R, _bri_t);
 | 
			
		||||
      col.G = scale8(col.G, _bri_t);
 | 
			
		||||
      col.B = scale8(col.B, _bri_t);
 | 
			
		||||
      col.W = scale8(col.W, _bri_t);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Set all the pixels in the group, ensuring _skipFirstMode is honored */
 | 
			
		||||
| 
						 | 
				
			
			@ -347,7 +350,7 @@ uint8_t WS2812FX::getPaletteCount()
 | 
			
		|||
  return 13 + GRADIENT_PALETTE_COUNT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//TODO transitions
 | 
			
		||||
//TODO effect transitions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
 | 
			
		||||
| 
						 | 
				
			
			@ -395,14 +398,15 @@ void WS2812FX::setColor(uint8_t slot, uint32_t c) {
 | 
			
		|||
    for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
 | 
			
		||||
    {
 | 
			
		||||
      if (_segments[i].isSelected()) {
 | 
			
		||||
        _segments[i].colors[slot] = c;
 | 
			
		||||
        _segments[i].setColor(slot, c, i);
 | 
			
		||||
        applied = true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!applyToAllSelected || !applied) {
 | 
			
		||||
    _segments[getMainSegmentId()].colors[slot] = c;
 | 
			
		||||
    uint8_t mainseg = getMainSegmentId();
 | 
			
		||||
    _segments[mainseg].setColor(slot, c, mainseg);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -605,6 +609,11 @@ void WS2812FX::setShowCallback(show_callback cb)
 | 
			
		|||
  _callback = cb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WS2812FX::setTransition(uint16_t t)
 | 
			
		||||
{
 | 
			
		||||
  _transitionDur = t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WS2812FX::setTransitionMode(bool t)
 | 
			
		||||
{
 | 
			
		||||
  unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
 | 
			
		||||
| 
						 | 
				
			
			@ -620,24 +629,26 @@ void WS2812FX::setTransitionMode(bool t)
 | 
			
		|||
/*
 | 
			
		||||
 * color blend function
 | 
			
		||||
 */
 | 
			
		||||
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend) {
 | 
			
		||||
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
 | 
			
		||||
  if(blend == 0)   return color1;
 | 
			
		||||
  if(blend == 255) return color2;
 | 
			
		||||
  uint16_t blendmax = b16 ? 0xFFFF : 0xFF;
 | 
			
		||||
  if(blend == blendmax) return color2;
 | 
			
		||||
  uint8_t shift = b16 ? 16 : 8;
 | 
			
		||||
 | 
			
		||||
  uint32_t w1 = (color1 >> 24) & 0xff;
 | 
			
		||||
  uint32_t r1 = (color1 >> 16) & 0xff;
 | 
			
		||||
  uint32_t g1 = (color1 >>  8) & 0xff;
 | 
			
		||||
  uint32_t b1 =  color1        & 0xff;
 | 
			
		||||
  uint32_t w1 = (color1 >> 24) & 0xFF;
 | 
			
		||||
  uint32_t r1 = (color1 >> 16) & 0xFF;
 | 
			
		||||
  uint32_t g1 = (color1 >>  8) & 0xFF;
 | 
			
		||||
  uint32_t b1 =  color1        & 0xFF;
 | 
			
		||||
 | 
			
		||||
  uint32_t w2 = (color2 >> 24) & 0xff;
 | 
			
		||||
  uint32_t r2 = (color2 >> 16) & 0xff;
 | 
			
		||||
  uint32_t g2 = (color2 >>  8) & 0xff;
 | 
			
		||||
  uint32_t b2 =  color2        & 0xff;
 | 
			
		||||
  uint32_t w2 = (color2 >> 24) & 0xFF;
 | 
			
		||||
  uint32_t r2 = (color2 >> 16) & 0xFF;
 | 
			
		||||
  uint32_t g2 = (color2 >>  8) & 0xFF;
 | 
			
		||||
  uint32_t b2 =  color2        & 0xFF;
 | 
			
		||||
 | 
			
		||||
  uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) >> 8;
 | 
			
		||||
  uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) >> 8;
 | 
			
		||||
  uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) >> 8;
 | 
			
		||||
  uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) >> 8;
 | 
			
		||||
  uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
 | 
			
		||||
  uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
 | 
			
		||||
  uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
 | 
			
		||||
  uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
 | 
			
		||||
 | 
			
		||||
  return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1044,4 +1055,4 @@ uint32_t WS2812FX::gamma32(uint32_t color)
 | 
			
		|||
  return ((w << 24) | (r << 16) | (g << 8) | (b));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t WS2812FX::_usedSegmentData = 0;
 | 
			
		||||
WS2812FX* WS2812FX::instance = nullptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ void setValuesFromMainSeg();
 | 
			
		|||
void resetTimebase();
 | 
			
		||||
void toggleOnOff();
 | 
			
		||||
void setAllLeds();
 | 
			
		||||
void setLedsStandard(bool justColors = false);
 | 
			
		||||
void setLedsStandard();
 | 
			
		||||
bool colorChanged();
 | 
			
		||||
void colorUpdated(int callMode);
 | 
			
		||||
void updateInterfaces(uint8_t callMode);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,13 +23,13 @@ void deserializeSegment(JsonObject elem, byte it)
 | 
			
		|||
 | 
			
		||||
    int segbri = elem["bri"] | -1;
 | 
			
		||||
    if (segbri == 0) {
 | 
			
		||||
      seg.setOption(SEG_OPTION_ON, 0);
 | 
			
		||||
      seg.setOption(SEG_OPTION_ON, 0, id);
 | 
			
		||||
    } else if (segbri > 0) {
 | 
			
		||||
      seg.opacity = segbri;
 | 
			
		||||
      seg.setOption(SEG_OPTION_ON, 1);
 | 
			
		||||
      seg.setOpacity(segbri, id);
 | 
			
		||||
      seg.setOption(SEG_OPTION_ON, 1, id);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON));
 | 
			
		||||
    seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON), id);
 | 
			
		||||
    
 | 
			
		||||
    JsonArray colarr = elem[F("col")];
 | 
			
		||||
    if (!colarr.isNull())
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ void deserializeSegment(JsonObject elem, byte it)
 | 
			
		|||
          if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
 | 
			
		||||
            int kelvin = colarr[i] | -1;
 | 
			
		||||
            if (kelvin <  0) continue;
 | 
			
		||||
            if (kelvin == 0) seg.colors[i] = 0;
 | 
			
		||||
            if (kelvin == 0) seg.setColor(i, 0, id);
 | 
			
		||||
            if (kelvin >  0) colorKtoRGB(kelvin, brgbw);
 | 
			
		||||
            colValid = true;
 | 
			
		||||
          } else { //HEX string, e.g. "FFAA00"
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ void deserializeSegment(JsonObject elem, byte it)
 | 
			
		|||
          if (sz == 0) continue; //do nothing on empty array
 | 
			
		||||
 | 
			
		||||
          byte cp = copyArray(colX, rgbw, 4);      
 | 
			
		||||
          if (cp == 1 && rgbw[0] == 0) seg.colors[i] = 0;
 | 
			
		||||
          if (cp == 1 && rgbw[0] == 0) seg.setColor(i, 0, id);
 | 
			
		||||
          colValid = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -66,8 +66,8 @@ void deserializeSegment(JsonObject elem, byte it)
 | 
			
		|||
        { 
 | 
			
		||||
          if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
 | 
			
		||||
          if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
 | 
			
		||||
        } else { //normal case, apply directly to segment (=> no transition!)
 | 
			
		||||
          seg.colors[i] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
 | 
			
		||||
        } else { //normal case, apply directly to segment
 | 
			
		||||
          seg.setColor(i, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), id);
 | 
			
		||||
          if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -168,6 +168,7 @@ bool deserializeState(JsonObject root)
 | 
			
		|||
  {
 | 
			
		||||
    transitionDelay = tr;
 | 
			
		||||
    transitionDelay *= 100;
 | 
			
		||||
    transitionDelayTemp = transitionDelay;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  tr = root[F("tt")] | -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +178,7 @@ bool deserializeState(JsonObject root)
 | 
			
		|||
    transitionDelayTemp *= 100;
 | 
			
		||||
    jsonTransitionOnce = true;
 | 
			
		||||
  }
 | 
			
		||||
  strip.setTransition(transitionDelayTemp);
 | 
			
		||||
  
 | 
			
		||||
  int cy = root[F("pl")] | -2;
 | 
			
		||||
  if (cy > -2) presetCyclingEnabled = (cy >= 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,24 +51,20 @@ void setAllLeds() {
 | 
			
		|||
  }
 | 
			
		||||
  if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY)
 | 
			
		||||
  {
 | 
			
		||||
    colorRGBtoRGBW(colT);
 | 
			
		||||
    colorRGBtoRGBW(colSecT);
 | 
			
		||||
    colorRGBtoRGBW(col);
 | 
			
		||||
    colorRGBtoRGBW(colSec);
 | 
			
		||||
  }
 | 
			
		||||
  strip.setColor(0, col[0], col[1], col[2], col[3]);
 | 
			
		||||
  strip.setColor(1, colSec[0], colSec[1], colSec[2], colSec[3]);
 | 
			
		||||
  if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY)
 | 
			
		||||
  {
 | 
			
		||||
    col[3] = 0; colSec[3] = 0;
 | 
			
		||||
  }
 | 
			
		||||
  strip.setColor(0, colT[0], colT[1], colT[2], colT[3]);
 | 
			
		||||
  strip.setColor(1, colSecT[0], colSecT[1], colSecT[2], colSecT[3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void setLedsStandard(bool justColors)
 | 
			
		||||
void setLedsStandard()
 | 
			
		||||
{
 | 
			
		||||
  for (byte i=0; i<4; i++)
 | 
			
		||||
  {
 | 
			
		||||
    colOld[i] = col[i];
 | 
			
		||||
    colT[i] = col[i];
 | 
			
		||||
    colSecOld[i] = colSec[i];
 | 
			
		||||
    colSecT[i] = colSec[i];
 | 
			
		||||
  }
 | 
			
		||||
  if (justColors) return;
 | 
			
		||||
  briOld = bri;
 | 
			
		||||
  briT = bri;
 | 
			
		||||
  setAllLeds();
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +141,7 @@ void colorUpdated(int callMode)
 | 
			
		|||
  }
 | 
			
		||||
  if (briT == 0)
 | 
			
		||||
  {
 | 
			
		||||
    setLedsStandard(true);                                            //do not color transition if starting from off
 | 
			
		||||
    //setLedsStandard(true); //do not color transition if starting from off!
 | 
			
		||||
    if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -160,15 +156,11 @@ void colorUpdated(int callMode)
 | 
			
		|||
    //set correct delay if not using notification delay
 | 
			
		||||
    if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
 | 
			
		||||
    jsonTransitionOnce = false;
 | 
			
		||||
    strip.setTransition(transitionDelayTemp);
 | 
			
		||||
    if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;}
 | 
			
		||||
    
 | 
			
		||||
    if (transitionActive)
 | 
			
		||||
    {
 | 
			
		||||
      for (byte i=0; i<4; i++)
 | 
			
		||||
      {
 | 
			
		||||
        colOld[i] = colT[i];
 | 
			
		||||
        colSecOld[i] = colSecT[i];
 | 
			
		||||
      }
 | 
			
		||||
      briOld = briT;
 | 
			
		||||
      tperLast = 0;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +169,7 @@ void colorUpdated(int callMode)
 | 
			
		|||
    transitionStartTime = millis();
 | 
			
		||||
  } else
 | 
			
		||||
  {
 | 
			
		||||
    strip.setTransition(0);
 | 
			
		||||
    setLedsStandard();
 | 
			
		||||
    strip.trigger();
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -222,11 +215,6 @@ void handleTransitions()
 | 
			
		|||
    }
 | 
			
		||||
    if (tper - tperLast < 0.004) return;
 | 
			
		||||
    tperLast = tper;
 | 
			
		||||
    for (byte i=0; i<4; i++)
 | 
			
		||||
    {
 | 
			
		||||
      colT[i] = colOld[i]+((col[i] - colOld[i])*tper);
 | 
			
		||||
      colSecT[i] = colSecOld[i]+((colSec[i] - colSecOld[i])*tper);
 | 
			
		||||
    }
 | 
			
		||||
    briT    = briOld   +((bri    - briOld   )*tper);
 | 
			
		||||
    
 | 
			
		||||
    setAllLeds();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ void parseLxJson(int lxValue, byte segId, bool secondary)
 | 
			
		|||
    } else {
 | 
			
		||||
      DEBUG_PRINT(F("LX: segment "));
 | 
			
		||||
      DEBUG_PRINTLN(segId);
 | 
			
		||||
      strip.getSegment(segId).colors[secondary] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
 | 
			
		||||
      strip.getSegment(segId).setColor(secondary, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), segId);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -244,7 +244,7 @@ bool checkCountdown()
 | 
			
		|||
    if (countdownMode) localTime = n - countdownTime + utcOffsetSecs;
 | 
			
		||||
    if (!countdownOverTriggered)
 | 
			
		||||
    {
 | 
			
		||||
      if (macroCountdown != 0) applyMacro(macroCountdown);
 | 
			
		||||
      if (macroCountdown != 0) applyPreset(macroCountdown);
 | 
			
		||||
      countdownOverTriggered = true;
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
 | 
			
		||||
bool applyPreset(byte index)
 | 
			
		||||
{
 | 
			
		||||
  if (index == 0) return false;
 | 
			
		||||
  if (fileDoc) {
 | 
			
		||||
    errorFlag = readObjectFromFileUsingId("/presets.json", index, fileDoc) ? ERR_NONE : ERR_FS_PLOAD;
 | 
			
		||||
    JsonObject fdo = fileDoc->as<JsonObject>();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -541,7 +541,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
 | 
			
		|||
      strip.applyToAllSelected = true;
 | 
			
		||||
      strip.setColor(2, t[0], t[1], t[2], t[3]);
 | 
			
		||||
    } else {
 | 
			
		||||
      strip.getSegment(selectedSeg).colors[2] = ((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24));
 | 
			
		||||
      strip.getSegment(selectedSeg).setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -667,9 +667,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
 | 
			
		|||
  pos = req.indexOf(F("SB="));
 | 
			
		||||
  if (pos > 0) {
 | 
			
		||||
    byte segbri = getNumVal(&req, pos);
 | 
			
		||||
    strip.getSegment(selectedSeg).setOption(SEG_OPTION_ON, segbri);
 | 
			
		||||
    strip.getSegment(selectedSeg).setOption(SEG_OPTION_ON, segbri, selectedSeg);
 | 
			
		||||
    if (segbri) {
 | 
			
		||||
      strip.getSegment(selectedSeg).opacity = segbri;
 | 
			
		||||
      strip.getSegment(selectedSeg).setOpacity(segbri, selectedSeg);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
// version code in format yymmddb (b = daily build)
 | 
			
		||||
#define VERSION 2101040
 | 
			
		||||
#define VERSION 2101080
 | 
			
		||||
 | 
			
		||||
//uncomment this if you have a "my_config.h" file you'd like to use
 | 
			
		||||
//#define WLED_USE_MY_CONFIG
 | 
			
		||||
| 
						 | 
				
			
			@ -342,11 +342,7 @@ WLED_GLOBAL bool interfacesInited _INIT(false);
 | 
			
		|||
WLED_GLOBAL bool wasConnected _INIT(false);
 | 
			
		||||
 | 
			
		||||
// color
 | 
			
		||||
WLED_GLOBAL byte colOld[]    _INIT_N(({ 0, 0, 0, 0 }));        // color before transition
 | 
			
		||||
WLED_GLOBAL byte colT[]      _INIT_N(({ 0, 0, 0, 0 }));          // color that is currently displayed on the LEDs
 | 
			
		||||
WLED_GLOBAL byte colIT[]     _INIT_N(({ 0, 0, 0, 0 }));         // color that was last sent to LEDs
 | 
			
		||||
WLED_GLOBAL byte colSecT[]   _INIT_N(({ 0, 0, 0, 0 }));
 | 
			
		||||
WLED_GLOBAL byte colSecOld[] _INIT_N(({ 0, 0, 0, 0 }));
 | 
			
		||||
WLED_GLOBAL byte colSecIT[]  _INIT_N(({ 0, 0, 0, 0 }));
 | 
			
		||||
 | 
			
		||||
WLED_GLOBAL byte lastRandomIndex _INIT(0);        // used to save last random color so the new one is not the same
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue