diff --git a/platformio.ini b/platformio.ini index 597eab7c0..3b8489d86 100644 --- a/platformio.ini +++ b/platformio.ini @@ -390,7 +390,8 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME lib_deps = ${esp32s2.lib_deps} [env:esp32c3] -platform = espressif32@5.1.1 +platform = espressif32@5.1.1 ;; well-tested on -C3, good compatibility with WLED +; platform = espressif32@~5.2.0 ;; might help in case you experience bootloops due to corrupted flash filesystem framework = arduino board = esp32-c3-devkitm-1 board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv diff --git a/usermods/Animated_Staircase/Animated_Staircase.h b/usermods/Animated_Staircase/Animated_Staircase.h index 1ef2c9593..151cf1d4a 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.h +++ b/usermods/Animated_Staircase/Animated_Staircase.h @@ -92,12 +92,14 @@ class Animated_Staircase : public Usermod { static const char _bottomEchoCm[]; void publishMqtt(bool bottom, const char* state) { +#ifndef WLED_DISABLE_MQTT //Check if MQTT Connected, otherwise it will crash the 8266 if (WLED_MQTT_CONNECTED){ char subuf[64]; sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)bottom); mqtt->publish(subuf, 0, false, state); } +#endif } void updateSegments() { @@ -345,6 +347,7 @@ class Animated_Staircase : public Usermod { uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; } +#ifndef WLED_DISABLE_MQTT /** * handling of MQTT message * topic only contains stripped topic (part after /wled/MAC) @@ -382,6 +385,7 @@ class Animated_Staircase : public Usermod { mqtt->subscribe(subuf, 0); } } +#endif void addToJsonState(JsonObject& root) { JsonObject staircase = root[FPSTR(_name)]; diff --git a/usermods/BH1750_v2/usermod_bh1750.h b/usermods/BH1750_v2/usermod_bh1750.h index a69e27514..b65332bc3 100644 --- a/usermods/BH1750_v2/usermod_bh1750.h +++ b/usermods/BH1750_v2/usermod_bh1750.h @@ -1,6 +1,10 @@ // force the compiler to show a warning to confirm that this file is included #warning **** Included USERMOD_BH1750 **** +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #pragma once #include "wled.h" @@ -156,6 +160,7 @@ public: { lastLux = lux; lastSend = millis(); +#ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { if (!mqttInitialized) @@ -170,6 +175,7 @@ public: { DEBUG_PRINTLN(F("Missing MQTT connection. Not publishing data")); } +#endif } } diff --git a/usermods/BME280_v2/usermod_bme280.h b/usermods/BME280_v2/usermod_bme280.h index c27adfc87..e643e62b5 100644 --- a/usermods/BME280_v2/usermod_bme280.h +++ b/usermods/BME280_v2/usermod_bme280.h @@ -1,6 +1,10 @@ // force the compiler to show a warning to confirm that this file is included #warning **** Included USERMOD_BME280 version 2.0 **** +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #pragma once #include "wled.h" diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 5cf6ac792..bf123a79d 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -194,6 +194,7 @@ class UsermodBattery : public Usermod if (autoOffEnabled && (autoOffThreshold >= bat->getLevel())) turnOff(); +#ifndef WLED_DISABLE_MQTT // SmartHome stuff // still don't know much about MQTT and/or HA if (WLED_MQTT_CONNECTED) { @@ -201,6 +202,7 @@ class UsermodBattery : public Usermod snprintf_P(buf, 63, PSTR("%s/voltage"), mqttDeviceTopic); mqtt->publish(buf, 0, false, String(voltage).c_str()); } +#endif } diff --git a/usermods/DHT/usermod_dht.h b/usermods/DHT/usermod_dht.h index 6253b85fa..b6142f432 100644 --- a/usermods/DHT/usermod_dht.h +++ b/usermods/DHT/usermod_dht.h @@ -1,6 +1,10 @@ #pragma once #include "wled.h" +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #include diff --git a/usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp b/usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp index 0a2662aac..1ca160501 100644 --- a/usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp +++ b/usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp @@ -1,3 +1,7 @@ +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #include "wled.h" #include #include // from https://github.com/olikraus/u8g2/ diff --git a/usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp b/usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp index 88d497905..d5fd4a0c2 100644 --- a/usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp +++ b/usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp @@ -1,3 +1,7 @@ +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #include "wled.h" #include #include // from https://github.com/olikraus/u8g2/ diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h index f716e48ec..af81170ac 100644 --- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h +++ b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h @@ -136,7 +136,7 @@ private: } } else { if (m_offPreset) { - if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(m_offPreset, NotifyUpdateMode); + applyPreset(m_offPreset, NotifyUpdateMode); return; } else if (prevPlaylist) { if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPlaylist, NotifyUpdateMode); @@ -159,6 +159,7 @@ private: void publishMqtt(const char* state) { + #ifndef WLED_DISABLE_MQTT //Check if MQTT Connected, otherwise it will crash the 8266 if (WLED_MQTT_CONNECTED) { char subuf[64]; @@ -166,11 +167,13 @@ private: strcat_P(subuf, PSTR("/motion")); mqtt->publish(subuf, 0, false, state); } + #endif } // Create an MQTT Binary Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop. void publishHomeAssistantAutodiscovery() { + #ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { StaticJsonDocument<600> doc; char uid[24], json_str[1024], buf[128]; @@ -200,6 +203,7 @@ private: mqtt->publish(buf, 0, true, json_str, payload_size); // do we really need to retain? } + #endif } /** diff --git a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h index 9c3be7cc2..60861e4c5 100644 --- a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h +++ b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h @@ -109,6 +109,7 @@ public: { lastLDRValue = currentLDRValue; +#ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { char subuf[45]; @@ -121,6 +122,7 @@ public: DEBUG_PRINTLN("Missing MQTT connection. Not publishing data"); } } +#endif } uint16_t getLastLDRValue() diff --git a/usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h b/usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h index 71c22da16..4a42a7d5a 100644 --- a/usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h +++ b/usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h @@ -1,3 +1,7 @@ +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #pragma once // this is remixed from usermod_v2_SensorsToMqtt.h (sensors_to_mqtt usermod) diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index a666639fe..b55076c73 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -29,6 +29,7 @@ class UsermodTemperature : public Usermod { bool degC = true; // using parasite power on the sensor bool parasite = false; + int8_t parasitePin = -1; // how often do we read from sensor? unsigned long readingInterval = USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL; // set last reading as "40 sec before boot", so first reading is taken after 20 sec @@ -53,6 +54,7 @@ class UsermodTemperature : public Usermod { static const char _enabled[]; static const char _readInterval[]; static const char _parasite[]; + static const char _parasitePin[]; //Dallas sensor quick (& dirty) reading. Credit to - Author: Peter Scargill, August 17th, 2013 float readDallas() { @@ -94,12 +96,14 @@ class UsermodTemperature : public Usermod { DEBUG_PRINTLN(F("Requesting temperature.")); oneWire->reset(); oneWire->skip(); // skip ROM - oneWire->write(0x44,parasite); // request new temperature reading (TODO: parasite would need special handling) + oneWire->write(0x44,parasite); // request new temperature reading + if (parasite && parasitePin >=0 ) digitalWrite(parasitePin, HIGH); // has to happen within 10us (open MOSFET) lastTemperaturesRequest = millis(); waitingForConversion = true; } void readTemperature() { + if (parasite && parasitePin >=0 ) digitalWrite(parasitePin, LOW); // deactivate power (close MOSFET) temperature = readDallas(); lastMeasurement = millis(); waitingForConversion = false; @@ -134,6 +138,7 @@ class UsermodTemperature : public Usermod { return false; } +#ifndef WLED_DISABLE_MQTT void publishHomeAssistantAutodiscovery() { if (!WLED_MQTT_CONNECTED) return; @@ -155,6 +160,7 @@ class UsermodTemperature : public Usermod { mqtt->publish(buf, 0, true, json_str, payload_size); HApublished = true; } +#endif public: @@ -173,6 +179,12 @@ class UsermodTemperature : public Usermod { delay(25); // try to find sensor } } + if (parasite && pinManager.allocatePin(parasitePin, true, PinOwner::UM_Temperature)) { + pinMode(parasitePin, OUTPUT); + digitalWrite(parasitePin, LOW); // deactivate power (close MOSFET) + } else { + parasitePin = -1; + } } else { if (temperaturePin >= 0) { DEBUG_PRINTLN(F("Temperature pin allocation failed.")); @@ -212,6 +224,7 @@ class UsermodTemperature : public Usermod { } errorCount = 0; +#ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { char subuf[64]; strcpy(subuf, mqttDeviceTopic); @@ -227,6 +240,7 @@ class UsermodTemperature : public Usermod { // publish something else to indicate status? } } +#endif } } @@ -236,6 +250,7 @@ class UsermodTemperature : public Usermod { */ //void connected() {} +#ifndef WLED_DISABLE_MQTT /** * subscribe to MQTT topic if needed */ @@ -246,6 +261,7 @@ class UsermodTemperature : public Usermod { publishHomeAssistantAutodiscovery(); } } +#endif /* * API calls te enable data exchange between WLED modules @@ -315,6 +331,7 @@ class UsermodTemperature : public Usermod { top["degC"] = degC; // usermodparam top[FPSTR(_readInterval)] = readingInterval / 1000; top[FPSTR(_parasite)] = parasite; + top[FPSTR(_parasitePin)] = parasitePin; DEBUG_PRINTLN(F("Temperature config saved.")); } @@ -340,6 +357,7 @@ class UsermodTemperature : public Usermod { readingInterval = top[FPSTR(_readInterval)] | readingInterval/1000; readingInterval = min(120,max(10,(int)readingInterval)) * 1000; // convert to ms parasite = top[FPSTR(_parasite)] | parasite; + parasitePin = top[FPSTR(_parasitePin)] | parasitePin; if (!initDone) { // first run: reading from cfg.json @@ -354,12 +372,21 @@ class UsermodTemperature : public Usermod { delete oneWire; pinManager.deallocatePin(temperaturePin, PinOwner::UM_Temperature); temperaturePin = newTemperaturePin; + pinManager.deallocatePin(parasitePin, PinOwner::UM_Temperature); // initialise setup(); } } // use "return !top["newestParameter"].isNull();" when updating Usermod with new features - return !top[FPSTR(_parasite)].isNull(); + return !top[FPSTR(_parasitePin)].isNull(); + } + + void appendConfigData() + { + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasite)).c_str()); + oappend(SET_F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasitePin)).c_str()); + oappend(SET_F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field } uint16_t getId() @@ -373,3 +400,4 @@ const char UsermodTemperature::_name[] PROGMEM = "Temperature"; const char UsermodTemperature::_enabled[] PROGMEM = "enabled"; const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s"; const char UsermodTemperature::_parasite[] PROGMEM = "parasite-pwr"; +const char UsermodTemperature::_parasitePin[] PROGMEM = "parasite-pwr-pin"; diff --git a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp index c7eb8ee09..78cc32a81 100644 --- a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp +++ b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp @@ -101,6 +101,7 @@ void userLoop() { if (temptimer - lastMeasure > 60000) { lastMeasure = temptimer; +#ifndef WLED_DISABLE_MQTT //Check if MQTT Connected, otherwise it will crash the 8266 if (mqtt != nullptr) { @@ -116,6 +117,7 @@ void userLoop() { t += "/temperature"; mqtt->publish(t.c_str(), 0, true, String(board_temperature).c_str()); } + #endif } // Check if we time interval for redrawing passes. diff --git a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp index 05d4e77a4..c9d9a527e 100644 --- a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp +++ b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp @@ -103,6 +103,7 @@ void userLoop() { { lastMeasure = tempTimer; +#ifndef WLED_DISABLE_MQTT // Check if MQTT Connected, otherwise it will crash the 8266 if (mqtt != nullptr) { @@ -122,6 +123,7 @@ void userLoop() { h += "/humidity"; mqtt->publish(h.c_str(), 0, true, String(board_humidity).c_str()); } + #endif } // Check if we time interval for redrawing passes. diff --git a/usermods/boblight/boblight.h b/usermods/boblight/boblight.h index 263d8743e..a1e257758 100644 --- a/usermods/boblight/boblight.h +++ b/usermods/boblight/boblight.h @@ -219,6 +219,7 @@ class BobLightUsermod : public Usermod { void enable(bool en) { enabled = en; } +#ifndef WLED_DISABLE_MQTT /** * handling of MQTT message * topic only contains stripped topic (part after /wled/MAC) @@ -249,6 +250,7 @@ class BobLightUsermod : public Usermod { // mqtt->subscribe(subuf, 0); //} } +#endif void addToJsonInfo(JsonObject& root) { diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index 7381a00df..de68e11b0 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -66,12 +66,14 @@ class MultiRelay : public Usermod { static const char _HAautodiscovery[]; void publishMqtt(int relay) { +#ifndef WLED_DISABLE_MQTT //Check if MQTT Connected, otherwise it will crash the 8266 if (WLED_MQTT_CONNECTED){ char subuf[64]; sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay); mqtt->publish(subuf, 0, false, _relay[relay].state ? "on" : "off"); } +#endif } /** @@ -182,7 +184,7 @@ class MultiRelay : public Usermod { */ MultiRelay() { const int8_t defPins[] = {MULTI_RELAY_PINS}; - for (int i=0; ipublish(buf, 0, true, json_str, payload_size); } } +#endif /** * setup() is called once at boot. WiFi is not yet connected at this point. diff --git a/usermods/sensors_to_mqtt/usermod_v2_SensorsToMqtt.h b/usermods/sensors_to_mqtt/usermod_v2_SensorsToMqtt.h index dd7aedc1f..972e2c866 100644 --- a/usermods/sensors_to_mqtt/usermod_v2_SensorsToMqtt.h +++ b/usermods/sensors_to_mqtt/usermod_v2_SensorsToMqtt.h @@ -1,3 +1,7 @@ +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #pragma once #include "wled.h" diff --git a/usermods/seven_segment_display/usermod_v2_seven_segment_display.h b/usermods/seven_segment_display/usermod_v2_seven_segment_display.h index 5c0022e02..e5b726e52 100644 --- a/usermods/seven_segment_display/usermod_v2_seven_segment_display.h +++ b/usermods/seven_segment_display/usermod_v2_seven_segment_display.h @@ -1,3 +1,7 @@ +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #pragma once #include "wled.h" diff --git a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h b/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h index b1a271a65..279774057 100644 --- a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h +++ b/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h @@ -1,3 +1,7 @@ +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #pragma once #include "wled.h" diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index 721cb7f09..4637d7a36 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -1,3 +1,7 @@ +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #pragma once #include "SHT85.h" diff --git a/usermods/smartnest/usermod_smartnest.h b/usermods/smartnest/usermod_smartnest.h index 82673578a..8d2b04ff9 100644 --- a/usermods/smartnest/usermod_smartnest.h +++ b/usermods/smartnest/usermod_smartnest.h @@ -1,3 +1,7 @@ +#ifndef WLED_ENABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + #pragma once #include "wled.h" diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 08d573038..969f459ea 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -44,9 +44,9 @@ uint16_t triwave16(uint16_t in) { } /* - * Generates a tristate square wave w/ attac & decay + * Generates a tristate square wave w/ attac & decay * @param x input value 0-255 - * @param pulsewidth 0-127 + * @param pulsewidth 0-127 * @param attdec attac & decay, max. pulsewidth / 2 * @returns signed waveform value */ @@ -62,7 +62,7 @@ int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) { } else if (x < pulsewidth - attdec) { //max return a; - } + } else if (x < pulsewidth) { //dec to 0 return (int16_t) (pulsewidth - x) * a / attdec; } @@ -93,13 +93,13 @@ uint16_t blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) { cycleTime += FRAMETIME*2; uint32_t it = strip.now / cycleTime; uint32_t rem = strip.now % cycleTime; - + bool on = false; if (it != SEGENV.step //new iteration, force on state for one frame, even if set time is too brief - || rem <= onTime) { + || rem <= onTime) { on = true; } - + SEGENV.step = it; //save previous iteration uint32_t color = on ? color1 : color2; @@ -193,8 +193,8 @@ uint16_t color_wipe(bool rev, bool useRandomColors) { { uint16_t index = (rev && back)? SEGLEN -1 -i : i; uint32_t col0 = useRandomColors? SEGMENT.color_wheel(SEGENV.aux0) : SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0); - - if (i < ledIndex) + + if (i < ledIndex) { SEGMENT.setPixelColor(index, back? col1 : col0); } else @@ -202,7 +202,7 @@ uint16_t color_wipe(bool rev, bool useRandomColors) { SEGMENT.setPixelColor(index, back? col0 : col1); if (i == ledIndex) SEGMENT.setPixelColor(index, color_blend(back? col0 : col1, back? col1 : col0, rem)); } - } + } return FRAMETIME; } @@ -283,7 +283,7 @@ static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade t */ uint16_t dynamic(boolean smooth=false) { if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed - + if(SEGENV.call == 0) { for (int i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8(); } @@ -297,7 +297,7 @@ uint16_t dynamic(boolean smooth=false) { } SEGENV.step = it; } - + if (smooth) { for (int i = 0; i < SEGLEN; i++) { SEGMENT.blendPixelColor(i, SEGMENT.color_wheel(SEGENV.data[i]),16); // TODO @@ -306,7 +306,7 @@ uint16_t dynamic(boolean smooth=false) { for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_wheel(SEGENV.data[i])); } - } + } return FRAMETIME; } @@ -340,7 +340,7 @@ uint16_t mode_breath(void) { if (counter > 8192) counter = 8192 - (counter - 8192); var = sin16(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 } - + uint8_t lum = 30 + var; for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); @@ -378,7 +378,7 @@ uint16_t scan(bool dual) uint16_t size = 1 + ((SEGMENT.intensity * SEGLEN) >> 9); uint16_t ledIndex = (prog * ((SEGLEN *2) - size *2)) >> 16; - SEGMENT.fill(SEGCOLOR(1)); + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); int led_offset = ledIndex - (SEGLEN - size); led_offset = abs(led_offset); @@ -404,7 +404,7 @@ uint16_t scan(bool dual) uint16_t mode_scan(void) { return scan(false); } -static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots;!,!,!;!"; +static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots,,,,,Overlay;!,!,!;!"; /* @@ -413,7 +413,7 @@ static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots;!,!,!;!"; uint16_t mode_dual_scan(void) { return scan(true); } -static const char _data_FX_MODE_DUAL_SCAN[] PROGMEM = "Scan Dual@!,# of dots;!,!,!;!"; +static const char _data_FX_MODE_DUAL_SCAN[] PROGMEM = "Scan Dual@!,# of dots,,,,,Overlay;!,!,!;!"; /* @@ -440,7 +440,7 @@ static const char _data_FX_MODE_RAINBOW[] PROGMEM = "Colorloop@!,Saturation;;!"; uint16_t mode_rainbow_cycle(void) { uint16_t counter = (strip.now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF; counter = counter >> 8; - + for (int i = 0; i < SEGLEN; i++) { //intensity/29 = 0 (1/16) 1 (1/8) 2 (1/4) 3 (1/2) 4 (1) 5 (2) 6 (4) 7 (8) 8 (16) uint8_t index = (i * (16 << (SEGMENT.intensity /29)) / SEGLEN) + counter; @@ -460,7 +460,7 @@ uint16_t running(uint32_t color1, uint32_t color2, bool theatre = false) { uint32_t cycleTime = 50 + (255 - SEGMENT.speed); uint32_t it = strip.now / cycleTime; bool usePalette = color1 == SEGCOLOR(0); - + for (int i = 0; i < SEGLEN; i++) { uint32_t col = color2; if (usePalette) color1 = SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0); @@ -530,6 +530,7 @@ uint16_t running_base(bool saw, bool dual=false) { } SEGMENT.setPixelColor(i, ca); } + return FRAMETIME; } @@ -567,7 +568,6 @@ static const char _data_FX_MODE_SAW[] PROGMEM = "Saw@!,Width;!,!;!"; * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_twinkle(void) { - //SEGMENT.fill(SEGCOLOR(1)); SEGMENT.fade_out(224); uint32_t cycleTime = 20 + (255 - SEGMENT.speed)*5; @@ -583,7 +583,7 @@ uint16_t mode_twinkle(void) { SEGENV.aux0++; SEGENV.step = it; } - + uint16_t PRNG16 = SEGENV.aux1; for (uint16_t i = 0; i < SEGENV.aux0; i++) @@ -604,7 +604,7 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0"; */ uint16_t dissolve(uint32_t color) { bool wa = (SEGCOLOR(1) != 0 && strip.getBrightness() < 255); //workaround, can't compare getPixel to color if not full brightness - + for (int j = 0; j <= SEGLEN / 15; j++) { if (random8() <= SEGMENT.intensity) { @@ -616,7 +616,7 @@ uint16_t dissolve(uint32_t color) { if (color == SEGCOLOR(0)) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); - } else { SEGMENT.setPixelColor(i, color); } + } else { SEGMENT.setPixelColor(i, color); } break; //only spawn 1 new pixel per frame per 50 LEDs } } else { //dissolve to secondary @@ -626,12 +626,12 @@ uint16_t dissolve(uint32_t color) { } } - if (SEGENV.call > (255 - SEGMENT.speed) + 15U) + if (SEGENV.call > (255 - SEGMENT.speed) + 15U) { SEGENV.aux0 = !SEGENV.aux0; SEGENV.call = 0; } - + return FRAMETIME; } @@ -659,7 +659,7 @@ static const char _data_FX_MODE_DISSOLVE_RANDOM[] PROGMEM = "Dissolve Rnd@Repeat * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_sparkle(void) { - for(int i = 0; i < SEGLEN; i++) { + if (!SEGMENT.check2) for(int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } uint32_t cycleTime = 10 + (255 - SEGMENT.speed)*2; @@ -669,11 +669,11 @@ uint16_t mode_sparkle(void) { SEGENV.aux0 = random16(SEGLEN); // aux0 stores the random led index SEGENV.step = it; } - + SEGMENT.setPixelColor(SEGENV.aux0, SEGCOLOR(0)); return FRAMETIME; } -static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!;!,!;!;;m12=0"; +static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!,,,,,,Overlay;!,!;!;;m12=0"; /* @@ -681,7 +681,7 @@ static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!;!,!;!;;m12=0"; * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_flash_sparkle(void) { - for(uint16_t i = 0; i < SEGLEN; i++) { + if (!SEGMENT.check2) for(uint16_t i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } @@ -694,7 +694,7 @@ uint16_t mode_flash_sparkle(void) { } return FRAMETIME; } -static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!;Bg,Fx;!;;m12=0"; +static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!,,,,,Overlay;Bg,Fx;!;;m12=0"; /* @@ -702,7 +702,7 @@ static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!;Bg,F * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_hyper_sparkle(void) { - for (int i = 0; i < SEGLEN; i++) { + if (!SEGMENT.check2) for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } @@ -717,7 +717,7 @@ uint16_t mode_hyper_sparkle(void) { } return FRAMETIME; } -static const char _data_FX_MODE_HYPER_SPARKLE[] PROGMEM = "Sparkle+@!,!;Bg,Fx;!;;m12=0"; +static const char _data_FX_MODE_HYPER_SPARKLE[] PROGMEM = "Sparkle+@!,!,,,,,Overlay;Bg,Fx;!;;m12=0"; /* @@ -754,7 +754,7 @@ static const char _data_FX_MODE_MULTI_STROBE[] PROGMEM = "Strobe Mega@!,!;!,!;!" * Android loading circle */ uint16_t mode_android(void) { - + for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } @@ -768,7 +768,7 @@ uint16_t mode_android(void) { } uint16_t a = SEGENV.step; - + if (SEGENV.aux0 == 0) { if (SEGENV.call %3 == 1) {a++;} @@ -778,7 +778,7 @@ uint16_t mode_android(void) { a++; if (SEGENV.call %3 != 1) SEGENV.aux1--; } - + if (a >= SEGLEN) a = 0; if (a + SEGENV.aux1 < SEGLEN) @@ -825,7 +825,7 @@ uint16_t chase(uint32_t color1, uint32_t color2, uint32_t color3, bool do_palett // Use intensity setting to vary chase up to 1/2 string length uint8_t size = 1 + (SEGMENT.intensity * SEGLEN >> 10); - uint16_t b = a + size; //"trail" of chase, filled with color1 + uint16_t b = a + size; //"trail" of chase, filled with color1 if (b > SEGLEN) b -= SEGLEN; uint16_t c = b + size; if (c > SEGLEN) c -= SEGLEN; @@ -945,7 +945,7 @@ uint16_t mode_colorful(void) { cols[3] = 0x0077F0F0; } for (size_t i = numColors; i < numColors*2 -1U; i++) cols[i] = cols[i-numColors]; - + uint32_t cycleTime = 50 + (8 * (uint32_t)(255 - SEGMENT.speed)); uint32_t it = strip.now / cycleTime; if (it != SEGENV.step) @@ -954,12 +954,12 @@ uint16_t mode_colorful(void) { if (SEGENV.aux0 >= numColors) SEGENV.aux0 = 0; SEGENV.step = it; } - + for (int i = 0; i < SEGLEN; i+= numColors) { for (int j = 0; j < numColors; j++) SEGMENT.setPixelColor(i + j, cols[SEGENV.aux0 + j]); } - + return FRAMETIME; } static const char _data_FX_MODE_COLORFUL[] PROGMEM = "Colorful@!,Saturation;1,2,3;!"; @@ -990,7 +990,7 @@ uint16_t mode_traffic_light(void) { if (SEGENV.aux0 > 3) SEGENV.aux0 = 0; SEGENV.step = strip.now; } - + return FRAMETIME; } static const char _data_FX_MODE_TRAFFIC_LIGHT[] PROGMEM = "Traffic Light@!,US style;,!;!"; @@ -1116,7 +1116,7 @@ uint16_t larson_scanner(bool dual) { if (SEGENV.step > index && SEGENV.step - index > SEGLEN/2) { SEGENV.aux0 = !SEGENV.aux0; } - + for (int i = SEGENV.step; i < index; i++) { uint16_t j = (SEGENV.aux0)?i:SEGLEN-1-i; SEGMENT.setPixelColor( j, SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0)); @@ -1177,7 +1177,7 @@ uint16_t mode_comet(void) { } else if (index < SEGENV.aux0 && index < 10) { for (int i = 0; i < index ; i++) { SEGMENT.setPixelColor( i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); - } + } } SEGENV.aux0 = index++; @@ -1335,13 +1335,13 @@ uint16_t mode_loading(void) { static const char _data_FX_MODE_LOADING[] PROGMEM = "Loading@!,Fade;!,!;!;;ix=16"; -//American Police Light with all LEDs Red and Blue +//American Police Light with all LEDs Red and Blue uint16_t police_base(uint32_t color1, uint32_t color2) { uint16_t delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster uint32_t it = strip.now / map(SEGMENT.speed, 0, 255, delay<<4, delay); uint16_t offset = it % SEGLEN; - + uint16_t width = ((SEGLEN*(SEGMENT.intensity+1))>>9); //max width is half the strip if (!width) width = 1; for (int i = 0; i < width; i++) { @@ -1354,7 +1354,7 @@ uint16_t police_base(uint32_t color1, uint32_t color2) } -//Police Lights Red and Blue +//Police Lights Red and Blue //uint16_t mode_police() //{ // SEGMENT.fill(SEGCOLOR(1)); @@ -1363,15 +1363,14 @@ uint16_t police_base(uint32_t color1, uint32_t color2) //static const char _data_FX_MODE_POLICE[] PROGMEM = "Police@!,Width;,Bg;0"; -//Police Lights with custom colors +//Police Lights with custom colors uint16_t mode_two_dots() { - SEGMENT.fill(SEGCOLOR(2)); + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2)); uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1); - return police_base(SEGCOLOR(0), color2); } -static const char _data_FX_MODE_TWO_DOTS[] PROGMEM = "Two Dots@!,Dot size;1,2,Bg;!"; +static const char _data_FX_MODE_TWO_DOTS[] PROGMEM = "Two Dots@!,Dot size,,,,,Overlay;1,2,Bg;!"; /* @@ -1519,7 +1518,7 @@ uint16_t tricolor_chase(uint32_t color1, uint32_t color2) { uint32_t it = strip.now / cycleTime; // iterator uint8_t width = (1 + (SEGMENT.intensity>>4)); // value of 1-16 for each colour uint8_t index = it % (width*3); - + for (int i = 0; i < SEGLEN; i++, index++) { if (index > (width*3)-1) index = 0; @@ -1549,7 +1548,7 @@ uint16_t mode_icu(void) { uint16_t dest = SEGENV.step & 0xFFFF; uint8_t space = (SEGMENT.intensity >> 3) +2; - SEGMENT.fill(SEGCOLOR(1)); + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); byte pindex = map(dest, 0, SEGLEN-SEGLEN/space, 0, 255); uint32_t col = SEGMENT.color_from_palette(pindex, false, false, 0); @@ -1580,7 +1579,7 @@ uint16_t mode_icu(void) { return SPEED_FORMULA_L; } -static const char _data_FX_MODE_ICU[] PROGMEM = "ICU@!,!;!,!;!"; +static const char _data_FX_MODE_ICU[] PROGMEM = "ICU@!,!,,,,,Overlay;!,!;!"; /* @@ -1598,7 +1597,7 @@ uint16_t mode_tricolor_wipe(void) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2)); } - + if(ledIndex < SEGLEN) { //wipe from 0 to 1 for (int i = 0; i < SEGLEN; i++) { @@ -1679,9 +1678,9 @@ uint16_t mode_multi_comet(void) uint32_t it = strip.now / cycleTime; if (SEGENV.step == it) return FRAMETIME; if (!SEGENV.allocateData(sizeof(uint16_t) * 8)) return mode_static(); //allocation failed - + SEGMENT.fade_out(SEGMENT.intensity); - + uint16_t* comets = reinterpret_cast(SEGENV.data); for (int i=0; i < 8; i++) { @@ -1761,7 +1760,7 @@ uint16_t mode_oscillate(void) uint16_t dataSize = sizeof(oscillator) * numOscillators; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - + Oscillator* oscillators = reinterpret_cast(SEGENV.data); if (SEGENV.call == 0) @@ -1800,7 +1799,7 @@ uint16_t mode_oscillate(void) } SEGMENT.setPixelColor(i, color); } - + SEGENV.step = it; return FRAMETIME; } @@ -1823,7 +1822,7 @@ uint16_t mode_lightning(void) SEGENV.aux0 = 200; //200ms delay after leader } - SEGMENT.fill(SEGCOLOR(1)); + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2 for (int i = ledstart; i < ledstart + ledlen; i++) @@ -1848,7 +1847,7 @@ uint16_t mode_lightning(void) } return FRAMETIME; } -static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!;!,!;!"; +static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!,,,,,Overlay;!,!;!"; // Pride2015 @@ -1892,6 +1891,7 @@ uint16_t mode_pride_2015(void) } SEGENV.step = sPseudotime; SEGENV.aux0 = sHue16; + return FRAMETIME; } static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;"; @@ -1917,30 +1917,31 @@ static const char _data_FX_MODE_JUGGLE[] PROGMEM = "Juggle@!,Trail;;!;;sx=16,ix= uint16_t mode_palette() { uint16_t counter = 0; - if (SEGMENT.speed != 0) + if (SEGMENT.speed != 0) { counter = (strip.now * ((SEGMENT.speed >> 3) +1)) & 0xFFFF; counter = counter >> 8; } - + bool noWrap = (strip.paletteBlend == 2 || (strip.paletteBlend == 0 && SEGMENT.speed == 0)); for (int i = 0; i < SEGLEN; i++) { uint8_t colorIndex = (i * 255 / SEGLEN) - counter; SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, noWrap, 255)); } + return FRAMETIME; } -static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!"; +static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!;;c3=0,o2=0"; // WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active // Fire2012 by Mark Kriegsman, July 2012 // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY -//// +//// // This basic one-dimensional 'fire' simulation works roughly as follows: // There's a underlying array of 'heat' cells, that model the temperature -// at each point along the line. Every cycle through the simulation, +// at each point along the line. Every cycle through the simulation, // four steps are performed: // 1) All cells cool down a little bit, losing heat to the air // 2) The heat from each cell drifts 'up' and diffuses a little @@ -1951,7 +1952,7 @@ static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!"; // Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). // // This simulation scales it self a bit depending on SEGLEN; it should look -// "OK" on anywhere from 20 to 100 LEDs without too much tweaking. +// "OK" on anywhere from 20 to 100 LEDs without too much tweaking. // // I recommend running this simulation at anywhere from 30-100 frames per second, // meaning an interframe delay of about 10-35 milliseconds. @@ -2069,6 +2070,7 @@ uint16_t mode_colorwaves() } SEGENV.step = sPseudotime; SEGENV.aux0 = sHue16; + return FRAMETIME; } static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!"; @@ -2085,6 +2087,7 @@ uint16_t mode_bpm() //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10))); } + return FRAMETIME; } static const char _data_FX_MODE_BPM[] PROGMEM = "Bpm@!;!;!;;sx=64"; @@ -2165,7 +2168,7 @@ uint16_t mode_noise16_3() uint16_t shift_y = 1234; uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions - uint32_t real_z = SEGENV.step*8; + uint32_t real_z = SEGENV.step*8; uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down uint8_t index = sin8(noise * 3); // map led color based on noise data @@ -2200,7 +2203,7 @@ uint16_t mode_colortwinkle() { uint16_t dataSize = (SEGLEN+7) >> 3; //1 bit per LED if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - + CRGB fastled_col, prev; fract8 fadeUpAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>2) : 68-strip.getBrightness(); fract8 fadeDownAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>3) : 68-strip.getBrightness(); @@ -2210,7 +2213,7 @@ uint16_t mode_colortwinkle() uint16_t index = i >> 3; uint8_t bitNum = i & 0x07; bool fadeUp = bitRead(SEGENV.data[index], bitNum); - + if (fadeUp) { CRGB incrementalColor = fastled_col; incrementalColor.nscale8_video(fadeUpAmount); @@ -2261,12 +2264,13 @@ uint16_t mode_lake() { for (int i = 0; i < SEGLEN; i++) { - int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; + int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; uint8_t lum = (index > wave3) ? index - wave3 : 0; //fastled_col = ColorFromPalette(SEGPALETTE, map(index,0,255,0,240), lum, LINEARBLEND); //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, 0, lum)); } + return FRAMETIME; } static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!"; @@ -2279,7 +2283,7 @@ uint16_t mode_meteor() { if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed byte* trail = SEGENV.data; - + byte meteorSize= 1+ SEGLEN / 10; uint16_t counter = strip.now * ((SEGMENT.speed >> 2) +8); uint16_t in = counter * SEGLEN >> 16; @@ -2316,7 +2320,7 @@ uint16_t mode_meteor_smooth() { if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed byte* trail = SEGENV.data; - + byte meteorSize= 1+ SEGLEN / 10; uint16_t in = map((SEGENV.step >> 6 & 0xFF), 0, 255, 0, SEGLEN -1); @@ -2331,7 +2335,7 @@ uint16_t mode_meteor_smooth() { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, false, 0, trail[i])); } } - + // draw meteor for (int j = 0; j < meteorSize; j++) { uint16_t index = in + j; @@ -2396,89 +2400,83 @@ typedef struct Ripple { #else #define MAX_RIPPLES 100 #endif -uint16_t ripple_base(bool rainbow) +uint16_t ripple_base() { uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266 uint16_t dataSize = sizeof(ripple) * maxRipples; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - + Ripple* ripples = reinterpret_cast(SEGENV.data); - // ranbow background or chosen background, all very dim. - if (rainbow) { - if (SEGENV.call ==0) { - SEGENV.aux0 = random8(); - SEGENV.aux1 = random8(); - } - if (SEGENV.aux0 == SEGENV.aux1) { - SEGENV.aux1 = random8(); - } - else if (SEGENV.aux1 > SEGENV.aux0) { - SEGENV.aux0++; - } else { - SEGENV.aux0--; - } - SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,235)); - } else { - SEGMENT.fill(SEGCOLOR(1)); - } - //draw wave - for (int i = 0; i < maxRipples; i++) - { + for (int i = 0; i < maxRipples; i++) { uint16_t ripplestate = ripples[i].state; - if (ripplestate) - { + if (ripplestate) { uint8_t rippledecay = (SEGMENT.speed >> 4) +1; //faster decay if faster propagation uint16_t rippleorigin = ripples[i].pos; uint32_t col = SEGMENT.color_from_palette(ripples[i].color, false, false, 255); - uint16_t propagation = ((ripplestate/rippledecay -1) * SEGMENT.speed); + uint16_t propagation = ((ripplestate/rippledecay - 1) * (SEGMENT.speed + 1)); int16_t propI = propagation >> 8; uint8_t propF = propagation & 0xFF; - int16_t left = rippleorigin - propI -1; uint8_t amp = (ripplestate < 17) ? triwave8((ripplestate-1)*8) : map(ripplestate,17,255,255,2); - for (int16_t v = left; v < left +4; v++) + #ifndef WLED_DISABLE_2D + if (SEGMENT.is2D()) { + uint16_t cx = rippleorigin >> 8; + uint16_t cy = rippleorigin & 0xFF; + uint8_t mag = scale8(cubicwave8((propF>>2)), amp); + if (propI > 0) SEGMENT.draw_circle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag)); + } else + #endif { - uint8_t mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp); - if (v < SEGLEN && v >= 0) - { + int16_t left = rippleorigin - propI -1; + for (int16_t v = left; v < left +4; v++) { + uint8_t mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp); SEGMENT.setPixelColor(v, color_blend(SEGMENT.getPixelColor(v), col, mag)); // TODO - } - int16_t w = left + propI*2 + 3 -(v-left); - if (w < SEGLEN && w >= 0) - { + int16_t w = left + propI*2 + 3 -(v-left); SEGMENT.setPixelColor(w, color_blend(SEGMENT.getPixelColor(w), col, mag)); // TODO } - } + } ripplestate += rippledecay; ripples[i].state = (ripplestate > 254) ? 0 : ripplestate; - } else //randomly create new wave - { - if (random16(IBN + 10000) <= SEGMENT.intensity) - { + } else {//randomly create new wave + if (random16(IBN + 10000) <= SEGMENT.intensity) { ripples[i].state = 1; - ripples[i].pos = random16(SEGLEN); + ripples[i].pos = SEGMENT.is2D() ? ((random8(SEGENV.virtualWidth())<<8) | (random8(SEGENV.virtualHeight()))) : random16(SEGLEN); ripples[i].color = random8(); //color } } } + return FRAMETIME; } #undef MAX_RIPPLES uint16_t mode_ripple(void) { - return ripple_base(false); + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); + return ripple_base(); } -static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #;,!;!"; +static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,,,,,Overlay;,!;!;12"; uint16_t mode_ripple_rainbow(void) { - return ripple_base(true); + if (SEGENV.call ==0) { + SEGENV.aux0 = random8(); + SEGENV.aux1 = random8(); + } + if (SEGENV.aux0 == SEGENV.aux1) { + SEGENV.aux1 = random8(); + } else if (SEGENV.aux1 > SEGENV.aux0) { + SEGENV.aux0++; + } else { + SEGENV.aux0--; + } + SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,235)); + return ripple_base(); } -static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!"; +static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!;12"; // TwinkleFOX by Mark Kriegsman: https://gist.github.com/kriegsman/756ea6dcae8e30845b5a @@ -2500,7 +2498,7 @@ CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) slowcycle16 += sin8(slowcycle16); slowcycle16 = (slowcycle16 * 2053) + 1384; uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); - + // Overall twinkle density. // 0 (NONE lit) to 8 (ALL lit at once). // Default is 5. @@ -2533,7 +2531,7 @@ CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) // This code takes a pixel, and if its in the 'fading down' // part of the cycle, it adjusts the color a little bit like the // way that incandescent bulbs fade toward 'red' as they dim. - if (fastcycle8 >= 128) + if (fastcycle8 >= 128) { uint8_t cooling = (fastcycle8 - 128) >> 4; c.g = qsub8(c.g, cooling); @@ -2577,7 +2575,7 @@ uint16_t twinklefox_base(bool cat) uint8_t backgroundBrightness = bg.getAverageLight(); for (int i = 0; i < SEGLEN; i++) { - + PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number uint16_t myclockoffset16= PRNG16; // use that number as clock offset PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number @@ -2634,7 +2632,7 @@ uint16_t mode_halloween_eyes() uint16_t eyeLength = (2*HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE; if (eyeLength >= maxWidth) return mode_static(); //bail if segment too short - SEGMENT.fill(SEGCOLOR(1)); //fill background + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); //fill background uint8_t state = SEGENV.aux1 >> 8; uint16_t stateTime = SEGENV.call; @@ -2646,15 +2644,15 @@ uint16_t mode_halloween_eyes() if (strip.isMatrix) SEGMENT.offset = random16(SEGMENT.virtualHeight()-1); // a hack: reuse offset since it is not used in matrices state = 1; } - + if (state < 2) { //fade eyes uint16_t startPos = SEGENV.aux0; uint16_t start2ndEye = startPos + HALLOWEEN_EYE_WIDTH + HALLOWEEN_EYE_SPACE; - + uint32_t fadestage = (strip.now - SEGENV.step)*255 / stateTime; if (fadestage > 255) fadestage = 255; uint32_t c = color_blend(SEGMENT.color_from_palette(SEGENV.aux1 & 0xFF, false, false, 0), SEGCOLOR(1), fadestage); - + for (int i = 0; i < HALLOWEEN_EYE_WIDTH; i++) { if (strip.isMatrix) { SEGMENT.setPixelColorXY(startPos + i, SEGMENT.offset, c); @@ -2669,7 +2667,7 @@ uint16_t mode_halloween_eyes() if (strip.now - SEGENV.step > stateTime) { state++; if (state > 2) state = 0; - + if (state < 2) { stateTime = 100 + SEGMENT.intensity*10; //eye fade time } else { @@ -2681,10 +2679,10 @@ uint16_t mode_halloween_eyes() } SEGENV.aux1 = (SEGENV.aux1 & 0xFF) + (state << 8); //save state - + return FRAMETIME; } -static const char _data_FX_MODE_HALLOWEEN_EYES[] PROGMEM = "Halloween Eyes@Duration,Eye fade time;!,!;!;12"; +static const char _data_FX_MODE_HALLOWEEN_EYES[] PROGMEM = "Halloween Eyes@Duration,Eye fade time,,,,,Overlay;!,!;!;12"; //Speed slider sets amount of LEDs lit, intensity sets unlit @@ -2703,7 +2701,7 @@ uint16_t mode_static_pattern() drawingLit = !drawingLit; } } - + return FRAMETIME; } static const char _data_FX_MODE_STATIC_PATTERN[] PROGMEM = "Solid Pattern@Fg size,Bg size;Fg,!;!;;pal=0"; @@ -2737,8 +2735,8 @@ static const char _data_FX_MODE_TRI_STATIC_PATTERN[] PROGMEM = "Solid Pattern Tr uint16_t spots_base(uint16_t threshold) { - SEGMENT.fill(SEGCOLOR(1)); - + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); + uint16_t maxZones = SEGLEN >> 2; uint16_t zones = 1 + ((SEGMENT.intensity * maxZones) >> 8); uint16_t zoneLen = SEGLEN / zones; @@ -2757,7 +2755,7 @@ uint16_t spots_base(uint16_t threshold) } } } - + return FRAMETIME; } @@ -2767,7 +2765,7 @@ uint16_t mode_spots() { return spots_base((255 - SEGMENT.speed) << 8); } -static const char _data_FX_MODE_SPOTS[] PROGMEM = "Spots@,Width;!,!;!"; +static const char _data_FX_MODE_SPOTS[] PROGMEM = "Spots@,Width,,,,,Overlay;!,!;!"; //Intensity slider sets number of "lights", LEDs per light fade in and out @@ -2778,7 +2776,7 @@ uint16_t mode_spots_fade() uint16_t tr = (t >> 1) + (t >> 2); return spots_base(tr); } -static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width;!,!;!"; +static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width,,,,,Overlay;!,!;!"; //each needs 12 bytes @@ -2794,13 +2792,13 @@ typedef struct Ball { uint16_t mode_bouncing_balls(void) { //allocate segment data const uint16_t strips = SEGMENT.nrOfVStrips(); // adapt for 2D - const size_t maxNumBalls = 16; + const size_t maxNumBalls = 16; uint16_t dataSize = sizeof(ball) * maxNumBalls; if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed - + Ball* balls = reinterpret_cast(SEGENV.data); - SEGMENT.fill(SEGCOLOR(2) ? BLACK : SEGCOLOR(1)); + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2) ? BLACK : SEGCOLOR(1)); // virtualStrip idea by @ewowi (Ewoud Wijma) // requires virtual strip # to be embedded into upper 16 bits of index in setPixelColor() @@ -2817,7 +2815,7 @@ uint16_t mode_bouncing_balls(void) { if (SEGENV.call == 0) { for (size_t i = 0; i < maxNumBalls; i++) balls[i].lastBounceTime = time; } - + for (size_t i = 0; i < numBalls; i++) { float timeSinceLastBounce = (time - balls[i].lastBounceTime)/((255-SEGMENT.speed)/64 +1); float timeSec = timeSinceLastBounce/1000.0f; @@ -2837,7 +2835,7 @@ uint16_t mode_bouncing_balls(void) { } else if (balls[i].height > 1.0f) { continue; // do not draw OOB ball } - + uint32_t color = SEGCOLOR(0); if (SEGMENT.palette) { color = SEGMENT.color_wheel(i*(256/MAX(numBalls, 8))); @@ -2857,7 +2855,7 @@ uint16_t mode_bouncing_balls(void) { return FRAMETIME; } -static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravity,# of balls;!,!,!;!;1;m12=1"; //bar +static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravity,# of balls,,,,,Overlay;!,!,!;!;1;m12=1"; //bar /* @@ -2878,7 +2876,7 @@ uint16_t sinelon_base(bool dual, bool rainbow=false) { if (rainbow) color2 = color1; //rainbow SEGMENT.setPixelColor(SEGLEN-1-pos, color2); } - if (SEGENV.aux0 != pos) { + if (SEGENV.aux0 != pos) { if (SEGENV.aux0 < pos) { for (int i = SEGENV.aux0; i < pos ; i++) { SEGMENT.setPixelColor(i, color1); @@ -2915,19 +2913,35 @@ uint16_t mode_sinelon_rainbow(void) { static const char _data_FX_MODE_SINELON_RAINBOW[] PROGMEM = "Sinelon Rainbow@!,Trail;,,!;!"; -//Rainbow with glitter, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6 +// utility function that will add random glitter to SEGMENT +void glitter_base(uint8_t intensity, uint32_t col = ULTRAWHITE) { + if (intensity > random8()) { + if (SEGMENT.is2D()) { + SEGMENT.setPixelColorXY(random16(SEGMENT.virtualWidth()),random16(SEGMENT.virtualHeight()), col); + } else { + SEGMENT.setPixelColor(random16(SEGLEN), col); + } + } +} + +//Glitter with palette background, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6 uint16_t mode_glitter() { - mode_palette(); - - if (SEGMENT.intensity > random8()) - { - SEGMENT.setPixelColor(random16(SEGLEN), ULTRAWHITE); - } - + if (!SEGMENT.check2) mode_palette(); // use "* Color 1" palette for solid background (replacing "Solid glitter") + glitter_base(SEGMENT.intensity, SEGCOLOR(2) ? SEGCOLOR(2) : ULTRAWHITE); return FRAMETIME; } -static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!;;!;;m12=0"; //pixels +static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!,,,,,Overlay;1,2,Glitter color;!;;pal=0,m12=0"; //pixels + + +//Solid colour background with glitter +uint16_t mode_solid_glitter() +{ + SEGMENT.fill(SEGCOLOR(0)); + glitter_base(SEGMENT.intensity, SEGCOLOR(2) ? SEGCOLOR(2) : ULTRAWHITE); + return FRAMETIME; +} +static const char _data_FX_MODE_SOLID_GLITTER[] PROGMEM = "Solid Glitter@,!;Bg,,Glitter color;;;m12=0"; //each needs 19 bytes @@ -2953,7 +2967,7 @@ uint16_t mode_popcorn(void) { Spark* popcorn = reinterpret_cast(SEGENV.data); bool hasCol2 = SEGCOLOR(2); - SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); + if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); struct virtualStrip { static void runStrip(uint16_t stripNr, Spark* popcorn) { @@ -3000,7 +3014,7 @@ uint16_t mode_popcorn(void) { return FRAMETIME; } -static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!;!,!,!;!;;m12=1"; //bar +static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!,,,,,Overlay;!,!,!;!;;m12=1"; //bar //values close to 100 produce 5Hz flicker, which looks very candle-y @@ -3061,7 +3075,7 @@ uint16_t candle(bool multi) s_target += offset; uint8_t dif = (s_target > s) ? s_target - s : s - s_target; - + fadeStep = dif >> speedFactor; if (fadeStep == 0) fadeStep = 1; } @@ -3129,26 +3143,26 @@ uint16_t mode_starburst(void) { uint16_t dataSize = sizeof(star) * numStars; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - + uint32_t it = millis(); - + star* stars = reinterpret_cast(SEGENV.data); - + float maxSpeed = 375.0f; // Max velocity float particleIgnition = 250.0f; // How long to "flash" float particleFadeTime = 1500.0f; // Fade out time - + for (int j = 0; j < numStars; j++) { // speed to adjust chance of a burst, max is nearly always. if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0) { - // Pick a random color and location. + // Pick a random color and location. uint16_t startPos = random16(SEGLEN-1); float multiplier = (float)(random8())/255.0 * 1.0; stars[j].color = CRGB(SEGMENT.color_wheel(random8())); - stars[j].pos = startPos; + stars[j].pos = startPos; stars[j].vel = maxSpeed * (float)(random8())/255.0 * multiplier; stars[j].birth = it; stars[j].last = it; @@ -3161,9 +3175,9 @@ uint16_t mode_starburst(void) { } } } - - SEGMENT.fill(SEGCOLOR(1)); - + + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); + for (int j=0; j> 1; - + if (stars[j].fragment[i] > 0) { //all fragments travel right, will be mirrored on other side stars[j].fragment[i] += stars[j].vel * dt * (float)var/3.0; @@ -3180,10 +3194,10 @@ uint16_t mode_starburst(void) { stars[j].last = it; stars[j].vel -= 3*stars[j].vel*dt; } - + CRGB c = stars[j].color; - // If the star is brand new, it flashes white briefly. + // If the star is brand new, it flashes white briefly. // Otherwise it just fades over time. float fade = 0.0f; float age = it-stars[j].birth; @@ -3191,7 +3205,7 @@ uint16_t mode_starburst(void) { if (age < particleIgnition) { c = CRGB(color_blend(WHITE, RGBW32(c.r,c.g,c.b,0), 254.5f*((age / particleIgnition)))); } else { - // Figure out how much to fade and shrink the star based on + // Figure out how much to fade and shrink the star based on // its age relative to its lifetime if (age > particleIgnition + particleFadeTime) { fade = 1.0f; // Black hole, all faded out @@ -3204,7 +3218,7 @@ uint16_t mode_starburst(void) { c = CRGB(color_blend(RGBW32(c.r,c.g,c.b,0), SEGCOLOR(1), f)); } } - + float particleSize = (1.0f - fade) * 2.0f; for (size_t index=0; index < STARBURST_MAX_FRAG*2; index++) { @@ -3217,7 +3231,7 @@ uint16_t mode_starburst(void) { int end = loc + particleSize; if (start < 0) start = 0; if (start == end) end++; - if (end > SEGLEN) end = SEGLEN; + if (end > SEGLEN) end = SEGLEN; for (int p = start; p < end; p++) { SEGMENT.setPixelColor(p, c.r, c.g, c.b); } @@ -3227,7 +3241,7 @@ uint16_t mode_starburst(void) { return FRAMETIME; } #undef STARBURST_MAX_FRAG -static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chance,Fragments;,!;!;;pal=11,m12=0"; +static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chance,Fragments,,,,,Overlay;,!;!;;pal=11,m12=0"; /* @@ -3258,15 +3272,14 @@ uint16_t mode_exploding_fireworks(void) SEGENV.aux1 = dataSize; } - //SEGMENT.fill(BLACK); SEGMENT.fade_out(252); - + Spark* sparks = reinterpret_cast(SEGENV.data); Spark* flare = sparks; //first spark is flare data float gravity = -0.0004f - (SEGMENT.speed/800000.0f); // m/s/s gravity *= rows; - + if (SEGENV.aux0 < 2) { //FLARE if (SEGENV.aux0 == 0) { //init flare flare->pos = 0; @@ -3276,10 +3289,10 @@ uint16_t mode_exploding_fireworks(void) flare->vel = sqrt(-2.0f * gravity * peakHeight); flare->velX = strip.isMatrix ? (random8(8)-4)/32.f : 0; // no X velocity on 1D flare->col = 255; //brightness - SEGENV.aux0 = 1; + SEGENV.aux0 = 1; } - - // launch + + // launch if (flare->vel > 12 * gravity) { // flare if (strip.isMatrix) SEGMENT.setPixelColorXY(int(flare->posX), rows - uint16_t(flare->pos) - 1, flare->col, flare->col, flare->col); @@ -3296,40 +3309,40 @@ uint16_t mode_exploding_fireworks(void) } else if (SEGENV.aux0 < 4) { /* * Explode! - * + * * Explosion happens where the flare ended. * Size is proportional to the height. */ int nSparks = flare->pos + random8(4); nSparks = constrain(nSparks, 1, numSparks); - + // initialize sparks if (SEGENV.aux0 == 2) { - for (int i = 1; i < nSparks; i++) { + for (int i = 1; i < nSparks; i++) { sparks[i].pos = flare->pos; sparks[i].posX = flare->posX; sparks[i].vel = (float(random16(0, 20000)) / 10000.0f) - 0.9f; // from -0.9 to 1.1 sparks[i].vel *= rows<32 ? 0.5f : 1; // reduce velocity for smaller strips sparks[i].velX = strip.isMatrix ? (float(random16(0, 4000)) / 10000.0f) - 0.2f : 0; // from -0.2 to 0.2 - sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright - //sparks[i].col = constrain(sparks[i].col, 0, 345); + sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright + //sparks[i].col = constrain(sparks[i].col, 0, 345); sparks[i].colIndex = random8(); - sparks[i].vel *= flare->pos/rows; // proportional to height + sparks[i].vel *= flare->pos/rows; // proportional to height sparks[i].velX *= strip.isMatrix ? flare->posX/cols : 0; // proportional to width sparks[i].vel *= -gravity *50; - } - //sparks[1].col = 345; // this will be our known spark - *dying_gravity = gravity/2; + } + //sparks[1].col = 345; // this will be our known spark + *dying_gravity = gravity/2; SEGENV.aux0 = 3; } - + if (sparks[1].col > 4) {//&& sparks[1].pos > 0) { // as long as our known spark is lit, work with all the sparks for (int i = 1; i < nSparks; i++) { sparks[i].pos += sparks[i].vel; sparks[i].posX += sparks[i].velX; sparks[i].vel += *dying_gravity; sparks[i].velX += strip.isMatrix ? *dying_gravity : 0; - if (sparks[i].col > 3) sparks[i].col -= 4; + if (sparks[i].col > 3) sparks[i].col -= 4; if (sparks[i].pos > 0 && sparks[i].pos < rows) { if (strip.isMatrix && !(sparks[i].posX >= 0 && sparks[i].posX < cols)) continue; @@ -3360,7 +3373,7 @@ uint16_t mode_exploding_fireworks(void) } } - return FRAMETIME; + return FRAMETIME; } #undef MAX_SPARKS static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gravity,Firing side;!,!;!;12;pal=11,ix=128"; @@ -3374,13 +3387,13 @@ uint16_t mode_drip(void) { //allocate segment data uint16_t strips = SEGMENT.nrOfVStrips(); - const int maxNumDrops = 4; + const int maxNumDrops = 4; uint16_t dataSize = sizeof(spark) * maxNumDrops; if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed Spark* drops = reinterpret_cast(SEGENV.data); - SEGMENT.fill(SEGCOLOR(1)); - + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); + struct virtualStrip { static void runStrip(uint16_t stripNr, Spark* drops) { @@ -3449,7 +3462,7 @@ uint16_t mode_drip(void) return FRAMETIME; } -static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips;!,!;!;;m12=1"; //bar +static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips,,,,,Overlay;!,!;!;;m12=1"; //bar /* @@ -3472,7 +3485,7 @@ uint16_t mode_tetrix(void) { if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed Tetris* drops = reinterpret_cast(SEGENV.data); - if (SEGENV.call == 0) SEGMENT.fill(SEGCOLOR(1)); // will fill entire segment (1D or 2D) + //if (SEGENV.call == 0) SEGMENT.fill(SEGCOLOR(1)); // will fill entire segment (1D or 2D), then use drop->step = 0 below // virtualStrip idea by @ewowi (Ewoud Wijma) // requires virtual strip # to be embedded into upper 16 bits of index in setPixelcolor() @@ -3482,11 +3495,10 @@ uint16_t mode_tetrix(void) { // initialize dropping on first call or segment full if (SEGENV.call == 0) { drop->stack = 0; // reset brick stack size - drop->step = 0; + drop->step = millis() + 2000; // start by fading out strip if (SEGMENT.check1) drop->col = 0;// use only one color from palette - //for (int i=0; istep == 0) { // init brick // speed calcualtion: a single brick should reach bottom of strip in X seconds // if the speed is set to 1 this should take 5s and at 255 it should take 0.25s @@ -3499,7 +3511,7 @@ uint16_t mode_tetrix(void) { drop->step = 1; // drop state (0 init, 1 forming, 2 falling) drop->brick = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick } - + if (drop->step == 1) { // forming if (random8()>>6) { // random drop drop->step = 2; // fall @@ -3538,7 +3550,7 @@ uint16_t mode_tetrix(void) { for (int stripNr=0; stripNr> 11)); if (SEGMENT.speed == 255) size = 255; - + if (percent <= 100) { for (int i = 0; i < SEGLEN; i++) { if (i < SEGENV.aux1) { @@ -3661,16 +3673,16 @@ static const char _data_FX_MODE_HEARTBEAT[] PROGMEM = "Heartbeat@!,!;!,!;!;;m12= // For Dan. // // -// In this animation, there are four "layers" of waves of light. +// In this animation, there are four "layers" of waves of light. // // Each layer moves independently, and each is scaled separately. // -// All four wave layers are added together on top of each other, and then -// another filter is applied that adds "whitecaps" of brightness where the +// All four wave layers are added together on top of each other, and then +// another filter is applied that adds "whitecaps" of brightness where the // waves line up with each other more. Finally, another pass is taken // over the led array to 'deepen' (dim) the blues and greens. // -// The speed and scale and motion each layer varies slowly within independent +// The speed and scale and motion each layer varies slowly within independent // hand-chosen ranges, which is why the code has a lot of low-speed 'beatsin8' functions // with a lot of oddly specific numeric ranges. // @@ -3685,7 +3697,7 @@ CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t uint16_t ci = cistart; uint16_t waveangle = ioff; uint16_t wavescale_half = (wavescale >> 1) + 20; - + waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i uint16_t s16 = sin16(waveangle) + 32768; uint16_t cs = scale16(s16, wavescale_half) + wavescale_half; @@ -3699,14 +3711,14 @@ uint16_t mode_pacifica() { uint32_t nowOld = strip.now; - CRGBPalette16 pacifica_palette_1 = - { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, + CRGBPalette16 pacifica_palette_1 = + { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 }; - CRGBPalette16 pacifica_palette_2 = - { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, + CRGBPalette16 pacifica_palette_2 = + { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F }; - CRGBPalette16 pacifica_palette_3 = - { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33, + CRGBPalette16 pacifica_palette_3 = + { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33, 0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF }; if (SEGMENT.palette) { @@ -3739,7 +3751,7 @@ uint16_t mode_pacifica() uint8_t basethreshold = beatsin8( 9, 55, 65); uint8_t wave = beat8( 7 ); - + for (int i = 0; i < SEGLEN; i++) { CRGB c = CRGB(2, 6, 10); // Render each of four layers, with different scales and speeds, that vary over time @@ -3747,7 +3759,7 @@ uint16_t mode_pacifica() c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401)); c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8(9, 10,38) , 0-beat16(503)); c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8(8, 10,28) , beat16(601)); - + // Add extra 'white' to areas where the four layers of light have lined up brightly uint8_t threshold = scale8( sin8( wave), 20) + basethreshold; wave += 7; @@ -3759,8 +3771,8 @@ uint16_t mode_pacifica() } //deepen the blues and greens - c.blue = scale8(c.blue, 145); - c.green = scale8(c.green, 200); + c.blue = scale8(c.blue, 145); + c.green = scale8(c.green, 200); c |= CRGB( 2, 5, 7); SEGMENT.setPixelColor(i, c.red, c.green, c.blue); @@ -3772,21 +3784,6 @@ uint16_t mode_pacifica() static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=51"; -//Solid colour background with glitter -uint16_t mode_solid_glitter() -{ - SEGMENT.fill(SEGCOLOR(0)); - - if (SEGMENT.intensity > random8()) - { - SEGMENT.setPixelColor(random16(SEGLEN), ULTRAWHITE); - } - - return FRAMETIME; -} -static const char _data_FX_MODE_SOLID_GLITTER[] PROGMEM = "Solid Glitter@,!;!;;;m12=0"; - - /* * Mode simulates a gradual sunrise */ @@ -3799,12 +3796,12 @@ uint16_t mode_sunrise() { SEGENV.step = millis(); //save starting time, millis() because now can change from sync SEGENV.aux0 = SEGMENT.speed; } - - SEGMENT.fill(0); + + SEGMENT.fill(BLACK); uint16_t stage = 0xFFFF; - + uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds - + if (SEGMENT.speed > 120) { //quick sunrise and sunset uint16_t counter = (strip.now >> 1) * (((SEGMENT.speed -120) >> 1) +1); stage = triwave16(counter); @@ -3816,7 +3813,7 @@ uint16_t mode_sunrise() { stage = map(s10SinceStart, 0, s10Target, 0, 0xFFFF); if (SEGMENT.speed > 60) stage = 0xFFFF - stage; //sunset } - + for (int i = 0; i <= SEGLEN/2; i++) { //default palette is Fire @@ -3963,12 +3960,12 @@ static const char _data_FX_MODE_SINEWAVE[] PROGMEM = "Sine"; uint16_t mode_flow(void) { uint16_t counter = 0; - if (SEGMENT.speed != 0) + if (SEGMENT.speed != 0) { counter = strip.now * ((SEGMENT.speed >> 2) +1); counter = counter >> 8; } - + uint16_t maxZones = SEGLEN / 6; //only looks good if each zone has at least 6 LEDs uint16_t zones = (SEGMENT.intensity * maxZones) >> 8; if (zones & 0x01) zones++; //zones must be even @@ -4001,7 +3998,6 @@ static const char _data_FX_MODE_FLOW[] PROGMEM = "Flow@!,Zones;;!;;m12=1"; //ver */ uint16_t mode_chunchun(void) { - //SEGMENT.fill(SEGCOLOR(1)); SEGMENT.fade_out(254); // add a bit of trail uint16_t counter = strip.now * (6 + (SEGMENT.speed >> 4)); uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment @@ -4178,7 +4174,7 @@ uint16_t mode_washing_machine(void) { speed /= quot; SEGENV.step += (speed * 128.0f); - + for (int i=0; i> 7)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(col, false, PALETTE_SOLID_WRAP, 3)); @@ -4267,19 +4263,19 @@ uint16_t mode_tv_simulator(void) { tvSimulator->sceeneColorBri = random8 ( 200, 240); // random start color-brightness for the sceene SEGENV.aux1 = 1; SEGENV.aux0 = 0; - } - + } + // slightly change the color-tone in this sceene if ( SEGENV.aux0 == 0) { // hue change in both directions j = random8(4 * colorIntensity); hue = (random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative ((j + tvSimulator->sceeneColorHue) < 767 ? tvSimulator->sceeneColorHue + j : tvSimulator->sceeneColorHue + j - 767) ; // positive - + // saturation j = random8(2 * colorIntensity); sat = (tvSimulator->sceeneColorSat - j) < 0 ? 0 : tvSimulator->sceeneColorSat - j; - + // brightness j = random8(100); bri = (tvSimulator->sceeneColorBri - j) < 0 ? 0 : tvSimulator->sceeneColorBri - j; @@ -4303,7 +4299,7 @@ uint16_t mode_tv_simulator(void) { ng = (uint8_t)gamma8(tvSimulator->actualColorG) * 257; nb = (uint8_t)gamma8(tvSimulator->actualColorB) * 257; - if (SEGENV.aux0 == 0) { // initialize next iteration + if (SEGENV.aux0 == 0) { // initialize next iteration SEGENV.aux0 = 1; // randomize total duration and fade duration for the actual color @@ -4319,7 +4315,7 @@ uint16_t mode_tv_simulator(void) { // fade from prev volor to next color if (tvSimulator->elapsed < tvSimulator->fadeTime) { - r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr); + r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr); g = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pg, ng); b = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pb, nb); } else { // Avoid divide-by-zero in map() @@ -4340,7 +4336,7 @@ uint16_t mode_tv_simulator(void) { tvSimulator->pb = nb; SEGENV.aux0 = 0; } - + return FRAMETIME; } static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;"; @@ -4386,7 +4382,7 @@ class AuroraWave { alive = true; } - CRGB getColorForLED(int ledIndex) { + CRGB getColorForLED(int ledIndex) { if(ledIndex < center - width || ledIndex > center + width) return 0; //Position out of range of this wave CRGB rgb; @@ -4399,7 +4395,7 @@ class AuroraWave { //The age of the wave determines it brightness. //At half its maximum age it will be the brightest. - float ageFactor = 0.1; + float ageFactor = 0.1; if((float)age / ttl < 0.5) { ageFactor = (float)age / (ttl / 2); } else { @@ -4411,7 +4407,7 @@ class AuroraWave { rgb.r = basecolor.r * factor; rgb.g = basecolor.g * factor; rgb.b = basecolor.b * factor; - + return rgb; }; @@ -4488,22 +4484,22 @@ uint16_t mode_aurora(void) { if (SEGCOLOR(1)) backlight++; if (SEGCOLOR(2)) backlight++; //Loop through LEDs to determine color - for (int i = 0; i < SEGLEN; i++) { + for (int i = 0; i < SEGLEN; i++) { CRGB mixedRgb = CRGB(backlight, backlight, backlight); //For each LED we must check each wave if it is "active" at this position. //If there are multiple waves active on a LED we multiply their values. for (int j = 0; j < SEGENV.aux1; j++) { CRGB rgb = waves[j].getColorForLED(i); - - if(rgb != CRGB(0)) { + + if(rgb != CRGB(0)) { mixedRgb += rgb; } } SEGMENT.setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2]); } - + return FRAMETIME; } static const char _data_FX_MODE_AURORA[] PROGMEM = "Aurora@!,!;1,2,3;!;;sx=24,pal=50"; @@ -4629,8 +4625,8 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so SEGENV.aux0 = 0; // start with red hue } - bool dot = false; - bool grad = true; + bool dot = SEGMENT.check3; + bool grad = SEGMENT.check1; byte numLines = SEGMENT.intensity/16 + 1; @@ -4646,24 +4642,26 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so byte xsteps = abs8(x1 - y1) + 1; byte ysteps = abs8(x2 - y2) + 1; byte steps = xsteps >= ysteps ? xsteps : ysteps; - + //Draw gradient line for (size_t i = 1; i <= steps; i++) { - byte dx = lerp8by8(x1, y1, i * 255 / steps); - byte dy = lerp8by8(x2, y2, i * 255 / steps); + uint8_t rate = i * 255 / steps; + byte dx = lerp8by8(x1, y1, rate); + byte dy = lerp8by8(x2, y2, rate); + //SEGMENT.setPixelColorXY(dx, dy, grad ? color.nscale8_video(255-rate) : color); // use addPixelColorXY for different look SEGMENT.addPixelColorXY(dx, dy, color); // use setPixelColorXY for different look - if (grad) SEGMENT.fadePixelColorXY(dx, dy, (i * 255 / steps)); //Draw gradient line + if (grad) SEGMENT.fadePixelColorXY(dx, dy, rate); } if (dot) { //add white point at the ends of line - SEGMENT.addPixelColorXY(x1, x2, WHITE); - SEGMENT.addPixelColorXY(y1, y2, WHITE); + SEGMENT.setPixelColorXY(x1, x2, WHITE); + SEGMENT.setPixelColorXY(y1, y2, DARKSLATEGRAY); } } - SEGMENT.blur(4); + if (SEGMENT.custom3) SEGMENT.blur(SEGMENT.custom3/2); return FRAMETIME; } // mode_2DColoredBursts() -static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Speed,# of lines;;!;2"; +static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Speed,# of lines,,,Blur,Gradient,,Dots;;!;2;c3=16"; ///////////////////// @@ -4705,10 +4703,9 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma if (SEGENV.call == 0) { SEGMENT.setUpLeds(); SEGMENT.fill(BLACK); - SEGENV.aux0 = 0; // hue } - uint8_t speeds = SEGMENT.speed/2; + uint8_t speeds = SEGMENT.speed/2 + 1; uint8_t freq = SEGMENT.intensity/8; uint32_t ms = millis() / 20; @@ -4717,17 +4714,21 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma for (int i = 0; i < rows; i++) { uint16_t x = beatsin8(speeds, 0, cols - 1, 0, i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, i * freq + 128); uint16_t x1 = beatsin8(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); - SEGENV.aux0 = i * 128 / cols + ms; //ewowi20210629: not width - 1 to avoid crash if width = 1 + uint8_t hue = (i * 128 / rows) + ms; + // skip every 4th row every now and then (fade it more) if ((i + ms / 8) & 3) { + // draw a gradient line between x and x1 x = x / 2; x1 = x1 / 2; - byte steps = abs8(x - x1) + 1; + uint8_t steps = abs8(x - x1) + 1; for (size_t k = 1; k <= steps; k++) { - byte dx = lerp8by8(x, x1, k * 255 / steps); - SEGMENT.addPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, SEGENV.aux0, 255, LINEARBLEND)); - SEGMENT.fadePixelColorXY(dx, i, (k * 255 / steps)); + uint8_t rate = k * 255 / steps; + uint8_t dx = lerp8by8(x, x1, rate); + //SEGMENT.setPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND).nscale8_video(rate)); + SEGMENT.addPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND)); // use setPixelColorXY for different look + SEGMENT.fadePixelColorXY(dx, i, rate); } - SEGMENT.addPixelColorXY(x, i, DARKSLATEGRAY); - SEGMENT.addPixelColorXY(x1, i, WHITE); + SEGMENT.setPixelColorXY(x, i, DARKSLATEGRAY); + SEGMENT.setPixelColorXY(x1, i, WHITE); } } @@ -4834,7 +4835,7 @@ static const char _data_FX_MODE_2DFRIZZLES[] PROGMEM = "Frizzles@X frequency,Y f /////////////////////////////////////////// typedef struct ColorCount { CRGB color; - int8_t count; + int8_t count; } colorCount; uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https://natureofcode.com/book/chapter-7-cellular-automata/ and https://github.com/DougHaber/nlife-color @@ -4843,17 +4844,18 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t dataSize = sizeof(CRGB) * SEGMENT.length(); // using width*height prevents reallocation if mirroring is enabled + const uint16_t crcBufferLen = (SEGMENT.width() + SEGMENT.height())*71/100; // roughly sqrt(2)/2 for better repetition detection (Ewowi) - if (!SEGENV.allocateData(dataSize + sizeof(unsigned long))) return mode_static(); //allocation failed + if (!SEGENV.allocateData(dataSize + sizeof(uint16_t)*crcBufferLen)) return mode_static(); //allocation failed CRGB *prevLeds = reinterpret_cast(SEGENV.data); - unsigned long *resetMillis = reinterpret_cast(SEGENV.data + dataSize); // triggers reset + uint16_t *crcBuffer = reinterpret_cast(SEGENV.data + dataSize); CRGB backgroundColor = SEGCOLOR(1); - if (SEGENV.call == 0 || strip.now - *resetMillis > 5000) { - *resetMillis = strip.now; - - random16_set_seed(strip.now); //seed the random generator + if (SEGENV.call == 0 || strip.now - SEGMENT.step > 5000) { + SEGENV.step = strip.now; + SEGENV.aux0 = 0; + random16_set_seed(millis()>>2); //seed the random generator //give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen) for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) { @@ -4861,17 +4863,18 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: if (state == 0) SEGMENT.setPixelColorXY(x,y, backgroundColor); else - SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 255)); } for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) prevLeds[XY(x,y)] = CRGB::Black; - - - SEGENV.aux1 = 0; - SEGENV.aux0 = 0xFFFF; + memset(crcBuffer, 0, sizeof(uint16_t)*crcBufferLen); + } else if (strip.now - SEGENV.step < FRAMETIME_FIXED * (uint32_t)map(SEGMENT.speed,0,255,64,4)) { + // update only when appropriate time passes (in 42 FPS slots) + return FRAMETIME; } //copy previous leds (save previous generation) + //NOTE: using lossy getPixelColor() is a benefit as endlessly repeating patterns will eventually fade out causing a reset for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) prevLeds[XY(x,y)] = SEGMENT.getPixelColorXY(x,y); //calculate new leds @@ -4908,8 +4911,8 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: uint32_t bgc = RGBW32(backgroundColor.r, backgroundColor.g, backgroundColor.b, 0); if ((col != bgc) && (neighbors < 2)) SEGMENT.setPixelColorXY(x,y, bgc); // Loneliness else if ((col != bgc) && (neighbors > 3)) SEGMENT.setPixelColorXY(x,y, bgc); // Overpopulation - else if ((col == bgc) && (neighbors == 3)) { // Reproduction - //find dominantcolor and assign to cell + else if ((col == bgc) && (neighbors == 3)) { // Reproduction + //find dominant color and assign to cell colorCount dominantColorCount = {backgroundColor, 0}; for (int i=0; i<9 && colorsCount[i].count != 0; i++) if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i]; @@ -4919,16 +4922,17 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: } //x,y // calculate CRC16 of leds - uint16_t crc = crc16((const unsigned char*)prevLeds, dataSize-1); //ewowi: prevLeds instead of leds work as well, tbd: compare more patterns, see SR! - + uint16_t crc = crc16((const unsigned char*)prevLeds, dataSize); // check if we had same CRC and reset if needed + bool repetition = false; + for (int i=0; i>1)); // update only when appropriate time passes (in 42 FPS slots) + return FRAMETIME; } // mode_2Dgameoflife() static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!;!,!;!;2"; @@ -5086,11 +5090,11 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline for (int i=0; i < 256; i ++) { //float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f; //float ylocn = float(cos8(now/4+i*2)) / 255.0f; - uint8_t xlocn = sin8(strip.now/2+i*(SEGMENT.speed>>5)); - uint8_t ylocn = cos8(strip.now/2+i*2); + uint8_t xlocn = sin8(millis()/4+i*(SEGMENT.speed>>5)); + uint8_t ylocn = cos8(millis()/4+i*2); xlocn = map(xlocn,0,255,0,cols-1); ylocn = map(ylocn,0,255,0,rows-1); - SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0)); } return FRAMETIME; @@ -5173,15 +5177,15 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have float speed = 0.25f * (1+(SEGMENT.speed>>6)); // get some 2 random moving points - uint8_t x2 = inoise8(strip.now * speed, 25355, 685 ) / 16; - uint8_t y2 = inoise8(strip.now * speed, 355, 11685 ) / 16; + uint8_t x2 = map(inoise8(strip.now * speed, 25355, 685), 0, 255, 0, cols-1); + uint8_t y2 = map(inoise8(strip.now * speed, 355, 11685), 0, 255, 0, rows-1); - uint8_t x3 = inoise8(strip.now * speed, 55355, 6685 ) / 16; - uint8_t y3 = inoise8(strip.now * speed, 25355, 22685 ) / 16; + uint8_t x3 = map(inoise8(strip.now * speed, 55355, 6685), 0, 255, 0, cols-1); + uint8_t y3 = map(inoise8(strip.now * speed, 25355, 22685), 0, 255, 0, rows-1); // and one Lissajou function - uint8_t x1 = beatsin8(23 * speed, 0, 15); - uint8_t y1 = beatsin8(28 * speed, 0, 15); + uint8_t x1 = beatsin8(23 * speed, 0, cols-1); + uint8_t y1 = beatsin8(28 * speed, 0, rows-1); for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { @@ -5200,7 +5204,7 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have dist += sqrt16((dx * dx) + (dy * dy)); // inverse result - byte color = 1000 / dist; + byte color = dist ? 1000 / dist : 255; // map color between thresholds if (color > 0 and color < 60) { @@ -5616,7 +5620,7 @@ uint16_t mode_2Dcrazybees(void) { SEGENV.step = millis() + (FRAMETIME * 8 / ((SEGMENT.speed>>5)+1)); SEGMENT.fadeToBlackBy(32); - + for (size_t i = 0; i < n; i++) { SEGMENT.addPixelColorXY(bee[i].aimX + 1, bee[i].aimY, CHSV(bee[i].hue, 255, 255)); SEGMENT.addPixelColorXY(bee[i].aimX, bee[i].aimY + 1, CHSV(bee[i].hue, 255, 255)); @@ -5792,7 +5796,7 @@ uint16_t mode_2Dfloatingblobs(void) { // reduce radius until it is < 1 blob->r[i] -= (fabs(blob->sX[i]) > fabs(blob->sY[i]) ? fabs(blob->sX[i]) : fabs(blob->sY[i])) * 0.05f; if (blob->r[i] < 1.f) { - blob->grow[i] = true; + blob->grow[i] = true; } } uint32_t c = SEGMENT.color_from_palette(blob->color[i], false, false, 0); @@ -5882,20 +5886,27 @@ uint16_t mode_2Dscrollingtext(void) { else SEGENV.aux0 = (cols + (numberOfLetters * letterWidth))/2; ++SEGENV.aux1 &= 0xFF; // color shift SEGENV.step = millis() + map(SEGMENT.speed, 0, 255, 10*FRAMETIME_FIXED, 2*FRAMETIME_FIXED); - - // we need it 3 times - SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color - SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color - SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color - for (int i = 0; i < numberOfLetters; i++) { - if (int(cols) - int(SEGENV.aux0) + letterWidth*(i+1) < 0) continue; // don't draw characters off-screen - SEGMENT.drawCharacter(text[i], int(cols) - int(SEGENV.aux0) + letterWidth*i, yoffset, letterWidth, letterHeight, SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0)); + if (!SEGMENT.check2) { + // we need it 3 times + SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color + SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color + SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color } } + for (int i = 0; i < numberOfLetters; i++) { + if (int(cols) - int(SEGENV.aux0) + letterWidth*(i+1) < 0) continue; // don't draw characters off-screen + uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0); + uint32_t col2 = BLACK; + if (SEGMENT.check1 && SEGMENT.palette == 0) { + col1 = SEGCOLOR(0); + col2 = SEGCOLOR(2); + } + SEGMENT.drawCharacter(text[i], int(cols) - int(SEGENV.aux0) + letterWidth*i, yoffset, letterWidth, letterHeight, col1, col2); + } return FRAMETIME; } -static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size;!,!;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0"; +static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,,Gradient,Overlay;!,!,Gradient;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0"; //////////////////////////// @@ -6184,7 +6195,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 32, 0, (float)SEGLEN/2.0); // map to pixels available in current segment + float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 32, 0, (float)SEGLEN/2.0); // map to pixels available in current segment uint16_t tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; @@ -6235,7 +6246,7 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0; segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivty" upscaling - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0); // map to pixels availeable in current segment + float mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0); // map to pixels availeable in current segment int tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; @@ -6283,7 +6294,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline. float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0; segmentSampleAvg *= 0.25; // divide by 4, to compensate for later "sensitivty" upscaling - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 64, 0, (SEGLEN-1)); // map to pixels availeable in current segment + float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 64, 0, (SEGLEN-1)); // map to pixels availeable in current segment int tempsamp = constrain(mySampleAvg,0,SEGLEN-1); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; @@ -6528,7 +6539,7 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline. // updated, similar to "plasma" effect - softhack007 uint8_t thisbright = cubicwave8(((i*(1 + (3*SEGMENT.speed/32)))+plasmoip->thisphase) & 0xFF)/2; thisbright += cos8(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. - + uint8_t colorIndex=thisbright; if (volumeSmth * SEGMENT.intensity / 64 < thisbright) {thisbright = 0;} @@ -6666,7 +6677,7 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. SEGENV.aux0 = 0; } - int fadeoutDelay = (256 - SEGMENT.speed) / 32; + int fadeoutDelay = (256 - SEGMENT.speed) / 32; if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(SEGMENT.speed); SEGENV.step += FRAMETIME; @@ -6732,11 +6743,11 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. um_data = simulateSound(SEGMENT.soundSim); } float FFT_MajorPeak = *(float*) um_data->u_data[4]; - float my_magnitude = *(float*) um_data->u_data[5] / 4.0f; + float my_magnitude = *(float*) um_data->u_data[5] / 4.0f; if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) if (SEGENV.call == 0) SEGMENT.fill(BLACK); - int fadeoutDelay = (256 - SEGMENT.speed) / 32; + int fadeoutDelay = (256 - SEGMENT.speed) / 32; if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(SEGMENT.speed); int locn = (log10f((float)FFT_MajorPeak) - 1.78f) * (float)SEGLEN/(MAX_FREQ_LOG10 - 1.78f); // log10 frequency range is from 1.78 to 3.71. Let's scale to SEGLEN. @@ -6824,13 +6835,13 @@ uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline. um_data = simulateSound(SEGMENT.soundSim); } float FFT_MajorPeak = *(float*) um_data->u_data[4]; - float my_magnitude = *(float*) um_data->u_data[5] / 16.0f; + float my_magnitude = *(float*) um_data->u_data[5] / 16.0f; if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) uint16_t fadeRate = 2*SEGMENT.speed - SEGMENT.speed*SEGMENT.speed/255; // Get to 255 as quick as you can. if (SEGENV.call == 0) SEGMENT.fill(BLACK); - int fadeoutDelay = (256 - SEGMENT.speed) / 64; + int fadeoutDelay = (256 - SEGMENT.speed) / 64; if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(fadeRate); for (int i=0; i < SEGMENT.intensity/32+1; i++) { @@ -6937,7 +6948,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline. float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0; segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0,32, 0, (float)SEGLEN/2.0); // map to pixels availeable in current segment + float mySampleAvg = mapf(segmentSampleAvg*2.0, 0,32, 0, (float)SEGLEN/2.0); // map to pixels availeable in current segment int tempsamp = constrain(mySampleAvg,0,SEGLEN/2); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; @@ -6979,7 +6990,7 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli if (SEGENV.call == 0) SEGMENT.fill(BLACK); //SEGMENT.fade_out(224); // Just in case something doesn't get faded. - int fadeoutDelay = (256 - SEGMENT.speed) / 96; + int fadeoutDelay = (256 - SEGMENT.speed) / 96; if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(4+ SEGMENT.speed/4); uint8_t numBins = map(SEGMENT.intensity,0,255,0,16); // Map slider to fftResult bins. @@ -7004,7 +7015,7 @@ uint16_t mode_rocktaves(void) { // Rocktaves. Same note from eac um_data = simulateSound(SEGMENT.soundSim); } float FFT_MajorPeak = *(float*) um_data->u_data[4]; - float my_magnitude = *(float*) um_data->u_data[5] / 16.0f; + float my_magnitude = *(float*) um_data->u_data[5] / 16.0f; if (SEGENV.call == 0) SEGMENT.fill(BLACK); SEGMENT.fadeToBlackBy(16); // Just in case something doesn't get faded. @@ -7050,7 +7061,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin float FFT_MajorPeak = *(float*) um_data->u_data[4]; uint8_t *maxVol = (uint8_t*)um_data->u_data[6]; uint8_t *binNum = (uint8_t*)um_data->u_data[7]; - float my_magnitude = *(float*) um_data->u_data[5] / 8.0f; + float my_magnitude = *(float*) um_data->u_data[5] / 8.0f; if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) @@ -7116,7 +7127,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. } if (SEGENV.call == 0) SEGMENT.fill(BLACK); - int fadeoutDelay = (256 - SEGMENT.speed) / 64; + int fadeoutDelay = (256 - SEGMENT.speed) / 64; if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(SEGMENT.speed); for (int x=0; x < cols; x++) { @@ -7129,7 +7140,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. uint32_t ledColor = BLACK; for (int y=0; y < barHeight; y++) { - if (SEGMENT.check1) //color_vertical / color bars toggle + if (SEGMENT.check1) //color_vertical / color bars toggle colorIndex = map(y, 0, rows-1, 0, 255); ledColor = SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0); @@ -7305,6 +7316,61 @@ uint16_t mode_2DAkemi(void) { return FRAMETIME; } // mode_2DAkemi static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette;2f;si=0"; //beatsin + + +// Distortion waves - ldirko +// https://editor.soulmatelights.com/gallery/1089-distorsion-waves +// apated for WLD by @blazoncek +uint16_t mode_2Ddistortionwaves() { + if (!strip.isMatrix) return mode_static(); // not a 2D set-up + + const uint16_t cols = SEGMENT.virtualWidth(); + const uint16_t rows = SEGMENT.virtualHeight(); + + uint8_t speed = SEGMENT.speed/32; + uint8_t scale = SEGMENT.intensity/32; + + uint8_t w = 2; + + uint16_t a = millis()/32; + uint16_t a2 = a/2; + uint16_t a3 = a/3; + + uint16_t cx = beatsin8(10-speed,0,cols-1)*scale; + uint16_t cy = beatsin8(12-speed,0,rows-1)*scale; + uint16_t cx1 = beatsin8(13-speed,0,cols-1)*scale; + uint16_t cy1 = beatsin8(15-speed,0,rows-1)*scale; + uint16_t cx2 = beatsin8(17-speed,0,cols-1)*scale; + uint16_t cy2 = beatsin8(14-speed,0,rows-1)*scale; + + uint16_t xoffs = 0; + for (int x = 0; x < cols; x++) { + xoffs += scale; + uint16_t yoffs = 0; + + for (int y = 0; y < rows; y++) { + yoffs += scale; + + byte rdistort = cos8((cos8(((x<<3)+a )&255)+cos8(((y<<3)-a2)&255)+a3 )&255)>>1; + byte gdistort = cos8((cos8(((x<<3)-a2)&255)+cos8(((y<<3)+a3)&255)+a+32 )&255)>>1; + byte bdistort = cos8((cos8(((x<<3)+a3)&255)+cos8(((y<<3)-a) &255)+a2+64)&255)>>1; + + byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 )); + byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 )); + byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 )); + + valueR = gamma8(cos8(valueR)); + valueG = gamma8(cos8(valueG)); + valueB = gamma8(cos8(valueB)); + + SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); + } + } + + return FRAMETIME; +} +static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale;;;2;"; + #endif // WLED_DISABLE_2D @@ -7388,7 +7454,7 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_FIRE_FLICKER, &mode_fire_flicker, _data_FX_MODE_FIRE_FLICKER); addEffect(FX_MODE_GRADIENT, &mode_gradient, _data_FX_MODE_GRADIENT); addEffect(FX_MODE_LOADING, &mode_loading, _data_FX_MODE_LOADING); - + addEffect(FX_MODE_FAIRY, &mode_fairy, _data_FX_MODE_FAIRY); addEffect(FX_MODE_TWO_DOTS, &mode_two_dots, _data_FX_MODE_TWO_DOTS); addEffect(FX_MODE_FAIRYTWINKLE, &mode_fairytwinkle, _data_FX_MODE_FAIRYTWINKLE); @@ -7503,6 +7569,7 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_2DBLOBS, &mode_2Dfloatingblobs, _data_FX_MODE_2DBLOBS); addEffect(FX_MODE_2DSCROLLTEXT, &mode_2Dscrollingtext, _data_FX_MODE_2DSCROLLTEXT); addEffect(FX_MODE_2DDRIFTROSE, &mode_2Ddriftrose, _data_FX_MODE_2DDRIFTROSE); + addEffect(FX_MODE_2DDISTORTIONWAVES, &mode_2Ddistortionwaves, _data_FX_MODE_2DDISTORTIONWAVES); addEffect(FX_MODE_2DGEQ, &mode_2DGEQ, _data_FX_MODE_2DGEQ); // audio @@ -7540,5 +7607,5 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_2DAKEMI, &mode_2DAkemi, _data_FX_MODE_2DAKEMI); // audio #endif // WLED_DISABLE_2D - + } diff --git a/wled00/FX.h b/wled00/FX.h index 9ef54805e..8db9e2552 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -250,6 +250,7 @@ #define FX_MODE_2DBLOBS 121 //gap fill #define FX_MODE_2DSCROLLTEXT 122 //gap fill #define FX_MODE_2DDRIFTROSE 123 //gap fill +#define FX_MODE_2DDISTORTIONWAVES 124 // WLED-SR effects (SR compatible IDs !!!) #define FX_MODE_PIXELS 128 @@ -519,9 +520,9 @@ typedef struct Segment { bool allocateData(size_t len); void deallocateData(void); void resetIfRequired(void); - /** + /** * Flags that before the next effect is calculated, - * the internal segment state should be reset. + * the internal segment state should be reset. * Call resetIfRequired before calling the next effect function. * Safe to call from interrupts and network requests. */ @@ -588,11 +589,13 @@ typedef struct Segment { void moveX(int8_t delta); void moveY(int8_t delta); void move(uint8_t dir, uint8_t delta); + void draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c); void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c); void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c); void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline - void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color); + void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0); void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline + void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline void wu_pixel(uint32_t x, uint32_t y, CRGB c); void blur1d(fract8 blur_amount); // blur all rows in 1 dimension void blur2d(fract8 blur_amount) { blur(blur_amount); } @@ -641,7 +644,7 @@ class WS2812FX { // 96 bytes } mode_data_t; static WS2812FX* instance; - + public: WS2812FX() : @@ -885,9 +888,9 @@ class WS2812FX { // 96 bytes uint16_t* customMappingTable; uint16_t customMappingSize; - + uint32_t _lastShow; - + uint8_t _segment_index; uint8_t _mainSegment; diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index be9464d32..27840a3a1 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -1,6 +1,6 @@ /* FX_2Dfcn.cpp contains all 2D utility functions - + LICENSE The MIT License (MIT) Copyright (c) 2022 Blaz Kristan (https://blaz.at/home) @@ -164,6 +164,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) if (leds) leds[XY(x,y)] = col; uint8_t _bri_t = currentBri(on ? opacity : 0); + if (!_bri_t && !transitional) return; if (_bri_t < 255) { byte r = scale8(R(col), _bri_t); byte g = scale8(G(col), _bri_t); @@ -271,7 +272,7 @@ void Segment::addPixelColorXY(int x, int y, uint32_t color) { void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade); - setPixelColor(x, y, pix); + setPixelColorXY(x, y, pix); } // blurRow: perform a blur on a row of a rectangular matrix @@ -428,6 +429,29 @@ void Segment::move(uint8_t dir, uint8_t delta) { } } +void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { + // Bresenham’s Algorithm + int d = 3 - (2*radius); + int y = radius, x = 0; + while (y >= x) { + setPixelColorXY(cx+x, cy+y, col); + setPixelColorXY(cx-x, cy+y, col); + setPixelColorXY(cx+x, cy-y, col); + setPixelColorXY(cx-x, cy-y, col); + setPixelColorXY(cx+y, cy+x, col); + setPixelColorXY(cx-y, cy+x, col); + setPixelColorXY(cx+y, cy-x, col); + setPixelColorXY(cx-y, cy-x, col); + x++; + if (d > 0) { + y--; + d += 4 * (x - y) + 10; + } else { + d += 4 * x + 6; + } + } +} + // by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { const uint16_t cols = virtualWidth(); @@ -437,7 +461,7 @@ void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { if (x * x + y * y <= radius * radius && int16_t(cx)+x>=0 && int16_t(cy)+y>=0 && int16_t(cx)+x= cols || x1 >= cols || y0 >= rows || y1 >= rows) return; const int16_t dx = abs(x1-x0), sx = x0dy ? dx : -dy)/2, e2; for (;;) { - addPixelColorXY(x0,y0,c); + setPixelColorXY(x0,y0,c); if (x0==x1 && y0==y1) break; e2 = err; if (e2 >-dx) { err -= dy; x0 += sx; } @@ -475,13 +499,16 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 // draws a raster font character on canvas // only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM -void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color) { +void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2) { if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported chr -= 32; // align with font table entries const uint16_t cols = virtualWidth(); const uint16_t rows = virtualHeight(); const int font = w*h; + CRGB col = CRGB(color); + CRGBPalette16 grad = CRGBPalette16(col, col2 ? CRGB(col2) : col); + //if (w<5 || w>6 || h!=8) return; for (int i = 0; i= 0 || x0 < cols) && ((bits>>(j+(8-w))) & 0x01)) { // bit set & drawing on-screen - addPixelColorXY(x0, y0, color); + addPixelColorXY(x0, y0, col); } } } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 7310cdee4..147f625bf 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -174,18 +174,18 @@ void Segment::deallocateData() { _dataLen = 0; } -/** +/** * If reset of this segment was requested, clears runtime * settings of this segment. * Must not be called while an effect mode function is running - * because it could access the data buffer and this method + * because it could access the data buffer and this method * may free that data buffer. */ void Segment::resetIfRequired() { if (reset) { if (leds && !Segment::_globalLeds) { free(leds); leds = nullptr; } //if (_t) { delete _t; _t = nullptr; transitional = false; } - next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; + next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; reset = false; // setOption(SEG_OPTION_RESET, false); } } @@ -243,12 +243,12 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { _lastPaletteChange = millis(); timeSinceLastChange = 0; } - if (timeSinceLastChange <= 500) { + if (timeSinceLastChange <= 250) { targetPalette = prevRandomPalette; // there needs to be 255 palette blends (48) for full blend but that is too resource intensive // so 128 is a compromise (we need to perform full blend of the two palettes as each segment can have random // palette selected but only 2 static palettes are used) - size_t noOfBlends = ((128U * timeSinceLastChange) / 500U); + size_t noOfBlends = ((128U * timeSinceLastChange) / 250U); for (size_t i=0; i= 0) speed = sOpt; - sOpt = extractModeDefaults(fx, "ix"); if (sOpt >= 0) intensity = sOpt; - sOpt = extractModeDefaults(fx, "c1"); if (sOpt >= 0) custom1 = sOpt; - sOpt = extractModeDefaults(fx, "c2"); if (sOpt >= 0) custom2 = sOpt; - sOpt = extractModeDefaults(fx, "c3"); if (sOpt >= 0) custom3 = sOpt; + sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED; + sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY; + sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1; + sOpt = extractModeDefaults(fx, "c2"); custom2 = (sOpt >= 0) ? sOpt : DEFAULT_C2; + sOpt = extractModeDefaults(fx, "c3"); custom3 = (sOpt >= 0) ? sOpt : DEFAULT_C3; + sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false; + sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false; + sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false; sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7); sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 7); sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt; sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt; sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business - sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); + sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0); } stateChanged = true; // send UDP/WS broadcast } @@ -574,6 +577,20 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) int y = roundf(cos_t(rad) * i); setPixelColorXY(x, y, col); } + // Bresenham’s Algorithm (may not fill every pixel) + //int d = 3 - (2*i); + //int y = i, x = 0; + //while (y >= x) { + // setPixelColorXY(x, y, col); + // setPixelColorXY(y, x, col); + // x++; + // if (d > 0) { + // y--; + // d += 4 * (x - y) + 10; + // } else { + // d += 4 * x + 6; + // } + //} } break; case M12_pCorner: @@ -596,6 +613,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) uint16_t len = length(); uint8_t _bri_t = currentBri(on ? opacity : 0); + if (!_bri_t && !transitional) return; if (_bri_t < 255) { byte r = scale8(R(col), _bri_t); byte g = scale8(G(col), _bri_t); @@ -620,7 +638,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) uint16_t indexSet = i + ((reverse) ? -j : j); if (indexSet >= start && indexSet < stop) { if (mirror) { //set the corresponding mirrored pixel - uint16_t indexMir = stop - indexSet + start - 1; + uint16_t indexMir = stop - indexSet + start - 1; indexMir += offset; // offset/phase if (indexMir >= stop) indexMir -= len; // wrap strip.setPixelColor(indexMir, col); @@ -745,7 +763,7 @@ void Segment::refreshLightCapabilities() { switch (type) { case TYPE_ANALOG_5CH: case TYPE_ANALOG_2CH: - capabilities |= 0x04; //segment supports white CCT + capabilities |= 0x04; //segment supports white CCT } } if (correctWB && !(type == TYPE_ANALOG_1CH || type == TYPE_ONOFF)) capabilities |= 0x04; //white balance correction (uses CCT slider) @@ -908,7 +926,7 @@ uint8_t Segment::get_random_wheel_index(uint8_t pos) { * Gets a single color from the currently selected palette. * @param i Palette Index (if mapping is true, the full palette will be _virtualSegmentLength long, if false, 255). Will wrap around automatically. * @param mapping if true, LED position in segment is considered for color - * @param wrap FastLED palettes will usally wrap back to the start smoothly. Set false to get a hard edge + * @param wrap FastLED palettes will usually wrap back to the start smoothly. Set false to get a hard edge * @param mcol If the default palette 0 is selected, return the standard color 0, 1 or 2 instead. If >2, Party palette is used instead * @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling) * @returns Single color from palette @@ -1056,7 +1074,7 @@ void WS2812FX::service() { //if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress()); delay = (*_mode[seg.currentMode(seg.mode)])(); if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++; - if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // foce faster updates during transition + if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition seg.handleTransition(); } @@ -1097,7 +1115,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i) //Stay safe with high amperage and have a reasonable safety margin! //I am NOT to be held liable for burned down garages! -//fine tune power estimation constants for your setup +//fine tune power estimation constants for your setup #define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA) //you can set it to 0 if the ESP is powered by USB and the LEDs by external @@ -1156,7 +1174,7 @@ void WS2812FX::estimateCurrentAndLimitBri() { uint32_t powerSum0 = powerSum; powerSum *= _brightness; - + if (powerSum > powerBudget) //scale brightness down to stay in current limit { float scale = (float)powerBudget / (float)powerSum; @@ -1180,7 +1198,7 @@ void WS2812FX::show(void) { if (callback) callback(); estimateCurrentAndLimitBri(); - + // some buses send asynchronously and this method will return before // all of the data has been sent. // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods @@ -1217,7 +1235,7 @@ void WS2812FX::setTargetFps(uint8_t fps) { void WS2812FX::setMode(uint8_t segid, uint8_t m) { if (segid >= _segments.size()) return; - + if (m >= getModeCount()) m = getModeCount() - 1; if (_segments[segid].mode != m) { diff --git a/wled00/alexa.cpp b/wled00/alexa.cpp index 3b7e80521..c122402a4 100644 --- a/wled00/alexa.cpp +++ b/wled00/alexa.cpp @@ -2,7 +2,7 @@ /* * Alexa Voice On/Off/Brightness/Color Control. Emulates a Philips Hue bridge to Alexa. - * + * * This was put together from these two excellent projects: * https://github.com/kakopappa/arduino-esp8266-alexa-wemo-switch * https://github.com/probonopd/ESP8266HueEmulator @@ -21,11 +21,11 @@ void alexaInit() espalexaDevice = new EspalexaDevice(alexaInvocationName, onAlexaChange, EspalexaDeviceType::extendedcolor); espalexa.addDevice(espalexaDevice); - // up to 9 devices (added second, third, ... i.e. index 1 to 9) serve for switching on up to nine presets (preset IDs 1 to 9 in WLED), + // up to 9 devices (added second, third, ... i.e. index 1 to 9) serve for switching on up to nine presets (preset IDs 1 to 9 in WLED), // names are identical as the preset names, switching off can be done by switching off any of them if (alexaNumPresets) { String name = ""; - for (byte presetIndex = 1; presetIndex <= alexaNumPresets; presetIndex++) + for (byte presetIndex = 1; presetIndex <= alexaNumPresets; presetIndex++) { if (!getPresetName(presetIndex, name)) break; // no more presets EspalexaDevice* dev = new EspalexaDevice(name.c_str(), onAlexaChange, EspalexaDeviceType::extendedcolor); @@ -44,7 +44,7 @@ void handleAlexa() void onAlexaChange(EspalexaDevice* dev) { EspalexaDeviceProperty m = dev->getLastChangedProperty(); - + if (m == EspalexaDeviceProperty::on) { if (dev->getId() == 0) // Device 0 is for on/off or macros @@ -56,7 +56,7 @@ void onAlexaChange(EspalexaDevice* dev) bri = briLast; stateUpdated(CALL_MODE_ALEXA); } - } else + } else { applyPreset(macroAlexaOn, CALL_MODE_ALEXA); if (bri == 0) dev->setValue(briLast); //stop Alexa from complaining if macroAlexaOn does not actually turn on @@ -82,7 +82,7 @@ void onAlexaChange(EspalexaDevice* dev) bri = 0; stateUpdated(CALL_MODE_ALEXA); } - } else + } else { applyPreset(macroAlexaOff, CALL_MODE_ALEXA); // below for loop stops Alexa from complaining if macroAlexaOff does not actually turn off diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 74f073e98..8250695f9 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -217,7 +217,7 @@ class Bus { static uint8_t _gAWM; // definition in FX_fcn.cpp static int16_t _cct; // definition in FX_fcn.cpp static uint8_t _cctBlend; // definition in FX_fcn.cpp - + uint32_t autoWhiteCalc(uint32_t c) { uint8_t aWM = _autoWhiteMode; if (_gAWM < 255) aWM = _gAWM; @@ -271,7 +271,7 @@ class BusDigital : public Bus { //Fix for turning off onboard LED breaking bus #ifdef LED_BUILTIN if (_bri == 0 && b > 0) { - if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins); + if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins); } #endif Bus::setBrightness(b); @@ -343,7 +343,7 @@ class BusDigital : public Bus { cleanup(); } - private: + private: uint8_t _colorOrder = COL_ORDER_GRB; uint8_t _pins[2] = {255, 255}; uint8_t _iType = I_NONE; @@ -477,7 +477,7 @@ class BusPwm : public Bus { cleanup(); } - private: + private: uint8_t _pins[5] = {255, 255, 255, 255, 255}; uint8_t _data[5] = {0}; #ifdef ARDUINO_ARCH_ESP32 @@ -553,7 +553,7 @@ class BusOnOff : public Bus { cleanup(); } - private: + private: uint8_t _pin = 255; uint8_t _data = 0; }; @@ -717,7 +717,7 @@ class BusManager { //do not call this method from system context (network callback) void removeAll() { DEBUG_PRINTLN(F("Removing all.")); - //prevents crashes due to deleting busses while in use. + //prevents crashes due to deleting busses while in use. while (!canAllShow()) yield(); for (uint8_t i = 0; i < numBusses; i++) delete busses[i]; numBusses = 0; diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 1c2468d63..323f75afe 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -699,7 +699,7 @@ class PolyBus { } }; static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { - RgbwColor col(0,0,0,0); + RgbwColor col(0,0,0,0); switch (busType) { case I_NONE: break; #ifdef ESP8266 @@ -771,7 +771,7 @@ class PolyBus { case I_HS_P98_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_SS_P98_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; } - + // upper nibble contains W swap information uint8_t w = col.W; switch (co >> 4) { @@ -866,7 +866,7 @@ class PolyBus { } } - //gives back the internal type index (I_XX_XXX_X above) for the input + //gives back the internal type index (I_XX_XXX_X above) for the input static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) { if (!IS_DIGITAL(busType)) return I_NONE; if (IS_2PIN(busType)) { //SPI LED chips diff --git a/wled00/button.cpp b/wled00/button.cpp index b34e3c384..fce21424d 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -24,12 +24,14 @@ void shortPressAction(uint8_t b) applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET); } +#ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { char subuf[64]; sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, "short"); } +#endif } void longPressAction(uint8_t b) @@ -43,12 +45,14 @@ void longPressAction(uint8_t b) applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); } +#ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { char subuf[64]; sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, "long"); } +#endif } void doublePressAction(uint8_t b) @@ -62,12 +66,14 @@ void doublePressAction(uint8_t b) applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET); } +#ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { char subuf[64]; sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, "double"); } +#endif } bool isButtonPressed(uint8_t i) @@ -105,20 +111,21 @@ void handleSwitch(uint8_t b) } if (buttonLongPressed[b] == buttonPressedBefore[b]) return; - + if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce) if (!buttonPressedBefore[b]) { // on -> off if (macroButton[b]) applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET); else { //turn on if (!bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);} - } + } } else { // off -> on if (macroLongPress[b]) applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); else { //turn off if (bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);} - } + } } +#ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { char subuf[64]; @@ -126,13 +133,14 @@ void handleSwitch(uint8_t b) else sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, !buttonPressedBefore[b] ? "off" : "on"); } +#endif buttonLongPressed[b] = buttonPressedBefore[b]; //save the last "long term" switch state } } #define ANALOG_BTN_READ_CYCLE 250 // min time between two analog reading cycles -#define STRIP_WAIT_TIME 6 // max wait time in case of strip.isUpdating() +#define STRIP_WAIT_TIME 6 // max wait time in case of strip.isUpdating() #define POT_SMOOTHING 0.25f // smoothing factor for raw potentiometer readings #define POT_SENSITIVITY 4 // changes below this amount are noise (POT scratching, or ADC noise) @@ -165,7 +173,7 @@ void handleAnalog(uint8_t b) //while(strip.isUpdating() && (millis() - wait_started < STRIP_WAIT_TIME)) { // delay(1); //} - //if (strip.isUpdating()) return; // give up + //if (strip.isUpdating()) return; // give up oldRead[b] = aRead; @@ -326,7 +334,7 @@ void esp32RMTInvertIdle() void handleIO() { handleButton(); - + //set relay when LEDs turn on if (strip.getBrightness()) { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index e2527581e..a547642e5 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -64,7 +64,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (apHide > 1) apHide = 1; CJSON(apBehavior, ap[F("behav")]); - + /* JsonArray ap_ip = ap["ip"]; for (byte i = 0; i < 4; i++) { @@ -136,7 +136,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { #endif JsonArray ins = hw_led["ins"]; - + if (fromFS || !ins.isNull()) { uint8_t s = 0; // bus iterator if (fromFS) busses.removeAll(); // can't safely manipulate busses directly in network callback @@ -210,14 +210,14 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { btnPin[s] = pin; #ifdef ARDUINO_ARCH_ESP32 // ESP32 only: check that analog button pin is a valid ADC gpio - if (((buttonType[s] == BTN_TYPE_ANALOG) || (buttonType[s] == BTN_TYPE_ANALOG_INVERTED)) && (digitalPinToAnalogChannel(btnPin[s]) < 0)) + if (((buttonType[s] == BTN_TYPE_ANALOG) || (buttonType[s] == BTN_TYPE_ANALOG_INVERTED)) && (digitalPinToAnalogChannel(btnPin[s]) < 0)) { // not an ADC analog pin DEBUG_PRINTF("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n", btnPin[s], s); btnPin[s] = -1; pinManager.deallocatePin(pin,PinOwner::Button); - } - else + } + else #endif { if (disablePullUp) { @@ -253,7 +253,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { // relies upon only being called once with fromFS == true, which is currently true. uint8_t s = 0; if (pinManager.allocatePin(btnPin[0], false, PinOwner::Button)) { // initialized to #define value BTNPIN, or zero if not defined(!) - ++s; // do not clear default button if allocated successfully + ++s; // do not clear default button if allocated successfully } for (; s 510) DMXAddress = 1; + CJSON(DMXSegmentSpacing, if_live_dmx[F("dss")]); + if (DMXSegmentSpacing > 150) DMXSegmentSpacing = 0; CJSON(DMXMode, if_live_dmx["mode"]); tdd = if_live[F("timeout")] | -1; @@ -497,7 +499,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { uint8_t it = 0; for (JsonObject timer : timers) { if (it > 9) break; - if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset + if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset CJSON(timerHours[it], timer[F("hour")]); CJSON(timerMinutes[it], timer["min"]); CJSON(timerMacro[it], timer["macro"]); @@ -864,6 +866,7 @@ void serializeConfig() { if_live_dmx[F("uni")] = e131Universe; if_live_dmx[F("seqskip")] = e131SkipOutOfSequence; if_live_dmx[F("addr")] = DMXAddress; + if_live_dmx[F("dss")] = DMXSegmentSpacing; if_live_dmx["mode"] = DMXMode; if_live[F("timeout")] = realtimeTimeoutMs / 100; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 0387a925a..5ab8a6f37 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -91,7 +91,7 @@ void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc r = round(329.698727446 * pow((temp - 60), -0.1332047592)); g = round(288.1221695283 * pow((temp - 60), -0.0755148492)); b = 255; - } + } //g += 12; //mod by Aircoookie, a bit less accurate but visibly less pinkish rgb[0] = (uint8_t) constrain(r, 0, 255); rgb[1] = (uint8_t) constrain(g, 0, 255); @@ -194,7 +194,7 @@ void colorFromDecOrHexString(byte* rgb, char* in) if (in[0] == 0) return; char first = in[0]; uint32_t c = 0; - + if (first == '#' || first == 'h' || first == 'H') //is HEX encoded { c = strtoul(in +1, NULL, 16); diff --git a/wled00/const.h b/wled00/const.h index 25056b660..cb2353f20 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -169,10 +169,14 @@ #define DMX_MODE_DISABLED 0 //not used #define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels) #define DMX_MODE_SINGLE_DRGB 2 //all LEDs same RGB color and master dimmer (4 channels) -#define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (11 channels) +#define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (15 channels) +#define DMX_MODE_EFFECT_W 7 //trigger standalone effects of WLED (18 channels) #define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels) #define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels) #define DMX_MODE_MULTIPLE_RGBW 6 //every LED is addressed with its own RGBW (ledCount * 4 channels) +#define DMX_MODE_EFFECT_SEGMENT 8 //trigger standalone effects of WLED (15 channels per segement) +#define DMX_MODE_EFFECT_SEGMENT_W 9 //trigger standalone effects of WLED (18 channels per segement) +#define DMX_MODE_PRESET 10 //apply presets (1 channel) //Light capability byte (unused) 0bRCCCTTTT //bits 0/1/2/3: specifies a type of LED driver. A single "driver" may have different chip models but must have the same protocol/behavior @@ -309,7 +313,7 @@ #define NTP_PACKET_SIZE 48 -//maximum number of rendered LEDs - this does not have to match max. physical LEDs, e.g. if there are virtual busses +//maximum number of rendered LEDs - this does not have to match max. physical LEDs, e.g. if there are virtual busses #ifndef MAX_LEDS #ifdef ESP8266 #define MAX_LEDS 1664 //can't rely on memory limit to limit this to 1600 LEDs @@ -338,7 +342,7 @@ #ifdef ESP8266 #define SETTINGS_STACK_BUF_SIZE 2048 #else -#define SETTINGS_STACK_BUF_SIZE 3096 +#define SETTINGS_STACK_BUF_SIZE 3096 #endif #ifdef WLED_USE_ETHERNET diff --git a/wled00/data/index.css b/wled00/data/index.css index 843d478f4..9a2e26427 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -436,6 +436,9 @@ button { left: 50%; margin-left: -92px; + /* Ensure tooltip goes away when mouse leaves control */ + pointer-events: none; + /* Fade in tooltip */ opacity: 0; transition: opacity 0.75s; @@ -865,8 +868,8 @@ select { transition-duration: 0.5s; -webkit-backface-visibility: hidden; -webkit-transform:translate3d(0,0,0); - -webkit-appearance: none; - -moz-appearance: none; + -webkit-appearance: none; + -moz-appearance: none; backface-visibility: hidden; transform:translate3d(0,0,0); text-overflow: ellipsis; @@ -890,8 +893,8 @@ div.sel-p:after { position: absolute; right: 10px; top: 22px; - width: 0; - height: 0; + width: 0; + height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 8px solid var(--c-f); @@ -1221,7 +1224,7 @@ TD .checkmark, TD .radiomark { line-height: 24px; vertical-align: middle; -webkit-filter: grayscale(100%); /* Safari 6.0 - 9.0 */ - filter: grayscale(100%); + filter: grayscale(100%); } .lbl-l { @@ -1331,7 +1334,7 @@ TD .checkmark, TD .radiomark { white-space: nowrap; text-overflow: ellipsis; -webkit-filter: grayscale(100%); /* Safari 6.0 - 9.0 */ - filter: grayscale(100%); + filter: grayscale(100%); } /* list item palette preview */ @@ -1362,7 +1365,7 @@ TD .checkmark, TD .radiomark { background: var(--c-2); border: 1px solid var(--c-3); -webkit-filter: grayscale(100%); /* Safari 6.0 - 9.0 */ - filter: grayscale(100%); + filter: grayscale(100%); } .fnd input[type="text"]:focus { diff --git a/wled00/data/index.js b/wled00/data/index.js index 2f8e905f7..131fd1226 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -807,7 +807,7 @@ function populateSegments(s) if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value) 1) ? "block":"none"; // rsbtn parent - if (Array.isArray(li.maps) && li.maps.length>1) { + if (!isM && Array.isArray(li.maps) && li.maps.length>1) { let cont = `Ledmap: "; @@ -837,7 +837,7 @@ function populateEffects() }); for (let ef of effects) { - // WLEDSR: add slider and color control to setFX (used by requestjson) + // add slider and color control to setFX (used by requestjson) let id = ef.id; let nm = ef.name+" "; let fd = ""; @@ -1362,7 +1362,7 @@ function readState(s,command=false) return true; } -// WLEDSR: control HTML elements for Slider and Color Control +// control HTML elements for Slider and Color Control (original ported form WLED-SR) // Technical notes // =============== // If an effect name is followed by an @, slider and color control is effective. @@ -1485,6 +1485,14 @@ function setEffectParameters(idx) pall.innerHTML = ' Color palette not used'; palw.style.display = "none"; } + // not all color selectors shown, hide palettes created from color selectors + // NOTE: this will disallow user to select "* Color ..." palettes which may be undesirable in some cases or for some users + //for (let e of (gId('pallist').querySelectorAll('.lstI')||[])) { + // let fltr = "* C"; + // if (cslCnt==1 && csel==0) fltr = "* Colors"; + // else if (cslCnt==2) fltr = "* Colors Only"; + // if (cslCnt < 3 && e.querySelector('.lstIname').innerText.indexOf(fltr)>=0) e.classList.add('hide'); else e.classList.remove('hide'); + //} } var jsonTimeout; @@ -1840,7 +1848,7 @@ ${makePlSel(plJson[i].end?plJson[i].end:0, true)} `; - if (Array.isArray(lastinfo.maps) && lastinfo.maps.length>1) { + if (!isM && Array.isArray(lastinfo.maps) && lastinfo.maps.length>1) { content += `
Ledmap: 
"; diff --git a/wled00/data/settings.htm b/wled00/data/settings.htm index 3032959dd..dc8e3838f 100644 --- a/wled00/data/settings.htm +++ b/wled00/data/settings.htm @@ -68,9 +68,9 @@ - + - + diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 20b8de8d0..45eb49800 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -9,6 +9,10 @@ var d=document,laprev=55,maxB=1,maxV=0,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32 var customStarts=false,startsDirty=[],maxCOOverrides=5; var loc = false, locip; + d.um_p = []; + d.rsvd = []; + d.ro_gpio = []; + d.max_gpio = 39; function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");} function B(){window.open("/settings","_self");} function gId(n){return d.getElementById(n);} @@ -23,10 +27,6 @@ // success event scE.addEventListener("load", () => { //console.log("File loaded"); - d.um_p = []; - d.rsvd = []; - d.ro_pins = []; - d.max_gpio = 39; GetV();checkSi();setABL(); if (d.um_p[0]==-1) d.um_p.shift(); }); @@ -66,7 +66,7 @@ for (k=0;ke==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);LCs[i].value="";LCs[i].focus();return false;} - else if (!(nm == "IR" || nm=="BT") && d.ro_pins.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);LCs[i].value="";LCs[i].focus();return false;} + else if (!(nm == "IR" || nm=="BT") && d.ro_gpio.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);LCs[i].value="";LCs[i].focus();return false;} for (j=i+1; j
Reboot required. Check out LedFx!
Skip out-of-sequence packets:
DMX start address:
+DMX segment spacing:
DMX mode:
E1.31 info
Timeout: ms
diff --git a/wled00/data/settings_um.htm b/wled00/data/settings_um.htm index aac373bce..94c26fd3e 100644 --- a/wled00/data/settings_um.htm +++ b/wled00/data/settings_um.htm @@ -7,6 +7,10 @@ Usermod Settings