Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 84 additions & 55 deletions wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,83 +458,112 @@ void Segment::handleRandomPalette() {
// strip must be suspended (strip.suspend()) before calling this function
// this function may call fill() to clear pixels if spacing or mapping changed (which requires setting _vWidth, _vHeight, _vLength or beginDraw())
void 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) {
// return if neither bounds nor grouping have changed
bool boundsUnchanged = (start == i1 && stop == i2);
// Sanitise inputs
if (i2 <= i1) { // For any values, this means deactivate the segment; we check i2 before i1 for this case
i2 = 0;
}

// If i1 is invalid, use old value
// Valid range is inside maxWidth, or in trailing segment range
if ((i1 >= Segment::maxWidth) && (i1 < Segment::maxWidth*Segment::maxHeight || i1 >= strip.getLengthTotal())) {
i1 = start;
}

// Check i2 validity
if (i2 > 0) {
// Clamp i2 to maximum length
if ((i1 >= Segment::maxWidth*Segment::maxHeight) && (i2 >= Segment::maxWidth*Segment::maxHeight)) {
// Trailing strip after 2D
i2 = MIN(i2,strip.getLengthTotal());
i1Y = 0; // 2D Y values are not used for trailing strip
i2Y = 1;
} else if (i2 > Segment::maxWidth) {
i2 = Segment::maxWidth;
}
}

#ifndef WLED_DISABLE_2D
boundsUnchanged &= (startY == i1Y && stopY == i2Y); // 2D
if (Segment::maxHeight>1) { // 2D
if (i1Y >= Segment::maxHeight) {
// Unlike i1 (X), Y values don't inherit old values if invalid
// This behaviour preserved for backwards compatibility
i1Y = 0;
}
if (i2Y > Segment::maxHeight) {
i2Y = Segment::maxHeight;
} else if (i2Y < 1) {
i2Y = 1;
}
} else
#endif
boundsUnchanged &= (grouping == grp && spacing == spc); // changing grouping and/or spacing changes virtual segment length (painting dimensions)
{
i1Y = 0;
i2Y = 1;
}

if (stop && (spc > 0 || m12 != map1D2D)) clear();
if (grp) { // prevent assignment of 0
grouping = grp;
spacing = spc;
} else {
grouping = 1;
spacing = 0;
if (grp == 0) { grp = 1; spc = 0; } // prevent assignment of 0
if (ofs == UINT16_MAX) ofs = offset; // keep current setting if passed illegal value
m12 = constrain(m12, 0, 7);

// Final safety check after all bounds adjustments
if ((i1 >= i2) || (i1Y >= i2Y)) {
i2 = 0; // disable segment
}
if (ofs < UINT16_MAX) offset = ofs;
map1D2D = constrain(m12, 0, 7);

// Inputs are ok, check if anything has changed
bool boundsUnchanged = (start == i1 && stop == i2)
#ifndef WLED_DISABLE_2D
&& ((Segment::maxHeight <= 1) || (startY == i1Y && stopY == i2Y))
#endif
&& (grouping == grp)
&& (spacing == spc)
&& (offset == ofs)
&& (m12 == map1D2D);

if (boundsUnchanged) return;

DEBUG_PRINTF_P(PSTR("Segment geometry: (%d,%d),(%d,%d) -> (%d,%d),(%d,%d) [%d,%d]\n"), start, stop, startY, stopY, (int)i1, (int)i2, (int)i1Y, (int)i2Y, (int) grp, (int)spc);

unsigned oldLength = length();

DEBUGFX_PRINTF_P(PSTR("Segment geometry: %d,%d -> %d,%d [%d,%d]\n"), (int)i1, (int)i2, (int)i1Y, (int)i2Y, (int)grp, (int)spc);
markForReset();
stopTransition(); // we can't use transition if segment dimensions changed
stateChanged = true; // send UDP/WS broadcast

// apply change immediately
if (i2 <= i1) { //disable segment
#ifdef WLED_ENABLE_GIF
endImagePlayback(this);
#endif
deallocateData();
p_free(pixels);
pixels = nullptr;
stop = 0;
return;
}
if (i1 < Segment::maxWidth || (i1 >= Segment::maxWidth*Segment::maxHeight && i1 < strip.getLengthTotal())) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D
stop = i2 > Segment::maxWidth*Segment::maxHeight && i1 >= Segment::maxWidth*Segment::maxHeight ? MIN(i2,strip.getLengthTotal()) : constrain(i2, 1, Segment::maxWidth); // check for 2D trailing strip
startY = 0;
stopY = 1;
#ifndef WLED_DISABLE_2D
if (Segment::maxHeight>1) { // 2D
if (i1Y < Segment::maxHeight) startY = i1Y;
stopY = constrain(i2Y, 1, Segment::maxHeight);
}
#endif
// safety check
if (start >= stop || startY >= stopY) {
#ifdef WLED_ENABLE_GIF
endImagePlayback(this);
#endif
deallocateData();
p_free(pixels);
pixels = nullptr;
stop = 0;
return;
}
// allocate FX render buffer
if (length() != oldLength) {
// apply change
start = i1;
stop = i2;
startY = i1Y;
stopY = i2Y;
grouping = grp;
spacing = spc;
offset = ofs;
map1D2D = m12;

// Cleanup check
auto newLength = length();
if ((newLength > 0) && (newLength != oldLength)) {
// 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
// Note we don't pass BFRALLOC_CLEAR as resetIfRequired() will initialize the buffer later
p_free(pixels);
pixels = static_cast<uint32_t*>(allocate_buffer(length() * sizeof(uint32_t), BFRALLOC_PREFER_PSRAM | BFRALLOC_NOBYTEACCESS));
if (!pixels) {
DEBUGFX_PRINTLN(F("!!! Not enough RAM for pixel buffer !!!"));
#ifdef WLED_ENABLE_GIF
endImagePlayback(this);
#endif
deallocateData();
errorFlag = ERR_NORAM_PX;
stop = 0;
return;
stop = 0; // will fall through into disable check below
}
}

if (length() == 0) {
#ifdef WLED_ENABLE_GIF
endImagePlayback(this);
#endif
deallocateData();
p_free(pixels);
pixels = nullptr;
} else {
refreshLightCapabilities();
}
refreshLightCapabilities();
}


Expand Down
Loading