@@ -404,59 +404,90 @@ void Segment::handleRandomPalette() {
404404// strip must be suspended (strip.suspend()) before calling this function
405405// this function may call fill() to clear pixels if spacing or mapping changed (which requires setting _vWidth, _vHeight, _vLength or beginDraw())
406406void Segment::setGeometry (uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t m12) {
407- // return if neither bounds nor grouping have changed
408- bool boundsUnchanged = (start == i1 && stop == i2);
407+ // constrain start/stop indexes, grouping, spacing and mapping
408+ const unsigned matrixSize = Segment::maxWidth*Segment::maxHeight; // in pixel count; equal to strip.getLengthTotal() for 1D set-up
409+ // i1 must be less than matrix width - 1 (1D/2D) or larger than matrix pixel count but smaller than total pixel count(2D)
410+ if (i1 >= matrixSize) {
411+ i1 = MIN (i1, strip.getLengthTotal () - 1 ); // limit trailing strip
412+ i1Y = 0 ; // this is 1D segment; force it
413+ i2Y = 1 ; // this is 1D segment; force it
414+ } else if (i1 >= Segment::maxWidth) {
415+ i1 = Segment::maxWidth - 1 ; // set to last column
416+ // i1 = start; // revert/ignore change (<0.15.3 behaviour)
417+ }
418+ // i2 must be smaller than total pixel count or smaller than martix width
419+ if (i2 > matrixSize && i1 >= matrixSize) {
420+ i2 = MIN (i2, strip.getLengthTotal ()); // limit trailing strip
421+ } else if (i2 > Segment::maxWidth) {
422+ i2 = Segment::maxWidth; // limit to matrix width
423+ }
409424 #ifndef WLED_DISABLE_2D
410- boundsUnchanged &= (startY == i1Y && stopY == i2Y); // 2D
425+ // for 2D constrain startY/stopY
426+ if (Segment::maxHeight > 1 ) { // 2D
427+ if (i1Y >= Segment::maxHeight) {
428+ i1Y = Segment::maxHeight - 1 ;
429+ // i1Y = startY; // revert/ignore change (<0.15.3 behaviour)
430+ }
431+ i2Y = constrain (i2Y, 1 , Segment::maxHeight);
432+ } else
411433 #endif
412- boundsUnchanged &= (grouping == grp && spacing == spc); // changing grouping and/or spacing changes virtual segment length (painting dimensions)
413-
414- if (stop && (spc > 0 || m12 != map1D2D)) clear ();
415- if (grp) { // prevent assignment of 0
416- grouping = grp;
417- spacing = spc;
418- } else {
419- grouping = 1 ;
420- spacing = 0 ;
434+ {
435+ i1Y = 0 ;
436+ i2Y = 1 ;
437+ int width = i2 - i1;
438+ if (ofs < UINT16_MAX && width <= (int )ofs) {
439+ ofs = width - 1 ; // same behaviour as in deserializeSegment()
440+ }
421441 }
422- if (ofs < UINT16_MAX) offset = ofs;
423- map1D2D = constrain (m12, 0 , 7 );
442+ // fix invalid grouping (and reset spacing)
443+ if (grp == 0 ) {
444+ grp = 1 ;
445+ spc = 0 ;
446+ }
447+ m12 = constrain (m12, 0 , M12_maxMapping);
448+
449+ // return if neither bounds, grouping or mapping have changed
450+ // changing grouping and/or spacing and/or mapping changes virtual segment length (painting dimensions)
451+ const bool boundsUnchanged = (start == i1 && stop == i2) &&
452+ #ifndef WLED_DISABLE_2D
453+ (startY == i1Y && stopY == i2Y) && // 2D
454+ #endif
455+ (grouping == grp && spacing == spc && m12 == map1D2D && ofs == offset);
424456
425- DEBUGFX_PRINTF_P (PSTR (" Geometry: (%d,%d -> %d,%d) [%d,%d] ofs:%d m:%d\n " ), (int )i1, (int )i2, (int )i1Y, (int )i2Y, (int )grp, (int )spc, (int )ofs, (int )m12);
426457 if (boundsUnchanged) return ;
427458
428- unsigned oldLength = length ( );
459+ DEBUGFX_PRINTF_P ( PSTR ( " Geometry: (%d,%d -> %d,%d) [%d,%d] ofs:%d m:%d \n " ), ( int )i1, ( int )i2, ( int )i1Y, ( int )i2Y, ( int )grp, ( int )spc, ( int )ofs, ( int )m12 );
429460
430461 markForReset ();
431462 if (_t) stopTransition (); // we can't use transition if segment dimensions changed
432463 stateChanged = true ; // send UDP/WS broadcast
433464
434- // apply change immediately
435- if (i2 <= i1) { // disable segment
436- deallocateData ();
437- p_free (pixels);
438- pixels = nullptr ;
439- stop = 0 ;
440- return ;
441- }
442- if (i1 < Segment::maxWidth || (i1 >= Segment::maxWidth*Segment::maxHeight && i1 < strip.getLengthTotal ())) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D
443- stop = i2 > Segment::maxWidth*Segment::maxHeight ? MIN (i2,strip.getLengthTotal ()) : constrain (i2, 1 , Segment::maxWidth);
444- startY = 0 ;
445- stopY = 1 ;
446- #ifndef WLED_DISABLE_2D
447- if (Segment::maxHeight>1 ) { // 2D
448- if (i1Y < Segment::maxHeight) startY = i1Y;
449- stopY = constrain (i2Y, 1 , Segment::maxHeight);
450- }
451- #endif
452465 // safety check
453- if (start >= stop || startY >= stopY ) {
466+ if (i2 <= i1 || i2Y <= i1Y ) { // disable segment if stop is smaller or equal to start
454467 deallocateData ();
455468 p_free (pixels);
456469 pixels = nullptr ;
457470 stop = 0 ;
471+ // reset grouping, spacing and offset on deactivation
472+ grouping = 1 ;
473+ spacing = 0 ;
474+ offset = 0 ;
458475 return ;
459476 }
477+
478+ if (spc > 0 || m12 != map1D2D) clear (); // clear entire segment if spacing or mapping changed
479+
480+ unsigned oldLength = length ();
481+ // apply change
482+ map1D2D = m12;
483+ grouping = grp;
484+ spacing = spc;
485+ start = i1;
486+ stop = i2;
487+ startY = i1Y;
488+ stopY = i2Y;
489+ if (ofs < UINT16_MAX) offset = ofs;
490+
460491 // allocate FX render buffer only if increased in size (prevent fragmentation)
461492 if (length () > oldLength) {
462493 // allocate render buffer (always entire segment), prefer IRAM/PSRAM. Note: impact on FPS with PSRAM buffer is low (<2% with QSPI PSRAM) on S2/S3
@@ -467,6 +498,7 @@ void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, ui
467498 deallocateData ();
468499 errorFlag = ERR_NORAM_PX;
469500 stop = 0 ;
501+ // no reset
470502 return ;
471503 }
472504
@@ -549,7 +581,7 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
549581 sOpt = extractModeDefaults (fx, " o1" ); check1 = (sOpt >= 0 ) ? (bool )sOpt : false ;
550582 sOpt = extractModeDefaults (fx, " o2" ); check2 = (sOpt >= 0 ) ? (bool )sOpt : false ;
551583 sOpt = extractModeDefaults (fx, " o3" ); check3 = (sOpt >= 0 ) ? (bool )sOpt : false ;
552- sOpt = extractModeDefaults (fx, " m12" ); if (sOpt >= 0 ) map1D2D = constrain (sOpt , 0 , 7 ); else map1D2D = M12_Pixels; // reset mapping if not defined (2D FX may not work)
584+ sOpt = extractModeDefaults (fx, " m12" ); if (sOpt >= 0 ) map1D2D = constrain (sOpt , 0 , M12_maxMapping ); else map1D2D = M12_Pixels; // reset mapping if not defined (2D FX may not work)
553585 sOpt = extractModeDefaults (fx, " rev" ); if (sOpt >= 0 ) reverse = (bool )sOpt ;
554586 sOpt = extractModeDefaults (fx, " mi" ); if (sOpt >= 0 ) mirror = (bool )sOpt ; // NOTE: setting this option is a risky business
555587 sOpt = extractModeDefaults (fx, " rY" ); if (sOpt >= 0 ) reverse_y = (bool )sOpt ;
0 commit comments