Segment layering & effect blending improvements

- Photoshop-style segment/layer blending
- return of strip ABL
- remove global LED buffer in favour of segment-local buffer
- new effect blending modes/transitions
- custom palettes moved out of WS2812FX class
- increased limits (matrix size, LED RAM)
- added "rainbow"-mode colorwheel
- replaced palettes with gamma unmodified ones
- move gamma adjustment to last step before sending to LEDs
- Segment & WS2812FX class reorganisation (mutable members, reordered members, protected members)
This commit is contained in:
Blaž Kristan
2025-04-22 22:37:18 +02:00
parent 353868414a
commit ee9ac947a1
32 changed files with 2723 additions and 2931 deletions

View File

@@ -29,8 +29,9 @@ bool presetNeedsSaving() {
static void doSaveState() {
bool persist = (presetToSave < 251);
unsigned long start = millis();
while (strip.isUpdating() && millis()-start < (2*FRAMETIME_FIXED)+1) yield(); // wait 2 frames
unsigned long maxWait = millis() + strip.getFrameTime();
while (strip.isUpdating() && millis() < maxWait) delay(1); // wait for strip to finish updating, accessing FS during sendout causes glitches
if (!requestJSONBufferLock(10)) return;
initPresetsFile(); // just in case if someone deleted presets.json using /edit
@@ -56,14 +57,10 @@ static void doSaveState() {
*/
#if defined(ARDUINO_ARCH_ESP32)
if (!persist) {
if (tmpRAMbuffer!=nullptr) free(tmpRAMbuffer);
w_free(tmpRAMbuffer);
size_t len = measureJson(*pDoc) + 1;
DEBUG_PRINTLN(len);
// if possible use SPI RAM on ESP32
if (psramSafe && psramFound())
tmpRAMbuffer = (char*) ps_malloc(len);
else
tmpRAMbuffer = (char*) malloc(len);
tmpRAMbuffer = (char*)w_malloc(len);
if (tmpRAMbuffer!=nullptr) {
serializeJson(*pDoc, tmpRAMbuffer, len);
} else {
@@ -80,8 +77,8 @@ static void doSaveState() {
// clean up
saveLedmap = -1;
presetToSave = 0;
free(saveName);
free(quickLoad);
w_free(saveName);
w_free(quickLoad);
saveName = nullptr;
quickLoad = nullptr;
playlistSave = false;
@@ -168,9 +165,9 @@ void handlePresets()
DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset);
#if defined(ARDUINO_ARCH_ESP32S3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3)
unsigned long start = millis();
while (strip.isUpdating() && millis() - start < FRAMETIME_FIXED) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches
#if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3)
unsigned long maxWait = millis() + strip.getFrameTime();
while (strip.isUpdating() && millis() < maxWait) delay(1); // wait for strip to finish updating, accessing FS during sendout causes glitches
#endif
#ifdef ARDUINO_ARCH_ESP32
@@ -206,7 +203,7 @@ void handlePresets()
#if defined(ARDUINO_ARCH_ESP32)
//Aircoookie recommended not to delete buffer
if (tmpPreset==255 && tmpRAMbuffer!=nullptr) {
free(tmpRAMbuffer);
w_free(tmpRAMbuffer);
tmpRAMbuffer = nullptr;
}
#endif
@@ -220,8 +217,8 @@ void handlePresets()
//called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)]
void savePreset(byte index, const char* pname, JsonObject sObj)
{
if (!saveName) saveName = static_cast<char*>(malloc(33));
if (!quickLoad) quickLoad = static_cast<char*>(malloc(9));
if (!saveName) saveName = static_cast<char*>(w_malloc(33));
if (!quickLoad) quickLoad = static_cast<char*>(w_malloc(9));
if (!saveName || !quickLoad) return;
if (index == 0 || (index > 250 && index < 255)) return;
@@ -267,8 +264,8 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
presetsModifiedTime = toki.second(); //unix time
updateFSInfo();
}
free(saveName);
free(quickLoad);
w_free(saveName);
w_free(quickLoad);
saveName = nullptr;
quickLoad = nullptr;
} else {